如何使用从音频上下文创建的分析器来检测播放的声音是否可听

How can i use an analyser created from an audioContext to detect if a playing sound is audible?

本文关键字:播放 检测 声音 是否 分析器 何使用 音频 上下文 创建      更新时间:2023-09-26

首先,我将描述我的问题,我正在从随机歌曲创建一个自动播放列表,其中一些歌曲在歌曲结束时有 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();

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

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

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

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

compressor.reduction.value包装在setIntervalrequestAnimationFrame中以检查更改。

编写所需的逻辑,以在此值更改(或不更改)时执行任何操作。

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

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