Karplus-Strong Algo 中的递归反馈 - 箭头
Recursive feedback in Karplus-Strong Algo - arrows
我正在尝试实现 Karplus-Strong algorithm using Euterpea 的最简单版本:
我的代码:
0.7 秒的白噪声爆发
burst :: AudSF () Double
burst = proc () -> do
burstEnv <- envLineSeg [1,1,0,0] [0.7, 0, 9.3] -< ()
noise <- noiseWhite 42 -< ()
outA -< burstEnv * noise
有问题的部分:
karplus :: AudSF Double Double
karplus = proc input -> do
rec filtered <- filterLowPass -< (delayed, 2000)
delayed <- delayLine 0.7 -< filtered + input
outA -< filtered + input
test1 函数应该创建一个 10 秒的文件,周期数为:
test1 = outFile "test1.wav" 10 $ burst >>> karplus
据我所知,反馈回路应该 运行 一直持续下去。
问题是输入只被延迟和过滤一次。它不再被送入循环。
我怀疑问题出在我不理解惰性求值或值传递。
问题不在于惰性求值或递归箭头;相反,filterLowPass
在 burst
上表现不佳:它在爆发结束后变为 NaN
。
我们可以通过 运行 看到它,例如在 GHCi 中:
λ» take 15 $ drop 30870 $ Control.SF.SF.run (strip $ burst >>> arr (,2000) >>> filterLowPass) $ repeat ()
[0.17166330080286152,0.27722776378398983,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN]
我强烈怀疑这是因为 burst
本身在接近尾声时表现异常:
λ» take 15 $ drop 30870 $ Control.SF.SF.run (strip $ burst) $ repeat ()
[0.5998949495013488,NaN,0.0,-0.0,-0.0,0.0,-0.0,-0.0,0.0,-0.0,-0.0,-0.0,0.0,-0.0,0.0]
我的建议是修复 burst
,使其不会在其末尾生成 NaN
,然后查看是否修复了所有问题。 0/-0 振荡可能是无害的。
尝试修复
我对 Euterpea 或声音合成一无所知;但是,通过对 burstEnv
使用非常短但非 0 的从 1 到 0 的过渡时间,我能够摆脱 NaN
。通过进一步减少突发和延迟线的长度,我想我得到了接近所需 "string-like" 声音的东西:
burst :: AudSF () Double
burst = proc () -> do
burstEnv <- envLineSeg [1,1,0,0] [0.01, 0.000001, 9.3] -< ()
noise <- noiseWhite 42 -< ()
outA -< burstEnv * noise
karplus :: AudSF Double Double
karplus = proc input -> do
rec delayed <- delayLine 0.01 -< filtered + input
filtered <- filterLowPass -< (delayed, 2000)
outA -< filtered + input
我正在尝试实现 Karplus-Strong algorithm using Euterpea 的最简单版本:
我的代码: 0.7 秒的白噪声爆发
burst :: AudSF () Double
burst = proc () -> do
burstEnv <- envLineSeg [1,1,0,0] [0.7, 0, 9.3] -< ()
noise <- noiseWhite 42 -< ()
outA -< burstEnv * noise
有问题的部分:
karplus :: AudSF Double Double
karplus = proc input -> do
rec filtered <- filterLowPass -< (delayed, 2000)
delayed <- delayLine 0.7 -< filtered + input
outA -< filtered + input
test1 函数应该创建一个 10 秒的文件,周期数为:
test1 = outFile "test1.wav" 10 $ burst >>> karplus
据我所知,反馈回路应该 运行 一直持续下去。
问题是输入只被延迟和过滤一次。它不再被送入循环。
我怀疑问题出在我不理解惰性求值或值传递。
问题不在于惰性求值或递归箭头;相反,filterLowPass
在 burst
上表现不佳:它在爆发结束后变为 NaN
。
我们可以通过 运行 看到它,例如在 GHCi 中:
λ» take 15 $ drop 30870 $ Control.SF.SF.run (strip $ burst >>> arr (,2000) >>> filterLowPass) $ repeat ()
[0.17166330080286152,0.27722776378398983,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN]
我强烈怀疑这是因为 burst
本身在接近尾声时表现异常:
λ» take 15 $ drop 30870 $ Control.SF.SF.run (strip $ burst) $ repeat ()
[0.5998949495013488,NaN,0.0,-0.0,-0.0,0.0,-0.0,-0.0,0.0,-0.0,-0.0,-0.0,0.0,-0.0,0.0]
我的建议是修复 burst
,使其不会在其末尾生成 NaN
,然后查看是否修复了所有问题。 0/-0 振荡可能是无害的。
尝试修复
我对 Euterpea 或声音合成一无所知;但是,通过对 burstEnv
使用非常短但非 0 的从 1 到 0 的过渡时间,我能够摆脱 NaN
。通过进一步减少突发和延迟线的长度,我想我得到了接近所需 "string-like" 声音的东西:
burst :: AudSF () Double
burst = proc () -> do
burstEnv <- envLineSeg [1,1,0,0] [0.01, 0.000001, 9.3] -< ()
noise <- noiseWhite 42 -< ()
outA -< burstEnv * noise
karplus :: AudSF Double Double
karplus = proc input -> do
rec delayed <- delayLine 0.01 -< filtered + input
filtered <- filterLowPass -< (delayed, 2000)
outA -< filtered + input