Technotronic - Move This-v2

Technotronic - Move This-v2

Log in to post a comment.

ditty.bpm = 50;

// =============== 1. KICK (subgrave) ===============
const kick = synth.def(class {
  constructor() {
    this.phase = 0;
  }
  process(note, env, tick, options) {
    const t = ditty.dt * this.phase++;
    // Frecuencia que decae rápidamente
    const freq = 60 + 200 * Math.exp(-t * 15);
    const wave = Math.sin(2 * Math.PI * freq * t);
    return wave * env.value * 0.9;
  }
});

// =============== 2. HI-HATS ===============
// Hi-hat cerrado (rápido)
const hihatClosed = synth.def((phase, env, tick, options) => {
  // Ruido blanco suavizado
  const noise = Math.random() * 2 - 1;
  // Filtro de paso alto simulado
  const filtered = noise * 0.7 + (noise > 0 ? 1 : -1) * 0.3;
  return filtered * env.value * 0.3;
});

// Hi-hat abierto (más largo)
const hihatOpen = synth.def((phase, env, tick, options) => {
  const noise = Math.random() * 2 - 1;
  return noise * env.value * 0.25;
});

// =============== 3. BAJO (onda cuadrada) ===============
const bass = synth.def((phase, env, tick, options) => {
  const wave = Math.sin(phase) >= 0 ? 1 : -1;
  return wave * env.value * 0.7;
});

// =============== 4. MELODÍA PRINCIPAL (saw + pulse) ===============
const lead = synth.def(class {
  constructor() {
    this.time = 0;
  }
  process(note, env, tick, options) {
    this.time += ditty.dt;
    const t = this.time;
    const freq = 440 * Math.pow(2, (note - 69) / 12);
    
    // Onda de sierra
    const saw = (t * freq) % 1 * 2 - 1;
    // Pulso ancho (25% duty cycle)
    const pulse = ((t * freq) % 1 < 0.25) ? 1 : -1;
    
    const mix = (saw * 0.6 + pulse * 0.4) * env.value;
    return mix * 0.5; // volumen ajustado
  }
});

// =============== 5. NOTAS DEL BAJO ===============
const bassNotes = [
  [0.00000,22.0,0.18750], [0.00000,29.0,0.18750],
  [0.25000,22.0,0.43750], [0.25000,29.0,0.43750],
  [0.50000,22.0,0.62500], [0.50000,29.0,0.62500],
  [0.68750,19.0,0.81250], [0.68750,26.0,0.81250],
  [0.87500,19.0,1.06250], [0.87500,26.0,1.06250],
  [1.06250,15.0,1.18750], [1.06250,22.0,1.18750],
  [1.18750,17.0,1.31250], [1.18750,24.0,1.31250],
  [1.37500,17.0,1.50000], [1.37500,24.0,1.50000],
  [1.56250,17.0,1.62500], [1.56250,24.0,1.62500],
  [1.68750,17.0,1.87500], [1.68750,24.0,1.87500],
  [1.87500,19.0,2.00000], [1.87500,26.0,2.00000],
  [2.00000,22.0,2.12500], [2.00000,29.0,2.12500],
  [2.12500,24.0,2.25000], [2.12500,31.0,2.25000],
  [2.25000,22.0,2.43750], [2.25000,29.0,2.43750],
  [2.50000,22.0,2.62500], [2.50000,29.0,2.62500],
  [2.68750,22.0,2.81250], [2.68750,29.0,2.81250],
  [2.81250,19.0,2.93750], [2.81250,26.0,2.93750],
  [3.00000,19.0,3.18750], [3.00000,26.0,3.18750],
  [3.18750,15.0,3.31250], [3.18750,22.0,3.31250],
  [3.31250,17.0,3.43750], [3.31250,24.0,3.43750],
  [3.50000,17.0,3.62500], [3.50000,24.0,3.62500],
  [3.68750,17.0,3.75000], [3.68750,24.0,3.75000],
  [3.81250,17.0,4.00000], [3.81250,24.0,4.00000],
  [3.96875,19.0,4.09375], [3.96875,26.0,4.09375],
  [4.09375,22.0,4.21875], [4.09375,29.0,4.21875],
  [4.21875,19.0,4.34375], [4.21875,26.0,4.34375],
  [4.34375,22.0,4.46875], [4.34375,29.0,4.46875],
  [4.53125,22.0,4.65625], [4.53125,29.0,4.65625],
  [4.71875,22.0,4.84375], [4.71875,29.0,4.84375],
  [4.84375,19.0,4.96875], [4.84375,26.0,4.96875],
  [5.03125,19.0,5.21875], [5.03125,26.0,5.21875],
  [5.21875,15.0,5.34375], [5.21875,22.0,5.34375],
  [5.34375,17.0,5.46875], [5.34375,24.0,5.46875],
  [5.53125,17.0,5.65625], [5.53125,24.0,5.65625],
  [5.71875,17.0,5.78125], [5.71875,24.0,5.78125],
  [5.84375,17.0,6.03125], [5.84375,24.0,6.03125],
  [6.00000,19.0,6.12500], [6.00000,26.0,6.12500],
  [6.12500,22.0,6.25000], [6.12500,29.0,6.25000],
  [6.25000,24.0,6.37500], [6.25000,31.0,6.37500],
  [6.37500,22.0,6.50000], [6.37500,29.0,6.50000],
  [6.56250,22.0,6.68750], [6.56250,29.0,6.68750],
  [6.75000,22.0,6.87500], [6.75000,29.0,6.87500],
  [6.87500,19.0,7.00000], [6.87500,26.0,7.00000],
  [7.06250,19.0,7.25000], [7.06250,26.0,7.25000],
  [7.25000,15.0,7.37500], [7.25000,22.0,7.37500],
  [7.31250,46.0,7.37500],
  [7.37500,17.0,7.50000], [7.37500,24.0,7.50000],
  [7.56250,17.0,7.68750], [7.56250,24.0,7.68750],
  [7.68750,46.0,7.75000],
  [7.75000,17.0,7.81250], [7.75000,24.0,7.81250], [7.75000,46.0,7.81250],
  [7.87500,17.0,8.06250], [7.87500,24.0,8.06250], [7.87500,46.0,8.06250]
];

