我正在开发一个使用Web Audio API创建乐器的简单项目,并编写了以下片段(您可以按' Q '来播放音符):
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/
并发现它是由切割声波引起的,因此我应该将音符保持在0 dB并根据需要升高/降低音量。但是,它只能在Chrome 上专门 ,如果我直接设置音量,则仅,如下所示:carrier_volume.gain.value = 1
。如果我使用linearRampToValueAtTime()
功能,即使在Chrome中也无效。
如果我尝试直接将初始音量设置为0,则会发生其他奇怪的事情。通过在初始化时使用carrier_volume.gain.value = 0
,播放的第一个音符将被删除,但下一个音符将正常播放。
有没有人找到解决这种烦人的点击噪音的解决方案,以及使用gain.value
和linearRampToValueAtTime()
时的延迟问题是什么?
答案 0 :(得分:1)
所以,这是交易 - linearRampToValueAtTime需要一个START时间。您打算“现在” - 当按下键时 - 但是您需要通过在按下键时设置当前值来使其显式化。此外,您不应在创建时使用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;
}
});
答案 1 :(得分:0)
设置音量的键
gainNode.gain.setValueAtTime(0.5, context.currentTime);
<button id="start">playSound</button>
const audioPlay = async url => {
const context = new AudioContext();
var gainNode = context.createGain();
const source = context.createBufferSource();
const audioBuffer = await fetch(url)
.then(res => res.arrayBuffer())
.then(ArrayBuffer => context.decodeAudioData(ArrayBuffer));
source.buffer = audioBuffer;
source.connect(gainNode);
gainNode.connect(context.destination);
gainNode.gain.setValueAtTime(0.5, context.currentTime); // volume, 0 means mute
source.start();
};
document.querySelector('#start').onclick = () => audioPlay('music/2.ogg');