Axel F-Beverly Hills Cop-v2

Axel F-Beverly Hills Cop-v2

Log in to post a comment.

//Axel F-Beverly Hills Cop-v2

ditty.bpm = 35;

// --- Sintetizadores ---
// Melodía: sierra brillante
const lead = synth.def((phase, env, tick, opt) => 
{
   // Normalizar fase a 0..1
  //const ph = (phase / (2 * Math.PI)) % 1.0;
        
  const wave = 2 * (phase % 1) - 1; // saw
  return wave * env.value;
});

// Bajo: cuadrada gruesa + más sustain
const bass = synth.def((phase, env, tick, opt) => {
  const wave = (phase % 1 < 0.5) ? 1 : -1; // square
  return wave * env.value;
});

// Kick: ruido con pitch descendente (simulación simple)
const kick = synth.def((phase, env, tick, opt) => {
  const t = tick; // tiempo real estable en Dittytoy

  // Evitar valores inválidos
  const freq = Math.max(20, 150 - t * 300);

  const s = Math.sin(t * freq * 2.0 * Math.PI);

  // Protecciones contra NaN
  if (isNaN(s)) return 0;

  return s * env.value * 0.9;
});

// Hi-hat: ruido blanco corto
const hihat = synth.def((phase, env, tick, opt) => {
  return (Math.random() * 2 - 1) * env.value * 0.4;
});


// === MELODÍA PRINCIPAL (tu secuencia original) ===
const leadNotes = [
  [0.00000, 53.0, 0.25000],
  [0.25000, 56.0, 0.43750],
  [0.43750, 53.0, 0.56250],
  [0.56250, 53.0, 0.62500],
  [0.62500, 58.0, 0.75000],
  [0.75000, 53.0, 0.87500],
  [0.87500, 51.0, 1.00000],
  [1.00000, 53.0, 1.25000],
  [1.25000, 60.0, 1.43750],
  [1.43750, 53.0, 1.56250],
  [1.56250, 53.0, 1.62500],
  [1.62500, 61.0, 1.75000],
  [1.75000, 60.0, 1.87500],
  [1.87500, 56.0, 2.00000],
  [2.00000, 53.0, 2.12500],
  [2.12500, 60.0, 2.25000],
  [2.25000, 65.0, 2.37500],
  [2.37500, 53.0, 2.43750],
  [2.43750, 51.0, 2.56250],
  [2.56250, 51.0, 2.62500],
  [2.62500, 48.0, 2.75000],
  [2.75000, 55.0, 2.87500],
  [2.87500, 53.0, 3.62500],
  [4.37500, 53.0, 4.62500],
  [4.62500, 56.0, 4.81250],
  [4.81250, 53.0, 4.93750],
  [4.93750, 53.0, 5.00000],
  [5.00000, 58.0, 5.12500],
  [5.12500, 53.0, 5.25000],
  [5.25000, 51.0, 5.37500],
  [5.37500, 53.0, 5.62500],
  [5.62500, 60.0, 5.81250],
  [5.81250, 53.0, 5.93750],
  [5.93750, 53.0, 6.00000],
  [6.00000, 61.0, 6.12500],
  [6.12500, 60.0, 6.25000],
  [6.25000, 56.0, 6.37500],
  [6.37500, 53.0, 6.50000],
  [6.50000, 60.0, 6.62500],
  [6.62500, 65.0, 6.75000],
  [6.75000, 53.0, 6.81250],
  [6.81250, 51.0, 6.93750],
  [6.93750, 51.0, 7.00000],
  [7.00000, 48.0, 7.12500],
  [7.12500, 55.0, 7.25000],
  [7.25000, 53.0, 8.00000],
  [8.00000, 29.0, 8.25000],
  [8.25000, 41.0, 8.43750],
  [8.43750, 27.0, 8.56250],
  [8.56250, 39.0, 8.62500],
  [8.62500, 24.0, 8.75000],
  [8.75000, 36.0, 8.87500],
  [8.87500, 27.0, 9.00000],
  [9.00000, 29.0, 9.25000],
  [9.25000, 41.0, 9.43750],
  [9.62500, 24.0, 9.68750],
  [9.68750, 36.0, 9.81250],
  [9.81250, 39.0, 9.93750],
  [9.93750, 41.0, 10.06250],
  [10.06250, 25.0, 10.31250],
  [10.31250, 37.0, 10.50000],
  [10.50000, 27.0, 10.62500],
  [10.62500, 39.0, 10.68750],
  [10.68750, 24.0, 10.81250],
  [10.81250, 36.0, 10.93750],
  [10.93750, 27.0, 11.06250],
  [11.06250, 29.0, 11.31250]
];

