0

I have this visualizer, everthing is working well. The only problem is that when you clear canvas with clean function, then click changeSrc, you can always see a visualizer from last song for a second. Can I get rid of this?

You might need to run it on js fiddle.

https://jsfiddle.net/t87wyzgd/6/

var renderVizualitationID,
  canvas, ctx, center_x, center_y, radius, bars,
  x_end, y_end, bar_height, bar_width,
  frequency_array,
  wrap, source;



wrap = $('.w')



canvas = document.getElementById("renderer");
ctx = canvas.getContext("2d");

bars = 200;
bar_width = 2;
multiplier = 0.7;



audio = new Audio();
audio.crossOrigin = "anonymous";

context = new(window.AudioContext || window.webkitAudioContext)();
analyser = context.createAnalyser();

audio.src = "https://api.soundcloud.com/tracks/42328219/stream?client_id=b1495e39071bd7081a74093816f77ddb"; // the source path
audio.loop = true;
source = context.createMediaElementSource(audio);
source.connect(analyser);
analyser.connect(context.destination);

frequency_array = new Uint8Array(analyser.frequencyBinCount);

audio.play();
animationLooper();







function animationLooper() {

  // set to the size of device

  canvas.width = wrap.width();
  canvas.height = wrap.height();


  // find the center of the window
  center_x = canvas.width / 2;
  center_y = canvas.height / 2;
  radius = canvas.height / 6;

  //draw a circle
  ctx.beginPath();
  ctx.arc(center_x, center_y, radius, 0, 2 * Math.PI);
  ctx.stroke();

  analyser.getByteFrequencyData(frequency_array);
  var i;
  for (i = 0; i < bars; i++) {

    //divide a circle into equal parts
    rads = Math.PI * 2 / bars;

    bar_height = frequency_array[i] * multiplier;

    // set coordinates
    x = center_x + Math.cos(rads * i) * (radius);
    y = center_y + Math.sin(rads * i) * (radius);
    x_end = center_x + Math.cos(rads * i) * (radius + bar_height);
    y_end = center_y + Math.sin(rads * i) * (radius + bar_height);

    //draw a bar
    var lineColor = "rgb(" + frequency_array[i] + ", " + frequency_array[i] + ", " + 205 + ")";

    ctx.strokeStyle = lineColor;
    ctx.lineWidth = bar_width;
    ctx.beginPath();
    ctx.moveTo(x, y);
    ctx.lineTo(x_end, y_end);
    ctx.stroke();

  }

  renderVizualitationID = requestAnimationFrame(animationLooper);
}

$('#clean').on('click',function() {
  if (renderVizualitationID) cancelAnimationFrame(renderVizualitationID);

  audio.pause();
  audio.src = '';

  ctx.clearRect(0, 0, canvas.width, canvas.height);

});

$('#changeSrc').on('click',function() {

 audio.src = "https://api.soundcloud.com/tracks/693365626/stream?client_id=r4wruADPCq7iqJomagvYpdehvILa2bgE"; // the source path

  audio.play();
  animationLooper();

});
.w {
  position: relative;
  top: 0;
  left: 0;
  width: 400px;
  height: 400px;
  background: #ccc;
}

#renderer {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: #111;

  background: #1D4350;

}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="w">
  <canvas id="renderer"></canvas>
</div>

<a id="clean" href="#" >clean</a>
<a id="changeSrc" href="#" >changeSrc</a>
Toniq
  • 4,492
  • 12
  • 50
  • 109

1 Answers1

1

This happens because your AudioAnalyser works by buffering the data, it simply unshifts new data as time passes. So when you pause your audio, it will still contain some data.

To avoid this, you can simply create a new AudioAnalyser in the clean function

var renderVizualitationID,
  canvas, ctx, center_x, center_y, radius, bars,
  x_end, y_end, bar_height, bar_width,
  frequency_array,
  wrap, source;



wrap = $('.w')



canvas = document.getElementById("renderer");
ctx = canvas.getContext("2d");

bars = 200;
bar_width = 2;
multiplier = 0.7;



audio = new Audio();
audio.crossOrigin = "anonymous";

context = new(window.AudioContext || window.webkitAudioContext)();
analyser = context.createAnalyser();

audio.src = "https://api.soundcloud.com/tracks/42328219/stream?client_id=b1495e39071bd7081a74093816f77ddb"; // the source path
audio.loop = true;
source = context.createMediaElementSource(audio);
source.connect(analyser);
analyser.connect(context.destination);

frequency_array = new Uint8Array(analyser.frequencyBinCount);

audio.play();
animationLooper();





// do not change the size of your canvas when you are drawing on it
// that will reset the whole canvas and require anew pixel buffer
// so do it only when really required
window.onresize = function() {
  // set to the size of device

  canvas.width = wrap.width();
  canvas.height = wrap.height();
};
window.onresize();

function animationLooper() {

  ctx.clearRect( 0, 0, canvas.width, canvas.height )

  // find the center of the window
  center_x = canvas.width / 2;
  center_y = canvas.height / 2;
  radius = canvas.height / 6;

  //draw a circle
  ctx.beginPath();
  ctx.arc(center_x, center_y, radius, 0, 2 * Math.PI);
  ctx.stroke();

  analyser.getByteFrequencyData(frequency_array);
  var i;
  for (i = 0; i < bars; i++) {

    //divide a circle into equal parts
    rads = Math.PI * 2 / bars;

    bar_height = frequency_array[i] * multiplier;

    // set coordinates
    x = center_x + Math.cos(rads * i) * (radius);
    y = center_y + Math.sin(rads * i) * (radius);
    x_end = center_x + Math.cos(rads * i) * (radius + bar_height);
    y_end = center_y + Math.sin(rads * i) * (radius + bar_height);

    //draw a bar
    var lineColor = "rgb(" + frequency_array[i] + ", " + frequency_array[i] + ", " + 205 + ")";

    ctx.strokeStyle = lineColor;
    ctx.lineWidth = bar_width;
    ctx.beginPath();
    ctx.moveTo(x, y);
    ctx.lineTo(x_end, y_end);
    ctx.stroke();

  }

  renderVizualitationID = requestAnimationFrame(animationLooper);
}

$('#clean').on('click',function() {
  if (renderVizualitationID) cancelAnimationFrame(renderVizualitationID);

  audio.pause();
  audio.src = '';
  frequency_array.fill( 0 );
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  // kill the previous one
  analyser.disconnect();
  // create a new analyser
  analyser = context.createAnalyser();
  source.connect( analyser );
  analyser.connect(context.destination);
});

$('#changeSrc').on('click',function() {

 audio.src = "https://api.soundcloud.com/tracks/693365626/stream?client_id=r4wruADPCq7iqJomagvYpdehvILa2bgE"; // the source path
  audio.play();
  animationLooper();  
});
.w {
  position: relative;
  top: 0;
  left: 0;
  width: 400px;
  height: 400px;
  background: #ccc;
}

#renderer {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: #111;

  background: #1D4350;

}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="w">
  <canvas id="renderer"></canvas>
</div>

<a id="clean" href="#" >clean</a>
<a id="changeSrc" href="#" >changeSrc</a>
Kaiido
  • 123,334
  • 13
  • 219
  • 285
  • Is this porformance effective to create new analyzer every time? – Toniq Oct 12 '19 at 15:31
  • That should have any measurable drawback, it will just get collected by the GC. Far less than what you were doing in your drawing function :P – Kaiido Oct 13 '19 at 00:53