admin管理员组文章数量:1390501
I create sounds using oscillator nodes and want to draw a frequency visualization on a canvas. When the oscillator is playing, the visualization looks like this (standard oscillator settings, see code below). .png
After the oscillator stopped playing (plete silence!), this is what I get. The exact result changes from run to run, sometimes the values even keep slightly changing after the stop. .png
I don't understand why the frequency data is not zero for all bins, when the sound is not playing.
Tested on Firefox 30.0 and Iron 34.0.1850.0 (Chrome)
Here's my sample code:
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript">
window.onload = function () {
var ctx = document.getElementById("canvas").getContext("2d");
var audioContext = new (window.AudioContext
|| window.webkitAudioContext || window.mozAudioContext)();
var analyser = audioContext.createAnalyser();
analyser.fftSize = 512;
analyser.connect(audioContext.destination);
var frequencyBins = new Uint8Array(analyser.frequencyBinCount);
var osc = audioContext.createOscillator();
osc.connect(analyser);
osc.start(audioContext.currentTime + 2);
osc.stop(audioContext.currentTime + 4);
var WIDTH = 512;
var HEIGHT = 100;
var value, h, w;
function draw() {
ctx.clearRect(0, 0, WIDTH, HEIGHT);
for (var i = 0; i < frequencyBins.length; i++) {
value = frequencyBins[i];
h = HEIGHT * (value / 255);
w = WIDTH / frequencyBins.length;
ctx.fillRect(i * w, HEIGHT - 1, w, -h);
}
};
function animate() {
analyser.getByteFrequencyData(frequencyBins);
draw();
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
};
</script>
</head>
<body>
<canvas id="canvas" width="512" height="100"></canvas>
</body>
</html>
I create sounds using oscillator nodes and want to draw a frequency visualization on a canvas. When the oscillator is playing, the visualization looks like this (standard oscillator settings, see code below). http://i58.tinypic./wtvwgz.png
After the oscillator stopped playing (plete silence!), this is what I get. The exact result changes from run to run, sometimes the values even keep slightly changing after the stop. http://i62.tinypic./2duji81.png
I don't understand why the frequency data is not zero for all bins, when the sound is not playing.
Tested on Firefox 30.0 and Iron 34.0.1850.0 (Chrome)
Here's my sample code:
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript">
window.onload = function () {
var ctx = document.getElementById("canvas").getContext("2d");
var audioContext = new (window.AudioContext
|| window.webkitAudioContext || window.mozAudioContext)();
var analyser = audioContext.createAnalyser();
analyser.fftSize = 512;
analyser.connect(audioContext.destination);
var frequencyBins = new Uint8Array(analyser.frequencyBinCount);
var osc = audioContext.createOscillator();
osc.connect(analyser);
osc.start(audioContext.currentTime + 2);
osc.stop(audioContext.currentTime + 4);
var WIDTH = 512;
var HEIGHT = 100;
var value, h, w;
function draw() {
ctx.clearRect(0, 0, WIDTH, HEIGHT);
for (var i = 0; i < frequencyBins.length; i++) {
value = frequencyBins[i];
h = HEIGHT * (value / 255);
w = WIDTH / frequencyBins.length;
ctx.fillRect(i * w, HEIGHT - 1, w, -h);
}
};
function animate() {
analyser.getByteFrequencyData(frequencyBins);
draw();
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
};
</script>
</head>
<body>
<canvas id="canvas" width="512" height="100"></canvas>
</body>
</html>
Share
Improve this question
edited Jun 22, 2014 at 21:13
Prometheus
asked Jun 22, 2014 at 20:56
PrometheusPrometheus
1,0256 silver badges16 bronze badges
7
-
1
Interesting observation. visualizing the input data by replacing
getByteFrequencyData
withgetByteTimeDomainData
suggests that actually the input buffer for the frequency analysis is not set to zero after the osc stops. On the other hand, the frequency graph looks like the time domain data was cut off in the middle. On my MacBook, when I set the osc time to around 15s, I see a constantly decaying frequency graph at the end. Have you verified the behavior with other input sources? – Peter Sorowka Commented Jun 23, 2014 at 0:00 - 1 Interesting indeed. I was wondering if it was the noise floor being picked up. I put your code in jsfiddle and added changed the minDecible value so we can see the noise floor. It doesn't seem to be like it's noise. jsfiddle/notthetup/7759c/2 – notthetup Commented Jun 23, 2014 at 0:09
- It seems when the Oscillator has stopped emitting new audio data, the last frame of data is kept and used to return the time and frequency domain data by the Analyser Node. jsfiddle/notthetup/7759c/3 – notthetup Commented Jun 23, 2014 at 0:14
- 1 @notthetup Sometimes the frequency data keeps changing after the stop. Had a few tests were the data slowly shifted towards higher frequencies. Might still be based on the last frame though, maybe the smoothingTimeConstant plays a role here? – Prometheus Commented Jun 23, 2014 at 13:43
- 1 I believe the WebAudio spec doesn't define the window to be used. But it seems like all browsers are using Blackman. lists.w3/Archives/Public/public-audio/2014AprJun/0001.html – notthetup Commented Jun 24, 2014 at 0:10
4 Answers
Reset to default 3I found a solution that works for me.
Instead of connecting the oscillator directly to the analyser, I pass the frequencies through a high-pass filter first. It seems that the value for the cutoff frequency can be set arbitrarily low, as long as it is not 0. Even with a cutoff of 0.00000001 the visualisation will be blank during silence.
http://jsfiddle/a2ZL9/3/
var analyser = audioContext.createAnalyser();
analyser.fftSize = 512;
analyser.connect(audioContext.destination);
var frequencyBins = new Uint8Array(analyser.frequencyBinCount);
var filter = audioContext.createBiquadFilter();
filter.type = "highpass";
filter.frequency.value = 0.0001;
filter.connect(analyser);
var osc = audioContext.createOscillator();
osc.connect(filter);
osc.start(audioContext.currentTime + 2);
osc.stop(audioContext.currentTime + 4);
It's not a noise floor. It happens with audio buffers too. It's a bug.
I had the same problem. It was analyserNode.smoothingTimeConstant, it has very high value by default. Try to analyserNode.smoothingTimeConstant = 0; //or 0.2 It will fix it
After experiencing the same issue I tried:
- Various biquad filters
- Various window functions
While I got the best results with a 2K-highpass/blackman bo, the freeze still persisted.
In the end I also had to adjust the min/max dB settings of the analyser. I had originally set min/max dB to -100/0.
- min dB of -101 yielded slow melting during silence.
- min dB of -150 yielded fast melting.
Intuitively it makes sense that increasing the response range of the analyser would resolve this issue. I assume it can be traced to quantization in the FFT algo.
Notes:
The highpass filter doubles overall processing overhead :(
While I also found that changing the smoothingTimeConstant to values approaching 1.0 resolved the freezing, it also induced lag in the responsiveness of the analyser (too smooth).
本文标签: javascriptWeb audioAnalyser frequency data not 0 during silenceStack Overflow
版权声明:本文标题:javascript - Web audio - Analyser frequency data not 0 during silence - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744625824a2616251.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论