淡入和淡出网络音频循环
Fading in and out Web Audio Loop
我正在浏览器中录制一些音频,然后想无缝循环播放,避免在开始时出现点击等问题。这意味着淡出它。
我可以将音量调高和调低一次,但无论如何我都找不到在每次循环再次开始时触发网络音频的 'ramp to value at time'。
有没有简单的方法来做到这一点?我有 10 个这样的缓冲区循环,所以我想尽可能避免大量昂贵的 setinterval 检查...
let source = audioContext.createBufferSource();
let gain = audioContext.createGain();
gain.gain.value = 0.01;
source.buffer = decodedData;
songLength = decodedData.duration;
source.loop = true;
source.connect(gain);
gain.connect(audioContext.destination);
source.start(0);
// fade in and out
gain.gain.exponentialRampToValueAtTime(0.2, audioContext.currentTime + 1);
gain.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + songLength);
考虑收听 ended
事件和 re-trigger 回放:
class FadeInLoop {
ctx
audioBuffer
gainNode
isPlaying = true
constructor(ctx, url) {
this.ctx = ctx
this.audioBuffer = fetch(url)
.then(response => response.arrayBuffer())
.then(arrayBuffer => ctx.decodeAudioData(arrayBuffer))
this.gainNode = ctx.createGain()
this.gainNode.connect(ctx.destination)
}
async start() {
this.isPlaying = true
const source = ctx.createBufferSource()
this.source = source
source.addEventListener('ended', e => {
if (this.isPlaying) { // repeat unless stop() was called
this.start()
}
})
source.connect(this.gainNode)
source.buffer = await this.audioBuffer
const now = this.ctx.currentTime
this.gainNode.gain.setValueAtTime(Number.EPSILON, now);
this.gainNode.gain.exponentialRampToValueAtTime(1, now + 0.055)
source.start(0)
}
stop() {
this.isPlaying = false
this.source?.stop()
}
}
const ctx = new AudioContext({ latencyHint: 'interactive' })
const loop = new FadeInLoop(ctx, 'https://batman.dev/static/71474264/loop.mp3')
<button onclick="loop.start()">Start</button>
<button onclick="loop.stop()">Stop</button>
我正在浏览器中录制一些音频,然后想无缝循环播放,避免在开始时出现点击等问题。这意味着淡出它。
我可以将音量调高和调低一次,但无论如何我都找不到在每次循环再次开始时触发网络音频的 'ramp to value at time'。
有没有简单的方法来做到这一点?我有 10 个这样的缓冲区循环,所以我想尽可能避免大量昂贵的 setinterval 检查...
let source = audioContext.createBufferSource();
let gain = audioContext.createGain();
gain.gain.value = 0.01;
source.buffer = decodedData;
songLength = decodedData.duration;
source.loop = true;
source.connect(gain);
gain.connect(audioContext.destination);
source.start(0);
// fade in and out
gain.gain.exponentialRampToValueAtTime(0.2, audioContext.currentTime + 1);
gain.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + songLength);
考虑收听 ended
事件和 re-trigger 回放:
class FadeInLoop {
ctx
audioBuffer
gainNode
isPlaying = true
constructor(ctx, url) {
this.ctx = ctx
this.audioBuffer = fetch(url)
.then(response => response.arrayBuffer())
.then(arrayBuffer => ctx.decodeAudioData(arrayBuffer))
this.gainNode = ctx.createGain()
this.gainNode.connect(ctx.destination)
}
async start() {
this.isPlaying = true
const source = ctx.createBufferSource()
this.source = source
source.addEventListener('ended', e => {
if (this.isPlaying) { // repeat unless stop() was called
this.start()
}
})
source.connect(this.gainNode)
source.buffer = await this.audioBuffer
const now = this.ctx.currentTime
this.gainNode.gain.setValueAtTime(Number.EPSILON, now);
this.gainNode.gain.exponentialRampToValueAtTime(1, now + 0.055)
source.start(0)
}
stop() {
this.isPlaying = false
this.source?.stop()
}
}
const ctx = new AudioContext({ latencyHint: 'interactive' })
const loop = new FadeInLoop(ctx, 'https://batman.dev/static/71474264/loop.mp3')
<button onclick="loop.start()">Start</button>
<button onclick="loop.stop()">Stop</button>