Reputation: 1140
First I'll describe my problem, I'm creating an automated playlist from random songs, some of the songs have 10-15 seconds of silence at the end of the song, what I'm trying to achieve is to detect from the analyser when a song has been in silence for 5 seconds and act on that.
So far I've got this:
var context, analyser, source, audio;
context = new (window.AudioContext || window.webkitAudioContext)();
analyser = context.createAnalyser();
audio = new Audio();
source = context.createMediaElementSource(audio)
source.connect(analyser);
analyser.connect(context.destination);
var playNext = function() {
var pickedSong;
// chooses a song from an api with several
// thousands of songs and store it in pickedSong
audio.src = pickedSong;
audio.play();
}
audio.addEventListener('ended', playNext);
playNext();
I know the answer is somewhere in the analyser but I haven't found any coherence in the data returned from It.
I can do something like this:
var frequencies = new Float32Array(analyser.frequencyBinCount);
analyser.getFloatFrequencyData(frequencies);
and the frequencies var would contain 2048 keys each with a random(to me) number (-48.11, -55, -67, etc...), do these numbers mean anything related to the perceived sound that is played?, how can i detect if it's low enough that people would think nothing is playing.
For the detection I mainly want something like this:
var isInSilence = function(){
return !audible;
}
var tries = 0;
var checker = function() {
tries = isInSilence() ? tries + 1 : 0;
if(tries >= 5) playNext();
setTimeout(checker, 1000);
}
checker();
The only missing part is detecting if the song is currently silent or not, any help would be appreciated.
Edit:
based on william's answer i managed to solve it by doing it this way:
var context, compressor, gain, source, audio;
context = new (window.AudioContext || window.webkitAudioContext)();
compressor = context.createDynamicsCompressor();
gain = context.createGain();
audio = new Audio();
source = context.createMediaElementSource(audio)
// Connecting source directly
source.connect(context.destination);
// Connecting source the the compresor -> muted gain
source.connect(compressor);
compressor.connect(gain);
gain.connect(context.destination);
gain.gain.value = 0; // muting the gain
compressor.threshold.value = -100;
var playNext = function() {
var pickedSong;
// chooses a song from an api with several
// thousands of songs and store it in pickedSong
audio.src = pickedSong;
audio.play();
}
audio.addEventListener('ended', playNext);
playNext();
var isInSilence = function(){
return compressor.reduction.value >= -50;
}
var tries = 0;
var checker = function() {
tries = isInSilence() ? tries + 1 : 0;
if(tries >= 5) playNext();
setTimeout(checker, 1000);
}
checker();
Upvotes: 6
Views: 1990
Reputation: 13908
For future reference - the values the analyzer returns for getFloatFrequencyValues are decibels of that particular signal - so "0" would be a hypothetical full signal, "-96" is well below normal dynamic range for a human.
It's probably easier for you to just use getByteFrequencyValues, which pre-munges values into 0-255; 0 is a reasonable noise floor. If you're looking for REALLY silence, just look for zeros in all the analyser bins - if you're looking for a quiet signal, the default -100 for minDecibels is probably too low, so look for a low number (10 or less? you'd have to experiment). Or change minDecibels - see the spec.
Upvotes: 1
Reputation: 4588
This is a possible solution using a different approach - the compressor node. It's a brief description but should be enough to let you fill in the details for your use case:
Create a compressor node and connect your input source to it.
Then connect the compressor to a gain node and mute the gain node ( set it to zero). Connect the gain node to the audioContext.destination
Take your input source and connect it to audioContext.destination
.
Set the compressor property values to detect the signal (so that it triggers the reduction value ).
Wrap compressor.reduction.value
in a setInterval
or requestAnimationFrame
to check for changes.
Code the logic needed to do whatever you want when this value changes ( or doesn't change ).
Upvotes: 4