Музыка, которую сочиняет браузер
Захотелось, чтобы в игре была фоновая музыка, но без файлов и без повторяющейся петли, которая надоедает к третьей партии. В итоге мелодию придумывает сам браузер, каждый раз немного по-новому.
Из чего она собрана
- Бас ходит по четырём нотам: ля, фа, соль, ми. Каждая звучит один такт.
- Мелодия берёт ноты из ля-минорной пентатоники. В ней нет полутонов, поэтому любые две соседние ноты звучат прилично, даже если выбраны случайно.
- Следующая нота мелодии отходит от предыдущей на одну-две ступени вверх или вниз. Без этого получаются скачки через октаву, и это уже не музыка, а будильник.
var PENTA = [0, 3, 5, 7, 10, 12, 15, 17];
var BASS = [45, 41, 43, 40];
music.note = clamp(music.note + [-2, -1, 1, 2][Math.floor(Math.random() * 4)], 0, PENTA.length - 1);
toneAt(midi(69 + PENTA[music.note]), beat * 0.9, 'triangle', 0.02, music.next);Иногда нота пропускается, и в мелодии появляются паузы. Ночью и в грозу пауз больше, а громкость ниже.
Почему не setInterval
Если играть ноты по таймеру JavaScript, ритм плывёт: таймер срабатывает то раньше, то позже, особенно когда браузер занят отрисовкой. Поэтому ноты планируются заранее по часам самого звукового движка, примерно на 150 мс вперёд:
while (music.next < audio.currentTime + 0.15) {
// запланировать ноту ровно на music.next
music.next += beat;
}Функция вызывается каждый кадр игры. Когда игра на паузе, кадров нет, и музыка замолкает сама, отдельно её останавливать не нужно.
Темп
Темп растёт вместе с уровнем, а во время тыгыдыка ускоряется ещё в полтора раза. Получается, что музыка подсказывает, как сейчас идут дела.
По умолчанию музыка выключена: кто открыл сайт на работе, не обрадуется внезапному звуку. Кнопка «музыка» под полем запоминает выбор.