Веб-аудио API: плавные переходы между аудио затухания вход / выход - PullRequest
0 голосов
/ 04 апреля 2019

У меня есть 3d пространство с разными зонами, каждая зона имеет свои звуки.Моя цель - сделать плавные переходы звука, когда пользователь перемещается из одной зоны в другую, в основном делая перекрестные помехи между звуковыми дорожками.Также я бы хотел изящно обработать случай, когда пользователь передумал и внезапно вернулся в только что оставленную зону, это означает, что отменяются новые аудиопереходы и постепенно возвращается к предыдущему состоянию.

Для этого я использую веб-аудио API , в частности linearRampToValueAtTime и cancelScheduledValues ​​, чтобы определить функции входа / выхода фейдов:

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» запускает fadeIn, а клавиша «O» запускает fadeOut:

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

Я получил противоречивые результаты.Иногда звук исчезает правильно, в других случаях он начинается внезапно в fadeIn или обрывается в fadeOut.Кажется, что вызов cancelScheduledValues ​​, когда переход не завершен, приводит к ошибочному поведению.Я хотел бы, чтобы это работало гладко даже при запуске fadeOut, когда fadeIn еще не завершена и наоборот.Я также пытался немного отложить linearRamps с помощью setTimeout, что-то вроде

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

, но получил одинаково неверные результаты.Я использую API неправильно?Любое предложение?

1 Ответ

2 голосов
/ 04 апреля 2019

Я думаю, что здесь происходит то, что, скажем, вы затихаете и еще не закончили рампу.Затем вы хотите исчезнуть, и отмените события, включая незаконченную рампу.Затем это постепенное изменение исчезает, и значение временной шкалы возвращается к значению предыдущего события.

Итак, как предполагает HankMoody , используйте cancelAndHoldAtTime, который предназначен для обработкиЭта проблема.Но, AFAIK, только Chrome имеет это.

Чтобы быть портативным, я думаю, что вы хотите сделать, это вычислить, где находится рампа в то время, когда вы хотите отменить.Скажем, значение v.Затем выполните

setValueAtTime(v, context.currentTime);
cancelScheduledValues(context.currentTime + eps);

, где eps - это небольшое значение около 1/context.sampleRate или более.

...