module Synthesizer.Dimensional.Causal.FilterParameter (
highpassFromFirstOrder,
lowpassFromFirstOrder,
firstOrder, FirstOrderGlobal,
butterworthLowpass,
butterworthHighpass,
chebyshevALowpass,
chebyshevAHighpass,
chebyshevBLowpass,
chebyshevBHighpass,
SecondOrderCascadeGlobal,
allpassCascade, AllpassCascadeGlobal,
allpassPhaser, AllpassPhaserGlobal,
FiltR.allpassFlangerPhase,
universal, UniversalGlobal,
highpassFromUniversal,
bandpassFromUniversal,
lowpassFromUniversal,
bandlimitFromUniversal,
moogLowpass, MoogLowpassGlobal,
) where
import qualified Synthesizer.Dimensional.Process as Proc
import qualified Synthesizer.Dimensional.Sample as Sample
import qualified Synthesizer.Dimensional.Amplitude as Amp
import qualified Synthesizer.Dimensional.Causal.ControlledProcess as CCProc
import qualified Synthesizer.Dimensional.Causal.Process as CausalD
import qualified Synthesizer.Dimensional.Arrow as ArrowD
import qualified Synthesizer.Causal.Process as Causal
import Control.Arrow (Arrow, arr, (<<^), (^<<), )
import qualified Synthesizer.Dimensional.Amplitude.Flat as Flat
import Synthesizer.Dimensional.Process
(toFrequencyScalar, )
import qualified Synthesizer.Dimensional.Rate.Filter as FiltR
import qualified Synthesizer.Plain.Filter.Recursive.FirstOrder as Filt1
import qualified Synthesizer.Plain.Filter.Recursive.Allpass as Allpass
import qualified Synthesizer.Plain.Filter.Recursive.Universal as UniFilter
import qualified Synthesizer.Plain.Filter.Recursive.Moog as Moog
import qualified Synthesizer.Plain.Filter.Recursive.SecondOrderCascade as Cascade
import qualified Synthesizer.Plain.Filter.Recursive.Butterworth as Butter
import qualified Synthesizer.Plain.Filter.Recursive.Chebyshev as Cheby
import qualified Synthesizer.Plain.Filter.Recursive as FiltRec
import Synthesizer.Utility (affineComb, )
import qualified Algebra.DimensionTerm as Dim
import qualified Number.NonNegative as NonNeg
import qualified Algebra.Transcendental as Trans
import qualified Algebra.Field as Field
import qualified Algebra.Module as Module
import Foreign.Storable (Storable)
import Data.Tuple.HT (swap, mapFst, )
import NumericPrelude.Numeric hiding (negate)
import NumericPrelude.Base as P
import Prelude ()
highpassFromFirstOrder, lowpassFromFirstOrder ::
CausalD.Single s amp amp (Filt1.Result yv) yv
highpassFromFirstOrder = homogeneousMap Filt1.highpass_
lowpassFromFirstOrder = homogeneousMap Filt1.lowpass_
data FirstOrderGlobal = FirstOrderGlobal
firstOrder ::
(Dim.C u, Trans.C q, Arrow arrow) =>
Proc.T s u q
(ArrowD.T arrow
(Sample.Dimensional (Dim.Recip u) q q)
(Sample.T FirstOrderGlobal (CCProc.RateDep s (Filt1.Parameter q))))
firstOrder =
flip fmap (Proc.withParam toFrequencyScalar) $ \toFreq ->
ArrowD.Cons $ \ (Amp.Numeric freqAmp) ->
swap $
(FirstOrderGlobal,
arr $
\ freq ->
(CCProc.RateDep $
Filt1.parameter $
freq * toFreq freqAmp))
instance Amp.C FirstOrderGlobal where
instance Amp.Primitive FirstOrderGlobal where primitive = FirstOrderGlobal
instance (Module.C q yv) =>
CCProc.C FirstOrderGlobal (Filt1.Parameter q)
(Sample.T amp yv) (Sample.T amp (Filt1.Result yv)) where
process =
return $ CausalD.consFlip $ \ (FirstOrderGlobal, amp) ->
(amp, Filt1.causal <<^ mapFst CCProc.unRateDep)
type SecondOrderCascade s u q arrow =
Proc.T s u q
(ArrowD.T arrow
(Sample.Dimensional Dim.Scalar q q,
Sample.Dimensional (Dim.Recip u) q q)
(Sample.T SecondOrderCascadeGlobal
(CCProc.RateDep s (Cascade.Parameter q))))
newtype SecondOrderCascadeGlobal = SecondOrderCascadeGlobal Int
butterworthLowpass, butterworthHighpass ::
(Arrow arrow, Trans.C q, Storable q, Dim.C u) =>
NonNeg.Int ->
SecondOrderCascade s u q arrow
chebyshevALowpass, chebyshevAHighpass ::
(Arrow arrow, Trans.C q, Storable q, Dim.C u) =>
NonNeg.Int ->
SecondOrderCascade s u q arrow
chebyshevBLowpass, chebyshevBHighpass ::
(Arrow arrow, Trans.C q, Storable q, Dim.C u) =>
NonNeg.Int ->
SecondOrderCascade s u q arrow
butterworthLowpass = higherOrderNoReso (Butter.checkedHalf "Parameter.butterworthLowpass") (Butter.parameter FiltRec.Lowpass)
butterworthHighpass = higherOrderNoReso (Butter.checkedHalf "Parameter.butterworthHighpass") (Butter.parameter FiltRec.Highpass)
chebyshevALowpass = higherOrderNoReso id (\n -> Cheby.canonicalizeParameterA . Cheby.parameterA FiltRec.Lowpass n)
chebyshevAHighpass = higherOrderNoReso id (\n -> Cheby.canonicalizeParameterA . Cheby.parameterA FiltRec.Highpass n)
chebyshevBLowpass = higherOrderNoReso id (Cheby.parameterB FiltRec.Lowpass)
chebyshevBHighpass = higherOrderNoReso id (Cheby.parameterB FiltRec.Highpass)
higherOrderNoReso ::
(Arrow arrow, Field.C a, Storable a, Dim.C u) =>
(Int -> Int) ->
(Int -> FiltRec.Pole a -> Cascade.Parameter a) ->
NonNeg.Int ->
SecondOrderCascade s u a arrow
higherOrderNoReso adjustOrder mkParam order =
let orderInt = NonNeg.toNumber order
in flip fmap (Proc.withParam toFrequencyScalar) $ \toFreq ->
ArrowD.Cons $ \ (resoAmp, Amp.Numeric freqAmp) ->
swap $
(SecondOrderCascadeGlobal $ adjustOrder orderInt,
let k = toFreq freqAmp
in arr $
\ (reso, freq) ->
CCProc.RateDep $
mkParam orderInt $
FiltRec.Pole (Flat.amplifySample resoAmp reso) (k*freq))
instance Amp.C SecondOrderCascadeGlobal where
instance (Storable q, Storable yv, Module.C q yv) =>
CCProc.C SecondOrderCascadeGlobal (Cascade.Parameter q)
(Sample.T amp yv) (Sample.T amp yv) where
process =
return $ CausalD.consFlip $ \ (SecondOrderCascadeGlobal orderInt, amp) ->
(amp, Cascade.causal orderInt <<^ mapFst CCProc.unRateDep)
highpassFromUniversal, lowpassFromUniversal,
bandpassFromUniversal, bandlimitFromUniversal ::
CausalD.Single s amp amp (UniFilter.Result yv) yv
highpassFromUniversal = homogeneousMap UniFilter.highpass
bandpassFromUniversal = homogeneousMap UniFilter.bandpass
lowpassFromUniversal = homogeneousMap UniFilter.lowpass
bandlimitFromUniversal = homogeneousMap UniFilter.bandlimit
data UniversalGlobal = UniversalGlobal
universal ::
(Dim.C u, Trans.C q, Arrow arrow) =>
Proc.T s u q
(ArrowD.T arrow
(Sample.Dimensional Dim.Scalar q q,
Sample.Dimensional (Dim.Recip u) q q)
(Sample.T UniversalGlobal (CCProc.RateDep s (UniFilter.Parameter q))))
universal =
flip fmap (Proc.withParam toFrequencyScalar) $ \toFreq ->
(ArrowD.Cons $ \ (resoAmp, Amp.Numeric freqAmp) ->
swap $
(UniversalGlobal,
let k = toFreq freqAmp
in arr $
\ (reso, freq) ->
CCProc.RateDep $
UniFilter.parameter $
FiltRec.Pole (Flat.amplifySample resoAmp reso) (k*freq)))
instance Amp.C UniversalGlobal where
instance Amp.Primitive UniversalGlobal where primitive = UniversalGlobal
instance (Module.C q yv) =>
CCProc.C UniversalGlobal (UniFilter.Parameter q)
(Sample.T amp yv) (Sample.T amp (UniFilter.Result yv)) where
process =
return $ CausalD.consFlip $ \ (UniversalGlobal, amp) ->
(amp, UniFilter.causal <<^ mapFst CCProc.unRateDep)
newtype MoogLowpassGlobal = MoogLowpassGlobal Int
moogLowpass ::
(Dim.C u, Trans.C q, Arrow arrow) =>
NonNeg.Int ->
Proc.T s u q
(ArrowD.T arrow
(Sample.Dimensional Dim.Scalar q q,
Sample.Dimensional (Dim.Recip u) q q)
(Sample.T MoogLowpassGlobal (CCProc.RateDep s (Moog.Parameter q))))
moogLowpass order =
let orderInt = NonNeg.toNumber order
in flip fmap (Proc.withParam toFrequencyScalar) $ \toFreq ->
ArrowD.Cons $ \ (resoAmp, Amp.Numeric freqAmp) ->
swap $
(MoogLowpassGlobal orderInt,
let k = toFreq freqAmp
in arr $
\ (reso, freq) ->
CCProc.RateDep $
Moog.parameter orderInt $
FiltRec.Pole (Flat.amplifySample resoAmp reso) (k*freq))
instance Amp.C MoogLowpassGlobal where
instance (Module.C q yv) =>
CCProc.C MoogLowpassGlobal (Moog.Parameter q)
(Sample.T amp yv) (Sample.T amp yv) where
process =
return $ CausalD.consFlip $ \ (MoogLowpassGlobal orderInt, amp) ->
(amp, Moog.lowpassCausal orderInt <<^ mapFst CCProc.unRateDep)
newtype AllpassCascadeGlobal = AllpassCascadeGlobal Int
allpassCascade ::
(Dim.C u, Trans.C q, Arrow arrow) =>
NonNeg.Int ->
q ->
Proc.T s u q
(ArrowD.T arrow
(Sample.Dimensional (Dim.Recip u) q q)
(Sample.T AllpassCascadeGlobal (CCProc.RateDep s (Allpass.Parameter q))))
allpassCascade order phase =
let orderInt = NonNeg.toNumber order
in flip fmap (Proc.withParam toFrequencyScalar) $ \toFreq ->
ArrowD.Cons $ \ (Amp.Numeric freqAmp) ->
swap $
(AllpassCascadeGlobal orderInt,
arr $
\ freq ->
CCProc.RateDep $
Allpass.cascadeParameter orderInt phase $
freq * toFreq freqAmp)
instance Amp.C AllpassCascadeGlobal where
instance (Module.C q yv) =>
CCProc.C AllpassCascadeGlobal (Allpass.Parameter q)
(Sample.T amp yv) (Sample.T amp yv) where
process =
return $ CausalD.consFlip $ \ (AllpassCascadeGlobal orderInt, amp) ->
(amp, Allpass.cascadeCausal orderInt <<^ mapFst CCProc.unRateDep)
newtype AllpassPhaserGlobal = AllpassPhaserGlobal Int
allpassPhaser ::
(Dim.C u, Trans.C q, Arrow arrow) =>
NonNeg.Int ->
Proc.T s u q
(ArrowD.T arrow
(Sample.Dimensional Dim.Scalar q q,
Sample.Dimensional (Dim.Recip u) q q)
(Sample.T AllpassPhaserGlobal (CCProc.RateDep s (q, Allpass.Parameter q))))
allpassPhaser order =
let orderInt = NonNeg.toNumber order
in flip fmap (Proc.withParam toFrequencyScalar) $ \toFreq ->
ArrowD.Cons $ \ (resoAmp, Amp.Numeric freqAmp) ->
swap $
(AllpassPhaserGlobal orderInt,
arr $
\ (reso, freq) ->
CCProc.RateDep $
(Flat.amplifySample resoAmp reso,
Allpass.flangerParameter orderInt $
freq * toFreq freqAmp))
instance Amp.C AllpassPhaserGlobal where
instance (Module.C q yv) =>
CCProc.C AllpassPhaserGlobal (q, Allpass.Parameter q)
(Sample.T amp yv) (Sample.T amp yv) where
process =
return $ CausalD.consFlip $ \ (AllpassPhaserGlobal orderInt, amp) ->
(amp,
uncurry affineComb
^<<
Causal.second (Causal.fanout
(Allpass.cascadeCausal orderInt) (Causal.map snd))
<<^
(\(CCProc.RateDep (r,p), x) -> (r,(p,x))))
homogeneousMap ::
(yv0 -> yv1) ->
CausalD.Single s amp amp yv0 yv1
homogeneousMap f =
CausalD.homogeneous (Causal.map f)