// =============== 6. MELODÍA PRINCIPAL (acordes agudos) ===============
const leadNotes = [
  [7.31250,46.0,7.37500],
  [7.68750,46.0,7.75000],
  [7.75000,46.0,7.81250],
  [7.87500,46.0,8.06250],
  [8.15625,46.0,8.21875],
  [8.40625,41.0,8.90625],
  [8.40625,46.0,9.40625],
  [8.78125,46.0,8.84375],
  [8.90625,49.0,9.09375],
  [9.09375,48.0,9.21875]
];

// =============== 7. PATRÓN DE BATERÍA (kick + hats) ===============
// Kick: en tiempos fuertes (0, 2, 4, 6...)
// Hi-hats: cada 1/8 (0.25, 0.5, 0.75, 1.0...)
function playDrums() {
  // Kick en beats 0, 2, 4, 6
  for (let i = 0; i < 8; i += 2) {
    kick.play(0, { duration: 0.25, attack: 0.001, release: 0.2, amp: 1.0 });
    sleep(2);
  }
}

// Programar batería y melodía
loop(() => {
  // === BATERÍA (kick + hi-hats) ===
  const drumEvents = [];
  // Kick en 0, 2, 4, 6
  [0, 2, 4, 6].forEach(t => {
    drumEvents.push({ time: t, type: 'kick' });
  });
  // Hi-hats cerrados cada 0.25 beats (ritmo house)
  for (let t = 0; t < 8; t += 0.25) {
    if (![0, 2, 4, 6].includes(t)) {
      drumEvents.push({ time: t, type: 'closed' });
    }
  }
  // Hi-hats abiertos en offbeats (opcional, para acentos)
  [1.5, 3.5, 5.5, 7.5].forEach(t => {
    drumEvents.push({ time: t, type: 'open' });
  });

  // Ordenar eventos de batería
  drumEvents.sort((a, b) => a.time - b.time);

  // === COMBINAR TODOS LOS EVENTOS ===
  const allEvents = {};

  // Añadir bajo
  bassNotes.forEach(([s, m, e]) => {
    if (!allEvents[s]) allEvents[s] = [];
    allEvents[s].push(() => bass.play(m+48, { duration: e - s, attack: 0.01, release: 0.08, amp: 0.8 }));
  });

  // Añadir melodía
  leadNotes.forEach(([s, m, e]) => {
    if (!allEvents[s]) allEvents[s] = [];
    allEvents[s].push(() => lead.play(m, { duration: e - s, attack: 0.01, release: 0.15, amp: 0.6 }));
  });

  // Añadir batería
  drumEvents.forEach(ev => {
    if (!allEvents[ev.time]) allEvents[ev.time] = [];
    allEvents[ev.time].push(() => {
      if (ev.type === 'kick') kick.play(0, { duration: 0.25, attack: 0.001, release: 0.2, amp: 1.0 });
      else if (ev.type === 'closed') hihatClosed.play(0, { duration: 0.125, attack: 0.001, release: 0.1, amp: 0.5 });
      else if (ev.type === 'open') hihatOpen.play(0, { duration: 0.5, attack: 0.001, release: 0.4, amp: 0.4 });
    });
  });

  // === REPRODUCIR TODO EN ORDEN ===
  const times = Object.keys(allEvents).map(Number).sort((a, b) => a - b);
  let currentTime = 0;

  for (const t of times) {
    if (t > currentTime) {
      sleep(t - currentTime);
      currentTime = t;
    }
    allEvents[t].forEach(fn => fn());
  }

  // Completar compás
  if (currentTime < 8) sleep(8 - currentTime);
}, { name: "Technotronic - Move This (Full Beat)" });