Web音频API:音频淡入/淡出之间的平滑过渡

时间:2019-04-04 09:47:17

标签: javascript audio html5-audio web-audio web-audio-api

我有一个带有不同区域的3d空间,每个区域都有自己的声音。我的目标是当用户从一个区域移动到另一个区域时,实现平滑的音频过渡,基本上在音轨之间进行淡入淡出。 当用户改变主意并突然返回到刚刚离开的区域时,我也希望能够优雅地处理这种情况,这意味着取消新的音频过渡并逐渐恢复为先前的状态。

为此,我使用web audio api,尤其是linearRampToValueAtTimecancelScheduledValues来定义淡入/淡出功能:

const fadeIn = (sound, time = 4, gain = 1.0) => {
    sound.gainNode.gain.cancelScheduledValues(sound.context.currentTime)
    !sound.isPlaying && sound.play()
    sound.gainNode.gain.linearRampToValueAtTime(gain, sound.context.currentTime + time)
}

const fadeOut = (sound, time = 4, gain = 0.0) => {
    sound.gainNode.gain.cancelScheduledValues(sound.context.currentTime)
    sound.gainNode.gain.linearRampToValueAtTime(gain, sound.context.currentTime + time)
}

我仅在一种声音上对此进行测试,按下键“ I”触发淡入,按下键“ O”触发淡出:

document.addEventListener("keyup", e => {
    switch (e.keyCode) {
        // I key
        case 73:
            fadeIn(mySound)
            break
        // O key
        case 79:
            fadeOut(mySound)
            break
})

我得到不一致的结果。有时,音频会正确淡入,而另一些时候,它会在fadeIn中突然开始或在fadeOut中切入。过渡未完成时,似乎调用 cancelScheduledValues 会导致行为不稳定。我希望即使在fadingIn尚未完成时触发fadeOut时,它也能平稳工作,反之亦然。我也尝试过使用setTimeout来延迟linearRamps,例如

setTimeout(() => sound.gainNode.gain.linearRampToValueAtTime(gain, sound.context.currentTime + time), 0.1)

,但结果同样错误。 我使用API​​的方式有误吗?有什么建议吗?

1 个答案:

答案 0 :(得分:2)

我认为这里正在发生的事情是,例如,您正在逐渐消失,还没有完成爬坡。然后,您需要淡出并取消事件,包括未完成的淡入斜坡。然后淡入渐变消失了,时间轴值又恢复为上一个事件的值。

因此,正如HankMoody建议的那样,请使用import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.security.InvalidKeyException; def hmac_sha256(String secretKey, String data) { try { Mac mac = Mac.getInstance("HmacSHA256") SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(), "HmacSHA256") mac.init(secretKeySpec) return mac.doFinal(data.getBytes()) } catch (InvalidKeyException e) { throw new RuntimeException("Invalid key exception while converting to HMac SHA256") } def x = hmac_sha256("secret", "my-data").encodeBase64().toString(); 来解决此问题。但是,AFAIK只有Chrome具有此功能。

为便于携带,我认为您要做的是计算要取消时斜坡的位置。假设值为cancelAndHoldAtTime。然后做

v

其中setValueAtTime(v, context.currentTime); cancelScheduledValues(context.currentTime + eps); eps附近的一个较小值,或者更大。