728x90
40음계 피아노
포함 기능:
- 화면에 40개 피아노 건반 표시
- 마우스 클릭 연주
- 키보드 연주 지원
- 8비트 칩튠(square wave) 사운드
- 건반 눌림 애니메이션
- 여러 옥타브 지원
사용 키:
- 1~0
- Q~P
- A~;
- Z~/
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>40음계 8비트 피아노</title>
<style>
body {
margin: 0;
background: #0f172a;
font-family: Arial, sans-serif;
color: white;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100vh;
overflow-x: auto;
}
h1 {
margin-bottom: 10px;
color: #38bdf8;
}
.info {
margin-bottom: 20px;
color: #cbd5e1;
}
.piano {
display: flex;
position: relative;
user-select: none;
}
.key {
width: 48px;
height: 220px;
border: 2px solid #111827;
background: white;
color: black;
display: flex;
align-items: flex-end;
justify-content: center;
padding-bottom: 12px;
box-sizing: border-box;
cursor: pointer;
font-weight: bold;
transition: 0.05s;
}
.key:active,
.key.active {
background: #93c5fd;
transform: translateY(2px);
}
.footer {
margin-top: 20px;
color: #94a3b8;
}
</style>
</head>
<body>
<h1>🎹 40음계 8비트 피아노</h1>
<div class="info">
키보드 또는 마우스로 연주 가능
</div>
<div class="piano" id="piano"></div>
<div class="footer">
1~0 / Q~P / A~; / Z~/ 키 사용
</div>
<script>
const AudioContext = window.AudioContext || window.webkitAudioContext;
const audioCtx = new AudioContext();
const keyboardMap = [
'1','2','3','4','5','6','7','8','9','0',
'q','w','e','r','t','y','u','i','o','p',
'a','s','d','f','g','h','j','k','l',';',
'z','x','c','v','b','n','m',',','.','/'
];
const piano = document.getElementById('piano');
const baseFreq = 130.81; // C3
const notes = {};
keyboardMap.forEach((key, index) => {
const freq = baseFreq * Math.pow(2, index / 12);
notes[key] = freq;
const keyEl = document.createElement('div');
keyEl.className = 'key';
keyEl.dataset.key = key;
keyEl.innerHTML = `<div>${key.toUpperCase()}</div>`;
keyEl.addEventListener('mousedown', async () => {
await audioCtx.resume();
playNote(freq, keyEl);
});
piano.appendChild(keyEl);
});
function playNote(freq, keyEl) {
const now = audioCtx.currentTime;
const osc = audioCtx.createOscillator();
const gain = audioCtx.createGain();
osc.type = 'square';
osc.frequency.setValueAtTime(freq, now);
gain.gain.setValueAtTime(0.25, now);
gain.gain.exponentialRampToValueAtTime(0.001, now + 1);
osc.connect(gain);
gain.connect(audioCtx.destination);
osc.start(now);
osc.stop(now + 1);
keyEl.classList.add('active');
setTimeout(() => {
keyEl.classList.remove('active');
}, 120);
}
document.addEventListener('keydown', async (e) => {
await audioCtx.resume();
const key = e.key.toLowerCase();
if (notes[key]) {
const keyEl = document.querySelector(`[data-key='${key}']`);
playNote(notes[key], keyEl);
}
});
</script>
</body>
</html>728x90
'Software > JavaScript' 카테고리의 다른 글
| javascript시작하기 - 비트박스 (0) | 2026.05.13 |
|---|---|
| Javascript 시작하기 - 그림판 (0) | 2026.05.10 |
| Javascript 시작하기 - ThreeJS로 육각형 그려서 크기 바꾸기#1 (0) | 2026.02.08 |
| Javascript 시작하기 - ThreeJS로 선그리기 #1 (0) | 2026.02.08 |
| 음성 인식 & 출력 예제 #1 (0) | 2026.02.06 |
