ditty.bpm = 126;
// --- 1. DÉFINITION DES SYNTHÉTISSEURS (UNE SEULE FOIS) ---
// Le Choeur "Freddie/Bowie"
const vocalSynth = synth.def((phase, env, tick, options) => {
const vibrato = Math.sin(tick * 30) * 0.002;
const v = Math.sin((phase + vibrato) * 2 * Math.PI) +
Math.sin((phase * 2 + vibrato) * 2 * Math.PI) * 0.5;
return v * env.value;
}, { attack: 0.5, release: 1 });
// Synthé Rock saturé (Ziggy)
const ziggySynth = synth.def(class {
constructor() { this.v0 = 0; }
process(phase, env) {
let v = (phase % 1) < 0.5 ? 1 : -1;
this.v0 += 0.3 * (v - this.v0);
return Math.tanh(this.v0 * 5) * env.value;
}
}, { attack: 0.05, release: 0.3 });
// Basse "Deacon" (Queen)
const deaconBass = synth.def((phase, env) => {
return Math.sin(phase * 2 * Math.PI) * env.value;
}, { attack: 0.01, release: 0.15 });
const powerKick = synth.def((phase, env, tick) => {
return Math.sin(phase * 2 * Math.PI * (1 + Math.exp(-tick * 15) * 6)) * env.value;
}, { attack: 0.001, release: 0.3 });
const noiseSynth = synth.def((phase, env) => (Math.random() * 2 - 1) * env.value, { attack: 0.001, release: 0.1 });
// --- 2. EFFETS ---
const GrandEcho = filter.def(class {
constructor(options) {
this.buffer = new Float32Array(options.time * ditty.sampleRate);
this.ptr = 0; this.fb = options.fb;
}
process(input) {
let out = input + this.buffer[this.ptr] * this.fb;
this.buffer[this.ptr] = out;
this.ptr = (this.ptr + 1) % this.buffer.length;
return out;
}
}, { time: 0.375, fb: 0.5 });
// --- 3. SÉQUENÇAGE (CYCLES DE 128 TEMPS) ---
// Batterie et final
loop((i) => {
const totalCycle = ditty.tick % 128;
const isFinal = totalCycle > 96;
if (totalCycle < 112) {
powerKick.play(c2, { amp: isFinal ? 1.5 : 1.1 });
}
if (isFinal) {
const speed = totalCycle > 112 ? 0.125 : 0.25;
noiseSynth.play(c4, { amp: (totalCycle - 96) / 32 });
sleep(speed);
} else {
sleep(1);
}
}, { name: 'drums' });
// Basse (Correction faite ici)
loop((i) => {
const totalCycle = ditty.tick % 128;
if (totalCycle < 120) {
const notes = [c2, c2, f2, g2];
const n = notes[i % notes.length];
// On appelle deaconBass.play et non synth.play
deaconBass.play(n, { amp: 0.6, release: 0.2 });
}
sleep(0.5);
}, { name: 'bass' });
// Voix (Entrent à 64 temps)
loop((i) => {
const totalCycle = ditty.tick % 128;
if (totalCycle > 64) {
const harmony = [c4, e4, g4, c5];
const note = harmony[i % harmony.length];
vocalSynth.play(note, {
amp: 0.15 + (totalCycle / 128 * 0.2),
filter: GrandEcho
});
}
sleep(2);
}, { name: 'voices' });
// Explosion Finale
loop((i) => {
const totalCycle = ditty.tick % 128;
if (totalCycle >= 120) {
[c3, e3, g3, c4].forEach(n => ziggySynth.play(n, { amp: 0.3 }));
noiseSynth.play(c4, { amp: 1, release: 4 });
}
sleep(8);
}, { name: 'explosion' });