如何使用从audioContext创建的分析器来检测播放的声音是否可听?

时间:2016-01-22 00:51:19

标签: javascript html5 html5-audio web-audio

首先我会描述我的问题,我从随机歌曲创建一个自动播放列表,一些歌曲在歌曲结尾处有10-15秒的静音,我是什么试图达到的目的是在歌曲静音5秒钟时从分析仪中检测并对其进行操作。

到目前为止,我已经得到了这个:

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();

我知道答案在分析仪的某个地方,但我发现从它返回的数据中没有任何连贯性。

我可以这样做:

var frequencies = new Float32Array(analyser.frequencyBinCount);
analyser.getFloatFrequencyData(frequencies);

并且频率var将包含2048个键,每个键具有随机(对我而言)数字(-48.11,-55,-67等等),这些数字是否表示与所感知的声音相关的任何内容? ,我怎么能检测到它是否足够低以至于人们不会想到什么都在播放。

对于检测,我主要想要这样的东西:

var isInSilence = function(){
    return !audible;
}

var tries = 0;

var checker = function() {
    tries = isInSilence() ? tries + 1 : 0;
    if(tries >= 5) playNext();
    setTimeout(checker, 1000);
}

checker();

唯一缺失的部分是检测歌曲目前是否保持沉默,任何帮助都将受到赞赏。

修改

根据威廉的回答,我设法通过这样做解决了这个问题:

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();

2 个答案:

答案 0 :(得分:4)

这是使用不同方法的可能解决方案 - 压缩器节点。这是一个简短的描述,但应该足以让您填写用例的详细信息:

创建压缩器节点并将输入源连接到它。 然后将压缩器连接到增益节点并将增益节点静音(将其设置为零)。将增益节点连接到audioContext.destination

获取输入源并将其连接到audioContext.destination

设置压缩器属性值以检测信号(以便触发减少值)。

compressor.reduction.valuesetInterval中换取requestAnimationFrame以检查更改。

编码在此值发生变化时(或不变更)执行任何操作所需的逻辑。

答案 1 :(得分:1)

为了将来参考 - 分析器为getFloatFrequencyValues返回的值是该特定信号的分贝 - 所以" 0"将是一个假设的完整信号," -96"远远低于人类的正常动态范围。

您可能更容易使用getByteFrequencyValues,它会将值预先设置为0-255; 0是合理的本底噪声。如果您正在寻找真正的静音,只需在所有分析仪箱中查找零 - 如果您正在寻找一个安静的信号,minDecibels的默认值-100可能太低,所以寻找一个较低的数字(10或更少?你必须进行实验)。或者更改minDecibels - 请参阅规范。