Ana
Ana

Reputation: 9

How do I animate this image to match with a BPM in P5.js?

So I am working with p5.js for class and I am very lost with it, as I dont understand very well. How do I animate this image to match with the sound? I tried frequency analysis but i dont know how to apply to the image. I wanted to animate it as i it was beating, like a heart, but according to the bpm sound i put in the sketch. here is the sketch + image + sound https://editor.p5js.org/FilipaRita/sketches/cUG6qNhIR

Upvotes: 0

Views: 1098

Answers (2)

Paul Wheeler
Paul Wheeler

Reputation: 20180

Actually finding the BMP for an entire piece of music would be a bit complicated (see this sound.stackexchange.com question), but if you just want to detect beats in real time I think you can probably hack something together that will work. Here is a visualization that I think will help you understand the data returned by fft.analyze():

const avgWindow = 20;
const threshold = 0.4;

let song;
let fft;
let beat;
let lastPeak;

function preload() {
  song = loadSound("https://www.paulwheeler.us/files/metronome.wav");
}

function setup() {
  createCanvas(400, 400);
  fft = new p5.FFT();
  song.loop();
  beat = millis();
}

function draw() {
  // Pulse white on the beat, then fade out with an inverse cube curve
  background(map(1 / pow((millis() - beat) / 1000 + 1, 3), 1, 0, 255, 100));
  drawSpectrumGraph(0, 0, width, height);
}

let i = 0;
// Graphing code adapted from https://jankozeluh.g6.cz/index.html by Jan Koželuh
function drawSpectrumGraph(left, top, w, h) {
  let spectrum = fft.analyze();

  stroke('limegreen');
  fill('darkgreen');
  strokeWeight(1);

  beginShape();
  vertex(left, top + h);

  let peak = 0;
  // compute a running average of values to avoid very
  // localized energy from triggering a beat.
  let runningAvg = 0;
  for (let i = 0; i < spectrum.length; i++) {
    vertex(
      //left + map(i, 0, spectrum.length, 0, w),
      // Distribute the spectrum values on a logarithmic scale
      // We do this because as you go higher in the spectrum
      // the same perceptible difference in tone requires a 
      // much larger chang in frequency.
      left + map(log(i), 0, log(spectrum.length), 0, w),
      // Spectrum values range from 0 to 255
      top + map(spectrum[i], 0, 255, h, 0)
    );

    runningAvg += spectrum[i] / avgWindow;
    if (i >= avgWindow) {
      runningAvg -= spectrum[i] / avgWindow;
    }
    if (runningAvg > peak) {
      peak = runningAvg;
    }
  }

  // any time there is a sudden increase in peak energy, call that a beat
  if (peak > lastPeak * (1 + threshold)) {
    // print(`tick ${++i}`);
    beat = millis();
  }
  lastPeak = peak;

  vertex(left + w, top + h);
  endShape(CLOSE);
  // this is the range of frequencies covered by the FFT
  let nyquist = 22050;

  // get the centroid (value in hz)
  let centroid = fft.getCentroid();

  // the mean_freq_index calculation is for the display.
  // centroid frequency / hz per bucket
  let mean_freq_index = centroid / (nyquist / spectrum.length);
  stroke('red');
  // convert index to x value using a logarithmic x axis
  let cx = map(log(mean_freq_index), 0, log(spectrum.length), 0, width);
  line(cx, 0, cx, h);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/addons/p5.sound.min.js"></script>

Hopefully this code with the comments helps you understand the data returned by fft.analyze() and you can use this as a starting point to achieve the effect you are looking for.

Disclaimer: I have experience with p5.js but I'm not an audio expert, so there could certainly be better ways to do this. Also while this approach works for this simple audio file there's a good chance it would fail horribly for actual music or real world environments.

Upvotes: 5

Ryan Porter
Ryan Porter

Reputation: 2182

If I were you then I would cheat and add some meta data that explicitly includes the timestamps of the beats. This would be a much simpler problem if you could shift the problem of beat detection to pre-processing. Maybe even do it by hand. Rather than trying to do it at runtime. The signal processing to do beat detection in an audio signal is non-trivial.

Upvotes: 0

Related Questions