我真的希望这个问题能够成为一个编程问题,并且最终不会出现声音力学问题......这就是......
我正在做一些实验,以便弄清楚Web Audio API的工作原理。我想要做的是一个简单的“挂断电话”声音循环播放。问题是当声音结束时,你可以听到一声非常烦人的“咔哒”声。我无法更好地解释它,但是如果你测试代码就可以听到它。
有什么方法可以避免这种情况吗?我可以申请一些过滤器吗?
var audioContext = new (AudioContext || webkitAudioContext)();
var frequencyOffset = 0
function boop(){
// Our sound source is a simple triangle oscillator
var oscillator = audioContext.createOscillator(); // Create sound source
oscillator.type = 'triangle';
// Adding a gain node just to lower the volume a bit and to make the
// sound less ear-piercing
var gain = audioContext.createGain();
oscillator.connect(gain);
gain.connect(audioContext.destination);
gain.gain.value = 0.1;
// Just for fun let the frequency increase on each itteration
oscillator.frequency.value = 200 + frequencyOffset;
oscillator.start(0);
// The sound should last for 250ms
setTimeout(function(){
oscillator.disconnect();
oscillator.stop();
gain.disconnect();
}, 250);
frequencyOffset += 1;
}
setInterval(boop, 500);
答案 0 :(得分:7)
这是一个音频问题,而不是编程问题。当波形在波浪中间停止/切割而非零交叉时,会发出您听到的咔嗒声。
音频范例中最简单的解决方案是快速淡出,而不仅仅是停止播放。
稍微复杂的解决方案是找到下一个过零点并在此点停止播放。
答案 1 :(得分:4)
看起来Web Audio API为开发人员提供了一种简单的方法,可以在不突然停止波形的情况下停止播放声源,并避免任何噪音和声音伪影。
var audioContext = new(AudioContext || webkitAudioContext)();
var frequencyOffset = 0
// Our sound source is a simple triangle oscillator
var oscillator = audioContext.createOscillator(); // Create sound source
oscillator.type = 'triangle';
// Adding a gain node just to lower the volume a bit and to make the
// sound less ear-piercing. It will also allow us to mute and replay
// our sound on demand
var gainNode = audioContext.createGain();
oscillator.connect(gainNode);
gainNode.connect(audioContext.destination);
gainNode.gain.value = 0;
oscillator.frequency.value = 200;
oscillator.start(0);
function boop() {
gainNode.gain.value = 0.1;
// The sound should last for 250ms
setTimeout(function() {
gainNode.gain.value = 0;
}, 250);
oscillator.frequency.value++;
}
setInterval(boop, 500);
答案 2 :(得分:2)
这里有一个简短的解释,说明为什么我们听到咔哒声(它是人耳的东西)以及如何使用Web音频API解决这个问题的好例子: http://alemangui.github.io/blog//2015/12/26/ramp-to-value.html
本文的主要内容是删除点击工作的指数方法更好; exponentialRampToValueAtTime 和 setTargetAtTime 。
使用setTargetAtTime删除点击
var context = new AudioContext();
var oscillator = context.createOscillator();
var gainNode = context.createGain();
oscillator.connect(gainNode);
gainNode.connect(context.destination)
oscillator.start();
stopButton.addEventListener('click', function() {
gainNode.gain.setTargetAtTime(0, context.currentTime, 0.015);
});
使用exponentialRampToValueAtTime删除点击
var context = new AudioContext();
var oscillator = context.createOscillator();
var gainNode = context.createGain();
oscillator.connect(gainNode);
gainNode.connect(context.destination)
oscillator.start();
stopButton.addEventListener('click', function() {
// Important! Setting a scheduled parameter value
gainNode.gain.setValueAtTime(gainNode.gain.value, context.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.0001, context.currentTime + 0.03);
});
这两个在我的用例中对我有用, exponentialRampToValueAtTime 工作稍微好一些。我仍然可以使用 setTargetAtTime 听到微弱的点击。