Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

114
Views
Improving visualizer look

I am not happy with how this code draws this music visualizer using canvas and getByteFrequencyData. https://share.getcloudapp.com/Kou7AJb1

It seems the bars are too large and I think its because the FFT (Fast Fourier Transform) array contains a wide spectrum of data but in my code I am generating n amount of bars based on the width of the canvas.

Then after having n bars I am mapping the FFT to the same index of the bar leaving out lots of useful information.

function convertRange(value: any, r1: any, r2: any) {
  return ((value - r1[0]) * (r2[1] - r2[0])) / (r1[1] - r1[0]) + r2[0];
}

// line up and down
const drawVisualizer2 = ({ canvas, frameData, background }: any) => {
  const ctx = canvas.getContext("2d");
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  // TODO: Improve?
  const bars = Math.round(canvas.width) / 15 - 1;
  const max_of_array = Math.max.apply(Math, frameData.fft);

  for (let i = 0; i < bars; i++) {
    const height = convertRange(frameData.fft[i], [0, max_of_array], [0, canvas.height / 2 - 20]);
    const centerY = canvas.height / 2;

    // draw the bar
    ctx.strokeStyle = background ? background.colors[0] : "#ffffff";
    ctx.lineWidth = 10;
    ctx.lineCap = "round";

    ctx.beginPath();
    ctx.moveTo((i + 1) * 15, centerY);
    ctx.lineTo((i + 1) * 15, centerY + height);
    ctx.stroke();

    ctx.beginPath();
    ctx.moveTo((i + 1) * 15, centerY);
    ctx.lineTo((i + 1) * 15, centerY - height);
    ctx.stroke();
  }
};

export default drawVisualizer2;

What I think needs to be done is average out the FFT based on the amount of bars in the loop. If that makes sense what is a practical approach code wise to achieve that?

I hope this makes sense, happy to clarify if needed.

about 4 years ago · Juan Pablo Isaza
1 answers
Answer question

0

I assume that frameData.fft is the Uint8Array containing the actual frequency data returned by the AnalyserNode.getByteFrequencyData() method.

Your assumption is right - the number of bars of course doesn't match the number of items stored in array and with a loop like

for (let i = 0; i < bars; i++) {
...
frameData.fft[i]
...
}

you're just using the first few values from zero up to the number of bars and ultimately skipping the entire rest of the array.

The fix is quite simple though:

Instead of grabbing values from the array in intervals of 1, the interval must be the number of elements in the array divided by the number of bars. This number is then multiplied by the variable i inside the for-loop and rounded as the division might result in a decimal number and the array's elements are at integer positions.

Here's an example:

let frameData = {
  fft: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
};
let bars = 5;
let steps = frameData.fft.length / bars;
for (let i = 0; i < bars; i++) {
  console.log(frameData.fft[Math.round(i * steps)]);
}

about 4 years ago · Juan Pablo Isaza Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!