{-# OPTIONS -fglasgow-exts -fno-implicit-prelude #-} {- | Copyright : (c) Henning Thielemann 2008 License : GPL Maintainer : synthesizer@henning-thielemann.de Stability : provisional Portability : requires multi-parameter type classes Comb filters, useful for emphasis of tones with harmonics and for repeated echos. We cannot generalize this to "Synthesizer.Generic.Signal" since we need control over the chunk size. -} module Synthesizer.Storable.Filter.Recursive.Comb where import qualified Synthesizer.Storable.Signal as Sig import qualified Synthesizer.Plain.Filter.Recursive.FirstOrder as Filt1 import qualified Synthesizer.Generic.Signal as SigG import qualified Synthesizer.Generic.SampledValue as Sample -- import qualified Synthesizer.Storable.Filter.Delay as Delay import Foreign.Storable (Storable) import qualified Algebra.Module as Module -- import qualified Algebra.Field as Field import qualified Algebra.Ring as Ring import qualified Algebra.Additive as Additive import Algebra.Module((*>)) import qualified Prelude as P import PreludeBase import NumericPrelude {- | The most simple version of the Karplus-Strong algorithm which is suitable to simulate a plucked string. It is similar to the 'runProc' function. -} {-# INLINE karplusStrong #-} karplusStrong :: (Ring.C a, Module.C a v, Sample.C v) => Filt1.Parameter a -> Sig.T v -> Sig.T v karplusStrong c wave = Sig.delayLoop (SigG.modifyStatic Filt1.lowpassModifier c) wave {- | Infinitely many equi-delayed exponentially decaying echos. The echos are clipped to the input length. We think it is easier (and simpler to do efficiently) to pad the input with zeros or whatever instead of cutting the result according to the input length. -} {-# INLINE run #-} run :: (Module.C a v, Storable v) => Int -> a -> Sig.T v -> Sig.T v run time gain = Sig.delayLoopOverlap time (amplify gain) {- | Echos of different delays. Chunk size must be smaller than all of the delay times. -} {-# INLINE runMulti #-} runMulti :: (Ring.C a, Module.C a v, Storable v) => [Int] -> a -> Sig.T v -> Sig.T v runMulti times gain x = let y = foldl (Sig.zipWith (+)) x (map (flip (Sig.delay Sig.defaultChunkSize zero) (amplify gain y)) times) -- (map (flip Delay.staticPos (gain *> y)) times) in y {- | Echos can be piped through an arbitrary signal processor. -} {-# INLINE runProc #-} runProc :: (Additive.C v, Storable v) => Int -> (Sig.T v -> Sig.T v) -> Sig.T v -> Sig.T v runProc = Sig.delayLoopOverlap {-# INLINE amplify #-} amplify :: (Storable v, Module.C a v) => a -> Sig.T v -> Sig.T v amplify gain = Sig.map (gain *>)