import { createRng, type MusicSpec, type NoteEvent } from '@rpg/engine';
/**
* Музыкальные темы: правило-базовый генератор (детерминированный, сиды) +
* компиляция движковым секвенсором (renderMusic → playLoopBuffer) прямо
* в рантайме — WAV-файлов для музыки нет. Тема лугов — пепельная
* ля-минорная пентатоника: пэд-дрон + редкая плак-мелодия восьмыми.
*/
/** Ля-минорная пентатоника от A3 (A C D E G + октава). */
const PENTATONIC = [57, 60, 62, 64, 67, 69, 72] as const;
/** Дрон-пэд: тоника/субмедианта по половинам лупа. */
function drone(from: number, to: number, beats: number): NoteEvent[] {
return [
{ beat: 0, dur: beats / 2, midi: from, vel: 0.5 },
{ beat: beats / 2, dur: beats / 2, midi: to, vel: 0.5 }
];
}
/** Мелодия восьмыми с паузами (вероятность ноты 0.55) — сид фиксирует рисунок. */
function melody(seed: number, beats: number): NoteEvent[] {
const rng = createRng(seed);
const notes: NoteEvent[] = [];
for (let eighth = 0; eighth < beats * 2; eighth++) {
if (!rng.chance(0.55)) continue;
notes.push({
beat: eighth * 0.5,
dur: 0.5,
midi: PENTATONIC[Math.floor(rng.next() * PENTATONIC.length)]!,
vel: 0.35 + rng.next() * 0.25
});
}
return notes;
}
/** Тема лугов: 16 долей на 70 bpm, дрон A2→G2 + плак по пентатонике. */
export const MEADOW_THEME: MusicSpec = {
bpm: 70,
beats: 16,
tracks: [
{ instrument: 'pad', notes: drone(45, 43, 16), gain: 0.9 },
{ instrument: 'pluck', notes: melody(20260907, 16) }
]
};
/** Реестр тем (ключ → спек); область ссылается на тему полем `theme`. */
export const THEMES: Record<string, MusicSpec> = {
meadows: MEADOW_THEME
};