module Synthesizer.Dimensional.Arrow where
import qualified Synthesizer.Dimensional.Sample as Sample
import Synthesizer.Dimensional.Sample (Amplitude, Displacement, )
import qualified Synthesizer.Dimensional.Signal.Private as SigA
import qualified Synthesizer.Dimensional.Amplitude.Flat as Flat
import qualified Synthesizer.Dimensional.Amplitude as Amp
import qualified Synthesizer.Dimensional.Rate as Rate
import qualified Synthesizer.Causal.Arrow as CausalArrow
import qualified Control.Arrow as Arrow
import qualified Control.Category as Category
import Control.Arrow (Arrow, ArrowLoop, (>>>), (***), )
import Control.Category (Category, )
import Control.Applicative (Applicative, liftA2, )
import qualified Synthesizer.State.Signal as Sig
import qualified Synthesizer.Generic.Signal as SigG
import qualified Algebra.Module as Module
import qualified Algebra.Field as Field
import qualified Algebra.Ring as Ring
import Algebra.Module ((*>))
import qualified Number.DimensionTerm as DN
import qualified Algebra.DimensionTerm as Dim
import NumericPrelude.Numeric (one)
import NumericPrelude.Base hiding (id)
import Prelude ()
newtype T arrow sample0 sample1 =
Cons (Amplitude sample0 ->
(arrow (Displacement sample0) (Displacement sample1),
Amplitude sample1))
type Single arrow amp0 amp1 yv0 yv1 =
T arrow (Sample.T amp0 yv0) (Sample.T amp1 yv1)
class CausalArrow.C arrow => Applicable arrow rate
instance Applicable (->) rate
infixl 9 `apply`
apply ::
(SigG.Transform sig (Displacement sample0),
SigG.Transform sig (Displacement sample1),
Applicable arrow rate) =>
T arrow sample0 sample1 ->
SigA.T rate (Amplitude sample0) (sig (Displacement sample0)) ->
SigA.T rate (Amplitude sample1) (sig (Displacement sample1))
apply (Cons f) (SigA.Cons rate xAmp samples) =
let (arrow, yAmp) = f xAmp
in SigA.Cons rate yAmp (CausalArrow.apply arrow samples)
applyFlat ::
(Flat.C yv0 amp0,
SigG.Transform sig yv0,
SigG.Transform sig yv1, Applicable arrow rate) =>
Single arrow (Amp.Flat yv0) amp1 yv0 yv1 ->
SigA.T rate amp0 (sig yv0) ->
SigA.T rate amp1 (sig yv1)
applyFlat f =
apply (canonicalizeFlat >>> f)
canonicalizeFlat ::
(Flat.C y flat, Arrow arrow) =>
Single arrow flat (Amp.Flat y) y y
canonicalizeFlat =
Cons $ \ amp -> (Arrow.arr (Flat.amplifySample amp), Amp.Flat)
applyConst ::
(Amp.C amp1, Ring.C y0, CausalArrow.C arrow) =>
Single arrow (Amp.Numeric amp0) amp1 y0 yv1 ->
amp0 ->
SigA.T (Rate.Phantom s) amp1 (Sig.T yv1)
applyConst (Cons f) x =
let (arrow, yAmp) = f (Amp.Numeric x)
in SigA.Cons Rate.Phantom yAmp
(CausalArrow.apply arrow (Sig.repeat one))
infixl 0 $/:, $/-
($/:) ::
(Applicative f,
SigG.Transform sig yv0, SigG.Transform sig yv1,
Applicable arrow rate) =>
f (Single arrow amp0 amp1 yv0 yv1) ->
f (SigA.T rate amp0 (sig yv0)) ->
f (SigA.T rate amp1 (sig yv1))
($/:) = liftA2 apply
($/-) ::
(Amp.C amp1, Functor f, Ring.C y0, CausalArrow.C arrow) =>
f (Single arrow (Amp.Numeric amp0) amp1 y0 yv1) ->
amp0 ->
f (SigA.T (Rate.Phantom s) amp1 (Sig.T yv1))
($/-) p x = fmap (flip applyConst x) p
id ::
(Category arrow) =>
T arrow sample sample
id =
Cons (\amp -> (Category.id, amp))
compose ::
(Category arrow) =>
T arrow sample0 sample1 ->
T arrow sample1 sample2 ->
T arrow sample0 sample2
compose (Cons f) (Cons g) =
Cons $ \ xAmp ->
let (causalXY, yAmp) = f xAmp
(causalYZ, zAmp) = g yAmp
in (causalXY Arrow.>>> causalYZ, zAmp)
instance (Category arrow) => Category (T arrow) where
id = id
(.) = flip compose
instance (Arrow arrow) => Arrow (T arrow) where
arr = error "Dimensional.Arrow.arr: sorry, there is no reasonable implementation"
first = first
second = second
(***) = split
(&&&) = fanout
arr ::
(Arrow arrow, Sample.Build sample0, Sample.Inspect sample1) =>
(sample0 -> sample1) -> T arrow sample0 sample1
arr f = Cons $ \amp0 ->
(Arrow.arr $ \yv0 ->
Sample.displacement $ f $ Sample.build amp0 yv0,
Sample.amplitude $ f $ Sample.build amp0 $
error $ "Dimensional.Arrow.arr: " ++
"output amplitude must not depend on input displacement")
first ::
(Arrow arrow) =>
T arrow sample0 sample1 ->
T arrow (sample0, sample) (sample1, sample)
first (Cons f) =
Cons $ \ (xAmp, amp) ->
let (arrow, yAmp) = f xAmp
in (Arrow.first arrow, (yAmp, amp))
second ::
(Arrow arrow) =>
T arrow sample0 sample1 ->
T arrow (sample, sample0) (sample, sample1)
second (Cons f) =
Cons $ \ (amp, xAmp) ->
let (arrow, yAmp) = f xAmp
in (Arrow.second arrow, (amp, yAmp))
split ::
(Arrow arrow) =>
T arrow sample0 sample1 ->
T arrow sample2 sample3 ->
T arrow (sample0, sample2) (sample1, sample3)
split f g =
compose (first f) (second g)
fanout ::
(Arrow arrow) =>
T arrow sample sample0 ->
T arrow sample sample1 ->
T arrow sample (sample0, sample1)
fanout f g =
compose double (split f g)
independentMap ::
(Arrow arrow) =>
(Amplitude sample0 -> Amplitude sample1) ->
(Displacement sample0 -> Displacement sample1) ->
T arrow sample0 sample1
independentMap f g =
Cons (\amp -> (Arrow.arr g, f amp))
double ::
(Arrow arrow) =>
T arrow sample (sample, sample)
double =
let aux :: sample -> (sample, sample)
aux x = (x, x)
in independentMap aux aux
forceDimensionalAmplitude ::
(Dim.C v, Field.C y, Module.C y yv, Arrow arrow) =>
DN.T v y ->
Single arrow (Amp.Dimensional v y) (Amp.Dimensional v y) yv yv
forceDimensionalAmplitude ampOut =
Cons $ \(Amp.Numeric ampIn) ->
(Arrow.arr (DN.divToScalar ampIn ampOut *>),
Amp.Numeric ampOut)
loop ::
(ArrowLoop arrow) =>
T arrow (restSampleIn, sample) (restSampleOut, sample) ->
T arrow restSampleIn restSampleOut
loop (Cons f) =
Cons $ \restAmpIn ->
let (arrow, (restAmpOut, amp)) = f (restAmpIn, amp)
in (Arrow.loop arrow, restAmpOut)
loopVolume ::
(Field.C y, Module.C y yv, Dim.C v,
ArrowLoop arrow) =>
DN.T v y ->
T arrow
(restSampleIn, Sample.T (Amp.Dimensional v y) yv)
(restSampleOut, Sample.T (Amp.Dimensional v y) yv) ->
T arrow restSampleIn restSampleOut
loopVolume ampIn f =
loop (f >>> second (forceDimensionalAmplitude ampIn))
loop2Volume ::
(Field.C y0, Module.C y0 yv0, Dim.C v0,
Field.C y1, Module.C y1 yv1, Dim.C v1,
ArrowLoop arrow) =>
(DN.T v0 y0, DN.T v1 y1) ->
T arrow
(restSampleIn, (Sample.T (Amp.Dimensional v0 y0) yv0,
Sample.T (Amp.Dimensional v1 y1) yv1))
(restSampleOut, (Sample.T (Amp.Dimensional v0 y0) yv0,
Sample.T (Amp.Dimensional v1 y1) yv1)) ->
T arrow restSampleIn restSampleOut
loop2Volume (ampIn0,ampIn1) f =
loop (f >>> second
(forceDimensionalAmplitude ampIn0 ***
forceDimensionalAmplitude ampIn1))