ditty.bpm = 50;
// --- Definir sintetizador de onda cuadrada ---
const square = synth.def((phase, env, tick, options) => {
const wave = (phase % 1 < 0.5) ? 1 : -1;
return wave * env.value;
});
// --- Convertir tus notas a array ---
const notes = [
[0.00000, 42.0, 0.12500],
[0.12500, 42.0, 0.25000],
[0.25000, 38.0, 0.37500],
[0.37500, 35.0, 0.50000],
[0.68750, 35.0, 0.81250],
[1.00000, 40.0, 1.12500],
[1.31250, 40.0, 1.43750],
[1.62500, 40.0, 1.75000],
[1.78125, 44.0, 1.90625],
[1.90625, 44.0, 2.03125],
[2.03125, 45.0, 2.15625],
[2.15625, 47.0, 2.28125],
[2.28125, 45.0, 2.40625],
[2.40625, 45.0, 2.53125],
[2.53125, 45.0, 2.65625],
[2.65625, 40.0, 2.78125],
[2.96875, 38.0, 3.09375],
[3.28125, 42.0, 3.40625],
[3.59375, 42.0, 3.71875],
[3.90625, 42.0, 4.03125],
[4.03125, 40.0, 4.15625],
[4.15625, 40.0, 4.28125],
[4.28125, 42.0, 4.40625],
[4.40625, 40.0, 4.53125],
[4.53125, 42.0, 4.65625],
[4.65625, 42.0, 4.78125],
[4.78125, 38.0, 4.90625],
[5.09375, 35.0, 5.21875],
[5.40625, 35.0, 5.53125],
[5.71875, 40.0, 5.84375],
[6.03125, 40.0, 6.15625],
[6.34375, 40.0, 6.46875],
[6.46875, 44.0, 6.59375],
[6.59375, 44.0, 6.71875],
[6.71875, 45.0, 6.84375],
[6.84375, 47.0, 6.96875],
[6.96875, 45.0, 7.09375],
[7.09375, 45.0, 7.21875],
[7.21875, 45.0, 7.34375],
[7.34375, 40.0, 7.46875],
[7.65625, 38.0, 7.78125],
[7.96875, 42.0, 8.09375],
[8.28125, 42.0, 8.40625],
[8.59375, 42.0, 8.71875],
[8.71875, 40.0, 8.84375],
[8.84375, 40.0, 8.96875],
[8.96875, 42.0, 9.09375],
[9.09375, 40.0, 9.21875],
[9.21875, 23.0, 10.21875],
[9.21875, 42.0, 9.34375],
[9.34375, 42.0, 9.46875],
[9.46875, 38.0, 9.59375],
[9.59375, 35.0, 9.71875],
[9.90625, 35.0, 10.03125],
[10.15625, 40.0, 10.28125],
[10.28125, 28.0, 11.28125],
[10.40625, 40.0, 10.53125],
[10.71875, 40.0, 10.84375],
[10.84375, 44.0, 10.96875],
[10.96875, 44.0, 11.09375],
[11.09375, 45.0, 11.21875],
[11.21875, 47.0, 11.34375],
[11.34375, 21.0, 12.34375],
[11.34375, 45.0, 11.46875],
[11.46875, 45.0, 11.59375],
[11.59375, 45.0, 11.71875],
[11.71875, 40.0, 11.84375],
[12.03125, 38.0, 12.15625],
[12.28125, 42.0, 12.40625],
[12.40625, 26.0, 13.53125],
[12.59375, 42.0, 12.71875],
[12.90625, 42.0, 13.03125],
[13.03125, 40.0, 13.53125],
[13.65625, 23.0, 14.65625],
[13.65625, 50.0, 14.03125],
[14.09375, 50.0, 14.34375],
[14.40625, 49.0, 14.53125],
[14.53125, 47.0, 15.71875],
[14.71875, 28.0, 15.71875],
[15.78125, 21.0, 17.03125],
[15.78125, 49.0, 15.90625],
[15.90625, 49.0, 16.15625],
[16.21875, 49.0, 16.46875],
[16.53125, 45.0, 17.03125],
[17.09375, 26.0, 18.28125],
[17.28125, 54.0, 17.53125],
[17.59375, 54.0, 17.71875],
[17.71875, 54.0, 17.96875],
[18.03125, 52.0, 18.28125],
[18.34375, 23.0, 19.53125],
[18.34375, 50.0, 18.84375],
[18.90625, 50.0, 19.03125],
[19.03125, 50.0, 19.15625],
[19.15625, 49.0, 19.40625],
[19.46875, 47.0, 20.46875],
[19.59375, 28.0, 20.78125],
[20.71875, 47.0, 20.84375],
[20.84375, 21.0, 21.90625],
[20.84375, 49.0, 21.09375],
[21.15625, 50.0, 21.28125],
[21.28125, 49.0, 21.53125],
[21.59375, 47.0, 21.84375],
[21.90625, 45.0, 22.21875],
[22.06250, 26.0, 23.31250],
[22.25000, 47.0, 22.50000],
[22.56250, 49.0, 22.68750],
[22.68750, 47.0, 22.93750],
[23.00000, 45.0, 23.62500],
[23.37500, 23.0, 24.50000],
[23.68750, 50.0, 23.93750],
[24.00000, 50.0, 24.25000],
[24.31250, 50.0, 24.43750],
[24.43750, 50.0, 25.56250],
[24.56250, 28.0, 25.56250],
[25.62500, 30.0, 26.56250],
[25.87500, 45.0, 26.00000],
[26.00000, 45.0, 26.12500],
[26.12500, 45.0, 26.25000],
[26.25000, 45.0, 26.37500],
[26.37500, 45.0, 26.50000],
[26.50000, 45.0, 26.62500],
[26.62500, 26.0, 26.93750],
[26.62500, 26.0, 27.62500],
[26.62500, 45.0, 26.75000],
[26.75000, 44.0, 27.12500],
[27.18750, 44.0, 27.25000],
[27.28125, 42.0, 27.65625],
[27.71875, 33.0, 28.71875],
[27.71875, 45.0, 28.71875],
[28.78125, 32.0, 29.78125],
[28.78125, 56.0, 29.78125],
[29.84375, 30.0, 30.78125],
[29.84375, 57.0, 30.78125]
];
// Ordenar por tiempo de inicio (por seguridad)
notes.sort((a, b) => a[0] - b[0]);
let noteIndex = 0;
const totalDuration = notes.length > 0 ? notes[notes.length - 1][2] : 32;
// --- Loop principal ---
loop(() => {
let currentTime = 0;
const timeStep = 0.03125; // 1/32 de nota → alta resolución
while (currentTime <= totalDuration) {
// Reproducir todas las notas que comienzan en este instante
while (
noteIndex < notes.length &&
Math.abs(notes[noteIndex][0] - currentTime) < 1e-4
) {
const [start, midi, end] = notes[noteIndex];
const duration = end - start;
square.play(midi, {
duration: duration, // en ticks (beats)
attack: 0.005, // en segundos
release: 0.08, // en segundos
amp: 0.65
});
noteIndex++;
}
sleep(timeStep);
currentTime += timeStep;
}
// Reiniciar para repetir la canción
noteIndex = 0;
}, { name: "Take On Me - Full" });