// === LÍNEA DE BAJO (basada en la progresión de acordes: Fm - C - Ab - Bb) ===
const bassNotes = [
  [0.0, 36, 0.5],    // C2 (raíz de C)
  [0.5, 41, 1.0],    // F2 (raíz de Fm)
  [1.0, 36, 1.5],
  [1.5, 41, 2.0],
  [2.0, 36, 2.5],
  [2.5, 41, 3.0],
  [3.0, 43, 4.0],    // Ab2 (raíz de Ab)
  [4.0, 36, 4.5],
  [4.5, 41, 5.0],
  [5.0, 36, 5.5],
  [5.5, 41, 6.0],
  [6.0, 36, 6.5],
  [6.5, 41, 7.0],
  [7.0, 43, 8.0],
  [8.0, 36, 8.5],
  [8.5, 41, 9.0],
  [9.0, 36, 9.5],
  [9.5, 41, 10.0],
  [10.0, 36, 10.5],
  [10.5, 41, 11.0],
  [11.0, 43, 12.0]
];

// === PERCUSIÓN (patrón de 2 compases: kick en 1 y 3, hi-hat en corcheas) ===
const percNotes = [];
const loopLength = 8.0; // 2 compases de 4/4 a 120 BPM = 8 beats
for (let t = 0; t < 12; t += 0.25) {
  // Hi-hat en cada 1/4 nota
  percNotes.push({ type: 'hat', time: t, dur: 0.05 });
  // Kick en tiempos 0, 2, 4, 6...
  if (t % 2 === 0) {
    percNotes.push({ type: 'kick', time: t, dur: 0.3 });
  }
}
// Añadir un extra kick en el compás 2 (como en la canción)
percNotes.push({ type: 'kick', time: 2.5, dur: 0.2 });


// --- Combinar y ordenar todo ---
// Convertir a formato común y mezclar
const allEvents = [];

// Añadir melodía
leadNotes.forEach(([start, midi, end]) => {
  allEvents.push({ time: start, type: 'lead', midi, dur: end - start });
});

// Añadir bajo
bassNotes.forEach(([start, midi, end]) => {
  allEvents.push({ time: start, type: 'bass', midi, dur: end - start });
});

// Añadir percusión
percNotes.forEach(e => {
  allEvents.push({ time: e.time, type: e.type, dur: e.dur });
});

// Ordenar por tiempo
allEvents.sort((a, b) => a.time - b.time);

// --- Loop principal ---
loop(() => {
  let currentTime = 0;
  const minStep = 0.0625; // 1/16
  let eventIndex = 0;

  const totalDuration = Math.max(...allEvents.map(e => e.time + e.dur)) + 0.5;

  while (currentTime <= totalDuration) {
    // Disparar eventos en este instante
    while (
      eventIndex < allEvents.length &&
      Math.abs(allEvents[eventIndex].time - currentTime) < 1e-5
    ) {
      const ev = allEvents[eventIndex];

      if (ev.type === 'lead') {
        lead.play(ev.midi+24, {
          duration: ev.dur,
          attack: 0.01,
          decay: 0.15,
          sustain: 0.2,
          release: 0.1,
          amp: 0.7
        });
      } else if (ev.type === 'bass') {
        bass.play(ev.midi, {
          duration: ev.dur,
          attack: 0.02,
          decay: 0.3,
          sustain: 0.4,
          release: 0.2,
          amp: 0.85
        });
      } else if (ev.type === 'kick') {
        kick.play(0, { // nota no importa, pitch interno
          duration: ev.dur,
          attack: 0.01,
          //decay: ev.dur - 0.02,
          decay: Math.max(0.01, ev.dur - 0.02),
          sustain: 0,
          release: 0.05,
          amp: 0.9
        });
      } else if (ev.type === 'hat') {
        hihat.play(0, {
          duration: ev.dur,
          attack: 0.001,
          decay: ev.dur,
          sustain: 0,
          release: 0.02,
          amp: 0.5
        });
      }

      eventIndex++;
    }

    sleep(minStep);
    currentTime += minStep;
  }

  // Reiniciar
  eventIndex = 0;
}, { name: 'Axel F - Full Version (Bass+D)' });