2015-10-14 142 views
0

我工作的一個簡單的項目,以創建一個工具,使用網絡音頻API,並寫了下面的代碼片段(您可以按「Q」打注):Web Audio API使用音量控制

var audio = new AudioContext(); 
 

 
var volume = 0; 
 
var attack = 1; 
 
var release = 1; 
 

 
var carrier = audio.createOscillator(); 
 
carrier.frequency.value = 440.00; 
 
carrier.type = "sine"; 
 
carrier.start(); 
 

 
var carrier_volume = audio.createGain(); 
 
carrier_volume.gain.linearRampToValueAtTime(volume, 0); 
 
carrier.connect(carrier_volume); 
 
carrier_volume.connect(audio.destination); 
 

 
document.addEventListener("keydown", function(e) { 
 
    if(e.keyCode == 81) { 
 
    carrier_volume.gain.linearRampToValueAtTime(1, audio.currentTime + attack); 
 
    } 
 
}); 
 

 
document.addEventListener("keyup", function(e) { 
 
    if(e.keyCode == 81) { 
 
    carrier_volume.gain.linearRampToValueAtTime(0, audio.currentTime + release); 
 
    } 
 
});

(如果你不熟悉的術語:「攻擊」是它需要說明的時間才能達到它的峯值,在我的示例1秒,「釋放」是一次在某人釋放密鑰後需要消失,本例中也爲1秒)。

問題是這樣的「點擊」聲音,你可以前後音符演奏後聽到。我做了一些研究:

How can I avoid this 'clicking' sound when I stop playing a sound?

http://modernweb.com/2014/03/31/creating-sound-with-the-web-audio-api-and-oscillators/

,發現它會通過削減聲波引起的,所以我應該保持音符在0dB玩和提高/根據需要降低音量。但是,它只適用於Chrome 專門只有如果我直接設置音量,就像這樣:carrier_volume.gain.value = 1。即使在Chrome中,如果我使用linearRampToValueAtTime()函數,它也不起作用。

其他奇怪的事情發生,如果我嘗試初始音量直接設置爲0。通過在初始化時使用carrier_volume.gain.value = 0,播放的第一個音符將被刪除,但下一個音符將正常播放。

有沒有人找到解決這個惱人的咔嗒聲的方法,以及在使用gain.valuelinearRampToValueAtTime()時都有什麼延遲問題?

回答

1

所以,這裏的交易 - 一個linearRampToValueAtTime需要的開始時間。你打算把它當作「現在」 - 當按下鍵時 - 但你需要明確指出,按下鍵時設置一個當前值。另外,您不應該在創建時使用linearRamp - 只需直接設置值。

如果您將初始體積直接設置爲0(通過.value),它不應該完全切出,但第一個斜坡不會有起始點 - 所以在linearRamp的時間過去之前它將保持爲零,並且然後它會跳到1

試試這個:

var audio = new AudioContext(); 

var volume = 0; 
var attack = 1; 
var release = 1; 

var carrier = audio.createOscillator(); 
carrier.frequency.value = 440.00; 
carrier.type = "sine"; 
carrier.start(); 

var carrier_volume = audio.createGain(); 
carrier_volume.gain.linearRampToValueAtTime(volume, 0); 
carrier.connect(carrier_volume); 
carrier_volume.connect(audio.destination); 

// remember whether we're playing or not; otherwise the keyboard repeat will confuse us 
var playing = false; 

document.addEventListener("keydown", function(e) { 
    if((e.keyCode == 81) && !playing) { 
    // first, in case we're overlapping with a release, cancel the release ramp 
    carrier_volume.gain.cancelScheduledValues(audio.currentTime); 

    // now, make sure to set a "scheduling checkpoint" of the current value 
    carrier_volume.gain.setValueAtTime(carrier_volume.gain.value,audio.currentTime); 

    // NOW, set the ramp 
    carrier_volume.gain.linearRampToValueAtTime(1, audio.currentTime + attack); 
    // Note that ideally, we would check the current value from above, and calculate 
    // the length of the attack based on it to keep a constant angle of the attack, 
    // rather than a constant time. (If we're half-way through a release when we 
    // start a new attack, the attack should only take 0.5s since we're already at 0.5.) 

    playing = true; 
    } 
}); 

document.addEventListener("keyup", function(e) { 
    if((e.keyCode == 81) && playing) { 
    // first, in case we're overlapping with an attack, cancel the attack ramp 
    carrier_volume.gain.cancelScheduledValues(audio.currentTime); 

    // now, make sure to set a "scheduling checkpoint" of the current value 
    carrier_volume.gain.setValueAtTime(carrier_volume.gain.value,audio.currentTime); 

    // NOW, set the ramp 
    carrier_volume.gain.linearRampToValueAtTime(0, audio.currentTime + release); 

    // Note that ideally, we would check the current value from above, and calculate 
    // the length of the release based on it to keep a constant angle of the release, 
    // rather than a constant time. (If we're half-way through an attack when we 
    // start a new release, the release should only take 0.5s since we're already at 0.5.) 
    playing = false; 
    } 
}); 
+0

非常感謝您!現在聽起來很順利。我也會嘗試一下你的計算攻擊/釋放的建議。 – adrield