2Pac - Changes Piano Sample

2Pac - Changes (Piano Sample

Log in to post a comment.

ditty.bpm = 40; // BPM original ≈ 92

// --- Sintetizador: piano suave tipo Rhodes (onda sinusoidal con sustain largo)
const piano = synth.def((phase, env, tick, opt) => {
  // Onda sinusoidal suave + ligera distorsión armónica sutil
  const sine = Math.sin(phase * 2 * Math.PI);
  // Añadir un armónico suave para dar calidez (como un piano real)
  const harmonic = 0.3 * Math.sin(2 * phase * 2 * Math.PI);
  return (sine + harmonic) * env.value;
});

// --- Convertir PNt a formato [start, midi, end] ---
const notes = [
  [0.00000,24.0,0.25000], [0.00000,28.0,0.25000], [0.00000,33.0,0.25000], [0.00000,52.0,0.25000],
  [0.25000,24.0,0.50000], [0.25000,28.0,0.50000], [0.25000,33.0,0.50000], [0.25000,52.0,0.50000],
  [0.50000,23.0,1.50000], [0.50000,28.0,1.50000], [0.50000,31.0,1.50000], [0.50000,52.0,0.87500],
  [1.50000,57.0,1.56250], [1.56250,55.0,1.62500],
  [1.62500,26.0,2.12500], [1.62500,30.0,2.12500], [1.62500,33.0,2.12500], [1.62500,57.0,1.87500],
  [1.87500,59.0,2.12500],
  [2.12500,24.0,3.12500], [2.12500,28.0,3.12500], [2.12500,31.0,3.12500], [2.12500,55.0,2.50000],
  [2.87500,52.0,3.12500],
  [3.12500,50.0,3.37500],
  [3.37500,23.0,4.00000], [3.37500,26.0,4.00000], [3.37500,31.0,4.00000], [3.37500,43.0,3.62500],
  [3.62500,45.0,3.75000], [3.75000,50.0,3.87500], [3.87500,55.0,4.00000],
  [4.00000,57.0,4.12500],
  [4.12500,26.0,4.75000], [4.12500,30.0,4.75000], [4.12500,33.0,4.75000], [4.12500,54.0,4.37500],
  [4.37500,52.0,4.50000], [4.50000,54.0,4.75000], [4.75000,52.0,4.87500],
  [4.81250,24.0,7.31250], [4.81250,28.0,7.31250], [4.81250,31.0,7.31250],
  [4.87500,50.0,5.37500],
  [6.12500,48.0,6.18750], [6.18750,50.0,6.25000], [6.25000,52.0,6.31250], [6.31250,55.0,6.37500],
  [6.37500,60.0,6.43750], [6.43750,62.0,6.50000], [6.43750,48.0,6.50000],
  [6.50000,50.0,6.56250], [6.56250,52.0,6.62500], [6.62500,55.0,6.68750],
  [6.68750,60.0,6.75000], [6.75000,62.0,6.81250], [6.81250,64.0,6.87500],
  [6.87500,67.0,7.62500],
  [7.62500,24.0,8.12500], [7.62500,28.0,8.12500], [7.62500,33.0,8.12500], [7.62500,60.0,8.12500],
  [8.18750,23.0,8.68750], [8.18750,28.0,8.68750], [8.18750,31.0,8.68750], [8.18750,59.0,8.68750],
  [8.75000,26.0,9.25000], [8.75000,30.0,9.25000], [8.75000,33.0,9.25000], [8.75000,57.0,9.00000],
  [9.00000,55.0,9.25000],
  [9.25000,24.0,9.87500], [9.25000,26.0,9.87500], [9.25000,31.0,9.87500], [9.25000,55.0,9.62500],
  [9.62500,55.0,9.87500],
  [9.93750,23.0,10.31250], [9.93750,26.0,10.31250], [9.93750,31.0,10.31250], [9.93750,47.0,10.12500],
  [10.12500,45.0,10.31250],
  [10.37500,26.0,10.87500], [10.37500,30.0,10.87500], [10.37500,33.0,10.87500], [10.37500,47.0,10.50000],
  [10.50000,54.0,10.68750], [10.68750,52.0,10.87500],
  [10.93750,24.0,11.93750], [10.93750,26.0,11.93750], [10.93750,31.0,11.93750], [10.93750,50.0,11.06250],
  [11.06250,43.0,11.43750], [11.43750,43.0,11.68750], [11.68750,43.0,11.93750],
  [11.93750,57.0,12.00000], [12.00000,59.0,12.06250],
  [12.06250,24.0,12.56250], [12.06250,28.0,12.56250], [12.06250,33.0,12.56250], [12.06250,60.0,12.56250],
  [12.62500,23.0,13.12500], [12.62500,28.0,13.12500], [12.62500,31.0,13.12500], [12.62500,59.0,13.12500],
  [13.18750,26.0,13.56250], [13.18750,30.0,13.56250], [13.18750,33.0,13.56250], [13.18750,57.0,13.37500],
  [13.37500,55.0,13.56250],
  [13.59375,24.0,14.09375], [13.59375,26.0,14.09375], [13.59375,31.0,14.09375], [13.59375,55.0,13.96875],
  [13.96875,55.0,14.09375],
  [14.15625,23.0,14.53125], [14.15625,26.0,14.53125], [14.15625,31.0,14.53125], [14.15625,47.0,14.34375],
  [14.34375,45.0,14.53125],
  [14.56250,26.0,15.06250], [14.56250,30.0,15.06250], [14.56250,33.0,15.06250], [14.56250,47.0,14.68750],
  [14.68750,54.0,14.93750], [14.93750,52.0,15.12500],
  [15.12500,24.0,16.12500], [15.12500,26.0,16.12500], [15.12500,31.0,16.12500], [15.12500,50.0,15.25000],
  [15.25000,43.0,15.75000], [15.75000,43.0,15.93750], [15.93750,43.0,16.12500]
];

// Ordenar por tiempo de inicio (por si acaso)
notes.sort((a, b) => a[0] - b[0]);

let noteIndex = 0;
const totalDuration = notes[notes.length - 1][2]; // último "end"

// --- Loop principal (como en tu ejemplo) ---
loop(() => {
  let currentTime = 0;
  const minStep = 0.0625; // resolución de 1/16

  while (currentTime <= totalDuration + 0.1) {
    // Disparar todas las notas que empiezan en currentTime
    while (
      noteIndex < notes.length &&
      Math.abs(notes[noteIndex][0] - currentTime) < 1e-5
    ) {
      const [start, midi, end] = notes[noteIndex];
      const duration = end - start;

      piano.play(midi+36, {
        duration: duration,
        attack: 0.1,      // ataque suave (como un piano real)
        decay: 0.3,
        sustain: 0.5,     // sustain alto para que los acordes suenen
        release: 0.6,     // release largo = notas se funden
        amp: 0.85
      });

      noteIndex++;
    }

    sleep(minStep);
    currentTime += minStep;
  }

  // Reiniciar para repetir
  noteIndex = 0;
}, { name: '2Pac - Changes (Piano Sample)' });