网络音频延迟

Web audio delay

我正在使用 klank.dev 构建一个简单的 Karplus Strong 弦乐效果器。它工作正常,直到中 C 以上的 F 左右,但不能再高了。例子贴在下面,你也可以试试here(klank只适用于Firefox atm)

有问题的行是 del: Tuple (g'delay 0.00305) (SProxy :: SProxy "combine")。如果你使延迟更长,即 0.009,它会如预期的那样变小。但是如果你把它变短,即0.002,在某个点音调停止上升。

网络音频是否对反馈循环中使用的延迟有硬性下限? MDN 报告最小值是 0.0,它在反馈中未使用时有效,但在反馈循环中我遇到了这个问题。感谢您的任何见解!

module A.Felicidade.Pluck where

import Prelude
import Data.Symbol (SProxy(..))
import Data.Tuple (Tuple(..))
import Data.Typelevel.Num (D1)
import FRP.Behavior (Behavior)
import FRP.Behavior.Audio (AudioUnit, audioWorkletGenerator, g'add, g'delay, g'gain, graph, runInBrowser, speaker')
import Foreign.Object as O
import Record.Extra (SLProxy(..), SNil)
import Type.Data.Graph (type (:/))
import Math(pi, sin, cos)
import Type.Klank.Dev (Klank, Worklets, klank)

worklets :: Worklets
worklets _ res rej =
  ( do
      res [ "https://klank-share.s3.eu-west-1.amazonaws.com/K16029410960343210.js" ]
  )

scene :: Number -> Behavior (AudioUnit D1)
scene time =
  pure
    $ speaker'
        ( graph
            { aggregators:
                { out: Tuple g'add (SLProxy :: SLProxy ("combine" :/ SNil))
                , combine: Tuple g'add (SLProxy :: SLProxy ("gain" :/ "mic" :/ SNil))
                , gain: Tuple (g'gain 0.9) (SLProxy :: SLProxy ("del" :/ SNil))
                }
            , processors:
                { del: Tuple (g'delay 0.00305) (SProxy :: SProxy "combine")
                }
            , generators:
                { mic:
                    audioWorkletGenerator
                      "klank-lf-burst"
                      (O.union (O.singleton "nsamples" 15.0) (O.singleton "freq" 1.0))
                }
            }
        ) where rad = time * pi

main :: Klank
main =
  klank
    { run = runInBrowser scene
    , worklets = worklets
    }

循环(循环)中的 DelayNode 将其延迟限制为最小 1 个渲染量子。参见 https://webaudio.github.io/web-audio-api/#DelayNode-attributes。一个渲染量子的时间是 128 / sampleRate。对于 44.1 kHz 的采样率,这大约是 3 毫秒。

没有办法解决这个问题,因为 WebAudio(当前)在 128 帧的块中工作,如果你有一个循环,所有块都需要 128 帧才能产生输出。

我知道的唯一解决方案是使用 AudioWorklet 实现图形中处于循环中的部分。这有效地从图中删除了循环,因此您可以做任何您需要做的事情。