Search code examples
javascriptmathcanvasaudiopeaks.js

Turning audio data into waveform data?


I don't understand how this https://github.com/bbc/peaks.js/blob/master/demo/TOL_6min_720p_download.json can be turned into a waveform visualization with peaks.

I see the data in that file is a flat array of numbers. I am trying to understand how to convert those numbers into something meaningful for visual drawing.

Check out this fiddle to see a deeper look into the code https://codesandbox.io/s/cool-dijkstra-fyw25?file=/src/App.js

The goal is to create peaks with a high and low that looks like the image. I assume every 2 indexes represent a peak, but I don't want to assume anything.

enter image description here

I am pulling the JSON and passing it into the draw function like this

  const peaksReq = await fetch(
    "https://raw.githubusercontent.com/bbc/peaks.js/master/demo/TOL_6min_720p_download.json"
  );
  const peaksData = await peaksReq.json();
  const peaks = peaksData.data;

  // peaks is now a flat array of numbers

The goal is to turn the flat peaks array into a bar like the image above. The first set of data is a bunch of 0's eventually a sequence with meaning looks something like this [-7,5,-27,25,-30,26,-29,30,-24,26]

My understanding -- a guess is to turn it into a 2d array like this [[-7,5],[-27,25],[-30,26],[-29,30],[-24,26]] then convert those numbers to px that will fit within a boundary. -7, 5 would go up and down relative to a center axiom.

The problem I don't quite understand how to solve is if it is within a 40px element how do we keep those numbers relative. i.e the center of 40px is 20px. The maximum a bar can go upwards in a 40px space from its center without going out of bounds is 20px, you could add a buffer of 5px and say 15px.


Solution

  • Expanding on my comment on getting the max and min then us those to get a relative value, I'm doing the 15px bounds as you suggested, so the center will be 0 and the upper bound will be 15px, and the lower bound -15px that will be used in our calculations...

    Here is what we can do:

    async function start() {
      const peaksReq = await fetch(
        "https://raw.githubusercontent.com/bbc/peaks.js/master/demo/TOL_6min_720p_download.json"
      );
      const peaksData = await peaksReq.json();
      const peaks = peaksData.data;
    
      const max = Math.max(...peaks)
      console.log(max, 15)
      
      const min = Math.min(...peaks)
      console.log(min, -15)
      
      console.log("---------------")
      for (let i = 801; i < 805; i++) {
        let val = peaks[i] * 15 / max
        if (peaks[i] < 0)
          val = peaks[i] * -15 / min
        val = Math.round(val*10)/10
        console.log(peaks[i], val)
      } 
    }
    
    start()

    I'm just sampling the peaks array in my output but that is what you need