synthesizer-llvm-0.6: src/Synthesizer/LLVM/CausalParameterized/ProcessPacked.hs
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE ForeignFunctionInterface #-}
module Synthesizer.LLVM.CausalParameterized.ProcessPacked where
import Synthesizer.LLVM.CausalParameterized.Process (T(Cons), )
import Synthesizer.LLVM.Parameterized.SignalPrivate (withStart, )
import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP
import qualified Synthesizer.LLVM.Parameter as Param
import qualified Synthesizer.LLVM.Frame as Frame
import qualified Synthesizer.LLVM.Frame.SerialVector as Serial
import qualified Synthesizer.LLVM.Frame.Stereo as Stereo
import qualified LLVM.Extra.ScalarOrVector as SoV
import qualified LLVM.Extra.Vector as Vector
import qualified LLVM.Extra.MaybeContinuation as Maybe
import qualified LLVM.Extra.Memory as Memory
import qualified LLVM.Extra.Class as Class
import qualified LLVM.Extra.Arithmetic as A
import qualified LLVM.Extra.Control as C
import LLVM.Extra.Class (MakeValueTuple, ValueTuple, undefTuple, )
import qualified LLVM.Core as LLVM
import LLVM.Core
(CodeGenFunction, Value, valueOf,
IsSized, IsArithmetic,
IsPrimitive, IsFirstClass, )
import qualified Types.Data.Bool as TypeBool
import qualified Types.Data.Num as TypeNum
import Types.Data.Ord ((:<:), )
import qualified Control.Monad.Trans.Class as MT
import qualified Control.Monad.Trans.State as MS
import qualified Control.Category as Cat
import qualified Control.Arrow as Arr
import Control.Arrow ((<<<), )
import Data.Tuple.HT (swap, )
import Data.Word (Word32, )
import Foreign.Storable (Storable, )
import NumericPrelude.Numeric
import NumericPrelude.Base hiding (and, iterate, map, zip, zipWith, )
{- |
Run a scalar process on packed data.
If the signal length is not divisible by the chunk size,
then the last chunk is dropped.
-}
pack ::
(Serial.Read va, n ~ Serial.Size va, a ~ Serial.Element va,
Serial.C vb, n ~ Serial.Size vb, b ~ Serial.Element vb) =>
T p a b -> T p va vb
pack (Cons next start stop createIOContext deleteIOContext) = Cons
(\param a s -> do
r <- Maybe.lift $ Serial.readStart a
((_,w2),(_,s2)) <-
Maybe.fromBool $
C.whileLoop
(valueOf True,
let w = undefTuple
in ((r,w),
(valueOf (fromIntegral $ Serial.sizeOfIterator w :: Word32), s)))
(\(cont,(_rw0,(i0,_s0))) ->
A.and cont =<<
A.cmp LLVM.CmpGT i0 A.zero)
(\(_,((r0,w0),(i0,s0))) -> Maybe.toBool $ do
(ai,r1) <- Maybe.lift $ Serial.readNext r0
(bi,s1) <- next param ai s0
Maybe.lift $ do
w1 <- Serial.writeNext bi w0
i1 <- A.dec i0
return ((r1,w1),(i1,s1)))
b <- Maybe.lift $ Serial.writeStop w2
return (b, s2))
start
stop
createIOContext
deleteIOContext
{- |
Like 'pack' but duplicates the code for the scalar process.
That is, for vectors of size n,
the code for the scalar causal process will be written n times.
This is efficient only for simple input processes.
-}
packSmall ::
(Serial.Read va, n ~ Serial.Size va, a ~ Serial.Element va,
Serial.C vb, n ~ Serial.Size vb, b ~ Serial.Element vb) =>
T p a b -> T p va vb
packSmall (Cons next start stop createIOContext deleteIOContext) = Cons
(\param a ->
MS.runStateT $
(MT.lift . Maybe.lift . Serial.assemble)
=<<
mapM (MS.StateT . next param)
=<<
(MT.lift $ Maybe.lift $ Serial.extractAll a))
start
stop
createIOContext
deleteIOContext
{- |
Run a packed process on scalar data.
If the signal length is not divisible by the chunk size,
then the last chunk is dropped.
In order to stay causal, we have to delay the output by @n@ samples.
-}
unpack ::
(Serial.Zero va, n ~ Serial.Size va, a ~ Serial.Element va,
Serial.Read vb, n ~ Serial.Size vb, b ~ Serial.Element vb,
Memory.C (Serial.WriteIt va), Memory.C (Serial.ReadIt vb),
Memory.C va,
Memory.C vb) =>
T p va vb -> T p a b
unpack (Cons next start stop createIOContext deleteIOContext) = Cons
(\param ai ((w0,r0),(i0,s0)) -> do
endOfVector <- Maybe.lift $ A.cmp LLVM.CmpEQ i0 A.zero
((w2,r2),(i2,s2)) <-
Maybe.fromBool $
C.ifThen endOfVector (valueOf True, ((w0,r0),(i0,s0))) $ do
a0 <- Serial.writeStop w0
(cont1, (b1,s1)) <- Maybe.toBool $ next param a0 s0
r1 <- Serial.readStart b1
w1 <- Serial.writeStart
return (cont1,
((w1, r1),
(valueOf $ fromIntegral $ Serial.size a0, s1)))
Maybe.lift $ do
w3 <- Serial.writeNext ai w2
(bi,r3) <- Serial.readNext r2
i3 <- A.dec i2
return (bi, ((w3,r3),(i3,s2))))
(withStart start $ \s -> do
w <- Serial.writeZero
return ((w, Class.undefTuple), (valueOf (0::Word32), s)))
(\context (_wr,(_i,state)) -> stop context state)
createIOContext
deleteIOContext
raise ::
(Storable a, IsArithmetic a,
MakeValueTuple a, ValueTuple a ~ (Value a),
IsPrimitive a, Memory.FirstClass a,
Memory.Stored a ~ am, IsSized am,
TypeNum.PositiveT n) =>
Param.T p a ->
T p (Serial.Value n a) (Serial.Value n a)
raise =
CausalP.map
(\x y -> Serial.upsample x >>= flip Frame.mix y)
amplify ::
(Storable a, IsArithmetic a,
MakeValueTuple a, ValueTuple a ~ (Value a),
IsPrimitive a, Memory.FirstClass a,
Memory.Stored a ~ am, IsSized am,
TypeNum.PositiveT n) =>
Param.T p a ->
T p (Serial.Value n a) (Serial.Value n a)
amplify =
CausalP.map
(\x y -> Serial.upsample x >>= flip Frame.amplifyMono y)
amplifyStereo ::
(Storable a, IsArithmetic a,
MakeValueTuple a, ValueTuple a ~ (Value a),
IsPrimitive a, Memory.FirstClass a,
Memory.Stored a ~ am, IsSized am,
TypeNum.PositiveT n) =>
Param.T p a ->
T p (Stereo.T (Serial.Value n a)) (Stereo.T (Serial.Value n a))
amplifyStereo =
CausalP.map
(\x y -> Serial.upsample x >>= flip Frame.amplifyStereo y)
osciCore ::
(Memory.FirstClass t, Memory.Stored t ~ tm, IsSized t, IsSized tm,
Vector.Real t, SoV.Fraction t, LLVM.IsFloating t,
TypeNum.PositiveT n) =>
T p (Serial.Value n t, Serial.Value n t) (Serial.Value n t)
osciCore =
CausalP.zipWithSimple A.addToPhase <<<
Arr.second
(CausalP.mapAccumSimple
(\a phase0 -> do
(phase1,b1) <- Serial.cumulate phase0 a
phase2 <- A.signedFraction phase1
return (b1,phase2))
(return A.zero))
osciSimple ::
(Memory.FirstClass t, Memory.Stored t ~ tm, IsSized t, IsSized tm,
Vector.Real t, SoV.Fraction t, LLVM.IsFloating t,
TypeNum.PositiveT n) =>
(forall r. Serial.Value n t -> CodeGenFunction r y) ->
T p (Serial.Value n t, Serial.Value n t) y
osciSimple wave =
CausalP.mapSimple wave <<< osciCore
shapeModOsci ::
(Memory.FirstClass t, Memory.Stored t ~ tm, IsSized t, IsSized tm,
Vector.Real t, SoV.Fraction t, LLVM.IsFloating t,
TypeNum.PositiveT n) =>
(forall r. c -> Serial.Value n t -> CodeGenFunction r y) ->
T p (c, (Serial.Value n t, Serial.Value n t)) y
shapeModOsci wave =
CausalP.zipWithSimple wave <<< Arr.second osciCore
delay1 ::
(Serial.C va, n ~ Serial.Size va, al ~ Serial.Element va,
Storable a,
MakeValueTuple a, ValueTuple a ~ al,
Memory.C al) =>
Param.T p a -> T p va va
delay1 initial =
CausalP.loop initial $
CausalP.mapSimple (fmap swap . uncurry Serial.shiftUp . swap)
differentiate ::
(Serial.C va, n ~ Serial.Size va, al ~ Serial.Element va,
A.Additive va,
Storable a,
MakeValueTuple a, ValueTuple a ~ al,
Memory.C al) =>
Param.T p a -> T p va va
differentiate initial =
Cat.id - delay1 initial
integrate ::
(Storable a, MakeValueTuple a, ValueTuple a ~ Value a, Vector.Arithmetic a,
Memory.FirstClass a, Memory.Stored a ~ am, IsSized am,
TypeNum.PositiveT n) =>
Param.T p a ->
T p (Serial.Value n a) (Serial.Value n a)
integrate =
CausalP.mapAccum
(\() a acc0 -> do
(acc1,b) <- Serial.cumulate acc0 a
return (b,acc1))
return
(return ())
arrayElement ::
(IsFirstClass a, LLVM.Value a ~ Serial.Element v, Serial.C v,
LLVM.GetValue (LLVM.Array dim a) index,
LLVM.ValueType (LLVM.Array dim a) index ~ a,
TypeNum.NaturalT index, TypeNum.NaturalT dim,
(index :<: dim) ~ TypeBool.True) =>
index -> T p (Value (LLVM.Array dim a)) v
arrayElement i =
CausalP.mapSimple Serial.upsample <<< CausalP.arrayElement i