BGM


<button onclick="startMusic()">๐ŸŽต ์Œ์•… ์‹œ์ž‘</button>

<script>
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
let isPlaying = false;

function playNote(freq, startTime, duration = 0.2, type = 'sine', volume = 0.3) {
const osc = audioCtx.createOscillator();
const gain = audioCtx.createGain();

osc.type = type;
osc.frequency.value = freq;

gain.gain.setValueAtTime(volume, startTime);
gain.gain.exponentialRampToValueAtTime(0.001, startTime + duration);

osc.connect(gain);
gain.connect(audioCtx.destination);

osc.start(startTime);
osc.stop(startTime + duration);
}

function scheduleRhythm(startTime, tempo, measures = 8) {
const beatTime = 60 / tempo;
const totalBeats = measures * 4;

for (let i = 0; i < totalBeats; i++) {
const t = startTime + i * beatTime;

if (i % 4 === 0) playNote(100, t, 0.1, 'square', 0.4); // Kick
if (i % 4 === 2) playNote(180, t, 0.1, 'triangle', 0.2); // Snare

const bassNotes = [130.81, 196.00, 220.00, 174.61]; // C-G-A-F
const bassFreq = bassNotes[Math.floor(i / 8) % 4];
if (i % 2 === 0) playNote(bassFreq, t, 0.2, 'sawtooth', 0.3);
}

return totalBeats * beatTime;
}

function scheduleMelodyPhase(startTime, tempo) {
const beat = 60 / tempo;

// Phase 1: ๊ธฐ - ๋‹จ์ˆœํ•˜๊ณ  ์•ˆ์ •์ ์ธ ๋ฉœ๋กœ๋”” (C E G ๋ฐ˜๋ณต)
[[523.25, 0], [659.25, 1], [783.99, 2], [659.25, 3]].forEach(([f, i]) =>
playNote(f, startTime + i * beat, 0.3, 'triangle', 0.2)
);

// Phase 2: ์Šน - ์Œ ์˜ฌ๋ผ๊ฐ€๊ณ  ์†๋„ ๋นจ๋ผ์ง
[[659.25, 4], [698.46, 4.5], [783.99, 5], [880.00, 5.5], [987.77, 6], [880.00, 6.5]].forEach(([f, i]) =>
playNote(f, startTime + i * beat, 0.2, 'triangle', 0.25)
);

// Phase 3: ์ „ - ๊ฐ•๋ ฌํ•˜๊ฒŒ! 16๋ถ„์Œํ‘œ ๋А๋‚Œ
[880.00, 987.77, 1046.50, 1174.66].forEach((f, idx) =>
playNote(f, startTime + (7 + idx * 0.25) * beat, 0.15, 'triangle', 0.25)
);

// Phase 4: ๊ฒฐ - ์ฒ˜์Œ ๋ฉœ๋กœ๋””์˜ ๋ณ€ํ˜•, ๋‚ฎ์•„์ง€๋ฉฐ ์•ˆ์ •๊ฐ
[[783.99, 8], [659.25, 9], [587.33, 10], [523.25, 11]].forEach(([f, i]) =>
playNote(f, startTime + i * beat, 0.25, 'triangle', 0.2)
);
}

function startMusic() {
if (isPlaying) return;
isPlaying = true;

const tempo1 = 120;
const tempo2 = 160;
const now = audioCtx.currentTime;

const dur1 = scheduleRhythm(now, tempo1, 8);
scheduleMelodyPhase(now, tempo1); // ๐ŸŽต ๊ธฐ์Šน์ „๊ฒฐ ๋ฉœ๋กœ๋””

function loopFastPart(start) {
const dur2 = scheduleRhythm(start, tempo2, 8);
scheduleMelodyPhase(start, tempo2);
setTimeout(() => loopFastPart(start + dur2), dur2 * 1000);
}

setTimeout(() => loopFastPart(now + dur1), dur1 * 1000);
}
</script>