synthesizer-llvm 0.9 → 1.0
raw patch · 111 files changed
+13877/−16474 lines, 111 filesdep +doctest-exitcode-stdiodep ~llvm-dsldep ~llvm-extradep ~llvm-tf
Dependencies added: doctest-exitcode-stdio
Dependency ranges changed: llvm-dsl, llvm-extra, llvm-tf, optparse-applicative, random, tfp, transformers, unsafe
Files
- Changes.md +6/−0
- alsa/Synthesizer/LLVM/Server/CausalPacked/Run.hs +17/−16
- alsa/Synthesizer/LLVM/Server/CausalPacked/Test.hs +55/−57
- alsa/Synthesizer/LLVM/Server/Packed/Run.hs +49/−43
- alsa/Synthesizer/LLVM/Server/Packed/Test.hs +103/−117
- alsa/Synthesizer/LLVM/Server/Scalar/Run.hs +27/−25
- alsa/Synthesizer/LLVM/Server/Scalar/Test.hs +9/−15
- example/Synthesizer/LLVM/ExampleUtility.hs +29/−0
- example/Synthesizer/LLVM/LAC2011.hs +52/−132
- example/Synthesizer/LLVM/LNdW2011.hs +139/−173
- example/Synthesizer/LLVM/Test.hs +1923/−2002
- example/Synthesizer/LLVM/TestALSA.hs +6/−1
- jack/Synthesizer/LLVM/Server/JACK.hs +21/−14
- render/Synthesizer/LLVM/Server/Render.hs +2/−1
- server/Synthesizer/LLVM/Server/CausalPacked/Arrange.hs +53/−49
- src/Synthesizer/LLVM/Causal/Controlled.hs +54/−35
- src/Synthesizer/LLVM/Causal/ControlledPacked.hs +61/−37
- src/Synthesizer/LLVM/Causal/Exponential2.hs +414/−0
- src/Synthesizer/LLVM/Causal/Functional.hs +519/−0
- src/Synthesizer/LLVM/Causal/FunctionalPlug.hs +376/−0
- src/Synthesizer/LLVM/Causal/Helix.hs +622/−0
- src/Synthesizer/LLVM/Causal/Parameterized.hs +67/−0
- src/Synthesizer/LLVM/Causal/Private.hs +301/−0
- src/Synthesizer/LLVM/Causal/Process.hs +786/−755
- src/Synthesizer/LLVM/Causal/ProcessPacked.hs +114/−112
- src/Synthesizer/LLVM/Causal/ProcessPrivate.hs +0/−306
- src/Synthesizer/LLVM/Causal/ProcessValue.hs +34/−38
- src/Synthesizer/LLVM/Causal/Render.hs +364/−0
- src/Synthesizer/LLVM/Causal/RingBufferForward.hs +281/−0
- src/Synthesizer/LLVM/CausalParameterized/Controlled.hs +0/−41
- src/Synthesizer/LLVM/CausalParameterized/ControlledPacked.hs +0/−48
- src/Synthesizer/LLVM/CausalParameterized/Functional.hs +0/−531
- src/Synthesizer/LLVM/CausalParameterized/FunctionalPlug.hs +0/−339
- src/Synthesizer/LLVM/CausalParameterized/Helix.hs +0/−636
- src/Synthesizer/LLVM/CausalParameterized/Process.hs +0/−1044
- src/Synthesizer/LLVM/CausalParameterized/ProcessPacked.hs +0/−114
- src/Synthesizer/LLVM/CausalParameterized/ProcessPrivate.hs +0/−518
- src/Synthesizer/LLVM/CausalParameterized/ProcessValue.hs +0/−100
- src/Synthesizer/LLVM/CausalParameterized/RingBuffer.hs +0/−59
- src/Synthesizer/LLVM/CausalParameterized/RingBufferForward.hs +0/−295
- src/Synthesizer/LLVM/Complex.hs +43/−7
- src/Synthesizer/LLVM/ConstantPiece.hs +22/−72
- src/Synthesizer/LLVM/EventIterator.hs +3/−3
- src/Synthesizer/LLVM/Filter/Allpass.hs +125/−221
- src/Synthesizer/LLVM/Filter/Butterworth.hs +42/−43
- src/Synthesizer/LLVM/Filter/Chebyshev.hs +59/−71
- src/Synthesizer/LLVM/Filter/ComplexFirstOrder.hs +52/−26
- src/Synthesizer/LLVM/Filter/ComplexFirstOrderPacked.hs +85/−99
- src/Synthesizer/LLVM/Filter/FirstOrder.hs +98/−257
- src/Synthesizer/LLVM/Filter/Moog.hs +57/−79
- src/Synthesizer/LLVM/Filter/NonRecursive.hs +67/−81
- src/Synthesizer/LLVM/Filter/SecondOrder.hs +116/−45
- src/Synthesizer/LLVM/Filter/SecondOrderCascade.hs +47/−126
- src/Synthesizer/LLVM/Filter/SecondOrderPacked.hs +62/−52
- src/Synthesizer/LLVM/Filter/Universal.hs +121/−30
- src/Synthesizer/LLVM/ForeignPtr.hs +10/−0
- src/Synthesizer/LLVM/Frame/Binary.hs +1/−0
- src/Synthesizer/LLVM/Frame/SerialVector.hs +61/−613
- src/Synthesizer/LLVM/Frame/SerialVector/Class.hs +523/−0
- src/Synthesizer/LLVM/Frame/SerialVector/Code.hs +279/−0
- src/Synthesizer/LLVM/Frame/SerialVector/Plain.hs +38/−0
- src/Synthesizer/LLVM/Frame/Stereo.hs +149/−29
- src/Synthesizer/LLVM/Frame/StereoInterleaved.hs +24/−311
- src/Synthesizer/LLVM/Frame/StereoInterleavedCode.hs +241/−0
- src/Synthesizer/LLVM/Generator/Core.hs +86/−0
- src/Synthesizer/LLVM/Generator/Exponential2.hs +0/−332
- src/Synthesizer/LLVM/Generator/Extra.hs +39/−0
- src/Synthesizer/LLVM/Generator/Private.hs +201/−0
- src/Synthesizer/LLVM/Generator/Render.hs +525/−0
- src/Synthesizer/LLVM/Generator/Signal.hs +345/−0
- src/Synthesizer/LLVM/Generator/SignalPacked.hs +351/−0
- src/Synthesizer/LLVM/Generator/Source.hs +148/−0
- src/Synthesizer/LLVM/Interpolation.hs +70/−9
- src/Synthesizer/LLVM/MIDI.hs +31/−139
- src/Synthesizer/LLVM/MIDI/BendModulation.hs +45/−15
- src/Synthesizer/LLVM/Parameter.hs +0/−12
- src/Synthesizer/LLVM/Parameterized/Signal.hs +0/−1000
- src/Synthesizer/LLVM/Parameterized/SignalPacked.hs +0/−287
- src/Synthesizer/LLVM/Parameterized/SignalPrivate.hs +0/−346
- src/Synthesizer/LLVM/Plug/Input.hs +117/−104
- src/Synthesizer/LLVM/Plug/Output.hs +35/−55
- src/Synthesizer/LLVM/Private.hs +26/−0
- src/Synthesizer/LLVM/Server/CausalPacked/Common.hs +37/−0
- src/Synthesizer/LLVM/Server/CausalPacked/Instrument.hs +353/−258
- src/Synthesizer/LLVM/Server/CausalPacked/InstrumentPlug.hs +59/−53
- src/Synthesizer/LLVM/Server/CausalPacked/Speech.hs +71/−56
- src/Synthesizer/LLVM/Server/CausalPacked/SpeechExplore.hs +43/−28
- src/Synthesizer/LLVM/Server/Common.hs +272/−75
- src/Synthesizer/LLVM/Server/CommonPacked.hs +13/−28
- src/Synthesizer/LLVM/Server/Packed/Instrument.hs +1491/−1486
- src/Synthesizer/LLVM/Server/Parameter.hs +0/−106
- src/Synthesizer/LLVM/Server/Scalar/Instrument.hs +82/−90
- src/Synthesizer/LLVM/Simple/Signal.hs +0/−384
- src/Synthesizer/LLVM/Simple/SignalPacked.hs +0/−166
- src/Synthesizer/LLVM/Simple/SignalPrivate.hs +0/−340
- src/Synthesizer/LLVM/Simple/Value.hs +0/−569
- src/Synthesizer/LLVM/Simple/Vanilla.hs +0/−86
- src/Synthesizer/LLVM/Storable/ChunkIterator.hs +3/−4
- src/Synthesizer/LLVM/Storable/Process.hs +10/−11
- src/Synthesizer/LLVM/Storable/Signal.hs +46/−136
- src/Synthesizer/LLVM/Storable/Vector.hs +2/−3
- src/Synthesizer/LLVM/Value.hs +39/−0
- src/Synthesizer/LLVM/Wave.hs +15/−2
- synthesizer-llvm.cabal +46/−37
- testsuite/Test/Main.hs +13/−7
- testsuite/Test/Synthesizer/LLVM/Filter.hs +189/−182
- testsuite/Test/Synthesizer/LLVM/Generator.hs +16/−35
- testsuite/Test/Synthesizer/LLVM/Helix.hs +50/−41
- testsuite/Test/Synthesizer/LLVM/Packed.hs +80/−79
- testsuite/Test/Synthesizer/LLVM/RingBufferForward.hs +67/−57
- testsuite/Test/Synthesizer/LLVM/Utility.hs +52/−38
Changes.md view
@@ -1,5 +1,11 @@ # Change log for the `synthesizer-llvm` package +## 1.0++* Move from `llvm-dsl` `Parameter` to `Exp` for parameters.+ Remove clumsy distinction between simple and parameterized+ `Signal`s and `Process`es.+ ## 0.9 * Clean separation between Haskell's `Storable` memory format
alsa/Synthesizer/LLVM/Server/CausalPacked/Run.hs view
@@ -20,10 +20,12 @@ import qualified Synthesizer.ALSA.CausalIO.Process as PAlsa import qualified Synthesizer.CausalIO.Process as PIO -import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP+import qualified Synthesizer.LLVM.Causal.Render as CausalRender+import qualified Synthesizer.LLVM.Causal.Process as Causal import qualified Synthesizer.LLVM.Storable.Signal as SigStL import qualified Synthesizer.LLVM.Frame.StereoInterleaved as StereoInt+import qualified Synthesizer.LLVM.Frame.Stereo as Stereo import qualified Data.StorableVector as SV @@ -34,8 +36,7 @@ import qualified Sound.MIDI.Message.Channel.Voice as VoiceMsg import qualified Sound.MIDI.Message.Channel as ChannelMsg -import Control.Arrow ((<<<), (^<<), arr)-import Control.Category (id)+import Control.Arrow (arr, (<<<), (^<<), (<<^)) import qualified Number.DimensionTerm as DN @@ -75,7 +76,7 @@ opt <- Option.get proc <- Arrange.keyboardFM- (CausalP.mapSimple StereoInt.interleave)+ (Causal.map StereoInt.interleave) (Option.channel opt) playFromEvents opt $ \ sampleRate -> SigStL.unpackStereoStrict ^<< proc sampleRate@@ -87,7 +88,7 @@ PIO.T (MIO.Events Event.T) (SV.Vector StereoVector)) keyboardDetuneFMCore opt = Arrange.keyboardDetuneFMCore- (CausalP.mapSimple StereoInt.interleave)+ (Causal.map StereoInt.interleave) (Option.sampleDirectory opt) keyboardDetuneFM :: IO ()@@ -111,7 +112,7 @@ opt <- Option.get proc <- Arrange.voderBand- (CausalP.mapSimple StereoInt.interleave)+ (Causal.map StereoInt.interleave) (Option.sampleDirectory opt) playFromEvents opt $ \ sampleRate ->@@ -124,7 +125,7 @@ opt <- Option.get proc <- Arrange.voderMask- (CausalP.mapSimple StereoInt.interleave)+ (Causal.map StereoInt.interleave) (Option.sampleDirectory opt) playFromEvents opt $ \ sampleRate ->@@ -137,7 +138,7 @@ opt <- Option.get proc <- Arrange.voderMaskEnv- (CausalP.mapSimple StereoInt.interleave)+ (Causal.map StereoInt.interleave) (Option.sampleDirectory opt) playFromEvents opt $ \ sampleRate ->@@ -150,7 +151,7 @@ opt <- Option.get proc <- Arrange.voderMaskSeparated- (CausalP.mapSimple StereoInt.interleave)+ (const $ Causal.map StereoInt.interleave) (Option.sampleDirectory opt) playFromEvents opt $ \ sampleRate ->@@ -158,7 +159,7 @@ <<< proc (Option.channel opt) (Option.extraChannel opt)- (VoiceMsg.toProgram 4) sampleRate+ (VoiceMsg.toProgram 4) sampleRate () voderMaskMulti :: IO () voderMaskMulti = do@@ -171,21 +172,21 @@ formant = do opt <- Option.get proc <-- Arrange.keyboardDetuneFMCore id+ Arrange.keyboardDetuneFMCore (arr Stereo.multiValue) (Option.sampleDirectory opt) form <- Speech.filterFormant- mix <- CausalP.processIO CausalP.mix+ mix <- CausalRender.run Causal.mix interleave <-- CausalP.processIO- (CausalP.mapSimple StereoInt.interleave)+ CausalRender.run+ (Causal.map StereoInt.interleave <<^ Stereo.unMultiValue) playFromEvents opt $ \ sampleRate -> arr SigStL.unpackStereoStrict <<<- interleave ()+ interleave <<< foldl1- (\x y -> mix () <<< Zip.arrowFanout x y)+ (\x y -> mix <<< Zip.arrowFanout x y) (zipWith (\n (freq, amp, reson) -> form sampleRate
alsa/Synthesizer/LLVM/Server/CausalPacked/Test.hs view
@@ -6,12 +6,11 @@ import qualified Synthesizer.LLVM.Server.SampledSound as Sample import qualified Synthesizer.LLVM.Server.Option as Option import qualified Synthesizer.LLVM.Server.Default as Default+import Synthesizer.LLVM.Server.CausalPacked.Common (chopEvents) import Synthesizer.LLVM.Server.CausalPacked.Arrange ((&+&), shortTime, controllerExponentialDim)-import Synthesizer.LLVM.Server.CommonPacked- (Vector)-import Synthesizer.LLVM.Server.Common hiding- (Instrument)+import Synthesizer.LLVM.Server.CommonPacked (Vector)+import Synthesizer.LLVM.Server.Common hiding (Instrument) import qualified Sound.ALSA.Sequencer.Event as Event -- import qualified Sound.ALSA.Sequencer.Connect as Connect@@ -38,15 +37,17 @@ import qualified Synthesizer.PiecewiseConstant.Signal as PC import qualified Synthesizer.CausalIO.Process as PIO -import qualified Synthesizer.LLVM.CausalParameterized.FunctionalPlug as FP-import qualified Synthesizer.LLVM.CausalParameterized.Functional as F-import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP-import qualified Synthesizer.LLVM.Parameterized.Signal as SigP+import qualified Synthesizer.LLVM.Causal.FunctionalPlug as FP+import qualified Synthesizer.LLVM.Causal.Functional as F+import qualified Synthesizer.LLVM.Causal.Render as CausalRender+import qualified Synthesizer.LLVM.Causal.Process as Causal+import qualified Synthesizer.LLVM.Generator.Render as Render+import qualified Synthesizer.LLVM.Generator.Signal as Sig import qualified Synthesizer.LLVM.Storable.Process as CausalSt import qualified Synthesizer.LLVM.Storable.Signal as SigStL import qualified Synthesizer.LLVM.MIDI.BendModulation as BM import qualified Synthesizer.LLVM.Wave as Wave-import Synthesizer.LLVM.CausalParameterized.Process (($*), ($<))+import Synthesizer.LLVM.Causal.Process (($*), ($<)) import qualified Synthesizer.Generic.Cut as CutG import qualified Synthesizer.Storable.Cut as CutSt@@ -58,11 +59,13 @@ import qualified Data.EventList.Relative.TimeMixed as EventListTM import qualified Data.EventList.Relative.BodyTime as EventListBT +import qualified LLVM.DSL.Expression as Expr+ import System.Path ((</>)) -import Control.Arrow ((<<<), (<<^), (^<<), arr, first)+import Control.Arrow (arr, (***), (<<<), (<<^), (^<<)) import Control.Category (id)-import Control.Applicative (pure, liftA2)+import Control.Applicative (liftA2) import Control.Monad (when) import Control.Monad.Trans.State (evalState) @@ -75,8 +78,9 @@ import Data.Word (Word8, Word32) import Data.Int (Int32) -import Foreign.Storable (Storable)+import qualified System.Unsafe as Unsafe import qualified System.IO as IO+import Foreign.Storable (Storable) import Control.Exception (bracket) import Prelude hiding (Real, id)@@ -229,10 +233,10 @@ opt <- Option.get arrange <- CausalSt.makeArranger amp <-- CausalP.processIO- (CausalP.mapSimple StereoInt.interleave <<<- CausalP.envelopeStereo <<<- first (CausalP.mapSimple Serial.upsample))+ CausalRender.run+ (Causal.map StereoInt.interleave <<<+ Causal.envelopeStereo <<<+ Causal.map Serial.upsample *** arr Stereo.unMultiValue) ping <- Instr.pingStereoReleaseFM @@ -269,7 +273,7 @@ let proc = arr SigStL.unpackStereoStrict <<<- amp ()+ amp <<< (MCS.controllerExponential controllerVolume (0.001, 1) (0.2::Float) <<^ Zip.second)@@ -321,8 +325,8 @@ opt <- Option.get amp <-- CausalP.processIO- (CausalP.mapSimple StereoInt.interleave)+ CausalRender.run+ (Causal.map StereoInt.interleave <<^ Stereo.unMultiValue) tomatoSmps <- makeSampledSounds opt @@ -337,7 +341,7 @@ writeTest (arr SigStL.unpackStereoStrict <<<- amp ()+ amp <<< tomato (last tomatoSmps) 0 440) $ map@@ -393,8 +397,8 @@ opt <- Option.get amp <-- CausalP.processIO- (CausalP.mapSimple StereoInt.interleave)+ CausalRender.run+ (Causal.map StereoInt.interleave <<^ Stereo.unMultiValue) tomatoSmps <- makeSampledSounds opt @@ -409,7 +413,7 @@ writeTest (arr SigStL.unpackStereoStrict <<<- amp ()+ amp <<< tomato (head tomatoSmps) 0 440) $ map@@ -424,9 +428,9 @@ lfo :: SVL.Vector Real lfo =- SigP.renderChunky (SVL.chunkSize 512)- (1 + 0.1 * SigP.osciSimple Wave.approxSine2 (pure (0::Float)) 0.0001)- ()+ Unsafe.performIO $+ fmap ($ SVL.chunkSize 512) $+ Render.run (1 + 0.1 * Sig.osci Wave.approxSine2 Expr.zero 0.0001) asMono :: vector Real -> vector Real asMono = id@@ -438,10 +442,8 @@ SVL.writeFile "/tmp/test.f32" . asMono .- (\f -> f smp lfo) =<<- CausalP.runStorableChunky- (CausalP.frequencyModulationLinear $- SigP.fromStorableVectorLazy id)+ (\f -> pioApply (f smp) lfo) =<<+ CausalRender.run Causal.frequencyModulationLinear frequencyModulationIO :: IO ()@@ -449,10 +451,7 @@ opt <- Option.get smp <- loadTomato opt - proc <-- CausalP.processIO- (CausalP.frequencyModulationLinear $- SigP.fromStorableVectorLazy id)+ proc <- CausalRender.run Causal.frequencyModulationLinear writeTest (proc smp :: PIO.T (SV.Vector Real) (SV.Vector Real)) $ SVL.chunks lfo@@ -462,10 +461,7 @@ opt <- Option.get smp <- loadTomato opt - proc <-- CausalP.processIO- (CausalP.frequencyModulationLinear $- SigP.fromStorableVector id)+ proc <- CausalRender.run Causal.frequencyModulationLinear writeTest (proc (SV.concat $ SVL.chunks smp) ::@@ -475,9 +471,9 @@ frequencyModulationSawIO :: IO () frequencyModulationSawIO = do proc <-- CausalP.processIO- (CausalP.frequencyModulationLinear- (CausalP.take 50000 $* SigP.osciSaw 0 id))+ CausalRender.run $ \freq ->+ Causal.frequencyModulationLinear+ (Causal.take 50000 $* Sig.osci Wave.saw 0 freq) writeTest (proc (0.01::Real) :: PIO.T (SV.Vector Real) (SV.Vector Real)) $ SVL.chunks lfo@@ -487,9 +483,7 @@ opt <- Option.get smp <- loadTomato opt - proc <-- CausalP.processIO- (CausalP.envelope $< SigP.fromStorableVectorLazy id)+ proc <- CausalRender.run $ \env -> Causal.envelope $< env writeTest (proc smp :: PIO.T (SV.Vector Real) (SV.Vector Real)) $ SVL.chunks lfo@@ -498,14 +492,15 @@ functional :: IO () functional = do phaser <-- CausalP.processIO $ F.withArgs $ \ratio ->- let freq = frequency id- noise = F.fromSignal $ SigP.noise 12 (recip freq)+ CausalRender.run $+ wrapped $ \(NoiseReference noiseRef) (SampleRate _sr) ->+ F.withArgs $ \ratio ->+ let noise = F.fromSignal $ Sig.noise 12 noiseRef in (1-ratio) * noise +- ratio * (CausalP.delayZero 100 F.$& noise)+ ratio * (Causal.delayZero 100 F.$& noise) writeTest- (phaser (sampleRate, 200000) ::+ (phaser sampleRate (200000 :: Real) :: PIO.T (EventListBT.T NonNegW.Int Float) (SV.Vector Float)) $ map (\y -> EventListBT.singleton y 10000) [0, 0.25, 0.5, 0.75, 1.00]@@ -514,12 +509,15 @@ functionalPlug :: IO () functionalPlug = do phaser <-- FP.withArgs $ \ratio0 ->- let freq = frequency id- ratio = FP.plug ratio0- noise = FP.fromSignal $ SigP.noise 12 (recip freq)+ FP.withArgs $ \ratio0 pl ->+ (\f ->+ case Expr.unzip pl of+ (sr,noiseRef) -> f (expSampleRate sr) noiseRef) $+ wrapped $ \(NoiseReference noiseRef) (SampleRate _sr) ->+ let ratio = FP.plug ratio0+ noise = FP.fromSignal $ Sig.noise 12 noiseRef in (1-ratio) * noise +- ratio * (CausalP.delayZero 100 FP.$& noise)+ ratio * (Causal.delayZero 100 FP.$& noise) writeTest (phaser () (sampleRate, 200000) ::@@ -531,9 +529,9 @@ makeUnpackStereoStrict :: IO (PIO.T (SV.Vector (Stereo.T Vector)) (SV.Vector (Stereo.T Real))) makeUnpackStereoStrict =- fmap (\proc -> SigStL.unpackStereoStrict ^<< proc ()) $- CausalP.processIO- (CausalP.mapSimple StereoInt.interleave)+ fmap (SigStL.unpackStereoStrict ^<<) $+ CausalRender.run+ (Causal.map StereoInt.interleave <<^ Stereo.unMultiValue) {- makeUnpackStereoStrict :: IO (SV.Vector (Stereo.T Vector) -> SV.Vector (Stereo.T Real))
alsa/Synthesizer/LLVM/Server/Packed/Run.hs view
@@ -20,14 +20,17 @@ import qualified Synthesizer.LLVM.Frame.Stereo as Stereo import qualified Synthesizer.LLVM.Filter.Universal as UniFilterL-import qualified Synthesizer.LLVM.CausalParameterized.ProcessPacked as CausalPS-import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP-import qualified Synthesizer.LLVM.Parameterized.Signal as SigP+import qualified Synthesizer.LLVM.Causal.Render as CausalRender+import qualified Synthesizer.LLVM.Causal.ProcessPacked as CausalPS+import qualified Synthesizer.LLVM.Causal.Process as Causal+import qualified Synthesizer.LLVM.Generator.Render as Render+import qualified Synthesizer.LLVM.Generator.Signal as Sig import qualified Synthesizer.LLVM.Storable.Signal as SigStL import qualified Synthesizer.LLVM.Wave as WaveL-import Synthesizer.LLVM.CausalParameterized.Process (($<), ($*))-import Synthesizer.LLVM.Parameter (($#))+import Synthesizer.LLVM.Causal.Process (($<), ($*)) +import LLVM.DSL.Expression (Exp)+ import qualified Synthesizer.Storable.Signal as SigSt import qualified Data.StorableVector.Lazy as SVL @@ -45,7 +48,7 @@ import qualified System.Path as Path import qualified Control.Applicative.HT as App-import Control.Arrow ((<<<), (^<<), arr)+import Control.Arrow (arr, (<<<), (^<<), (<<^)) import Control.Applicative (pure, liftA2, liftA3, (<*>)) import Control.Monad.Trans.State (evalState) @@ -108,13 +111,13 @@ frequencyModulation = do opt <- Option.get osc <-- SigP.runChunky- ((CausalPS.osciSimple WaveL.triangle $< zero)- $* Instr.frequencyFromBendModulation- (frequencyConst 10)- (Instr.modulation (\fm -> (fm,880))))+ Render.run $+ wrapped $ \(Instr.Modulation fm) ->+ constant frequency 10 $ \speed _sr ->+ ((CausalPS.osci WaveL.triangle $< zero)+ $* Instr.frequencyFromBendModulation speed fm) withMIDIEventsMono opt play $ \vectorChunkSize sampleRate ->- osc vectorChunkSize . (,) sampleRate .+ osc vectorChunkSize sampleRate . flip (,) (880::Real) . evalState (PC.bendWheelPressure (Option.channel opt) 2 0.04 (0.03::Real)) @@ -123,10 +126,10 @@ keyboard = do opt <- Option.get sound <- Instr.pingRelease $/ 0.4 $/ 0.1- amp <- CausalP.runStorableChunky (CausalPS.amplify (arr id))+ amp <- CausalRender.run CausalPS.amplify arrange <- SigStL.makeArranger withMIDIEventsMono opt play $ \vectorChunkSize sampleRate ->- (amp :: Real -> SigSt.T Vector -> SigSt.T Vector) 0.2 .+ pioApply (amp (0.2::Real)) . arrange vectorChunkSize . evalState (Gen.sequence (Option.channel opt) $@@ -137,12 +140,12 @@ opt <- Option.get sound <- Instr.pingStereoRelease $/ 0.4 $/ 0.1 amp <-- CausalP.runStorableChunky- (CausalP.mapSimple StereoInt.interleave <<<- CausalPS.amplifyStereo (arr id))+ CausalRender.run $ \vol ->+ Causal.map StereoInt.interleave <<<+ CausalPS.amplifyStereo vol <<^ Stereo.unMultiValue arrange <- SigStL.makeArranger withMIDIEventsStereo opt play $ \vectorChunkSize sampleRate ->- (amp :: Real -> SigSt.T (Stereo.T Vector) -> SigSt.T StereoVector) 0.2 .+ pioApply (amp (0.2 :: Real)) . arrange vectorChunkSize . evalState (Gen.sequence (Option.channel opt) $@@ -153,12 +156,12 @@ opt <- Option.get str <- Instr.softStringFM amp <-- CausalP.runStorableChunky- (CausalP.mapSimple StereoInt.interleave <<<- CausalPS.amplifyStereo (arr id))+ CausalRender.run $ \vol ->+ Causal.map StereoInt.interleave <<<+ CausalPS.amplifyStereo vol <<^ Stereo.unMultiValue arrange <- SigStL.makeArranger withMIDIEventsStereo opt play $ \vectorChunkSize sampleRate ->- (amp :: Real -> SigSt.T (Stereo.T Vector) -> SigSt.T StereoVector) 0.2 .+ pioApply (amp (0.2 :: Real)) . arrange vectorChunkSize . evalState (do fm <- PC.bendWheelPressure (Option.channel opt) 2 0.04 0.03@@ -171,12 +174,12 @@ str <- Instr.softStringFM tin <- Instr.tineStereoFM $/ 0.4 $/ 0.1 amp <-- CausalP.runStorableChunky- (CausalP.mapSimple StereoInt.interleave <<<- CausalPS.amplifyStereo (arr id))+ CausalRender.run $ \vol ->+ Causal.map StereoInt.interleave <<<+ CausalPS.amplifyStereo vol <<^ Stereo.unMultiValue arrange <- SigStL.makeArranger withMIDIEventsStereo opt play $ \vectorChunkSize sampleRate ->- (amp :: Real -> SigSt.T (Stereo.T Vector) -> SigSt.T StereoVector) 0.2 .+ pioApply (amp (0.2 :: Real)) . arrange vectorChunkSize . evalState (do fm <- PC.bendWheelPressure (Option.channel opt) 2 0.04 0.03@@ -240,10 +243,10 @@ arrange <- SigStL.makeArranger amp <-- CausalP.runStorableChunky- (CausalP.mapSimple StereoInt.interleave <<<- CausalP.envelopeStereo $<- Instr.piecewiseConstantVector (arr id))+ CausalRender.run $ \ctrl ->+ (Causal.map StereoInt.interleave <<<+ Causal.envelopeStereo $< Instr.piecewiseConstantVector ctrl)+ <<^ Stereo.unMultiValue return $ \chan pgm vcsize sr -> do let evHead =@@ -421,7 +424,7 @@ ctrls <- PCS.fromChannel chan - fmap (amp volume . arrange vcsize) $+ fmap (pioApply (amp volume) . arrange vcsize) $ Gen.sequenceModulatedMultiProgram ctrls chan pgm (map (\sound fm -> sound fm $ sr) $@@ -436,35 +439,38 @@ opt <- Option.get proc <- keyboardDetuneFMCore (Option.sampleDirectory opt) withMIDIEventsStereo opt play $ \vectorChunkSize sampleRate ->- evalState (proc (Option.channel opt) (VoiceMsg.toProgram 0) vectorChunkSize sampleRate)+ evalState+ (proc (Option.channel opt) (VoiceMsg.toProgram 0)+ vectorChunkSize sampleRate) keyboardFilter :: IO () keyboardFilter = do opt <- Option.get proc <- keyboardDetuneFMCore (Option.sampleDirectory opt)- mix <- CausalP.runStorableChunky $+ mix <- CausalRender.run $ \xs -> arr id +- (CausalP.mapSimple (StereoInt.amplify 0.5)+ (Causal.map (StereoInt.amplify 0.5) <<<- CausalP.fromSignal (SigP.fromStorableVectorLazy (arr id)))+ Causal.fromSignal xs) lowpass0 <-- CausalP.runStorableChunky $- CausalP.mapSimple StereoInt.interleave+ CausalRender.run $ \cutoff ->+ Causal.map StereoInt.interleave <<< -- CausalPS.amplifyStereo 0.1 <<< CausalPS.pack- (CausalP.stereoFromMonoControlled- (UniFilter.lowpass ^<< UniFilterL.causal) $<- (SigP.interpolateConstant $# (fromIntegral vectorSize :: Real))- (piecewiseConstant (arr id)))+ (Causal.stereoFromMonoControlled+ (UniFilter.lowpass ^<< UniFilterL.causalExp) $<+ Sig.interpolateConstant (fromIntegral vectorSize :: Exp Int)+ (UniFilterL.unMultiValueParameter <$> piecewiseConstant cutoff)) <<<- CausalP.mapSimple StereoInt.deinterleave+ Causal.map StereoInt.deinterleave let lowpass :: Option.SampleRate Real -> PC.T Real -> PC.T Real -> SigSt.T StereoVector -> SigSt.T StereoVector lowpass (Option.SampleRate sr) resons freqs =+ pioApply $ lowpass0 $ fmap UniFilter.parameter $ PC.zipWith FiltR.Pole resons $ fmap (/ sr) freqs @@ -490,5 +496,5 @@ proc (Option.channel opt) (VoiceMsg.toProgram 0) vectorChunkSize sampleRate return- (pureMusic `mix`+ (pioApply (mix pureMusic) $ lowpass sampleRate resonance freq filterMusic))
alsa/Synthesizer/LLVM/Server/Packed/Test.hs view
@@ -3,29 +3,29 @@ import qualified Synthesizer.LLVM.Server.Packed.Instrument as Instr import qualified Synthesizer.LLVM.Server.Default as Default import qualified Synthesizer.LLVM.Server.SampledSound as Sample+import Synthesizer.LLVM.Server.Packed.Instrument (InputArg(Modulation)) import Synthesizer.LLVM.Server.ALSA (makeNote)-import Synthesizer.LLVM.Server.CommonPacked- (Vector, vectorSize)-import Synthesizer.LLVM.Server.Common hiding- (Instrument)+import Synthesizer.LLVM.Server.CommonPacked (Vector, vectorSize)+import Synthesizer.LLVM.Server.Common hiding (Instrument) import qualified Sound.ALSA.Sequencer.Event as Event import qualified Synthesizer.MIDI.PiecewiseConstant as PC import qualified Synthesizer.MIDI.Generic as Gen import qualified Synthesizer.LLVM.Frame.Stereo as Stereo-import qualified Synthesizer.LLVM.Frame.SerialVector as Serial+import qualified Synthesizer.LLVM.Frame.SerialVector.Plain as Serial import qualified Synthesizer.ALSA.Storable.Play as Play import Synthesizer.MIDI.Storable (Instrument, chunkSizesFromLazyTime) import qualified Synthesizer.LLVM.MIDI.BendModulation as BM-import qualified Synthesizer.LLVM.CausalParameterized.ProcessPacked as CausalPS-import qualified Synthesizer.LLVM.Parameterized.SignalPacked as SigPS-import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP-import qualified Synthesizer.LLVM.Parameterized.Signal as SigP+import qualified Synthesizer.LLVM.Causal.ProcessPacked as CausalPS+import qualified Synthesizer.LLVM.Causal.Render as CausalRender+import qualified Synthesizer.LLVM.Causal.Process as Causal+import qualified Synthesizer.LLVM.Generator.SignalPacked as SigPS+import qualified Synthesizer.LLVM.Generator.Render as Render import qualified Synthesizer.LLVM.Storable.Signal as SigStL-import Synthesizer.LLVM.CausalParameterized.Process (($*))+import Synthesizer.LLVM.Causal.Process (($*)) import qualified Synthesizer.Storable.Cut as CutSt import qualified Synthesizer.Storable.Signal as SigSt@@ -36,7 +36,7 @@ import qualified Data.EventList.Relative.BodyTime as EventListBT import Control.Arrow ((<<<), arr)-import Control.Applicative (pure, liftA, liftA2)+import Control.Applicative (pure, liftA, liftA2, (<$>)) import Control.Monad.Trans.State (evalState) import qualified Numeric.NonNegative.Wrapper as NonNegW@@ -212,11 +212,8 @@ liftA (\osc smp _fm _vel _freq _dur -> osc chunkSize (Sample.body smp))- (SigP.runChunky- (let smp = arr id- in fmap (\x -> Stereo.cons x x) $- SigPS.pack $- SigP.fromStorableVectorLazy smp))+ (Render.run $ \smp ->+ fmap (\x -> Stereo.consMultiValue x x) $ SigPS.pack smp) sampledSoundTest1 :: IO (Sample.T ->@@ -226,15 +223,13 @@ liftA (\osc smp _fm _vel _freq _dur -> osc chunkSize (Sample.body smp))- (SigP.runChunky- (let smp = arr id- in CausalP.stereoFromMono- (CausalPS.pack- (CausalP.frequencyModulationLinear- (SigP.fromStorableVectorLazy smp)))+ (Render.run $ \smp ->+ Stereo.multiValue <$>+ Causal.stereoFromMono+ (CausalPS.pack (Causal.frequencyModulationLinear smp)) $* liftA2 Stereo.cons (SigPS.constant 0.999)- (SigPS.constant 1.001)))+ (SigPS.constant 1.001)) -- $* (SigPS.constant $# Stereo.cons 0.999 1.001))) sampledSoundTest2 ::@@ -250,20 +245,18 @@ SigSt.drop (Sample.start pos) $ Sample.body smp in SVP.take (chunkSizesFromLazyTime dur) $- osc chunkSize- (sampleRate, (body, (fm, freq * Sample.period pos))))- (SigP.runChunky- (let smp = signal fst- fm = Instr.modulation snd- in (CausalP.stereoFromMono- (CausalPS.pack- (CausalP.frequencyModulationLinear- (SigP.fromStorableVectorLazy smp)))+ osc chunkSize sampleRate body (fm, freq * Sample.period pos))+ (Render.run $+ wrapped $ \(Signal smp) (Modulation fm) ->+ constant frequency 3 $ \speed _sr ->+ Stereo.multiValue <$>+ ((Causal.stereoFromMono+ (CausalPS.pack (Causal.frequencyModulationLinear smp)) <<< liftA2 Stereo.cons (CausalPS.amplify 0.999) (CausalPS.amplify 1.001))- $* Instr.frequencyFromBendModulation (frequencyConst 3) fm))+ $* Instr.frequencyFromBendModulation speed fm)) sampledSoundTest3SpaceLeak :: IO (Sample.T ->@@ -278,30 +271,28 @@ Without (periodic) frequency modulation we could just split the piecewise constant control curve @fm@. -}- let (sustainFM, releaseFM) =+ let sustainFM, releaseFM :: SigSt.T Vector+ (sustainFM, releaseFM) = SVP.splitAt (chunkSizesFromLazyTime dur) $- (SigSt.repeat chunkSize+ SigSt.repeat chunkSize (Serial.replicate (freq*Sample.period pos/sampleRatePlain))- :: SigSt.T Vector) pos = Sample.positions smp amp = 2 * amplitudeFromVelocity vel (attack, sustain, release) = Sample.parts smp- in osc- (amp,- attack `SigSt.append`- SVL.cycle (SigSt.take (Sample.loopLength pos) sustain))- sustainFM- `SigSt.append`- osc (amp,release) releaseFM)- (CausalP.runStorableChunky- (let smp = arr snd- amp = arr fst- in CausalPS.amplifyStereo amp+ in pioApply+ (osc amp+ (attack `SigSt.append`+ SVL.cycle (SigSt.take (Sample.loopLength pos) sustain)))+ sustainFM+ `SigSt.append`+ pioApply (osc amp release) releaseFM)+ (CausalRender.run $ \amp smp ->+ Stereo.multiValue <$>+ (CausalPS.amplifyStereo amp <<<- CausalP.stereoFromMono+ Causal.stereoFromMono (CausalPS.pack- (CausalP.frequencyModulationLinear- (SigP.fromStorableVectorLazy smp)))+ (Causal.frequencyModulationLinear smp)) <<< liftA2 Stereo.cons (CausalPS.amplify 0.999)@@ -320,18 +311,20 @@ Without (periodic) frequency modulation we could just split the piecewise constant control curve @fm@. -}- let (sustainFM, releaseFM) =+ let sustainFM, releaseFM :: SigSt.T Vector+ (sustainFM, releaseFM) = SVP.splitAt (chunkSizesFromLazyTime dur) $- (freqMod- (chunkSizesFromLazyTime (PC.duration fm))- (sampleRate, (fm, freq*Sample.period pos)) :: SigSt.T Vector)+ pioApplyToLazyTime+ (freqMod sampleRate (fm, freq*Sample.period pos))+ (PC.duration fm) pos = Sample.positions smp in SigSt.map (\x -> Stereo.cons x x) (sustainFM `SigSt.append` releaseFM))- (SigP.runChunkyPattern- (Instr.frequencyFromBendModulation- (frequencyConst 3) (Instr.modulation id)))+ (CausalRender.run $+ wrapped $ \(Modulation fm) ->+ constant frequency 3 $ \speed _sr ->+ Causal.fromSignal $ Instr.frequencyFromBendModulation speed fm) sampledSoundTest5LargeSpaceLeak :: IO (Sample.T ->@@ -346,26 +339,27 @@ Without (periodic) frequency modulation we could just split the piecewise constant control curve @fm@. -}- let (sustainFM, releaseFM) =+ let sustainFM, releaseFM :: SigSt.T Vector+ (sustainFM, releaseFM) = SVP.splitAt (chunkSizesFromLazyTime dur) $- (freqMod- (chunkSizesFromLazyTime (PC.duration fm))- (sampleRate, (fm, freq*Sample.period pos)) :: SigSt.T Vector)+ pioApplyToLazyTime+ (freqMod sampleRate (fm, freq*Sample.period pos))+ (PC.duration fm) pos = Sample.positions smp amp = 2 * amplitudeFromVelocity vel (attack, sustain, release) = Sample.parts smp- in osc- (amp,- attack `SigSt.append`- SVL.cycle (SigSt.take (Sample.loopLength pos) sustain))- sustainFM- `SigSt.append`- osc (amp,release) releaseFM)- (CausalP.runStorableChunky- (arr (\x -> Stereo.cons x x)))- (SigP.runChunkyPattern- (Instr.frequencyFromBendModulation- (frequencyConst 3) (Instr.modulation id)))+ in pioApply+ (osc amp+ (attack `SigSt.append`+ SVL.cycle (SigSt.take (Sample.loopLength pos) sustain)))+ sustainFM+ `SigSt.append`+ pioApply (osc amp release) releaseFM)+ (CausalRender.run $ \ _amp _smp -> arr (\x -> Stereo.consMultiValue x x))+ (CausalRender.run $+ wrapped $ \(Modulation fm) ->+ constant frequency 3 $ \speed _sr ->+ Causal.fromSignal $ Instr.frequencyFromBendModulation speed fm) sampledSoundSmallSpaceLeak4 ::@@ -375,17 +369,16 @@ sampledSoundSmallSpaceLeak4 = liftA (\osc smp _fm _vel freq dur ->- let (sustainFM, releaseFM) =+ let sustainFM, releaseFM :: SigSt.T Vector+ (sustainFM, releaseFM) = SVP.splitAt (chunkSizesFromLazyTime dur) $- (SigSt.repeat chunkSize+ SigSt.repeat chunkSize (Serial.replicate (freq*Sample.period pos/sampleRatePlain))- :: SigSt.T Vector) pos = Sample.positions smp- in osc () sustainFM+ in pioApply osc sustainFM `SigSt.append` SigSt.map (\x -> Stereo.cons x x) releaseFM)- (CausalP.runStorableChunky- (arr (\x -> Stereo.cons x x)))+ (CausalRender.run $ arr (\x -> Stereo.consMultiValue x x)) sampledSoundSmallSpaceLeak4a :: IO (Sample.T ->@@ -395,15 +388,13 @@ liftA (\osc smp _fm _vel freq dur -> case SVP.splitAt (chunkSizesFromLazyTime dur) $- (SigSt.repeat chunkSize- (Serial.replicate (freq*Sample.period (Sample.positions smp) / sampleRatePlain))- :: SigSt.T Vector) of+ SigSt.repeat chunkSize+ (Serial.replicate (freq*Sample.period (Sample.positions smp) / sampleRatePlain)) of (sustainFM, releaseFM) ->- osc () sustainFM+ pioApply osc (sustainFM :: SigSt.T Vector) `SigSt.append` SigSt.map (\x -> Stereo.cons x x) releaseFM)- (CausalP.runStorableChunky- (arr (\x -> Stereo.cons x x)))+ (CausalRender.run $ arr (\x -> Stereo.consMultiValue x x)) sampledSoundNoSmallSpaceLeak3 :: IO (Sample.T ->@@ -412,11 +403,11 @@ sampledSoundNoSmallSpaceLeak3 = pure (\smp _fm _vel freq dur ->- let (sustainFM, releaseFM) =+ let sustainFM, releaseFM :: SigSt.T Vector+ (sustainFM, releaseFM) = SVP.splitAt (chunkSizesFromLazyTime dur) $- (SigSt.repeat chunkSize+ SigSt.repeat chunkSize (Serial.replicate (freq*Sample.period pos/sampleRatePlain))- :: SigSt.T Vector) pos = Sample.positions smp in SigSt.map (\x -> Stereo.cons x x) sustainFM `SigSt.append`@@ -433,18 +424,17 @@ sampledSoundNoSmallSpaceLeak2 = liftA (\osc smp _fm _vel freq dur ->- let (sustainFM, releaseFM) =+ let sustainFM, releaseFM :: SigSt.T Vector+ (sustainFM, releaseFM) = SVP.splitAt (chunkSizesFromLazyTime dur) $- (SigSt.repeat chunkSize+ SigSt.repeat chunkSize (Serial.replicate (freq*Sample.period pos/sampleRatePlain))- :: SigSt.T Vector) pos = Sample.positions smp- in osc ()+ in pioApply osc (amplifySVL sustainFM `SigSt.append` amplifySVL releaseFM))- (CausalP.runStorableChunky- (arr (\x -> Stereo.cons x x)))+ (CausalRender.run $ arr (\x -> Stereo.consMultiValue x x)) sampledSoundSmallSpaceLeak1 :: IO (Sample.T ->@@ -453,17 +443,16 @@ sampledSoundSmallSpaceLeak1 = liftA (\osc smp _fm _vel freq dur ->- let (sustainFM, releaseFM) =+ let sustainFM, releaseFM :: SigSt.T Vector+ (sustainFM, releaseFM) = SVP.splitAt (chunkSizesFromLazyTime dur) $- (SigSt.repeat chunkSize+ SigSt.repeat chunkSize (Serial.replicate (freq*Sample.period pos/sampleRatePlain))- :: SigSt.T Vector) pos = Sample.positions smp- in osc () sustainFM+ in pioApply osc sustainFM `SigSt.append`- osc () releaseFM)- (CausalP.runStorableChunky- (arr (\x -> Stereo.cons x x)))+ pioApply osc releaseFM)+ (CausalRender.run $ arr (\x -> Stereo.consMultiValue x x)) sampledSoundSmallSpaceLeak0 :: IO (Sample.T ->@@ -478,23 +467,22 @@ Without (periodic) frequency modulation we could just split the piecewise constant control curve @fm@. -}- let (sustainFM, releaseFM) =+ let sustainFM, releaseFM :: SigSt.T Vector+ (sustainFM, releaseFM) = SVP.splitAt (chunkSizesFromLazyTime dur) $- (SigSt.repeat chunkSize+ SigSt.repeat chunkSize (Serial.replicate (freq*Sample.period pos/sampleRatePlain))- :: SigSt.T Vector) pos = Sample.positions smp amp = 2 * amplitudeFromVelocity vel (attack, sustain, release) = Sample.parts smp- in osc- (amp,- attack `SigSt.append`- SVL.cycle (SigSt.take (Sample.loopLength pos) sustain))+ in pioApply+ (osc amp+ (attack `SigSt.append`+ SVL.cycle (SigSt.take (Sample.loopLength pos) sustain))) sustainFM `SigSt.append`- osc (amp,release) releaseFM)- (CausalP.runStorableChunky- (arr (\x -> Stereo.cons x x)))+ pioApply (osc amp release) releaseFM)+ (CausalRender.run $ \ _amp _smp -> arr (\x -> Stereo.consMultiValue x x)) makeSample :: Int -> Sample.T makeSample size =@@ -571,10 +559,10 @@ let stereoPlain = SigSt.map (\x -> Stereo.cons x x) SVL.writeFile "test.f32" $ let dur = NonNegChunky.fromChunks $ repeat $ SVL.chunkSize 10+ sustainFM, releaseFM :: SigSt.T Vector !(sustainFM, releaseFM) = SVP.splitAt dur $- (SigSt.repeat chunkSize (Serial.replicate 1)- :: SigSt.T Vector)+ SigSt.repeat chunkSize (Serial.replicate 1) in case 3::Int of -- no leak 0 -> stereoLLVM $ sustainFM `SigSt.append` releaseFM@@ -633,8 +621,7 @@ SVL.writeFile "test.f32" $ arrange vectorChunkSize $ evalState- (let evs =- EventListBT.cons (BM.Cons 0.01 0.001) 10 evs+ (let evs = EventListBT.cons (BM.Cons 0.01 0.001) 10 evs in Gen.sequenceCore Default.channel Gen.errorNoProgram (Gen.Modulator () return@@ -646,8 +633,7 @@ sequenceFM1 = do arrange <- SigStL.makeArranger sound <- Instr.softStringFM $/- let evs =- EventListBT.cons (BM.Cons 0.01 0.001) 10 evs+ let evs = EventListBT.cons (BM.Cons 0.01 0.001) 10 evs in evs -- sound <- Instr.softStringReleaseEnvelope SVL.writeFile "test.f32" $
alsa/Synthesizer/LLVM/Server/Scalar/Run.hs view
@@ -3,20 +3,23 @@ import qualified Synthesizer.LLVM.Server.Scalar.Instrument as Instr import qualified Synthesizer.LLVM.Server.Option as Option import Synthesizer.LLVM.Server.ALSA (Output, play, startMessage)-import Synthesizer.LLVM.Server.Common+import Synthesizer.LLVM.Server.CausalPacked.Common (transposeModulation)+import Synthesizer.LLVM.Server.Common hiding (transposeModulation) import qualified Sound.ALSA.Sequencer.Event as Event import qualified Data.EventList.Relative.TimeBody as EventList -import qualified Synthesizer.LLVM.Frame.Stereo as Stereo+import qualified Synthesizer.LLVM.MIDI.BendModulation as BM import qualified Synthesizer.LLVM.MIDI as MIDIL-import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP-import qualified Synthesizer.LLVM.Parameterized.Signal as SigP+import qualified Synthesizer.LLVM.Frame.Stereo as Stereo+import qualified Synthesizer.LLVM.Causal.Render as CausalRender+import qualified Synthesizer.LLVM.Causal.Process as Causal+import qualified Synthesizer.LLVM.Generator.Render as Render import qualified Synthesizer.LLVM.Storable.Signal as SigStL import qualified Synthesizer.LLVM.Wave as WaveL-import Synthesizer.LLVM.Causal.Process (($<#), ($*))+import Synthesizer.LLVM.Causal.Process (($<), ($*)) -import qualified Synthesizer.Storable.Signal as SigSt+import qualified Synthesizer.Storable.Signal as SigSt import qualified Synthesizer.ALSA.EventList as Ev @@ -25,8 +28,9 @@ import qualified Sound.MIDI.Message.Channel.Voice as VoiceMsg -import Control.Arrow ((<<<), arr)+import Control.Arrow ((^<<), (<<^)) import Control.Monad.Trans.State (evalState)+import Control.Applicative ((<$>)) import Control.Exception (bracket) @@ -57,35 +61,31 @@ -freq :: Option.SampleRate Real -> Real -> Real-freq (Option.SampleRate sampleRate) f =- f / sampleRate-- pitchBend :: IO () pitchBend = do opt <- Option.get osc <-- SigP.runChunky- ((CausalP.osciSimple WaveL.triangle $<# (zero::Real))- $* piecewiseConstant (arr id))+ Render.run $ \fm ->+ Causal.osci WaveL.triangle $< zero $* piecewiseConstant fm withMIDIEvents opt play $ \chunkSize sampleRate -> (id :: SigSt.T Real -> SigSt.T Real) . osc chunkSize .- evalState (PC.pitchBend (Option.channel opt) 2 (freq sampleRate 880))+ evalState (PC.pitchBend (Option.channel opt) 2 (frequency sampleRate 880)) frequencyModulation :: IO () frequencyModulation = do opt <- Option.get osc <-- SigP.runChunky- (((CausalP.osciSimple WaveL.triangle $<# (zero::Real))- <<< (MIDIL.frequencyFromBendModulation (frequencyConst (10::Real))))- $* piecewiseConstant (arr (\(sr,ctrl) -> transposeModulation sr 880 ctrl)))+ Render.run $+ constant frequency 10 $ \speed _sr fm ->+ Causal.osci WaveL.triangle+ $< zero+ $* (MIDIL.frequencyFromBendModulation speed+ $* piecewiseConstant (fmap BM.unMultiValue <$> fm)) withMIDIEvents opt play $ \chunkSize sampleRate -> (id :: SigSt.T Real -> SigSt.T Real) .- osc chunkSize . (,) sampleRate .+ osc chunkSize sampleRate . transposeModulation sampleRate 880 . evalState (PC.bendWheelPressure (Option.channel opt) 2 0.04 (0.03::Real)) @@ -100,10 +100,10 @@ (Instr.pingReleaseEnvelope $/ 0.4 $/ 0.1) -} sound <- Instr.pingRelease $/ 0.4 $/ 0.1- amp <- CausalP.runStorableChunky (CausalP.amplify (arr id))+ amp <- CausalRender.run Causal.amplify arrange <- SigStL.makeArranger withMIDIEvents opt play $ \chunkSize sampleRate ->- (amp :: Real -> SigSt.T Real -> SigSt.T Real) 0.2 .+ pioApply (amp (0.2 :: Real)) . arrange chunkSize . evalState (Gen.sequence@@ -114,10 +114,12 @@ keyboardStereo = do opt <- Option.get sound <- Instr.pingStereoRelease $/ 0.4 $/ 0.1- amp <- CausalP.runStorableChunky (CausalP.amplifyStereo (arr id))+ amp <-+ CausalRender.run $ \vol ->+ Stereo.multiValue ^<< Causal.amplifyStereo vol <<^ Stereo.unMultiValue arrange <- SigStL.makeArranger withMIDIEvents opt play $ \chunkSize sampleRate ->- (amp :: Real -> SigSt.T (Stereo.T Real) -> SigSt.T (Stereo.T Real)) 0.2 .+ pioApply (amp (0.2 :: Real)) . arrange chunkSize . evalState (Gen.sequence
alsa/Synthesizer/LLVM/Server/Scalar/Test.hs view
@@ -13,10 +13,10 @@ import qualified Synthesizer.MIDI.PiecewiseConstant as PC import qualified Synthesizer.MIDI.Generic as Gen -import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP-import qualified Synthesizer.LLVM.Parameterized.Signal as SigP+import qualified Synthesizer.LLVM.Causal.Process as Causal+import qualified Synthesizer.LLVM.Generator.Render as Render import qualified Synthesizer.LLVM.Wave as WaveL-import Synthesizer.LLVM.Causal.Process (($<#), ($*))+import Synthesizer.LLVM.Causal.Process (($<), ($*)) import qualified Synthesizer.Storable.Cut as CutSt import qualified Synthesizer.Storable.Signal as SigSt@@ -24,7 +24,6 @@ import qualified Data.EventList.Relative.TimeBody as EventList -import Control.Arrow (arr) import Control.Monad.Trans.State (evalState) import NumericPrelude.Numeric (zero)@@ -34,9 +33,6 @@ chunkSize :: SVL.ChunkSize chunkSize = Play.defaultChunkSize -sampleRatePlain :: Real-sampleRatePlain = case Default.sampleRate of SampleRate r -> r- sampleRate :: SampleRate Real sampleRate = Default.sampleRate @@ -44,13 +40,12 @@ pitchBend0 :: IO () pitchBend0 = do osc <-- SigP.runChunky- ((CausalP.osciSimple WaveL.triangle $<# (zero::Real))- $* piecewiseConstant (arr id))+ Render.run $ \fm ->+ Causal.osci WaveL.triangle $< zero $* piecewiseConstant fm SVL.writeFile "test.f32" $ (id :: SigSt.T Real -> SigSt.T Real) . osc chunkSize .- evalState (PC.pitchBend Default.channel 2 (880/sampleRatePlain)) $+ evalState (PC.pitchBend Default.channel 2 (frequency sampleRate 880)) $ let evs = EventList.cons 100 [] evs in EventList.cons 0 ([]::[Event.T]) evs @@ -58,13 +53,12 @@ pitchBend1 = do opt <- Option.get osc <-- SigP.runChunky- ((CausalP.osciSimple WaveL.triangle $<# (zero::Real))- $* piecewiseConstant (arr id))+ Render.run $ \fm ->+ Causal.osci WaveL.triangle $< zero $* piecewiseConstant fm withMIDIEvents opt (record "test.f32") $ \ _size _rate -> (id :: SigSt.T Real -> SigSt.T Real) . osc chunkSize .- evalState (PC.pitchBend Default.channel 2 (880/sampleRatePlain))+ evalState (PC.pitchBend Default.channel 2 (frequency sampleRate 880)) pitchBend2 :: IO () pitchBend2 = do
+ example/Synthesizer/LLVM/ExampleUtility.hs view
@@ -0,0 +1,29 @@+module Synthesizer.LLVM.ExampleUtility where++import qualified Synthesizer.LLVM.Frame.SerialVector as Serial+import qualified Synthesizer.LLVM.Frame.Stereo as Stereo++import Type.Data.Num.Decimal (D4, D16)++import Data.Word (Word32)+++type Id a = a -> a++asMono :: Id (vector Float)+asMono = id++asStereo :: Id (vector (Stereo.T Float))+asStereo = id++asMonoPacked :: Id (vector (Serial.T D4 Float))+asMonoPacked = id++asMonoPacked16 :: Id (vector (Serial.T D16 Float))+asMonoPacked16 = id++asWord32 :: Id (vector Word32)+asWord32 = id++asWord32Packed :: Id (vector (Serial.T D4 Word32))+asWord32Packed = id
example/Synthesizer/LLVM/LAC2011.hs view
@@ -2,6 +2,8 @@ {-# OPTIONS_GHC -fno-warn-unused-imports #-} module Synthesizer.LLVM.LAC2011 where +import Synthesizer.LLVM.ExampleUtility+ import qualified Synthesizer.LLVM.Filter.ComplexFirstOrderPacked as BandPass import qualified Synthesizer.LLVM.Filter.Allpass as Allpass import qualified Synthesizer.LLVM.Filter.Butterworth as Butterworth@@ -11,34 +13,32 @@ import qualified Synthesizer.LLVM.Filter.SecondOrderPacked as Filt2P import qualified Synthesizer.LLVM.Filter.Moog as Moog import qualified Synthesizer.LLVM.Filter.Universal as UniFilter-import qualified Synthesizer.LLVM.CausalParameterized.Controlled as CtrlP-import qualified Synthesizer.LLVM.CausalParameterized.ControlledPacked as CtrlPS-import qualified Synthesizer.LLVM.CausalParameterized.ProcessPacked as CausalPS-import qualified Synthesizer.LLVM.CausalParameterized.ProcessValue as CausalPV-import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP-import qualified Synthesizer.LLVM.Causal.ProcessValue as CausalV+import qualified Synthesizer.LLVM.Causal.Controlled as Ctrl import qualified Synthesizer.LLVM.Causal.Process as Causal-import qualified Synthesizer.LLVM.Simple.Signal as Gen+import qualified Synthesizer.LLVM.Generator.Render as Render+import qualified Synthesizer.LLVM.Generator.SignalPacked as GenP+import qualified Synthesizer.LLVM.Generator.Signal as Gen import qualified Synthesizer.LLVM.Storable.Signal as SigStL import qualified Synthesizer.LLVM.Frame.SerialVector as Serial import qualified Synthesizer.LLVM.Frame as Frame import qualified Synthesizer.LLVM.Wave as Wave-import qualified Synthesizer.LLVM.Parameter as Param +import qualified LLVM.DSL.Expression as Expr+import LLVM.DSL.Expression (Exp)+ import qualified LLVM.Extra.ScalarOrVector as SoV import qualified LLVM.Extra.Memory as Memory import qualified LLVM.Extra.Arithmetic as A+import qualified LLVM.Extra.Multi.Vector as MultiVector+import qualified LLVM.Extra.Multi.Value as MultiValue import qualified LLVM.Extra.Tuple as Tuple-import LLVM.Core (Value, value, valueOf, Vector, constVector, constOf)-import LLVM.Util.Arithmetic () -- Floating instance for TValue+ import qualified LLVM.Core as LLVM-import Type.Data.Num.Decimal (D4, D8, D16, d0, d1, d2, d3, d4, d5, d6, d7, d8)+ import qualified Type.Data.Num.Decimal as TypeNum+import Type.Data.Num.Decimal (D4, D8, D16, d0, d1, d2, d3, d4, d5, d6, d7, d8) -import qualified Synthesizer.LLVM.Parameterized.SignalPacked as GenPS-import qualified Synthesizer.LLVM.Parameterized.Signal as GenP import Synthesizer.LLVM.Causal.Process (($<), ($*), ($*#))-import Synthesizer.LLVM.Parameter (($#)) import qualified Synthesizer.Plain.Filter.Recursive as FiltR import qualified Synthesizer.Plain.Filter.Recursive.FirstOrder as Filt1Core@@ -70,7 +70,6 @@ -- import qualified Sound.ALSA.PCM as ALSA -- import qualified Synthesizer.ALSA.Storable.Play as Play -import Data.Word (Word32) import Data.List (genericLength) import System.Random (randomRs, mkStdGen) @@ -85,52 +84,23 @@ import qualified NumericPrelude.Base as P -asMono :: vector Float -> vector Float-asMono = id--asStereo :: vector (Stereo.T Float) -> vector (Stereo.T Float)-asStereo = id--asMonoPacked :: vector (LLVM.Vector D4 Float) -> vector (LLVM.Vector D4 Float)-asMonoPacked = id--asMonoPacked16 :: vector (LLVM.Vector D16 Float) -> vector (LLVM.Vector D16 Float)-asMonoPacked16 = id--asWord32 :: vector Word32 -> vector Word32-asWord32 = id--asWord32Packed :: vector (LLVM.Vector D4 Word32) -> vector (LLVM.Vector D4 Word32)-asWord32Packed = id---playStereo :: Gen.T (Stereo.T (Value Float)) -> IO ()-playStereo =- playStereoStream .- Gen.renderChunky (SVL.chunkSize 100000)+playStereo :: Gen.T (Stereo.T (MultiValue.T Float)) -> IO ()+playStereo sig =+ playStereoStream . ($ SVL.chunkSize 100000) =<<+ Render.run (fmap Stereo.multiValue sig) playStereoStream :: SVL.Vector (Stereo.T Float) -> IO () playStereoStream = playStreamSox -playMono :: Gen.T (Value Float) -> IO ()-playMono =- playMonoStream .- Gen.renderChunky (SVL.chunkSize 100000)--playMonoParam :: GenP.T () (Value Float) -> IO ()-playMonoParam =- playMonoStream .- ($ ()) .- ($ SVL.chunkSize 100000) <=<- GenP.runChunky+playMono :: Gen.MV Float -> IO ()+playMono sig = playMonoStream . ($ SVL.chunkSize 100000) =<< Render.run sig -playMonoPacked :: GenP.T () (Serial.Value D4 Float) -> IO ()+playMonoPacked :: Gen.T (MultiValue.T (Serial.T D4 Float)) -> IO () playMonoPacked = playMonoStream . SigStL.unpack .- ($ ()) . ($ SVL.chunkSize 100000) <=<- GenP.runChunky+ Render.run playMonoStream :: SVL.Vector Float -> IO () playMonoStream = playStreamSox@@ -139,7 +109,7 @@ {- play :: (C.MakeValueTuple y, Tuple.ValueOf y ~ a, Memory.C a struct) =>- Gen.T a -> IO ()+ Gen.MV a -> IO () play = playStreamSox . Gen.renderChunky (SVL.chunkSize 100000)@@ -167,26 +137,12 @@ intSecond :: Ring.C a => Float -> a intSecond t = fromInteger $ round $ t * sampleRate -secondP :: Param.T p Float -> Param.T p Float-secondP t = t * sampleRate--hertzP :: Param.T p Float -> Param.T p Float-hertzP f = f / sampleRate- second :: Field.C a => a -> a second t = t * sampleRate hertz :: Field.C a => a -> a hertz f = f / sampleRate -{--second :: Float -> Param.T p Float-second t = return (t * sampleRate)--hertz :: Float -> Param.T p Float-hertz f = return (f / sampleRate)--}- sine :: IO () sine = playMono (0.99 * Gen.osci Wave.sine 0 (hertz 440))@@ -209,18 +165,11 @@ playStereo (traverse (Gen.osci Wave.triangle 0 . hertz) (Stereo.cons 439 441)) -fst :: Arrow arrow => arrow (a,b) a-fst = arr P.fst--snd :: Arrow arrow => arrow (a,b) b-snd = arr P.snd-- pingParam :: IO (Float -> SVL.Vector Float) pingParam = fmap ($ SVL.chunkSize 1024) $- GenP.runChunky $- GenP.exponential2 (second 0.3) 1 * GenP.osciSimple Wave.triangle 0 id+ Render.run $ \freq ->+ Gen.exponential2 (second 0.3) 1 * Gen.osci Wave.triangle 0 freq playPingParam :: IO () playPingParam = do@@ -240,8 +189,8 @@ pingParam2 :: IO ((Float, Float) -> SVL.Vector Float) pingParam2 = fmap ($ SVL.chunkSize 1024) $- GenP.runChunky $- GenP.exponential2 (second 0.3) fst * GenP.osciSimple Wave.triangle 0 snd+ Render.run $ \(amp,freq) ->+ Gen.exponential2 (second 0.3) amp * Gen.osci Wave.triangle 0 freq playMelody2 :: IO () playMelody2 = do@@ -249,86 +198,57 @@ playMonoStream $ SVL.concat $ map (SVL.take (intSecond 0.2) . png) $ zip (map sin $ [0,0.1..]) (cycle $ map hertz [440, 550, 660, 880]) -retard :: GenP.T p (Value Float) -> GenP.T p (Value Float)+retard :: Gen.MV Float -> Gen.MV Float retard xs =- CausalP.frequencyModulationLinear xs .- CausalV.map Field.recip $*- GenP.rampCore (1 / secondP 10) 1+ Causal.frequencyModulationLinear xs .+ Causal.map Field.recip $*+ (1 + Gen.rampInf (second 10)) playRetarded :: IO () playRetarded = do mel <- melody- playMonoParam $ retard $ GenP.fromStorableVectorLazy $ pure $ mel+ ret <- Render.run retard+ playMonoStream $ ret (SVL.chunkSize 10000) mel -pingGen :: GenP.T p (Value Float)+pingGen :: Gen.MV Float pingGen =- GenP.exponential2 (second 0.5) 0.7 *- GenP.osciSimple Wave.triangle 0 (hertzP 440)--delayp :: Param.T p Int -> CausalP.T p (Value Float) (Value Float)-delayp = CausalP.delayZero+ Gen.exponential2 (second 0.5) 0.7 *+ Gen.osci Wave.triangle 0 (hertz 440) delay :: IO () delay =- playMonoParam $- pingGen + 0.7 * (delayp (intSecond 0.5) $* pingGen)+ playMono $+ pingGen + 0.7 * (Causal.delay 0 (intSecond 0.5) $* pingGen) delayArrow :: IO () delayArrow =- playMonoParam- ((id + 0.7 * delayp (intSecond 0.5)) $* pingGen)+ playMono+ ((id + 0.7 * Causal.delay 0 (intSecond 0.5)) $* pingGen) comb :: IO () comb =- playMonoParam $- (CausalP.loopZero- (id &&& 0.7 * delayp (intSecond 0.5)- <<< CausalP.mix) $*+ playMono $+ (Causal.loopZero+ (id &&& 0.7 * Causal.delay 0 (intSecond 0.5)+ <<< Causal.mix) $* pingGen) -lfoSine ::- Param.T p Float ->- GenP.T p (Moog.Parameter D8 (Value Float))+lfoSine :: Exp Float -> Gen.T (Moog.Parameter D8 (MultiValue.T Float)) lfoSine reduct =- Causal.map (Moog.parameter d8 (valueOf (30::Float))) .- CausalP.mapExponential 2 (hertz 700) $*- GenP.osciSimple Wave.sine 0 (reduct * hertz 0.1)+ Causal.map (Moog.parameter d8 30 . (hertz 700 *) . (2**))+ $*+ Gen.osci Wave.sine 0 (reduct * hertz 0.1) filterSweep :: IO () filterSweep =- playMonoParam $- (0.2 * CtrlP.processCtrlRate 128 lfoSine- $* GenP.noise 0 0.3)+ playMono $+ (Ctrl.processCtrlRate 128 lfoSine $* Gen.noise 0 (recip $ hertz 3.5e6)) pingPacked :: IO () pingPacked =- playMonoPacked (GenPS.exponential2 (second 1) 1 * GenPS.osciSimple Wave.triangle 0 (hertz 440))----{--Module can be loaded into GHCi only when synthesizer-llvm was installed with-$ cabal install --enable-shared--In contrast to that, you have to install with-$ cabal install -fbuildTests -fbuildExamples --enable-shared --disable-library-profiling --ghc-option=-dynamic-for build the executables.-But then GHCi complains:--$ ghci-GHCi, version 6.12.3: http://www.haskell.org/ghc/ :? for help-Loading package ghc-prim ... linking ... done.-Loading package integer-gmp ... linking ... done.-Loading package base ... linking ... done.-Loading package ffi-1.0 ... linking ... done.-[1 of 1] Compiling Main ( src/Synthesizer/LLVM/Test.hs, interpreted )--src/Synthesizer/LLVM/Test.hs:4:0:- Bad interface file: /home/thielema/.cabal/lib/synthesizer-llvm-0.3/ghc-6.12.3/Synthesizer/LLVM/Filter/ComplexFirstOrderPacked.hi- mismatched interface file ways (wanted "", got "dyn")-Failed, modules loaded: none.--}+ playMonoPacked $+ GenP.exponential2 (second 1) 1 * GenP.osci Wave.triangle 0 (hertz 440)
example/Synthesizer/LLVM/LNdW2011.hs view
@@ -1,17 +1,27 @@ {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-} {-# OPTIONS_GHC -fno-warn-unused-imports #-} module Synthesizer.LLVM.LNdW2011 where +import Synthesizer.LLVM.ExampleUtility++import qualified Synthesizer.LLVM.Causal.Render as Render+import qualified Synthesizer.LLVM.Causal.ProcessPacked as CausalP+import qualified Synthesizer.LLVM.Causal.Process as Causal+import qualified Synthesizer.LLVM.Generator.Render as SigRender+import qualified Synthesizer.LLVM.Generator.SignalPacked as GenP+import qualified Synthesizer.LLVM.Generator.Signal as Gen+ import qualified Synthesizer.LLVM.Plug.Input as PIn import qualified Synthesizer.LLVM.Plug.Output as POut import qualified Synthesizer.MIDI.PiecewiseConstant.ControllerSet as PCS import qualified Synthesizer.MIDI.EventList as Ev import qualified Synthesizer.MIDI.CausalIO.ControllerSelection as MCS import qualified Synthesizer.MIDI.CausalIO.Process as PMIDI+import qualified Synthesizer.MIDI.Value as MV import qualified Synthesizer.ALSA.CausalIO.Process as PALSA import qualified Synthesizer.CausalIO.Process as PIO-import qualified Synthesizer.MIDI.Value as MV import qualified Synthesizer.Zip as Zip import Synthesizer.ALSA.EventList (ClientName(ClientName)) @@ -28,34 +38,28 @@ import qualified Synthesizer.LLVM.Filter.SecondOrderPacked as Filt2P import qualified Synthesizer.LLVM.Filter.Moog as Moog import qualified Synthesizer.LLVM.Filter.Universal as UniFilter-import qualified Synthesizer.LLVM.CausalParameterized.Controlled as CtrlP-import qualified Synthesizer.LLVM.CausalParameterized.ControlledPacked as CtrlPS-import qualified Synthesizer.LLVM.CausalParameterized.ProcessPacked as CausalPS-import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP-import qualified Synthesizer.LLVM.Causal.Process as Causal-import qualified Synthesizer.LLVM.Simple.Signal as Gen-import qualified Synthesizer.LLVM.Simple.Value as Value import qualified Synthesizer.LLVM.Storable.Signal as SigStL import qualified Synthesizer.LLVM.Frame.SerialVector as Serial import qualified Synthesizer.LLVM.Frame as Frame import qualified Synthesizer.LLVM.Wave as Wave-import qualified Synthesizer.LLVM.Parameter as Param +import qualified LLVM.DSL.Expression as Expr+import LLVM.DSL.Expression (Exp)++import qualified LLVM.Extra.Multi.Value as MultiValue import qualified LLVM.Extra.ScalarOrVector as SoV import qualified LLVM.Extra.Memory as Memory import qualified LLVM.Extra.Arithmetic as A import qualified LLVM.Extra.Tuple as Tuple+import qualified LLVM.Core as LLVM import LLVM.Core (Value, value, valueOf, constVector, constOf) import LLVM.Util.Arithmetic () -- Floating instance for TValue-import qualified LLVM.Core as LLVM import qualified Type.Data.Num.Decimal as TypeNum import Type.Data.Num.Decimal (D4, D8, D16, d0, d1, d2, d3, d4, d5, d6, d7, d8) -import qualified Synthesizer.LLVM.Parameterized.SignalPacked as GenPS-import qualified Synthesizer.LLVM.Parameterized.Signal as GenP-import Synthesizer.LLVM.Causal.Process (($<), ($*), ($*#), ($<#))-import Synthesizer.LLVM.Parameter (($#))+import qualified Synthesizer.Causal.Class as CausalClass+import Synthesizer.Causal.Class (($<), ($*)) import qualified Synthesizer.Plain.Filter.Recursive as FiltR import qualified Synthesizer.Plain.Filter.Recursive.FirstOrder as Filt1Core@@ -65,17 +69,17 @@ import qualified Control.Monad.Trans.State as State import qualified Control.Arrow as Arr-import Control.Arrow (Arrow, arr, (&&&), (^<<), (^>>))+import Control.Arrow (Arrow, arr, (&&&), (***), (^<<), (^>>), (>>^)) import Control.Category ((<<<), (.), id, (>>>)) import Control.Monad (liftM2, (<=<))-import Control.Applicative (liftA2, pure)+import Control.Applicative (liftA2, pure, (<$>)) import Control.Functor.HT (void) import Data.Tuple.HT (mapPair) import Data.Traversable (traverse) -import Foreign.Storable (Storable) import qualified Data.StorableVector.Lazy as SVL import qualified Data.StorableVector as SV+import Foreign.Storable (Storable) import qualified Data.EventList.Relative.TimeBody as EventList import qualified Data.EventList.Relative.BodyTime as EventListBT@@ -95,13 +99,13 @@ import qualified Sound.ALSA.PCM as ALSA import qualified Synthesizer.ALSA.Storable.Play as Play -import Data.Word (Word32) import Data.List (genericLength) import System.Random (randomRs, mkStdGen) import qualified System.IO as IO import qualified Algebra.NormedSpace.Euclidean as NormedEuc+import qualified Algebra.Algebraic as Algebraic import qualified Algebra.Field as Field import qualified Algebra.Ring as Ring import qualified Algebra.Additive as Additive@@ -112,52 +116,24 @@ import qualified NumericPrelude.Base as P -asMono :: vector Float -> vector Float-asMono = id--asStereo :: vector (Stereo.T Float) -> vector (Stereo.T Float)-asStereo = id--asMonoPacked :: vector Vector -> vector Vector-asMonoPacked = id--asMonoPacked16 :: vector (LLVM.Vector D16 Float) -> vector (LLVM.Vector D16 Float)-asMonoPacked16 = id--asWord32 :: vector Word32 -> vector Word32-asWord32 = id--asWord32Packed :: vector (LLVM.Vector D4 Word32) -> vector (LLVM.Vector D4 Word32)-asWord32Packed = id---playStereo :: Gen.T (Stereo.T (Value Float)) -> IO ()-playStereo =- playStereoStream .- Gen.renderChunky (SVL.chunkSize 100000)+playStereo :: Gen.T (Stereo.T (MultiValue.T Float)) -> IO ()+playStereo sig =+ playStereoStream . ($ SVL.chunkSize 100000) =<<+ SigRender.run (fmap Stereo.multiValue sig) playStereoStream :: SVL.Vector (Stereo.T Float) -> IO () playStereoStream = playStreamSox -playMono :: Gen.T (Value Float) -> IO ()-playMono =- playMonoStream .- Gen.renderChunky (SVL.chunkSize 100000)--playMonoParam :: GenP.T () (Value Float) -> IO ()-playMonoParam =- playMonoStream .- ($ ()) .- ($ SVL.chunkSize 100000) <=<- GenP.runChunky+playMono :: Gen.MV Float -> IO ()+playMono sig =+ playMonoStream . ($ SVL.chunkSize 100000) =<< SigRender.run sig -playMonoPacked :: GenP.T () VectorValue -> IO ()+playMonoPacked :: Gen.T VectorValue -> IO () playMonoPacked = playMonoStream . SigStL.unpack .- ($ ()) . ($ SVL.chunkSize 100000) <=<- GenP.runChunky+ SigRender.run playMonoStream :: SVL.Vector Float -> IO () playMonoStream = playStreamSox@@ -180,9 +156,9 @@ sampleRate :: Ring.C a => a sampleRate = 44100 -type Vector = Serial.Plain VectorSize Float+type Vector = Serial.T VectorSize Float type VectorSize = TypeNum.D4-type VectorValue = Serial.Value VectorSize Float+type VectorValue = MultiValue.T Vector vectorSize :: Int vectorSize =@@ -226,11 +202,9 @@ modulation :: IO () modulation = do- proc <-- CausalP.processIO- (0.95 * (CausalP.osciSimple Wave.approxSine4 $< 0))+ proc <- Render.run (0.95 * (Causal.osci Wave.approxSine4 $< 0)) playFromEvents 0.01 (0.015::Double)- ((proc () :: PIO.T (EventListBT.T NonNegW.Int Float) (SV.Vector Float))+ ((proc :: PIO.T (EventListBT.T NonNegW.Int Float) (SV.Vector Float)) . PMIDI.controllerExponential (ChannelMsg.toChannel 0)@@ -241,32 +215,31 @@ vectorBlockSize :: Double vectorBlockSize = fromIntegral $ 150*vectorSize -subsample :: (Integral.C t) => t -> t -> State.State t t-subsample step t =- State.state $ \r -> divMod (r+t) step-{-- do modify (t+)- (q,r) <- gets (flip divMod step)- put r- return q--}+subsample, _subsample :: (Integral.C t) => t -> t -> State.State t t+subsample step t = State.state $ \r -> divMod (r+t) step+_subsample step t = do+ State.modify (t+)+ (q,r) <- State.gets (flip divMod step)+ State.put r+ return q subsampleBT :: EventListBT.T NonNegW.Int a -> EventListBT.T NonNegW.Int a subsampleBT = flip State.evalState NonNeg.zero .- EventListBT.mapTimeM (subsample (NonNegW.fromNumberMsg "vectorSize" vectorSize))+ EventListBT.mapTimeM+ (subsample (NonNegW.fromNumberMsg "vectorSize" vectorSize)) modulationPacked :: IO () modulationPacked = do proc <-- CausalP.processIO- (0.95 * (CausalPS.osciSimple Wave.approxSine4 $< 0)+ Render.run+ (0.95 * (CausalP.osci Wave.approxSine4 $< 0) . Causal.map Serial.upsample) playFromEvents 0.01 (vectorBlockSize/sampleRate) (arr SigStL.unpackStrict .- (proc () :: PIO.T (EventListBT.T NonNegW.Int Float) (SV.Vector Vector))+ (proc :: PIO.T (EventListBT.T NonNegW.Int Float) (SV.Vector Vector)) . arr subsampleBT .@@ -279,14 +252,14 @@ bubbles :: IO () bubbles = do proc <-- CausalP.processIO- (0.95 * (CausalP.osciSimple Wave.sine $< 0)+ Render.run+ (0.95 * (Causal.osci Wave.sine $< 0) . (fst.fst * (1 + snd.fst * snd)) .- Arr.second (CausalP.osciSimple Wave.saw $< 0))+ Arr.second (Causal.osci Wave.saw $< 0)) playFromEvents 0.01 (0.015::Double)- ((proc () ::+ ((proc :: PIO.T (Zip.T (Zip.T@@ -327,23 +300,23 @@ bubblesSet :: IO () bubblesSet = do proc <-- CausalP.processIOCore+ Render.runPlugged (PIn.controllerSet d6)- (CausalP.arrayElement d0 *- (CausalP.osciSimple Wave.sine $< 0)+ (Causal.arrayElement d0 *+ (Causal.osci Wave.sine $< 0) .- (CausalP.arrayElement d1+ (Causal.arrayElement d1 *- (1 - CausalP.arrayElement d2 *- (CausalP.osciSimple Wave.saw $< 0) .- CausalP.arrayElement d3)+ (1 - Causal.arrayElement d2 *+ (Causal.osci Wave.saw $< 0) .+ Causal.arrayElement d3) *- (1 - CausalP.arrayElement d4 *- (CausalP.osciSimple Wave.saw $< 0) .- CausalP.arrayElement d5)))+ (1 - Causal.arrayElement d4 *+ (Causal.osci Wave.saw $< 0) .+ Causal.arrayElement d5))) POut.storableVector playFromEvents 0.01 (0.015::Double)- ((proc () :: PIO.T (PCS.T Int Float) (SV.Vector Float))+ ((proc :: PIO.T (PCS.T Int Float) (SV.Vector Float)) . bubbleControl) @@ -357,25 +330,25 @@ bubblesPacked :: IO () bubblesPacked = do proc <-- CausalP.processIOCore+ Render.runPlugged (PIn.controllerSet d6)- (CausalPS.arrayElement d0 *- (CausalPS.osciSimple Wave.approxSine4 $< 0)+ (CausalP.arrayElement d0 *+ (CausalP.osci Wave.approxSine4 $< 0) .- (CausalPS.arrayElement d1+ (CausalP.arrayElement d1 *- (1 - CausalPS.arrayElement d2 *- (CausalPS.osciSimple Wave.saw $< 0) .- CausalPS.arrayElement d3)+ (1 - CausalP.arrayElement d2 *+ (CausalP.osci Wave.saw $< 0) .+ CausalP.arrayElement d3) *- (1 - CausalPS.arrayElement d4 *- (CausalPS.osciSimple Wave.saw $< 0) .- CausalPS.arrayElement d5)))+ (1 - CausalP.arrayElement d4 *+ (CausalP.osci Wave.saw $< 0) .+ CausalP.arrayElement d5))) POut.storableVector playFromEvents 0.01 (vectorBlockSize/sampleRate) (arr SigStL.unpackStrict .- (proc () :: PIO.T (PCS.T Int Float) (SV.Vector Vector))+ (proc :: PIO.T (PCS.T Int Float) (SV.Vector Vector)) . arr subsamplePCS .@@ -389,88 +362,79 @@ that cannot be satisfied with @LLVM.Vector@s. -} moveAround2dLifted ::- (A.Transcendental v, v ~ A.Scalar v, A.PseudoModule v,- A.Real v, A.RationalConstant v) =>- Value.T v -> Value.T v -> (Value.T v, Value.T v) ->- CausalP.T p (v, v) (v, v)+ (Expr.Aggregate ve vl, Algebraic.C ve, NormedEuc.Sqr ve ve) =>+ ve -> ve -> (ve, ve) -> Causal.T (vl, vl) (vl, vl) moveAround2dLifted att sonicDelay ear =- Causal.map- (uncurry $ Value.unlift2 $ curry $ Spatial.moveAround att sonicDelay ear)+ Causal.map (Spatial.moveAround att sonicDelay ear) moveAround2d ::- (A.Algebraic v, A.RationalConstant v) =>- Value.T v -> Value.T v -> (Value.T v, Value.T v) ->- CausalP.T p (v, v) (v, v)+ (ve ~ Exp v, vl ~ MultiValue.T v,+ MultiValue.Algebraic v, MultiValue.RationalConstant v) =>+ ve -> ve -> (ve, ve) -> Causal.T (vl, vl) (vl, vl) moveAround2d att sonicDelay ear =- Causal.map $ Value.flattenFunction $+ Causal.map $ (\dist -> (sonicDelay*dist, 1/(att+dist)^2)) . euclideanNorm2d . subtract ear euclideanNorm2d ::- (A.Algebraic a) =>- (Value.T a, Value.T a) -> Value.T a-euclideanNorm2d (x,y) =- Value.sqrt $ Value.square x + Value.square y--mapFunc ::- (Value.Flatten a, Value.Flatten b) =>- (a -> b) ->- CausalP.T p (Value.Registers a) (Value.Registers b)-mapFunc f =- Causal.map (Value.flattenFunction f)+ (MultiValue.Algebraic a) =>+ (Exp a, Exp a) -> Exp a+euclideanNorm2d (x,y) = Expr.sqrt $ Expr.sqr x + Expr.sqr y flyChannel ::- (Value.T (Value Float), Value.T (Value Float)) ->- CausalP.T p (Value Float, (Value Float, Value Float)) (Value Float)+ (ae ~ Exp Float, al ~ MultiValue.T Float) =>+ (ae, ae) -> Causal.T (al, (al, al)) al flyChannel ear = ((snd ^>> moveAround2d 1 0.1 ear >>> Arr.first (negate id)) &&& (Arr.second- (2 * ((CausalP.differentiate $# (0::Float, 0::Float))- >>>- mapFunc euclideanNorm2d))+ (2 * (Causal.differentiate (0,0) >>> Causal.map euclideanNorm2d)) >>>- CausalP.mix))+ Causal.mix)) >>> arr (\((phase,volume), speed) -> (volume, (phase,speed))) >>>- Arr.second (CausalP.osciSimple Wave.saw)+ Arr.second (Causal.osci Wave.saw) >>>- (CausalP.envelope * 10)+ (Causal.envelope * 10) fly :: IO () fly = do- let slow, fast :: CausalP.T p (Value Float) (Value Float)+ let slow, fast :: Causal.T (MultiValue.T Float) (MultiValue.T Float) slow =- Filt1.lowpassCausal $<#- Filt1Core.parameter (1/sampleRate::Float)+ Filt1.lowpassCausal $<+ Gen.constant (Filt1Core.parameter (1/sampleRate :: Exp Float)) fast =- Filt1.lowpassCausal $<#- Filt1Core.parameter (30/sampleRate::Float)+ Filt1.lowpassCausal $<+ Gen.constant (Filt1Core.parameter (30/sampleRate :: Exp Float)) proc <-- CausalP.processIOCore+ Render.runPlugged (PIn.controllerSet d5)- ((CausalP.arrayElement d0 &&&+ ((Causal.arrayElement d0 &&& (liftA2 (,)- (CausalP.arrayElement d2)+ (Causal.arrayElement d2) (liftA2 (,)- ((CausalP.arrayElement d3 >>> slow)+ ((Causal.arrayElement d3 >>> slow) +- CausalP.arrayElement d1 *- (CausalP.fromSignal (GenP.noise 366210 0.3) >>> fast >>> fast))- ((CausalP.arrayElement d4 >>> slow)+ Causal.arrayElement d1 *+ (CausalClass.fromSignal (Gen.noise 366210 0.3)+ >>> fast >>> fast))+ ((Causal.arrayElement d4 >>> slow) +- CausalP.arrayElement d1 *- (CausalP.fromSignal (GenP.noise 234298 0.3) >>> fast >>> fast)))+ Causal.arrayElement d1 *+ (CausalClass.fromSignal (Gen.noise 234298 0.3)+ >>> fast >>> fast))) >>> liftA2 Stereo.cons (flyChannel (-1,0)) (flyChannel ( 1,0)))) >>>- CausalP.envelopeStereo)+ Causal.envelopeStereo+ >>^+ Stereo.multiValue) POut.storableVector playFromEvents 0.01 (0.015::Double)- ((proc () :: PIO.T (PCS.T Int Float) (SV.Vector (Stereo.T Float)))+ ((proc :: PIO.T (PCS.T Int Float) (SV.Vector (Stereo.T Float))) . MCS.filter [ MCS.controllerExponential Ctrl.volume (0.001, 0.99) 0.2,@@ -483,64 +447,66 @@ flyChannelPacked ::- (Value.T VectorValue, Value.T VectorValue) ->- CausalP.T p (VectorValue, (VectorValue, VectorValue)) VectorValue+ (ae ~ Exp Vector, al ~ VectorValue) =>+ (ae, ae) -> Causal.T (al, (al, al)) al flyChannelPacked ear = ((snd ^>> moveAround2d 1 0.1 ear >>> Arr.first (negate id)) &&& (Arr.second- (2 * ((CausalPS.differentiate $# (0::Float, 0::Float))- >>>- mapFunc euclideanNorm2d))+ (2 * (CausalP.differentiate 0 *** CausalP.differentiate 0+ >>>+ Causal.map euclideanNorm2d)) >>>- CausalP.mix))+ Causal.mix)) >>> arr (\((phase,volume), speed) -> (volume, (phase,speed))) >>>- Arr.second (CausalPS.osciSimple Wave.saw)+ Arr.second (CausalP.osci Wave.saw) >>>- CausalP.envelope+ Causal.envelope >>>- CausalPS.amplify 10+ CausalP.amplify 10 flyPacked :: IO () flyPacked = do- let slow, fast :: CausalP.T p VectorValue VectorValue+ let slow, fast :: Causal.T VectorValue VectorValue slow =- Filt1.lowpassCausalPacked $<#- Filt1Core.parameter (1/sampleRate::Float)+ Filt1.lowpassCausalPacked $<+ Gen.constant (Filt1Core.parameter (1/sampleRate :: Exp Float)) fast =- Filt1.lowpassCausalPacked $<#- Filt1Core.parameter (30/sampleRate::Float)+ Filt1.lowpassCausalPacked $<+ Gen.constant (Filt1Core.parameter (30/sampleRate :: Exp Float)) proc <-- CausalP.processIOCore+ Render.runPlugged (PIn.controllerSet d5)- ((CausalPS.arrayElement d0 &&&+ ((CausalP.arrayElement d0 &&& (liftA2 (,)- (CausalPS.arrayElement d2)+ (CausalP.arrayElement d2) (liftA2 (,)- ((CausalPS.arrayElement d3 >>> slow)+ ((CausalP.arrayElement d3 >>> slow) +- CausalPS.arrayElement d1 *- (CausalP.fromSignal (GenPS.noise 366210 0.3) >>> fast >>> fast))- ((CausalPS.arrayElement d4 >>> slow)+ CausalP.arrayElement d1 *+ (CausalClass.fromSignal (GenP.noise 366210 0.3)+ >>> fast >>> fast))+ ((CausalP.arrayElement d4 >>> slow) +- CausalPS.arrayElement d1 *- (CausalP.fromSignal (GenPS.noise 234298 0.3) >>> fast >>> fast)))+ CausalP.arrayElement d1 *+ (CausalClass.fromSignal (GenP.noise 234298 0.3)+ >>> fast >>> fast))) >>> liftA2 Stereo.cons (flyChannelPacked (-1,0)) (flyChannelPacked ( 1,0)))) >>>- CausalP.envelopeStereo- >>>- Causal.map StereoInt.interleave)+ Causal.envelopeStereo+ >>^+ Stereo.multiValueSerial) POut.storableVector playFromEvents 0.01 (vectorBlockSize/sampleRate)- (arr SigStL.unpackStereoStrict+ (arr SigStL.unpackStrict .- (proc () :: PIO.T (PCS.T Int Float) (SV.Vector (StereoInt.T VectorSize Float)))+ (proc :: PIO.T (PCS.T Int Float) (SV.Vector (Serial.T VectorSize (Stereo.T Float)))) . arr subsamplePCS .
example/Synthesizer/LLVM/Test.hs view
@@ -1,2005 +1,1926 @@-{-# LANGUAGE Rank2Types #-}-{-# LANGUAGE TypeFamilies #-}-module Main where--import Synthesizer.LLVM.LAC2011 ()--import qualified Synthesizer.LLVM.Server.Default as Default-import qualified Synthesizer.LLVM.Server.SampledSound as Sample--import qualified Synthesizer.LLVM.Filter.ComplexFirstOrderPacked as BandPass-import qualified Synthesizer.LLVM.Filter.Allpass as Allpass-import qualified Synthesizer.LLVM.Filter.Butterworth as Butterworth-import qualified Synthesizer.LLVM.Filter.Chebyshev as Chebyshev-import qualified Synthesizer.LLVM.Filter.FirstOrder as Filt1-import qualified Synthesizer.LLVM.Filter.SecondOrder as Filt2-import qualified Synthesizer.LLVM.Filter.SecondOrderPacked as Filt2P-import qualified Synthesizer.LLVM.Filter.Moog as Moog-import qualified Synthesizer.LLVM.Filter.Universal as UniFilter-import qualified Synthesizer.LLVM.Filter.NonRecursive as FiltNR-import qualified Synthesizer.LLVM.CausalParameterized.Controlled as CtrlP-import qualified Synthesizer.LLVM.CausalParameterized.ControlledPacked as CtrlPS-import qualified Synthesizer.LLVM.CausalParameterized.ProcessPacked as CausalPS-import qualified Synthesizer.LLVM.CausalParameterized.ProcessValue as CausalPV-import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP-import qualified Synthesizer.LLVM.CausalParameterized.Functional as Func-import qualified Synthesizer.LLVM.CausalParameterized.Helix as Helix-import qualified Synthesizer.LLVM.Causal.ProcessValue as CausalV-import qualified Synthesizer.LLVM.Causal.Process as Causal-import qualified Synthesizer.LLVM.Interpolation as Interpolation-import qualified Synthesizer.LLVM.Simple.Signal as Sig-import qualified Synthesizer.LLVM.Simple.Value as Value-import qualified Synthesizer.LLVM.Storable.Signal as SigStL-import qualified Synthesizer.LLVM.Wave as Wave-import qualified Synthesizer.LLVM.Parameter as Param-import qualified Synthesizer.LLVM.Parameterized.SignalPacked as SigPS-import qualified Synthesizer.LLVM.Parameterized.Signal as SigP-import Synthesizer.LLVM.CausalParameterized.Functional (($&), (&|&))-import Synthesizer.LLVM.Causal.Process (($<), ($>), ($*), ($*#))-import Synthesizer.LLVM.Simple.Value ((%>), (%&&))-import Synthesizer.LLVM.Parameter (($#))--import qualified Synthesizer.LLVM.Frame.StereoInterleaved as StereoInt-import qualified Synthesizer.LLVM.Frame.Stereo as Stereo-import qualified Synthesizer.LLVM.Frame.SerialVector as Serial-import qualified Synthesizer.LLVM.Frame as Frame--import qualified LLVM.Extra.Memory as Memory-import qualified LLVM.Extra.Arithmetic as A-import qualified LLVM.Extra.Maybe as Maybe--import qualified LLVM.Core as LLVM-import LLVM.Core (Value, valueOf, Vector)-import LLVM.Util.Arithmetic () -- Floating instance for TValue--import qualified Type.Data.Num.Decimal as TypeNum-import Type.Data.Num.Decimal (D4, D8, D16)-import Type.Base.Proxy (Proxy)--import qualified Synthesizer.CausalIO.Process as PIO-import qualified Synthesizer.Causal.Class as CausalClass-import qualified Synthesizer.Zip as Zip-import qualified Synthesizer.State.Control as CtrlS-import qualified Synthesizer.State.Signal as SigS--import qualified Synthesizer.Plain.Filter.Recursive as FiltR-import qualified Synthesizer.Plain.Filter.Recursive.FirstOrder as Filt1Core-import qualified Synthesizer.Plain.Filter.Recursive.SecondOrder as Filt2Core--import Control.Arrow (Arrow, arr, (&&&), (^<<), (<<^), (***))-import Control.Category ((<<<), (.), id)-import Control.Applicative (pure, liftA2)-import Control.Functor.HT (void)-import Control.Monad (when)--import qualified Data.StorableVector.Lazy as SVL-import qualified Data.StorableVector as SV-import Foreign.Storable (Storable)--import qualified Data.EventList.Relative.TimeBody as EventList-import qualified Data.EventList.Relative.BodyTime as EventListBT-import qualified Data.EventList.Relative.MixedTime as EventListMT-import qualified Data.EventList.Relative.TimeMixed as EventListTM-import qualified Numeric.NonNegative.Wrapper as NonNeg--import qualified Sound.Sox.Option.Format as SoxOption-import qualified Sound.Sox.Play as SoxPlay--- import qualified Synthesizer.ALSA.Storable.Play as Play--import qualified Data.NonEmpty.Class as NonEmptyC-import qualified Data.NonEmpty as NonEmpty-import Data.NonEmpty ((!:))-import Data.Traversable (sequenceA)-import Data.Word (Word32)-import Data.List (genericLength)-import System.Path ((</>))-import System.Random (randomRs, mkStdGen)--import qualified System.IO as IO-import Control.Exception (bracket)--import Prelude hiding (fst, snd, id, (.))-import qualified NumericPrelude.Numeric as NP-import qualified Prelude as P---asMono :: vector Float -> vector Float-asMono = id--asStereo :: vector (Stereo.T Float) -> vector (Stereo.T Float)-asStereo = id--asMonoPacked :: vector (Serial.Plain D4 Float) -> vector (Serial.Plain D4 Float)-asMonoPacked = id--asMonoPacked16 :: vector (Serial.Plain D16 Float) -> vector (Serial.Plain D16 Float)-asMonoPacked16 = id--asStereoInterleaved :: vector (StereoInt.T D4 Float) -> vector (StereoInt.T D4 Float)-asStereoInterleaved = id--asWord32 :: vector Word32 -> vector Word32-asWord32 = id--asWord32Packed :: vector (Serial.Plain D4 Word32) -> vector (Serial.Plain D4 Word32)-asWord32Packed = id---{- |-> playStereo (Sig.amplifyStereo 0.3 $ stereoOsciSaw 0.01)--Unfortunately: If you call :reload,-then the next attempt to play something will be answered by:--ghci: JITEmitter.cpp:110: <unnamed>::JITResolver::JITResolver(llvm::JIT&): Assertion `TheJITResolver == 0 && "Multiple JIT resolvers?"' failed.--}-playStereo :: Sig.T (Stereo.T (Value Float)) -> IO ()-playStereo =- playStereoVector .- Sig.renderChunky (SVL.chunkSize 100000)--playStereoVector :: SVL.Vector (Stereo.T Float) -> IO ()-playStereoVector =- void . SoxPlay.simple SVL.hPut SoxOption.none 44100--playMono :: Sig.T (Value Float) -> IO ()-playMono =- playMonoVector .- Sig.renderChunky (SVL.chunkSize 100000)--playMonoVector :: SVL.Vector Float -> IO ()-playMonoVector =- void . SoxPlay.simple SVL.hPut SoxOption.none 44100---playFileMono :: FilePath -> IO ()-playFileMono fileName = do- IO.withFile fileName IO.ReadMode $ \h ->- playStereo .- Sig.fromStorableVectorLazy .- asStereo . snd- =<< SVL.hGetContentsAsync (SVL.chunkSize 4321) h- return ()---frequency :: Float -> Param.T p Float-frequency = return--{- |-Assist GHC-7.10.3 with determining the type of causal processes.-GHC-7.8.4 and GHC-8.0.1 do not need it.--}-causalP :: CausalP.T p a b -> CausalP.T p a b-causalP = id---constant :: Float -> IO ()-constant y =- SV.writeFile "speedtest.f32" $ asMono $ flip Sig.render 1000 $ Sig.constant y--saw :: IO ()-saw =- SV.writeFile "speedtest.f32" $- asMono $- flip Sig.render 10000000 $- Sig.osciSaw 0 0.01--exponential :: IO ()-exponential =- SV.writeFile "speedtest.f32" $- asMono $- flip Sig.render 10000000 $- Sig.exponential2 50000 1--triangle :: IO ()-triangle =- SV.writeFile "speedtest.f32" $- asMono $- flip Sig.render 10000000 $- Sig.osci Wave.triangle 0.25 0.01--trianglePack :: IO ()-trianglePack =- SV.writeFile "speedtest.f32" $- asMonoPacked $- (\xs -> SigP.render xs (div 10000000 4) ()) $- Sig.map Wave.triangle $- SigPS.packSmall $- SigP.osciCore 0.25 (frequency 4.015803e-4)--trianglePacked :: IO ()-trianglePacked =- SV.writeFile "speedtest.f32" $- asMonoPacked $- (\xs -> SigP.render xs (div 10000000 4) ()) $- (causalP (CausalPS.osciSimple Wave.triangle)- $< SigPS.constant 0.25- $* SigPS.constant 0.01)--triangleReplicate :: IO ()-triangleReplicate =- SV.writeFile "speedtest.f32" $- asMonoPacked $- (\xs -> SigP.render xs (div 10000000 4) ()) $- (causalP- (CausalPS.shapeModOsci- (\k p -> do- x <- Wave.triangle =<< Wave.replicate k p- y <- Wave.approxSine4 =<< Wave.halfEnvelope p- A.mul x y))- $< SigPS.rampInf 1000000- $< SigPS.constant 0- $* SigPS.constant 0.01)--rationalSine :: IO ()-rationalSine =- SV.writeFile "speedtest.f32" $- asMonoPacked $- (\xs -> SigP.render xs (div 10000000 4) ()) $- (causalP (CausalPS.shapeModOsci Wave.rationalApproxSine1)- $< (0.001 + SigPS.rampInf 10000000)- $< SigPS.constant 0- $* SigPS.constant 0.01)--rationalSineStereo :: IO ()-rationalSineStereo =- SV.writeFile "speedtest.f32" $- SigStL.unpackStereoStrict $- asStereoInterleaved $- (\xs -> SigP.render xs (div 10000000 4) ()) $- Sig.map StereoInt.interleave $- liftA2 Stereo.cons- (causalP (CausalPS.shapeModOsci Wave.rationalApproxSine1)- $< (0.001 + SigPS.rampInf 10000000)- $< SigPS.constant (-0.25)- $* SigPS.constant 0.00999)- (causalP (CausalPS.shapeModOsci Wave.rationalApproxSine1)- $< (0.001 + SigPS.rampInf 10000000)- $< SigPS.constant 0.25- $* SigPS.constant 0.01001)---pingSig :: Float -> Sig.T (Value Float)-pingSig freq =- Sig.envelope- (Sig.exponential2 50000 1)- (Sig.osciSaw 0.5 freq)--pingSigP :: Param.T p Float -> SigP.T p (Value Float)-pingSigP freq =- SigP.envelope- (SigP.exponential2 50000 1)- (SigP.osciSaw 0.5 freq)--ping :: IO ()-ping =- SV.writeFile "speedtest.f32" $- asMono $- flip Sig.render 10000000 $- pingSig 0.01--pingSigPacked :: SigP.T Float (Serial.Value D4 Float)-pingSigPacked =- let freq = id- in SigP.envelope- (SigPS.exponential2 50000 1)- (SigPS.osciSimple Wave.saw 0 freq)--pingPacked :: IO ()-pingPacked =- SV.writeFile "speedtest.f32" $- asMonoPacked $- (\xs -> SigP.render xs (div 10000000 4) 0.01) $- pingSigPacked--pingUnpack :: IO ()-pingUnpack =- SV.writeFile "speedtest.f32" $- asMono $- (\xs -> SigP.render xs 10000000 0.01) $- SigPS.unpack $- pingSigPacked--pingSmooth :: IO ()-pingSmooth =- SV.writeFile "speedtest-scalar.f32" $- asMono $- (\xs -> SigP.render xs 10000000 ()) $- (causalP Filt1.lowpassCausal- $< (fmap Filt1Core.Parameter $- 1 - (Sig.exponential2 50000 1))- $* SigP.osciSimple Wave.triangle 0 (frequency 0.01))--pingSmoothPacked :: IO ()-pingSmoothPacked =- SV.writeFile "speedtest-vector.f32" $- asMonoPacked $- (\xs -> SigP.render xs (div 10000000 4) ()) $- (causalP Filt1.lowpassCausalPacked- $< (fmap Filt1Core.Parameter $- 1 - (Sig.exponential2 (50000/4) 1))- $* SigPS.osciSimple Wave.triangle 0 (frequency 0.01))--stereoOsciSaw :: Float -> Sig.T (Stereo.T (Value Float))-stereoOsciSaw freq =- liftA2 Stereo.cons- (Sig.osciSaw 0.0 (freq*1.001) `Sig.mix`- Sig.osciSaw 0.2 (freq*1.003) `Sig.mix`- Sig.osciSaw 0.1 (freq*0.995))- (Sig.osciSaw 0.1 (freq*1.005) `Sig.mix`- Sig.osciSaw 0.7 (freq*0.997) `Sig.mix`- Sig.osciSaw 0.5 (freq*0.999))--stereoOsciSawPacked :: Float -> Sig.T (Stereo.T (Value Float))-stereoOsciSawPacked freq =- let mix4 =- Frame.mixVector .- flip asTypeOf (undefined :: Value (Vector D4 Float))- in liftA2 Stereo.cons- (Sig.map mix4 $- Sig.osciPlain Wave.saw- (valueOf $ LLVM.consVector 0.0 0.2 0.1 0.4)- (valueOf $ fmap (freq*) $- LLVM.consVector 1.001 1.003 0.995 0.996))- (Sig.map mix4 $- Sig.osciPlain Wave.saw- (valueOf $ LLVM.consVector 0.1 0.7 0.5 0.7)- (valueOf $ fmap (freq*) $- LLVM.consVector 1.005 0.997 0.999 1.001))--stereoOsciSawPacked2 :: Float -> Sig.T (Stereo.T (Value Float))-stereoOsciSawPacked2 freq =- Sig.map (Frame.mixVectorToStereo .- flip asTypeOf (undefined :: Value (Vector D8 Float))) $- Sig.osciPlain (Wave.trapezoidSkew (A.fromRational' 0.2))- (valueOf $ LLVM.consVector 0.0 0.2 0.1 0.4 0.1 0.7 0.5 0.7)- (valueOf $ fmap (freq*) $- LLVM.consVector 1.001 1.003 0.995 0.996 1.005 0.997 0.999 1.001)--stereo :: IO ()-stereo =- SV.writeFile "speedtest.f32" $- asStereo $- flip Sig.render 10000000 $- Sig.amplifyStereo 0.25 $- stereoOsciSawPacked2 0.01--lazy :: IO ()-lazy =- SVL.writeFile "speedtest.f32" $- SVL.take 10000000 $- asMono $- Sig.renderChunky (SVL.chunkSize 100000)- {- SVL.defaultChunkSize - too slow -} $- Sig.envelope- (Sig.exponential2 50000 1)- (Sig.osci Wave.sine 0.5 0.01 :: Sig.T (Value Float))--lazyStereo :: IO ()-lazyStereo =- SVL.writeFile "speedtest.f32" $- SVL.take 10000000 $- asStereo $- Sig.renderChunky (SVL.chunkSize 100000) $- Sig.amplifyStereo 0.25 $- stereoOsciSawPacked 0.01--packTake :: IO ()-packTake =- SVL.writeFile "speedtest.f32" $- asMonoPacked $- flip (SigP.renderChunky (SVL.chunkSize 1000)) () $- SigPS.packRotate $- (CausalP.take 5 $*- SigP.osciSimple Wave.saw 0 (frequency 0.01))--chord :: Float -> Sig.T (Stereo.T (Value Float))-chord base =- {-- This exceeds available vector registers- and thus needs more stack accesses.- Thus it needs twice as much time as the simple mixing.- However doing all 32 oscillators in parallel- and mix them in one go might be still faster.-- foldl1 (Sig.zipWith Frame.mixStereoV) $- -}- NonEmpty.foldBalanced Sig.mix $- fmap (\f -> stereoOsciSawPacked2 (base*f)) $- 0.25 !: 1.00 : 1.25 : 1.50 : []--lazyChord :: IO ()-lazyChord =- SVL.writeFile "speedtest.f32" $- SVL.take 10000000 $- asStereo $- Sig.renderChunky (SVL.chunkSize 100000) $- Sig.amplifyStereo 0.1 $- chord 0.005--filterSweepComplex :: IO ()-filterSweepComplex =- SVL.writeFile "speedtest.f32" $- SVL.take 10000000 $- asStereo $- Sig.renderChunky (SVL.chunkSize 100000) $- Sig.amplifyStereo 0.3 $- Causal.apply BandPass.causal $- Sig.zip- (Sig.map (BandPass.parameter (valueOf 100)) $- Sig.map (\x -> 0.01 * exp (2 * return x)) $- Sig.osci Wave.sine 0 (0.1/44100)) $- chord 0.005--lfoSineCausal ::- CausalP.T p (Value Float) a -> Param.T p Float -> SigP.T p a-lfoSineCausal f reduct =- CausalP.apply f $- Sig.map (\x -> 0.01 * exp (2 * return x)) $- SigP.osciSimple Wave.sine 0 (reduct * 0.1/44100)--lfoSine ::- (Memory.C a) =>- (forall r. Value Float -> LLVM.CodeGenFunction r a) ->- Param.T p Float ->- SigP.T p a-lfoSine f = lfoSineCausal (Causal.map f)--filterSweep :: IO ()-filterSweep =- SVL.writeFile "speedtest.f32" $- SVL.take 10000000 $- asMono $- flip (SigP.renderChunky (SVL.chunkSize 10000)) () $- (0.2 *- CtrlP.processCtrlRate 128- (lfoSine (Filt2.bandpassParameter (valueOf 100)))- $* SigP.osciSimple Wave.saw 0 (frequency 0.01))--filterSweepPacked :: IO ()-filterSweepPacked =- SVL.writeFile "speedtest.f32" $- SVL.take (div 10000000 4) $- asMonoPacked $- flip (SigP.renderChunky (SVL.chunkSize 10000)) () $- (0.2 *- CtrlPS.processCtrlRate 128- (lfoSine (Filt2.bandpassParameter (valueOf 100)))- $* SigPS.osciSimple Wave.saw 0 0.01)--exponentialFilter2Packed :: IO ()-exponentialFilter2Packed =- SVL.writeFile "speedtest.f32" $- SVL.take (div 10000000 16) $- asMonoPacked16 $- flip (SigP.renderChunky (SVL.chunkSize 10000)) () $- (causalP Filt2.causalPacked- $< (SigP.constant $#- Filt2Core.Parameter (1::Float) 0 0 0 0.99)- $* (--- (CausalP.delay1 $# Serial.fromFixedList (0.1 !: 0.01 !: 0.001 !: 0.0001 !: Empty.Cons))--- (CausalP.delay1 $# Serial.replicate (1::Float))- (CausalP.delay1 $# Serial.fromFixedList ((1::Float) !: NonEmptyC.repeat 0))- $* 0))--filterSweepPacked2 :: IO ()-filterSweepPacked2 =- SVL.writeFile "speedtest.f32" $- SVL.take 10000000 $- asMono $- flip (SigP.renderChunky (SVL.chunkSize 10000)) () $- (0.2 *- CtrlP.processCtrlRate 128- (lfoSine (Filt2P.bandpassParameter (valueOf 100)))- $* SigP.osciSimple Wave.saw 0 (frequency 0.01))--butterworthNoisePacked :: IO ()-butterworthNoisePacked =- SVL.writeFile "speedtest.f32" $- SVL.take (div 10000000 4) $- asMonoPacked $- flip (SigP.renderChunky (SVL.chunkSize 10000)) () $- (CausalPS.amplify 0.2 .- CtrlPS.processCtrlRate 128- (lfoSineCausal- (CausalClass.applyConstFst- (Butterworth.parameterCausal TypeNum.d3 FiltR.Lowpass)- (valueOf 0.5)))- $* SigPS.noise 0 0.3)--chebyshevNoisePacked :: IO ()-chebyshevNoisePacked =- SVL.writeFile "speedtest.f32" $- SVL.take (div 10000000 4) $- asMonoPacked $- flip (SigP.renderChunky (SVL.chunkSize 10000)) () $- (CausalPS.amplify 0.2 .- CtrlPS.processCtrlRate 128- (lfoSineCausal- (CausalClass.applyConstFst- (Chebyshev.parameterCausalA TypeNum.d5 FiltR.Lowpass)- (valueOf 0.5)))- $* SigPS.noise 0 0.3)--{--Provoke non-aligned vector accesses by calling alloca for a record of 5 floats-in LLVM-2.6.-However, the vector accesses are those of noise.-Using scalar Noise there is no problem.--}-noiseAllocaBug :: IO ()-noiseAllocaBug =- SVL.writeFile "speedtest.f32" $- SVL.take (div 10000000 4) $- asMonoPacked $- flip (SigP.renderChunky (SVL.chunkSize 10000)) () $- (CausalPS.amplify 0.2 . Filt2.causalPacked- $< (Sig.map (const $ Memory.load =<< LLVM.alloca) $- (Sig.constant (0::Float)))- $* SigPS.noise 0 0.3)--noiseAllocaScalar :: IO ()-noiseAllocaScalar =- SVL.writeFile "speedtest.f32" $- SVL.take 10000000 $- asMono $- flip (SigP.renderChunky (SVL.chunkSize 10000)) () $- (0.2 * causalP Filt2.causal- $< (Sig.map (const $- (Memory.load =<< LLVM.alloca ::- LLVM.CodeGenFunction r (Filt2.Parameter (Value Float)))) $- (Sig.constant (0::Float)))- $* SigP.noise 0 0.3)---upsample :: IO ()-upsample =- SVL.writeFile "speedtest.f32" $- SVL.take 10000000 $- asMono $- Sig.renderChunky (SVL.chunkSize 100000) $- (let reduct = 128 :: Float- in flip Causal.applyConst reduct $ Causal.interpolateConstant $- Sig.osci Wave.sine 0 (reduct*0.1/44100))---filterSweepControlRateCausal ::- Causal.T- (Stereo.T (Value Float))- (Stereo.T (Value Float))-filterSweepControlRateCausal =- Causal.amplifyStereo 0.3 <<<- BandPass.causal <<<- Causal.feedFst- (let reduct = 128- in flip Causal.applyConst reduct $ Causal.interpolateConstant $- Sig.map (BandPass.parameter (valueOf 100)) $- Sig.map (\x -> 0.01 * exp (2 * return x)) $- Sig.osci Wave.sine 0 (reduct*0.1/44100))--filterSweepControlRateProc ::- Sig.T (Stereo.T (Value Float)) ->- Sig.T (Stereo.T (Value Float))-filterSweepControlRateProc =- Causal.apply filterSweepControlRateCausal--{- |-Trigonometric functions are very slow in LLVM-because they are translated to calls to C's math library.-Thus it is advantageous to compute filter parameters-at a lower rate and interpolate constantly.--}-filterSweepControlRate :: IO ()-filterSweepControlRate =- SVL.writeFile "speedtest.f32" $- asStereo $- SVL.take 10000000 $- Sig.renderChunky (SVL.chunkSize 100000) $- filterSweepControlRateProc $- chord 0.005---filterSweepMusic :: IO ()-filterSweepMusic = do- music <- SV.readFile "lichter.f32"- SVL.writeFile "speedtest.f32" $- asStereo $- Sig.renderChunky (SVL.chunkSize 100000) $- Sig.amplifyStereo 20 $- filterSweepControlRateProc $- Sig.fromStorableVector $- (music :: SV.Vector (Stereo.T Float))---playFilterSweepMusicLazy :: IO ()-playFilterSweepMusicLazy = do- IO.withFile "lichter.f32" IO.ReadMode $ \h ->- playStereo .--- Sig.amplifyStereo 1.125 .- Sig.amplifyStereo 20 .- filterSweepControlRateProc .- Sig.fromStorableVectorLazy .- asStereo . snd- =<< SVL.hGetContentsAsync (SVL.chunkSize 4321) h- return ()--playFilterSweepMusicCausal :: IO ()-playFilterSweepMusicCausal = do- music <- SV.readFile "lichter.f32"- _ <- SoxPlay.simple SV.hPut SoxOption.none 44100 $- asStereo $- Causal.applyStorable- (Causal.amplifyStereo 20 <<< filterSweepControlRateCausal) $- (music :: SV.Vector (Stereo.T Float))- return ()--playFilterSweepMusicCausalLazy :: IO ()-playFilterSweepMusicCausalLazy = do- IO.withFile "lichter.f32" IO.ReadMode $ \h ->- playStereoVector .- Causal.applyStorableChunky- (Causal.amplifyStereo 20 <<< filterSweepControlRateCausal) .- asStereo . snd- =<< SVL.hGetContentsAsync (SVL.chunkSize 43210) h- return ()--deinterleaveProc ::- IO (Float ->- PIO.T- (SV.Vector (StereoInt.T D4 Float))- (Zip.T- (SV.Vector (StereoInt.T D4 Float))- (SV.Vector (StereoInt.T D4 Float))))-deinterleaveProc =- CausalP.processIO deinterleaveCausal--deinterleaveCausal ::- CausalP.T Float- (StereoInt.Value D4 Float)- (StereoInt.Value D4 Float, StereoInt.Value D4 Float)-deinterleaveCausal =- Func.withArgs $ \input ->- let env =- Func.fromSignal $- 0.5 * (1 + SigPS.osciSimple (Wave.triangleSquarePower 4) 0 id)- in (Causal.zipWith StereoInt.envelope $& env &|& input)- &|&- (Causal.zipWith StereoInt.envelope $& (1-env) &|& input)--deinterleave :: IO ()-deinterleave = do- proc <- deinterleaveProc- runSplitProcess (proc (2/44100))---disturbProc, disturbFMProc ::- IO (PIO.T- (SV.Vector (StereoInt.T D4 Float))- (Zip.T- (SV.Vector (StereoInt.T D4 Float))- (SV.Vector (StereoInt.T D4 Float))))-disturbProc =- fmap ($()) $ CausalP.processIO $ crossMix disturbCausal--disturbCausal, disturbFMCausal ::- CausalP.T p (StereoInt.Value D4 Float) (StereoInt.Value D4 Float)-disturbCausal =- Func.withArgs $ \inputInt ->- let tone =- Func.fromSignal $- SigPS.osciSimple Wave.triangle 0 (440/44100)- getEnvelope x =- Filt1.lowpassCausalPacked $&- (Func.fromSignal $- (SigP.constant $# Filt1Core.parameter (1/44100::Float)))- &|&- (CausalV.map abs $& x)- envelopedTone x = getEnvelope x * tone- in Causal.map StereoInt.interleave $&- CausalPS.amplifyStereo 5 $&- Stereo.liftApplicative envelopedTone- (Causal.map StereoInt.deinterleave $& inputInt)--disturbFMProc =- fmap ($()) $ CausalP.processIO $ crossMix disturbFMCausal--disturbFMCausal =- Func.withArgs $ \inputInt ->- let getEnvelope x =- Filt1.lowpassCausalPacked $&- (Func.fromSignal $- (SigP.constant $# Filt1Core.parameter (1/44100::Float)))- &|&- (CausalV.map abs $& x)- modulatedTone x =- getEnvelope x *- (CausalPS.osciSimple Wave.triangle $&- NP.zero- &|&- 10 *- getEnvelope- ((CausalPS.differentiate $# (0 :: Float)) $& x))- in Causal.map StereoInt.interleave $&- CausalPS.amplifyStereo 5 $&- Stereo.liftApplicative modulatedTone- (Causal.map StereoInt.deinterleave $& inputInt)--disturb :: IO ()-disturb =- runSplitProcess =<< disturbFMProc---wowFlutterProc ::- IO (PIO.T- (SV.Vector (StereoInt.T D4 Float))- (Zip.T- (SV.Vector (StereoInt.T D4 Float))- (SV.Vector (StereoInt.T D4 Float))))-wowFlutterProc =- fmap ($()) $ CausalP.processIO $ crossMix wowFlutterCausal--wowFlutterCausal ::- CausalP.T p (StereoInt.Value D4 Float) (StereoInt.Value D4 Float)-wowFlutterCausal =- Func.withArgs $ \inputInt ->- let freq =- Func.fromSignal $ (44100*) $- 0.01 * (1 + SigPS.osciSimple Wave.triangle 0 (1/44100 :: Param.T p Float)) +- 0.01 * (1 + SigPS.osciSimple Wave.approxSine2 0 (1.23/44100 :: Param.T p Float))- modulatedTone x =- CausalPS.pack- (CausalP.delayControlledInterpolated Interpolation.linear- (0 :: Param.T p Float) (441*2*2+10))- $&- freq &|& x- in Causal.map StereoInt.interleave $&- Stereo.liftApplicative modulatedTone- (Causal.map StereoInt.deinterleave $& inputInt)--crossMix ::- CausalP.T p (StereoInt.Value D4 Float) (StereoInt.Value D4 Float) ->- CausalP.T p- (StereoInt.Value D4 Float)- (StereoInt.Value D4 Float, StereoInt.Value D4 Float)-crossMix proc =- ((fst NP.+ snd) &&& (fst NP.- snd))- .- (id &&& proc)- .- Causal.map (StereoInt.amplify 0.5)---wowFlutter :: IO ()-wowFlutter =- runSplitProcess =<< wowFlutterProc----scrambleProc0, scrambleProc1 ::- IO (Float ->- PIO.T- (SV.Vector (StereoInt.T D4 Float))- (Zip.T- (SV.Vector (StereoInt.T D4 Float))- (SV.Vector (StereoInt.T D4 Float))))-scrambleProc0 =- CausalP.processIO $- deinterleaveCausal NP.+- (id &&& NP.negate id) .- Causal.map (StereoInt.amplify 0.5) . wowFlutterCausal--scrambleProc1 =- CausalP.processIO $- deinterleaveCausal NP.+- (id &&& NP.negate id) .- Causal.map (StereoInt.amplify 0.3) .- (wowFlutterCausal NP.+ disturbFMCausal)--scramble :: IO ()-scramble = do- proc <- scrambleProc1- runSplitProcess (proc (2/44100))---runSplitProcess ::- (Storable a) =>- PIO.T (SV.Vector a) (Zip.T (SV.Vector a) (SV.Vector a)) ->- IO ()-runSplitProcess proc = do- void $- IO.withFile "/tmp/test.f32" IO.ReadMode $ \h ->- IO.withFile "/tmp/even.f32" IO.WriteMode $ \h0 ->- IO.withFile "/tmp/odd.f32" IO.WriteMode $ \h1 ->-- case proc of- PIO.Cons next create delete ->- {-- Is the use of 'bracket' correct?- I think 'delete' must be called with the final state,- not with the initial one.- -}- bracket create delete $- let chunkSize = 543210- loop s0 = do- chunk <- SV.hGet h chunkSize- (Zip.Cons y0 y1, s1) <- next chunk s0- SV.hPut h0 y0- SV.hPut h1 y1- when- (SV.length y0 >= SV.length chunk &&- SV.length y1 >= SV.length chunk &&- SV.length chunk >= chunkSize)- (loop s1)- in loop---antimixProc ::- IO (SVL.Vector (StereoInt.T D4 Float) ->- PIO.T- (SV.Vector (StereoInt.T D4 Float))- (Zip.T- (SV.Vector (StereoInt.T D4 Float))- (SV.Vector (StereoInt.T D4 Float))))-antimixProc =- CausalP.processIO $ crossMix $- Causal.map (StereoInt.amplify 0.5) .- (CausalP.fromSignal $ SigP.fromStorableVectorLazy id)--antimix :: IO ()-antimix = do- proc <- antimixProc- void $- IO.withFile "/tmp/test.f32" IO.ReadMode $ \h ->- IO.withFile "/tmp/even.f32" IO.WriteMode $ \h0 ->- IO.withFile "/tmp/odd.f32" IO.WriteMode $ \h1 -> do- let chunkSize = SVL.chunkSize 543210- input <- fmap snd $ SVL.hGetContentsAsync chunkSize h- let vectorSize = 4- additive = SVL.drop (div 44100 vectorSize) input-{-- additive =- case SVL.splitAt (div 44100 vectorSize) input of- (prefix, suffix) ->- SVL.append suffix $- SVL.replicate chunkSize (SVL.length prefix) StereoInt.zero--}-{-- additive =- case SVL.splitAt (div 44100 vectorSize) input of- (prefix, suffix) -> SVL.append suffix prefix--}-- case proc additive of- PIO.Cons next create delete ->- {-- Is the use of 'bracket' correct?- I think 'delete' must be called with the final state,- not with the initial one.- -}- bracket create delete $ \state ->- let loop cs0 s0 =- case cs0 of- [] -> return ()- c : cs -> do- (Zip.Cons y0 y1, s1) <- next c s0- SV.hPut h0 y0- SV.hPut h1 y1- when- (SV.length y0 >= SV.length c &&- SV.length y1 >= SV.length c)- (loop cs s1)- in loop (SVL.chunks input) state---arrangeLazy :: IO ()-arrangeLazy = do- IO.hSetBuffering IO.stdout IO.NoBuffering- arrange <- SigStL.makeArranger- print $- arrange (SVL.chunkSize 2) $- EventList.fromPairList $- (0, SVL.pack (SVL.chunkSize 2) [1,2::Double]) :- (0, SVL.pack (SVL.chunkSize 2) [3,4,5,6]) :- (2, SVL.pack (SVL.chunkSize 2) [7,8,9,10]) :- -- repeat (2, SVL.empty)--- (2, SVL.empty) :--- (2, SVL.empty) :--- (2::NonNeg.Int, error "undefined sound") :- error "end of list"- -- []---{- |-This is inefficient because pingSig is compiled by LLVM-for every occurence of the sound!--randomTones :: IO ()-randomTones = do- playMonoVector $- SigStL.arrange (SVL.chunkSize 12345) $- EventList.fromPairList $ zip- (cycle $ map (flip div 16 . (44100*)) [1,2,3])- (cycle $ map (SVL.take 44100 . Sig.renderChunky (SVL.chunkSize 54321) .- pingSig . (0.01*))- [1,1.25,1.5,2])- return ()--}--{- |-So far we have not managed to compile signals-that depend on parameters.-Thus in order to avoid much recompilation,-we compile and render a few sounds in advance.--}-pingTones :: [SVL.Vector Float]-pingTones =- map (SVL.take 44100 . Sig.renderChunky (SVL.chunkSize 4321) .- pingSig . (0.01*))- [1,1.25,1.5,2]--pingTonesIO :: IO [SVL.Vector Float]-pingTonesIO =- fmap- (\pingVec ->- map- (SVL.take 44100 .- pingVec (SVL.chunkSize 4321) .- (0.01*))- [1,1.25,1.5,2])- (SigP.runChunky $ pingSigP id)--{--Arrange itself does not seem to have a space leak with temporary data.-However it may leak sound data.-This is not very likely because this would result in a large memory leak.--Generate random tones in order to see whether generated sounds leak.-How does 'arrange' compare with 'concat'?--}--cycleTones :: IO ()-cycleTones = do--- playMono $- pings <- pingTonesIO- SVL.writeFile "test.f32" $--- Play.auto (0.01::Double) 44100 $- asMono $-{--after 13min runtime memory consumption increased from 2.5 to 3.9-and we get lot of buffer underruns with this implementation of amplification-(renderChunky . amplify . fromStorableVector)--}- Sig.renderChunky (SVL.chunkSize 432109) $- Sig.amplify 0.1 $- Sig.fromStorableVectorLazy $-{--after 20min memory consumption increased from 2.5 to 3.4-and we get lot of buffer underruns with applyStorableChunky--}-{--applyStorableChunky applied to concatenated zero vectors-starts with memory consumption 1.0 and after an hour, it's still 1.1-without buffer underruns.--}-{-- CausalP.applyStorableChunky (CausalP.amplify $# (0.1::Float)) () $- asMono $--}-{--with chunksize 12345678-after 50min runtime the memory consumption increased from 12.0 to 26.2--with chunksize 123-after 25min runtime the memory consumption is constant 7.4-however at start time there 5 buffer underruns, but no more-probably due to initial LLVM compilation--with chunksize 1234567 and SVL.replicate instead of pingTones-we get memory consumption from 1.3 to 3.2 in 15min,-while producing lots of buffer underruns.-After 45min in total, it is still 3.2 of memory consumption.-Is this a memory leak, or isn't it?--with chunksize 12345678 and SVL.replicate-we get from 5.6 to 10.2 in 3min-to 14.9 after total 13min.--}-{-- SigStL.arrange (SVL.chunkSize 12345678) $- EventList.fromPairList $ zip- (repeat (div 44100 8))--- (cycle $ map (flip div 4 . (44100*)) [1,2,3])--}-{--With plain concatenation of those zero vectors-we stay constantly at 0.4 memory consumption and no buffer underruns over 30min.--}- SVL.concat- (cycle pings)--- (repeat $ SVL.replicate (SVL.chunkSize 44100) 44100 0)- return ()---tonesChunkSize :: SVL.ChunkSize-numTones :: Int--{--For one-time-compiled fill functions,-larger chunks have no relevant effect on the processing speed.--}-(tonesChunkSize, numTones) =- (SVL.chunkSize 441, 200)--- (SVL.chunkSize 44100, 200)--fst :: Arrow arrow => arrow (a,b) a-fst = arr P.fst--snd :: Arrow arrow => arrow (a,b) b-snd = arr P.snd---{-# NOINLINE makePing #-}-makePing :: IO ((Float,Float) -> SVL.Vector Float)-makePing =- fmap ($tonesChunkSize) $- SigP.runChunky $- Param.withTuple1 $ \(halfLife, freq) ->- SigP.envelope- (SigP.exponential2 halfLife 1)- (SigP.osciSaw 0.5 freq)--tonesDown :: IO ()-tonesDown = do- let dist = div 44100 10- pingp <- makePing- arrange <- SigStL.makeArranger- playMonoVector $- CausalP.applyStorableChunky (CausalP.amplify id) (0.03::Float) $- arrange tonesChunkSize $- EventList.fromPairList $ zip- (repeat (NonNeg.fromNumber dist))- (map (SVL.take (numTones * dist) . curry pingp 50000) $- iterate (0.999*) 0.01)- return ()---vibes :: SigP.T (Float,Float) (Value Float)-vibes =- let freq = snd- modDepth = fst- halfLife = 5000- -- sine = Wave.sine- sine = Wave.approxSine4- in causalP CausalP.envelope- $< SigP.exponential2 halfLife 1- $* (((CausalP.osciSimple sine- $< (causalP CausalP.envelope- $< SigP.exponential2 halfLife modDepth- $* (CausalP.osciSimple sine- $* SigP.constant (return (0::Float) &&& (2*freq)))))- <<<- CausalP.mapLinear (0.01*freq) freq- <<<- CausalP.osciSimple sine)- $* SigP.constant (return (0::Float, 0.0001::Float)))--makeVibes :: IO ((Float,Float) -> SVL.Vector Float)-makeVibes =- fmap ($tonesChunkSize) $- SigP.runChunky vibes--vibesCycleVector :: ((Float,Float) -> SVL.Vector Float) -> IO (SVL.Vector Float)-vibesCycleVector pingp =- (\evs -> fmap (\arrange -> arrange tonesChunkSize evs) SigStL.makeArranger) $- EventList.fromPairList $ zip- (repeat 5000)- (map (SVL.take 50000 . pingp) $- zip- (map (\k -> 0.5 * (1 - cos k)) $ iterate (0.05+) 0)- (cycle $ map (0.01*) [1, 1.25, 1.5, 2]))--vibesCycle :: IO ()-vibesCycle = do- sig <- vibesCycleVector =<< makeVibes- playMonoVector $- CausalP.applyStorableChunky (CausalP.amplify id) (0.2::Float) sig- return ()--vibesEcho :: IO ()-vibesEcho = do- sig <- vibesCycleVector =<< makeVibes- playMonoVector $- CausalP.applyStorableChunky- (CausalP.amplify id <<<- CausalP.comb (0.5 :: Param.T p Float) 7000)- (0.2::Float) sig- return ()--vibesReverb :: IO ()-vibesReverb = do- sig <- vibesCycleVector =<< makeVibes- playMonoVector $- CausalP.applyStorableChunky- (CausalP.amplify id <<<- CausalP.reverbSimple (mkStdGen 142) 16 (0.9,0.97) (400,1000))- (0.3::Float) sig- return ()--vibesReverbEfficient :: IO ()-vibesReverbEfficient = do- sig <- vibesCycleVector =<< makeVibes- playMonoVector $- CausalP.applyStorableChunky- (CausalP.amplify id <<<- (CausalP.reverb $# mkStdGen 142 $# 16 $# (0.9,0.97) $# (400,1000)))- (0.3::Float) sig- return ()--vibesReverbStereo :: IO ()-vibesReverbStereo = do- sig <- vibesCycleVector =<< makeVibes- void $ playStereoVector $- CausalP.applyStorableChunky- (CausalP.stereoFromMonoParameterized- (\amp seed ->- CausalP.amplify amp- <<<- CausalP.reverb (fmap mkStdGen seed)- 16 (pure (0.9,0.97)) (pure (400,1000)))- (pure $ Stereo.cons 142 857)- <<^- (\x -> Stereo.cons x x))- (0.3::Float) sig----stair :: IO ()-stair =- SVL.writeFile "speedtest.f32" $- SVL.take 10000000 $- asMono $- flip (SigP.renderChunky tonesChunkSize) () $- SigP.piecewiseConstant $- return $- EventListBT.fromPairList $- zip- (iterate (/2) (1::Float))- (iterate (2*) (1::NonNeg.Int))---filterBass :: IO ()-filterBass =- void $- playStereoVector $- asStereo $- flip (SigP.renderChunky tonesChunkSize) () $- CausalP.apply- (BandPass.causal- <<<- CausalP.feedSnd- (liftA2 Stereo.cons- (SigP.osciSimple Wave.saw 0 (frequency 0.001499))- (SigP.osciSimple Wave.saw 0 (frequency 0.001501)))- <<<- Causal.map (BandPass.parameter (valueOf (100::Float)))) $- SigP.piecewiseConstant $- return $ EventListBT.fromPairList $- zip- (map (((0.01::Float)*) . (2**) . (/12) . fromInteger) $- randomRs (0,24) (mkStdGen 998))- (repeat (6300::NonNeg.Int))---{- |-This function is not very efficient,-since it compiles an LLVM mixing routine-for every pair of mixer inputs.--}-mixVectorRecompile ::- SVL.Vector Float -> SVL.Vector Float -> SVL.Vector Float-mixVectorRecompile xs ys =- Sig.renderChunky tonesChunkSize $- Sig.mix- (Sig.fromStorableVectorLazy xs)- (Sig.fromStorableVectorLazy ys)--mixVectorParamIO ::- IO (SVL.Vector Float -> SVL.Vector Float -> SVL.Vector Float)-mixVectorParamIO =- fmap curry $- fmap ($tonesChunkSize) $- SigP.runChunky- (SigP.mix- (SigP.fromStorableVectorLazy fst)- (SigP.fromStorableVectorLazy snd))--mixVectorCausalIO ::- IO (SVL.Vector Float -> SVL.Vector Float -> SVL.Vector Float)-mixVectorCausalIO =- CausalP.runStorableChunky- (CausalP.mix $<- SigP.fromStorableVectorLazy id)--mixVectorCausal ::- SVL.Vector Float -> SVL.Vector Float -> SVL.Vector Float-mixVectorCausal =- CausalP.applyStorableChunky- (CausalP.mix $<- SigP.fromStorableVectorLazy id)--mixVectorStereo ::- SVL.Vector (Stereo.T Float) ->- SVL.Vector (Stereo.T Float) ->- SVL.Vector (Stereo.T Float)-mixVectorStereo =- CausalP.applyStorableChunky- (CausalP.mix $< SigP.fromStorableVectorLazy id)--mixVectorStereoIO ::- IO (SVL.Vector (Stereo.T Float) ->- SVL.Vector (Stereo.T Float) ->- SVL.Vector (Stereo.T Float))-mixVectorStereoIO =- CausalP.runStorableChunky- (CausalP.mix $< SigP.fromStorableVectorLazy id)--{--slightly slower than mixVectorParam--}-mixVectorHaskell ::- SVL.Vector Float -> SVL.Vector Float -> SVL.Vector Float-mixVectorHaskell = SVL.zipWith (+)--toneMix :: IO ()-toneMix = do- pingp <- makePing- mix <- mixVectorCausalIO- playMonoVector $- Causal.applyStorableChunky (Causal.amplify 0.1) $- foldl1 mix $- map (curry pingp 1000000) $- take numTones $- iterate (*(2/3)) 0.01- return ()--fadeEnvelope :: SigP.T (Int, Int) (Value Float)-fadeEnvelope =- let dur :: Param.T (Int, Int) Float- dur = fmap fromIntegral fst- in SigP.parabolaFadeIn dur- `SigP.append`- (CausalP.take snd $* Sig.constant 1)- `SigP.append`- SigP.parabolaFadeOut dur--fadeEnvelopeWrite :: IO ()-fadeEnvelopeWrite =- SVL.writeFile "speedtest.f32" $- asMono $- SigP.renderChunky (SVL.chunkSize 1234)- fadeEnvelope (100000, 200000)----- | normalize a list of numbers, such that they have a specific average--- Cf. haskore-supercollider/src/Haskore/Interface/SuperCollider/Example.hs-normalizeLevel :: Fractional a => a -> [a] -> [a]-normalizeLevel newAvrg xs =- let avrg = sum xs / genericLength xs- in map ((newAvrg-avrg)+) xs--stereoOsciSawP :: SigP.T Float (Stereo.T (Value Float))-stereoOsciSawP =- let n = 5- volume :: Float- volume = recip $ sqrt $ fromIntegral n- detunes :: [Float]- detunes =- normalizeLevel 1 $ take (2*n) $- randomRs (0,0.03) $ mkStdGen 912- phases :: [Float]- phases = randomRs (0,1) $ mkStdGen 54- in stereoFromMonoParameterizedSignal- (\_ params ->- (SigP.amplify $# volume) $- multiMixSignal- (\_ phaseFreq ->- SigP.osciSaw- (fmap fst phaseFreq)- (fmap snd phaseFreq))- params)- (arr- (\freq ->- uncurry Stereo.cons $ splitAt n $- zipWith- (\phase detune -> (phase, detune*freq))- phases detunes))--stereoFromMonoParameterizedSignal ::- (forall q. Param.T q p -> Param.T q x -> SigP.T q (Value Float)) ->- Param.T p (Stereo.T x) -> SigP.T p (Stereo.T (Value Float))-stereoFromMonoParameterizedSignal f ps =- CausalP.toSignal $- CausalP.stereoFromMonoParameterized (\p -> CausalP.fromSignal . f p) ps- <<^- (\() -> Stereo.cons () ())--multiMixSignal ::- (forall q. Param.T q p -> Param.T q x -> SigP.T q (Value Float)) ->- Param.T p [x] -> SigP.T p (Value Float)-multiMixSignal f =- CausalP.toSignal . multiMix (\p x -> CausalP.fromSignal $ f p x)--multiMix ::- (forall q. Param.T q p -> Param.T q x -> CausalP.T q a (Value Float)) ->- Param.T p [x] -> CausalP.T p a (Value Float)-multiMix f ps =- CausalP.replicateControlledParam- (\p x -> CausalP.mix <<< CausalP.first (f p x)) ps- <<^- (\a -> (a, A.zero))--stereoOsciSawVector :: Float -> SVL.Vector (Stereo.T Float)-stereoOsciSawVector =- SigP.renderChunky tonesChunkSize stereoOsciSawP--stereoOsciSawChord :: NonEmpty.T [] Float -> SVL.Vector (Stereo.T Float)-stereoOsciSawChord =- NonEmpty.foldBalanced mixVectorStereo . fmap stereoOsciSawVector--stereoOsciSawPad :: Int -> NonEmpty.T [] Float -> SVL.Vector (Stereo.T Float)-stereoOsciSawPad dur pitches =- let attack = 20000- in CausalP.applyStorableChunky- (CausalP.envelopeStereo $< fadeEnvelope)- (attack, dur-attack)- (stereoOsciSawChord pitches)--a0, as0, b0, c1, cs1, d1, ds1, e1, f1, fs1, g1, gs1,- a1, as1, b1, c2, cs2, d2, ds2, e2, f2, fs2, g2, gs2,- a2, as2, b2, c3, cs3, d3, ds3, e3, f3, fs3, g3, gs3,- a3, as3, b3, c4, cs4, d4, ds4, e4, f4, fs4, g4, gs4 :: Float-a0 : as0 : b0 : c1 : cs1 : d1 : ds1 : e1 : f1 : fs1 : g1 : gs1 :- a1 : as1 : b1 : c2 : cs2 : d2 : ds2 : e2 : f2 : fs2 : g2 : gs2 :- a2 : as2 : b2 : c3 : cs3 : d3 : ds3 : e3 : f3 : fs3 : g3 : gs3 :- a3 : as3 : b3 : c4 : cs4 : d4 : ds4 : e4 : f4 : fs4 : g4 : gs4 : _ =- iterate ((2 ** recip 12) *) (55/44100)---chordSequence :: [(Int, NonEmpty.T [] Float)]-chordSequence =- (2, f1 !: f2 : a2 : c3 : []) :- (1, g1 !: g2 : b2 : d3 : []) :- (2, c2 !: g2 : c3 : e3 : []) :- (1, f1 !: a2 : c3 : f3 : []) :- (2, g1 !: g2 : b2 : d3 : []) :- (1, gs1 !: gs2 : b2 : e3 : []) :- (2, a1 !: e2 : a2 : c3 : []) :- (1, g1 !: g2 : b2 : d3 : []) :- (3, c2 !: g2 : c3 : e3 : []) :-- (2, f1 !: f2 : a2 : c3 : []) :- (1, g1 !: g2 : b2 : d3 : []) :- (2, c2 !: g2 : c3 : e3 : []) :- (1, f1 !: a2 : c3 : f3 : []) :- (2, g1 !: g2 : b2 : d3 : []) :- (1, gs1 !: gs2 : b2 : e3 : []) :- (2, a1 !: e2 : a2 : c3 : []) :- (1, g1 !: g2 : b2 : e3 : []) :- (3, c2 !: e2 : g2 : c3 : []) :- []---withDur :: (Int -> a -> v) -> Int -> a -> (v, NonNeg.Int)-withDur f d ps =- let dur = d*30000- in (f dur ps, NonNeg.fromNumber dur)---padMusic :: IO ()-padMusic = do- arrange <- SigStL.makeArranger- playStereoVector $- CausalP.applyStorableChunky (CausalP.amplifyStereo id) (0.1::Float) $- arrange tonesChunkSize $- EventListTM.switchTimeR const $- EventListMT.consTime 0 $- EventListBT.fromPairList $- map (\(d,ps) -> withDur stereoOsciSawPad d ps)- chordSequence- return ()---lowpassSweepControlRateCausal ::- CausalP.T p- (Stereo.T (Value Float))- (Stereo.T (Value Float))-lowpassSweepControlRateCausal =--- CausalP.stereoFromVector $- CausalP.stereoFromMono $- UniFilter.lowpass ^<<- CtrlP.processCtrlRate 128- (lfoSine (UniFilter.parameter (valueOf (10::Float))))---moogSweepControlRateCausal ::- CausalP.T p- (Stereo.T (Value Float))- (Stereo.T (Value Float))-moogSweepControlRateCausal =--- CausalP.stereoFromVector $- CausalP.stereoFromMono $- CtrlP.processCtrlRate 128- (lfoSine (Moog.parameter TypeNum.d8 (valueOf (10::Float))))---filterMusic :: IO ()-filterMusic = do- arrange <- SigStL.makeArranger- pad <- stereoOsciSawPadIO- void $ playStereoVector $- CausalP.applyStorableChunky- (CausalP.amplifyStereo id <<<- moogSweepControlRateCausal) (0.05::Float) $- arrange tonesChunkSize $- EventListTM.switchTimeR const $- EventListMT.consTime 0 $- EventListBT.fromPairList $- map (\(d,ps) -> withDur pad d ps)- chordSequence----stereoOsciSawVectorIO :: IO (Float -> SVL.Vector (Stereo.T Float))-stereoOsciSawVectorIO =- fmap ($tonesChunkSize) $- SigP.runChunky $- stereoOsciSawP--applyFadeEnvelopeIO ::- IO (Int -> SVL.Vector (Stereo.T Float) -> SVL.Vector (Stereo.T Float))-applyFadeEnvelopeIO =- fmap- (\envelope dur sig ->- let attack = 20000- in envelope (attack, dur-attack) sig)- (CausalP.runStorableChunky- (CausalP.envelopeStereo $< fadeEnvelope))--stereoOsciSawChordIO :: IO (NonEmpty.T [] Float -> SVL.Vector (Stereo.T Float))-stereoOsciSawChordIO = do- sawv <- stereoOsciSawVectorIO- mix <- mixVectorStereoIO- return (NonEmpty.foldBalanced mix . fmap sawv)--stereoOsciSawPadIO ::- IO (Int -> NonEmpty.T [] Float -> SVL.Vector (Stereo.T Float))-stereoOsciSawPadIO = do- chrd <- stereoOsciSawChordIO- envelope <- applyFadeEnvelopeIO- return $- \ dur pitches -> envelope dur (chrd pitches)--padMusicIO :: IO ()-padMusicIO = do- arrange <- SigStL.makeArranger- pad <- stereoOsciSawPadIO- playStereoVector $- CausalP.applyStorableChunky (CausalP.amplifyStereo id) (0.08::Float) $- arrange tonesChunkSize $- EventListTM.switchTimeR const $- EventListMT.consTime 0 $- EventListBT.fromPairList $- map (uncurry (withDur pad)) $- chordSequence- return ()--{--Apply the envelope separately to each tone of the chord-and mix all tones by 'arrange'.--}-padMusicSeparate :: IO ()-padMusicSeparate = do- arrange <- SigStL.makeArranger- osci <- stereoOsciSawVectorIO- env <- applyFadeEnvelopeIO- playStereoVector $- CausalP.applyStorableChunky (CausalP.amplifyStereo id) (0.08::Float) $- arrange tonesChunkSize $- EventList.flatten $- EventListTM.switchTimeR const $- EventListMT.consTime 0 $- EventListBT.fromPairList $- map (uncurry (withDur (\d ps ->- map (\p -> env d (osci p)) $ NonEmpty.flatten ps))) $- chordSequence- return ()---delay :: IO ()-delay =- SVL.writeFile "speedtest.f32" $- asMono $- flip (SigP.renderChunky tonesChunkSize) (0, 10000) $- (CausalP.delayZero fst . CausalP.take snd- $*- SigP.osciSaw 0 (frequency 0.01))--delayStereo :: IO ()-delayStereo =- SVL.writeFile "speedtest.f32" $- asStereo $- flip (SigP.renderChunky tonesChunkSize) (7, 10000) $- (CausalP.take snd . liftA2 Stereo.cons id (CausalP.delayZero fst)- $*- SigP.osciSaw 0 (frequency 0.01))--delayPhaser :: IO ()-delayPhaser =- SVL.writeFile "speedtest.f32" $- asStereo $- flip (SigP.renderChunky tonesChunkSize) 40000 $- Func.compileSignal $- let osci = Func.fromSignal $ SigP.osciSaw 0 (frequency 0.01)- ctrl =- Func.fromSignal $- SigP.osciSimple Wave.triangle 0 $ frequency (1/20000)- in CausalP.take id $&- liftA2 Stereo.cons- osci- (CausalP.delayControlledInterpolated Interpolation.cubic- (0 :: Param.T p Float) 100- $&- (50+50*ctrl) &|& osci)----allpassControl ::- (TypeNum.Natural n) =>- Proxy n ->- SigP.T Float (Allpass.CascadeParameter n (Value Float))-allpassControl order =- let reduct = id- in SigP.interpolateConstant reduct $- lfoSine (Allpass.flangerParameter order) reduct--allpassPhaserCausal, allpassPhaserPipeline ::- SigP.T Float (Value Float) ->- SigP.T Float (Value Float)-allpassPhaserCausal =- let order = TypeNum.d16- in CausalP.apply- (0.5 * Allpass.phaser $< allpassControl order)--allpassPhaserPipeline =- let order = TypeNum.d16- in -- (F.nest (TypeNum.integralFromProxy order) SigP.tail .) $- SigP.drop (return $ TypeNum.integralFromProxy order) .- CausalP.apply- (0.5 * Allpass.phaserPipeline $< allpassControl order)--allpassPhaser :: IO ()-allpassPhaser =- SVL.writeFile "speedtest.f32" $- asMono $- SVL.take 10000000 $- flip (SigP.renderChunky (SVL.chunkSize 100000)) 128 $- allpassPhaserPipeline $- SigP.osciSaw 0 (frequency 0.01)--noise :: IO ()-noise =- SVL.writeFile "speedtest.f32" $- asMono $- SVL.take 10000000 $- flip (SigP.renderChunky (SVL.chunkSize 100000)) () $- SigP.noise 0 0.3--noisePacked :: IO ()-noisePacked =- SVL.writeFile "speedtest.f32" $- asMonoPacked $- SVL.take (div 10000000 4) $- flip (SigP.renderChunky (SVL.chunkSize 100000)) () $- SigPS.noise 0 0.3--- SigPS.pack (SigP.noise 0 0.3)--- SigPS.packSmall (SigP.noise 0 0.3)--frequencyModulationStorable :: IO ()-frequencyModulationStorable = do- smp <- SigP.runChunky (SigP.osciSaw 0 (frequency 0.01))- SVL.writeFile "speedtest.f32" $- asMono $- flip (SigP.renderChunky (SVL.chunkSize 100000)) () $- (CausalP.frequencyModulationLinear- (SigP.fromStorableVectorLazy $#- (SVL.take 1000000 $ asMono $- smp (SVL.chunkSize 1000) ()))- $*# (0.3::Float))--frequencyModulation :: IO ()-frequencyModulation =- SVL.writeFile "speedtest.f32" $- asMono $- SVL.take 10000000 $- flip (SigP.renderChunky (SVL.chunkSize 100000)) () $- (CausalP.frequencyModulationLinear- (SigP.osciSaw 0 (frequency 0.01))- $* Sig.exponential2 500000 1)--frequencyModulationStereo :: IO ()-frequencyModulationStereo = do- smp <- SigP.runChunky (SigP.osciSaw 0 (frequency 0.01))- SVL.writeFile "speedtest.f32" $- asStereo $- flip (SigP.renderChunky (SVL.chunkSize 100000)) () $- (CausalP.stereoFromMono- (CausalP.frequencyModulationLinear- (SigP.fromStorableVectorLazy $#- (SVL.take 1000000 $ asMono $- smp (SVL.chunkSize 1000) ())))- $*# Stereo.cons (0.2999::Float) 0.3001)--frequencyModulationProcess :: IO ()-frequencyModulationProcess =- SVL.writeFile "speedtest.f32" .- asMono .- (\f ->- f () $ asMono $- SigP.renderChunky (SVL.chunkSize 512)- (1 + 0.1 * SigP.osciSimple Wave.approxSine2 (pure (0::Float)) 0.0001)- ()) =<<- CausalP.runStorableChunky- (CausalP.frequencyModulationLinear- (CausalP.take 50000 $*- SigP.osciSaw 0 (frequency 0.01)))----quantize :: IO ()-quantize =-{-- SV.writeFile "speedtest.f32" $- asMono $- (\xs -> SigP.render xs 10000000 ()) $--}- SVL.writeFile "speedtest.f32" $- asMono $- SVL.take 10000000 $- flip (SigP.renderChunky (SVL.chunkSize 100000)) () $- ((CausalP.quantizeLift $# (5.5::Float)) id $*- SigP.osciSaw 0 (frequency 0.01))--quantizedFilterControl :: IO ()-quantizedFilterControl =- SVL.writeFile "speedtest.f32" $- asMono $- SVL.take 10000000 $- flip (SigP.renderChunky (SVL.chunkSize 100000)) () $- CausalP.apply (0.3 * (UniFilter.lowpass ^<< CtrlP.process)) $- SigP.zip- ((CausalP.quantizeLift $# (128::Float))- (Causal.map (UniFilter.parameter (valueOf 100)) <<<--- (Causal.map (Moog.parameter TypeNum.d8 (valueOf 100)) <<<- CausalV.map (\x -> 0.01 * exp (2 * x)))- $* SigP.osciSimple Wave.approxSine2 0 (frequency (0.1/44100))) $- SigP.osciSaw 0 (frequency 0.01)---arrowNonShared :: IO ()-arrowNonShared =- SVL.writeFile "speedtest.f32" $- asStereo $- SVL.take 10000000 $- flip (SigP.renderChunky (SVL.chunkSize 100000)) () $- (let osci = CausalP.osciSimple Wave.approxSine2- in liftA2 Stereo.cons osci osci $*- SigP.constant (return (0::Float, 0.01::Float)))--arrowShared :: IO ()-arrowShared =- SVL.writeFile "speedtest.f32" $- asStereo $- SVL.take 10000000 $- flip (SigP.renderChunky (SVL.chunkSize 100000)) () $- (let osci = Func.lift (CausalP.osciSimple Wave.approxSine2)- in Func.compile (liftA2 Stereo.cons osci osci) $*- SigP.constant (return (0::Float, 0.01::Float)))--arrowIndependent :: IO ()-arrowIndependent =- SVL.writeFile "speedtest.f32" $- asStereo $- SVL.take 10000000 $- flip (SigP.renderChunky (SVL.chunkSize 100000)) () $- (let osci = CausalP.osciSimple Wave.approxSine2- in Func.compile- (fmap (uncurry Stereo.cons) $- osci *** osci $&- Func.lift id) $*- SigP.constant (return ((0::Float, 0.01::Float), (0.25::Float, 0.01001::Float))))---rampDown :: Int -> SV.Vector Float-rampDown n =- SigS.toStrictStorableSignal n $- CtrlS.line n (1, 0)--impulses :: Int -> Float -> SVL.Vector Float-impulses n x =- SVL.fromChunks $- concatMap (\k -> [SV.singleton x, SV.replicate k 0]) $- take n $ iterate (2*) 1--convolution :: IO ()-convolution =- SVL.writeFile "speedtest.f32" $- asMono $- CausalP.applyStorableChunky- (FiltNR.convolve id)- (rampDown 1000)- (impulses 18 0.1)--convolutionPacked :: IO ()-convolutionPacked =- SVL.writeFile "speedtest.f32" $- asMonoPacked $- CausalP.applyStorableChunky- (FiltNR.convolvePacked id)- (rampDown 1000)- (asMonoPacked $- (\xs -> SigP.renderChunky SVL.defaultChunkSize xs ()) $- SigPS.pack $- SigP.fromStorableVectorLazy $- pure $ impulses 18 0.1)----helixSaw :: IO ()-helixSaw = do- let srcFreq = 0.01- srcLength :: Float- srcLength = 40000- osci <- SigP.run $ SigP.osciSaw 0 (pure srcFreq) * (1-SigP.ramp id)- let perc = asMono $ osci (round srcLength) srcLength- SV.writeFile "osci-saw.f32" perc- stretched <-- SigP.runChunky $- Func.compileSignal $- (Helix.static Interpolation.cubic Interpolation.cubic- 100 (pure $ recip srcFreq) snd- $&- (Func.fromSignal $ Sig.amplify srcLength $ SigP.ramp fst)- &|&- (CausalP.osciCore $& 0 &|& 0.01))- SVL.writeFile "osci-stretched.f32" $ asMono $- stretched SVL.defaultChunkSize (80000 :: Float, perc)---loadTomato :: IO (Float, SVL.Vector Float)-loadTomato = do- let Sample.Info name _sampleRate positions = Sample.tomatensalat- word <- Sample.load (Default.sampleDirectory </> name)- return (Sample.period $ head positions, word)--helixOsci :: Param.T p Float -> Func.T p a (Value Float)-helixOsci period =- CausalP.osciCore $&- 0 &|& Func.fromSignal (SigP.constant (recip period))--helixSpeechStaticSig ::- Func.T p () (Value Float) ->- Param.T p (SVL.Vector Float) ->- Param.T p Float ->- SigP.T p (Value Float)-helixSpeechStaticSig shape word period =- Func.compileSignal- (Helix.static Interpolation.linear Interpolation.linear- (fmap round period) period- (fmap (SV.concat . SVL.chunks) word)- $&- shape- &|&- helixOsci period)--helixSpeechStaticSpeed ::- Param.T p Float ->- Param.T p (SVL.Vector Float) ->- Param.T p Float ->- SigP.T p (Value Float)-helixSpeechStaticSpeed speed word =- helixSpeechStaticSig- (Func.fromSignal- (CausalPV.takeWhile (%>)- (fmap ((fromIntegral :: Int -> Float) . SVL.length) word) $*- SigP.rampSlope speed))- word--helixSpeechStatic :: IO ()-helixSpeechStatic = do- smp <- loadTomato- stretched <-- SigP.runChunky $- Param.withTuple1 $ \(speed, (period, word)) ->- helixSpeechStaticSpeed speed word period- SVL.writeFile "speech-stretched.f32" $ asMono $- stretched SVL.defaultChunkSize (0.5, smp)--helixSpeechDynamicSig ::- Func.T p () (Value Float) ->- Param.T p (SVL.Vector Float) ->- Param.T p Float ->- SigP.T p (Value Float)-helixSpeechDynamicSig shape word period =- Func.compileSignal- (Helix.dynamicLimited Interpolation.linear Interpolation.linear- (fmap round period) period (SigP.fromStorableVectorLazy word)- $&- shape- &|&- helixOsci period)--helixSpeechDynamicSpeed ::- Param.T p Float ->- Param.T p (SVL.Vector Float) ->- Param.T p Float ->- SigP.T p (Value Float)-helixSpeechDynamicSpeed speed =- helixSpeechDynamicSig (Func.fromSignal $ SigP.constant speed)--helixSpeechDynamic :: IO ()-helixSpeechDynamic = do- smp <- loadTomato- stretched <-- SigP.runChunky $- Param.withTuple1 $ \(speed, (period, word)) ->- helixSpeechDynamicSpeed speed word period- SVL.writeFile "speech-stretched.f32" $ asMono $- stretched SVL.defaultChunkSize (0.5, smp)--helixSpeechCompare :: IO ()-helixSpeechCompare = do- smp <- loadTomato- stretched <-- SigP.runChunky $- Param.withTuple1 $ \(speed, (period, word)) ->- sequenceA $- Stereo.cons- (helixSpeechStaticSpeed speed word period)- (helixSpeechDynamicSpeed speed word period)- SVL.writeFile "speech-stretched.f32" $ asStereo $- stretched SVL.defaultChunkSize (0.5, smp)--helixSpeechVariCompare :: IO ()-helixSpeechVariCompare = do- smp <- loadTomato- stretched <-- SigP.runChunky $- Param.withTuple1 $ \(period, word) ->- sequenceA $- let speed =- Func.fromSignal $ SigP.cycle $- SigP.fromStorableVector $ pure $- SV.pack [0.2, 0.5, 1, 1.5, 1.8 :: Float]- in Stereo.cons- (helixSpeechStaticSig- ((CausalP.integrate $# (0::Float)) $& speed) word period)- (helixSpeechDynamicSig speed word period)- SVL.writeFile "speech-stretched.f32" $ asStereo $- stretched SVL.defaultChunkSize smp---helixLimited :: IO ()-helixLimited = do- let period = 100- srcLength = 500- dstLength = 5000- speed :: Param.T p Float- speed = 0.5- osci =- 0.5- *- SigP.ramp (pure (fromIntegral srcLength :: Float))- *- SigP.osciSimple Wave.approxSine2 0 (recip period)- renderOsci <- SigP.run osci- let osciVec = renderOsci srcLength ()- SV.writeFile "helix-orig.f32" $ asMono osciVec-- let stretchedStatic =- Helix.static Interpolation.linear Interpolation.linear- (fmap round period) period (pure osciVec)- $&- Func.fromSignal (SigP.rampSlope speed)- &|&- helixOsci period- stretchedDynamic =- Helix.dynamic Interpolation.linear Interpolation.linear- (fmap round period) period osci- $&- Func.fromSignal (SigP.constant speed)- &|&- helixOsci period- stretched = liftA2 Stereo.cons stretchedStatic stretchedDynamic- renderHelix <- SigP.run $ Func.compileSignal stretched- SV.writeFile "helix-stretched.f32" $ asStereo $ renderHelix dstLength ()---cycleRamp :: IO ()-cycleRamp =- SVL.writeFile "speedtest.f32" . asMono .- (\f -> f SVL.defaultChunkSize (10000::Float)) =<<- SigP.runChunky- (CausalP.take 100000 $*- (SigP.cycle $ SigP.append (SigP.ramp id) (1 - SigP.ramp id)))--zigZag :: IO ()-zigZag =- SVL.writeFile "speedtest.f32" . asMono .- (\f -> f SVL.defaultChunkSize (-3::Float)) =<<- SigP.runChunky- (CausalP.take 100000 $* (Helix.zigZag id $* 0.0001))--zigZagPacked :: IO ()-zigZagPacked =- SVL.writeFile "speedtest.f32" . asMonoPacked .- (\f -> f SVL.defaultChunkSize (-3::Float)) =<<- SigP.runChunky- (let vectorSize = 4- in CausalP.take (pure $ div 100000 vectorSize) $*- (Helix.zigZagPacked id $* 0.0001))---trigger :: IO ()-trigger =- SVL.writeFile "speedtest.f32" . asMono .- (\f -> f SVL.defaultChunkSize (0.01 :: Float)) =<<- SigP.runChunky- (let pause len =- CausalClass.applyConst (CausalP.take len) Maybe.nothing- pulse :: Float -> Param.T p Int -> SigP.T p (Maybe.T (Value Float))- pulse freq len =- CausalP.take len .- arr (flip Maybe.fromBool (valueOf freq)) .- CausalP.delay1 (pure True) $*# False- in Sig.zipWith (flip Maybe.select) (SigP.noise 0 0.01) $- (CausalP.trigger- (\_ freq -> CausalP.take 150000 $* pingSigP freq) $*- pause 50000 `SigP.append`- pulse 0.004 100000 `SigP.append`- pulse 0.005 200000 `SigP.append`- pulse 0.006 400000))---triggerLFO :: SigP.T p (Value Float)-triggerLFO =- SigP.osciSimple Wave.approxSine2 0 (pure (0.00015 :: Float))- +- SigP.osciSimple Wave.approxSine2 0 (pure (0.000037 :: Float))--trackZeros :: CausalP.T p (Value Float) (Value Bool)-trackZeros =- CausalV.zipWith (\x y -> x %&& Value.not y) .- (id &&& CausalP.delay1 (pure False)) .- CausalV.map (%> 0)--fmPingSig :: Param.T p Float -> Param.T p Float -> SigP.T p (Value Float)-fmPingSig freq depth =- SigP.envelope- (Sig.exponential2 5000 1)- ((CausalP.osciSimple Wave.approxSine2 $> SigP.constant freq)- $*- (SigP.constant depth * SigP.osciSimple Wave.approxSine2 0 (2*freq)))--sweepTrigger :: IO ()-sweepTrigger =- SVL.writeFile "speedtest.f32" . asMono .- (\f -> f SVL.defaultChunkSize (0.01 :: Float)) =<<- SigP.runChunky- (Sig.zipWith (flip Maybe.select) (SigP.noise 0 0.01) $- (CausalP.trigger (const $ fmPingSig (pure (0.005 :: Float))) $*- liftA2 Maybe.fromBool- (CausalP.take 10000000 . trackZeros $* triggerLFO)- (5 * SigP.osciSimple Wave.approxSine2 0 (pure (0.00001 :: Float)))))+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE FlexibleContexts #-}+module Main where++import Synthesizer.LLVM.LAC2011 ()+import Synthesizer.LLVM.ExampleUtility++import qualified Synthesizer.LLVM.Server.Default as Default+import qualified Synthesizer.LLVM.Server.SampledSound as Sample++import qualified Synthesizer.LLVM.Filter.ComplexFirstOrderPacked as BandPass+import qualified Synthesizer.LLVM.Filter.Allpass as Allpass+import qualified Synthesizer.LLVM.Filter.Butterworth as Butterworth+import qualified Synthesizer.LLVM.Filter.Chebyshev as Chebyshev+import qualified Synthesizer.LLVM.Filter.FirstOrder as Filt1+import qualified Synthesizer.LLVM.Filter.SecondOrder as Filt2+import qualified Synthesizer.LLVM.Filter.SecondOrderPacked as Filt2P+import qualified Synthesizer.LLVM.Filter.Moog as Moog+import qualified Synthesizer.LLVM.Filter.Universal as UniFilter+import qualified Synthesizer.LLVM.Filter.NonRecursive as FiltNR+import qualified Synthesizer.LLVM.Causal.Helix as Helix+import qualified Synthesizer.LLVM.Causal.ControlledPacked as CtrlPS+import qualified Synthesizer.LLVM.Causal.Controlled as Ctrl+import qualified Synthesizer.LLVM.Causal.Render as CausalRender+import qualified Synthesizer.LLVM.Causal.ProcessPacked as CausalPS+import qualified Synthesizer.LLVM.Causal.Process as Causal+import qualified Synthesizer.LLVM.Causal.Functional as Func+import qualified Synthesizer.LLVM.Generator.Render as Render+import qualified Synthesizer.LLVM.Generator.SignalPacked as SigPS+import qualified Synthesizer.LLVM.Generator.Core as SigCore+import qualified Synthesizer.LLVM.Generator.Source as Source+import qualified Synthesizer.LLVM.Generator.Signal as Sig+import qualified Synthesizer.LLVM.Interpolation as Interpolation+import qualified Synthesizer.LLVM.Storable.Signal as SigStL+import qualified Synthesizer.LLVM.ConstantPiece as Const+import qualified Synthesizer.LLVM.Wave as Wave+import Synthesizer.LLVM.Causal.Functional (($&), (&|&))+import Synthesizer.LLVM.Causal.Process (($<), ($>), ($*), ($<#), ($*#))++import qualified Synthesizer.LLVM.Frame.StereoInterleaved as StereoInt+import qualified Synthesizer.LLVM.Frame.Stereo as Stereo+import qualified Synthesizer.LLVM.Frame.SerialVector as Serial++import qualified LLVM.DSL.Expression.Maybe as ExprMaybe+import qualified LLVM.DSL.Expression as Expr+import LLVM.DSL.Expression (Exp, (>*), (&&*))++import qualified LLVM.Extra.Multi.Value.Marshal as Marshal+import qualified LLVM.Extra.Multi.Vector.Instance as MultiVectorI+import qualified LLVM.Extra.Multi.Vector as MultiVector+import qualified LLVM.Extra.Multi.Value as MultiValue+import qualified LLVM.Extra.Arithmetic as A+import qualified LLVM.Extra.Tuple as Tuple+import qualified LLVM.Extra.Maybe as Maybe++import qualified LLVM.Core as LLVM+import LLVM.Util.Arithmetic () -- Floating instance for TValue++import qualified Type.Data.Num.Decimal as TypeNum+import Type.Data.Num.Decimal (D2, D4, (:*:))+import Type.Base.Proxy (Proxy)++import qualified Synthesizer.CausalIO.Process as PIO+import qualified Synthesizer.Causal.Class as CausalClass+import qualified Synthesizer.Zip as Zip+import qualified Synthesizer.State.Control as CtrlS+import qualified Synthesizer.State.Signal as SigS++import qualified Synthesizer.Plain.Filter.Recursive as FiltR+import qualified Synthesizer.Plain.Filter.Recursive.FirstOrder as Filt1Core++import Control.Arrow (Arrow, arr, first, (&&&), (^<<), (<<^), (***))+import Control.Category ((<<<), (.), id)+import Control.Applicative (liftA2)+import Control.Functor.HT (void)+import Control.Monad (when, join)++import qualified Data.StorableVector.Lazy as SVL+import qualified Data.StorableVector as SV+import Foreign.Storable (Storable)++import qualified Data.EventList.Relative.TimeBody as EventList+import qualified Data.EventList.Relative.BodyTime as EventListBT+import qualified Data.EventList.Relative.MixedTime as EventListMT+import qualified Data.EventList.Relative.TimeMixed as EventListTM+import qualified Numeric.NonNegative.Wrapper as NonNeg++import qualified Sound.Sox.Option.Format as SoxOption+import qualified Sound.Sox.Play as SoxPlay+-- import qualified Synthesizer.ALSA.Storable.Play as Play++import qualified Data.NonEmpty.Class as NonEmptyC+import qualified Data.NonEmpty as NonEmpty+import qualified Data.Foldable as Fold+import Data.Function.HT (nest)+import Data.NonEmpty ((!:))+import Data.Semigroup ((<>))+import Data.Traversable (sequenceA)+import Data.Tuple.HT (mapSnd)+import System.Path ((</>))+import System.Random (randomRs, mkStdGen)++import qualified System.Unsafe as Unsafe+import qualified System.IO as IO+import Control.Exception (bracket)++import qualified Algebra.Field as Field++import qualified NumericPrelude.Numeric as NP+import qualified Prelude as P+import NumericPrelude.Numeric (fromIntegral, sum, (+), (-), (/), (*))+import Prelude hiding (fst, snd, id, (.), fromIntegral, sum, (+), (-), (/), (*))+++asStereoPacked :: Id (vector (Serial.T D4 (Stereo.T Float)))+asStereoPacked = id++asStereoInterleaved :: Id (vector (StereoInt.T D4 Float))+asStereoInterleaved = id+++{- |+> playStereo (Sig.amplifyStereo 0.3 $ stereoOsciSaw 0.01)+-}+playStereo :: Sig.T (Stereo.T (MultiValue.T Float)) -> IO ()+playStereo sig =+ playStereoVector . ($ SVL.chunkSize 100000) =<<+ Render.run (Stereo.multiValue <$> sig)++playStereoVector :: SVL.Vector (Stereo.T Float) -> IO ()+playStereoVector =+ void . SoxPlay.simple SVL.hPut SoxOption.none 44100++playMono :: Sig.MV Float -> IO ()+playMono sig = playMonoVector . ($ SVL.chunkSize 100000) =<< Render.run sig++playMonoVector :: SVL.Vector Float -> IO ()+playMonoVector =+ void . SoxPlay.simple SVL.hPut SoxOption.none 44100+++playFileMono :: FilePath -> IO ()+playFileMono fileName = do+ f <- Render.run id+ IO.withFile fileName IO.ReadMode $ \h ->+ playStereoVector . f (SVL.chunkSize 100000) .+ asStereo . snd+ =<< SVL.hGetContentsAsync (SVL.chunkSize 4321) h+++frequency :: Float -> Exp Float+frequency = Expr.cons++{- |+Assist GHC-7.10.3 with determining the type of causal processes.+GHC-7.8.4 and GHC-8.0.1 do not need it.+-}+causalP :: Causal.T a b -> Causal.T a b+causalP = id+++constant :: Float -> IO ()+constant y =+ (SV.writeFile "speedtest.f32" . asMono =<<) $+ fmap ($ 1000) $ Render.run $+ Sig.constant (Expr.cons y)++saw :: IO ()+saw =+ (SV.writeFile "speedtest.f32" . asMono =<<) $+ fmap ($ 10000000) $ Render.run $+ Sig.osci Wave.saw 0 0.01++exponential :: IO ()+exponential =+ (SV.writeFile "speedtest.f32" . asMono =<<) $+ fmap ($ 10000000) $ Render.run $+ Sig.exponential2 50000 1++triangle :: IO ()+triangle =+ (SV.writeFile "speedtest.f32" . asMono =<<) $+ fmap ($ 10000000) $ Render.run $+ Sig.osci Wave.triangle 0.25 0.01++trianglePack :: IO ()+trianglePack =+ (SV.writeFile "speedtest.f32" . asMonoPacked =<<) $+ fmap ($ div 10000000 4) $ Render.run $+ (Causal.map (Expr.liftM Wave.triangle) $*) $+ SigPS.packSmall $+ SigCore.osci 0.25 (4.015803e-4)++trianglePacked :: IO ()+trianglePacked =+ (SV.writeFile "speedtest.f32" . asMonoPacked =<<) $+ fmap ($ div 10000000 4) $ Render.run $+ (CausalPS.osci Wave.triangle+ $< SigPS.constant 0.25+ $* SigPS.constant 0.01)++triangleReplicate :: IO ()+triangleReplicate =+ (SV.writeFile "speedtest.f32" . asMonoPacked =<<) $+ fmap ($ div 10000000 4) $ Render.run $+ (CausalPS.shapeModOsci+ (\k p -> do+ x <- Wave.triangle =<< Wave.replicate k p+ y <- Wave.approxSine4 =<< Wave.halfEnvelope p+ A.mul x y)+ $< SigPS.rampInf 1000000+ $< SigPS.constant 0+ $* SigPS.constant 0.01)++rationalSine :: IO ()+rationalSine =+ (SV.writeFile "speedtest.f32" . asMonoPacked =<<) $+ fmap ($ div 10000000 4) $ Render.run $+ (CausalPS.shapeModOsci Wave.rationalApproxSine1+ $< (0.001 + SigPS.rampInf 10000000)+ $< SigPS.constant 0+ $* SigPS.constant 0.01)++rationalSineStereo :: IO ()+rationalSineStereo =+ (SV.writeFile "speedtest.f32" . asStereoPacked =<<) $+ fmap ($ div 10000000 4) $ Render.run $+ fmap Stereo.multiValueSerial $+ liftA2 Stereo.cons+ (CausalPS.shapeModOsci Wave.rationalApproxSine1+ $< (0.001 + SigPS.rampInf 10000000)+ $< SigPS.constant (-0.25)+ $* SigPS.constant 0.00999)+ (CausalPS.shapeModOsci Wave.rationalApproxSine1+ $< (0.001 + SigPS.rampInf 10000000)+ $< SigPS.constant 0.25+ $* SigPS.constant 0.01001)+++pingSig :: Float -> Sig.MV Float+pingSig freq =+ Sig.exponential2 50000 1+ *+ Sig.osci Wave.saw 0.5 (Expr.cons freq)++pingSigP :: Exp Float -> Sig.MV Float+pingSigP freq =+ Sig.exponential2 50000 1+ *+ Sig.osci Wave.saw 0.5 freq++ping :: IO ()+ping =+ (SV.writeFile "speedtest.f32" . asMono =<<) $+ fmap ($ 10000000) $ Render.run $+ pingSig 0.01++pingSigPacked :: Exp Float -> Sig.T (CausalPS.Serial D4 Float)+pingSigPacked freq =+ SigPS.exponential2 50000 1+ *+ SigPS.osci Wave.saw 0 freq++pingPacked :: IO ()+pingPacked =+ (SV.writeFile "speedtest.f32" . asMonoPacked =<<) $+ fmap (\f -> f (div 10000000 4) (0.01::Float)) $ Render.run $+ pingSigPacked++pingUnpack :: IO ()+pingUnpack =+ (SV.writeFile "speedtest.f32" . asMono =<<) $+ fmap (\f -> f 10000000 (0.01::Float)) $ Render.run $+ SigPS.unpack . pingSigPacked++pingSmooth :: IO ()+pingSmooth =+ SV.writeFile "speedtest-scalar.f32" . asMono . ($ 10000000) =<<+ Render.run+ (Filt1.lowpassCausal+ $< fmap Filt1Core.Parameter (1 - Sig.exponential2 50000 1)+ $* Sig.osci Wave.triangle 0 0.01)++pingSmoothPacked :: IO ()+pingSmoothPacked =+ SV.writeFile "speedtest-vector.f32" . asMonoPacked . ($ div 10000000 4) =<<+ Render.run+ (Filt1.lowpassCausalPacked+ $< fmap Filt1Core.Parameter (1 - Sig.exponential2 (50000/4) 1)+ $* SigPS.osci Wave.triangle 0 0.01)++stereoOsciSaw :: Exp Float -> Sig.T (Stereo.T (MultiValue.T Float))+stereoOsciSaw freq =+ liftA2 Stereo.cons+ (Sig.osci Wave.saw 0.0 (freq*1.001) ++ Sig.osci Wave.saw 0.2 (freq*1.003) ++ Sig.osci Wave.saw 0.1 (freq*0.995))+ (Sig.osci Wave.saw 0.1 (freq*1.005) ++ Sig.osci Wave.saw 0.7 (freq*0.997) ++ Sig.osci Wave.saw 0.5 (freq*0.999))++stereoOsciSawPacked :: Float -> Sig.T (Stereo.T (MultiValue.T Float))+stereoOsciSawPacked freq =+ let mix4 = Expr.liftM $ MultiVector.sum . MultiVectorI.fromMultiValue+ in liftA2 Stereo.cons+ ((Causal.map mix4 $*) $+ Sig.osci Wave.saw+ (Expr.cons $ LLVM.consVector 0.0 0.2 0.1 0.4)+ (Expr.cons $ fmap (freq*) $+ LLVM.consVector 1.001 1.003 0.995 0.996))+ ((Causal.map mix4 $*) $+ Sig.osci Wave.saw+ (Expr.cons $ LLVM.consVector 0.1 0.7 0.5 0.7)+ (Expr.cons $ fmap (freq*) $+ LLVM.consVector 1.005 0.997 0.999 1.001))++stereoDeinterleave :: NonEmpty.T [] a -> NonEmpty.T [] (Stereo.T a)+stereoDeinterleave xt =+ case xt of+ NonEmpty.Cons _ [] -> error "stereoDeinterleave: singleton"+ NonEmpty.Cons x0 (x1:xs) ->+ Stereo.cons x0 x1 !:+ let go (y0:y1:ys) = Stereo.cons y0 y1 : go ys+ go [] = []+ go [_] = error "stereoDeinterleave: odd length"+ in go xs++mixVectorToStereo ::+ (TypeNum.Positive n, MultiVector.Additive a) =>+ MultiVector.T n a -> LLVM.CodeGenFunction r (Stereo.T (MultiValue.T a))+mixVectorToStereo =+ NonEmpty.foldBalanced (\x y -> join $ liftA2 A.add x y) .+ fmap sequenceA . stereoDeinterleave . MultiVector.dissectList1++mixVec ::+ (TypeNum.Positive n, MultiVector.Additive a) =>+ Exp (LLVM.Vector n a) -> Stereo.T (Exp a)+mixVec =+ Stereo.unExpression .+ Expr.liftM+ (fmap Stereo.multiValue . mixVectorToStereo . MultiVectorI.fromMultiValue)++stereoOsciSawPacked2 :: Float -> Sig.T (Stereo.T (MultiValue.T Float))+stereoOsciSawPacked2 freq =+ (Causal.map mixVec $*) $+ Sig.osci (Wave.trapezoidSlope (A.fromRational' 5))+ (Expr.cons $ LLVM.consVector 0.0 0.2 0.1 0.4 0.1 0.7 0.5 0.7)+ (Expr.cons $ fmap (freq*) $+ LLVM.consVector 1.001 1.003 0.995 0.996 1.005 0.997 0.999 1.001)++stereo :: IO ()+stereo =+ SV.writeFile "speedtest.f32" . asStereo . ($ 10000000) =<<+ Render.run+ (Stereo.multiValue <$> Causal.amplifyStereo 0.25+ $* stereoOsciSawPacked2 0.01)++lazy :: IO ()+lazy =+ (SVL.writeFile "speedtest.f32" . asMono . SVL.take 10000000 =<<) $+ fmap ($ SVL.chunkSize 100000) $+ Render.run {- SVL.defaultChunkSize - too slow -}+ (Causal.envelope+ $< Sig.exponential2 50000 1+ $* Sig.osci Wave.sine 0.5 0.01)++lazyStereo :: IO ()+lazyStereo =+ (SVL.writeFile "speedtest.f32" . asStereo . SVL.take 10000000 =<<) $+ fmap ($ SVL.chunkSize 100000) $+ Render.run+ (Stereo.multiValue <$> Causal.amplifyStereo 0.25+ $* stereoOsciSawPacked 0.01)++packTake :: IO ()+packTake =+ (SVL.writeFile "speedtest.f32" . asMonoPacked . ($ SVL.chunkSize 1000) =<<) $+ (Render.run . SigPS.packRotate)+ (Causal.take 5 $* Sig.osci Wave.saw 0 (frequency 0.01))++chord :: Float -> Sig.T (Stereo.T (MultiValue.T Float))+chord base =+ {-+ This exceeds available vector registers+ and thus needs more stack accesses.+ Thus it needs twice as much time as the simple mixing.+ However doing all 32 oscillators in parallel+ and mix them in one go might be still faster.++ foldl1 (Sig.zipWith Frame.mixStereoV) $+ -}+ NonEmpty.foldBalanced (+) $+ fmap (\f -> stereoOsciSawPacked2 (base*f)) $+ 0.25 !: 1.00 : 1.25 : 1.50 : []++lazyChord :: IO ()+lazyChord =+ (SVL.writeFile "speedtest.f32" . asStereo . SVL.take 10000000 =<<) $+ fmap ($ SVL.chunkSize 100000) $+ Render.run (Stereo.multiValue <$> Causal.amplifyStereo 0.1 $* chord 0.005)++filterSweepComplex :: IO ()+filterSweepComplex =+ playStereo $+ (Causal.amplifyStereo 0.3 . BandPass.causal+ $< (Causal.map (\x -> BandPass.parameter 100 (0.01 * exp (2*x))) $*+ Sig.osci Wave.sine 0 (0.1/44100))+ $* chord 0.005)++lfoSineCausal ::+ Causal.T (MultiValue.T Float) a -> Exp Float -> Sig.T a+lfoSineCausal f reduct =+ f . Causal.map (\x -> 0.01 * exp (2*x)) $*+ Sig.osci Wave.sine 0 (reduct * 0.1/44100)++lfoSine ::+ (Expr.Aggregate ae a) =>+ (Exp Float -> ae) ->+ Exp Float -> Sig.T a+lfoSine f = lfoSineCausal (Causal.map f)++filterSweep :: IO ()+filterSweep =+ (SVL.writeFile "speedtest.f32" . asMono . SVL.take 10000000 =<<) $+ fmap ($ SVL.chunkSize 10000) $+ Render.run $+ (0.2 * Ctrl.processCtrlRate 128 (lfoSine (Filt2.bandpassParameter 100))+ $* Sig.osci Wave.saw 0 (frequency 0.01))++filterSweepPacked :: IO ()+filterSweepPacked =+ (SVL.writeFile "speedtest.f32" . asMonoPacked =<<) $+ fmap (SVL.take (div 10000000 4)) $+ fmap ($ SVL.chunkSize 10000) $+ Render.run+ (0.2 *+ CtrlPS.processCtrlRate 128 (lfoSine (Filt2.bandpassParameter 100))+ $* SigPS.osci Wave.saw 0 (frequency 0.01))++exponentialFilter2Packed :: IO ()+exponentialFilter2Packed =+ (SVL.writeFile "speedtest.f32" . asMonoPacked16 =<<) $+ fmap (SVL.take (div 10000000 16)) $+ fmap ($ SVL.chunkSize 10000) $+ Render.run+ (Filt2.causalPacked+ $< Sig.constant (Filt2.Parameter 1 0 0 0 0.99)+ $* (+-- (Causal.delay1 $ Serial.fromFixedList (0.1 !: 0.01 !: 0.001 !: 0.0001 !: Empty.Cons))+-- (Causal.delay1 $ Serial.replicate 1)+ (Causal.delay1 $ Serial.fromFixedList (1 !: NonEmptyC.repeat 0))+ $* 0))++filterSweepPacked2 :: IO ()+filterSweepPacked2 =+ (SVL.writeFile "speedtest.f32" . asMono . SVL.take 10000000 =<<) $+ fmap ($ SVL.chunkSize 10000) $+ Render.run+ (0.2 *+ Ctrl.processCtrlRate 128 (lfoSine (Filt2P.bandpassParameter 100))+ $* Sig.osci Wave.saw 0 (frequency 0.01))++butterworthNoisePacked :: IO ()+butterworthNoisePacked =+ (SVL.writeFile "speedtest.f32" . asMonoPacked =<<) $+ fmap (SVL.take (div 10000000 4)) $+ fmap ($ SVL.chunkSize 10000) $+ Render.run+ (CausalPS.amplify 0.2 .+ CtrlPS.processCtrlRate 128+ (lfoSineCausal+ (Butterworth.parameterCausal TypeNum.d3 FiltR.Lowpass $<# 0.5))+ $* SigPS.noise 0 0.3)++chebyshevNoisePacked :: IO ()+chebyshevNoisePacked =+ (SVL.writeFile "speedtest.f32" . asMonoPacked =<<) $+ fmap (SVL.take (div 10000000 4)) $+ fmap ($ SVL.chunkSize 10000) $+ Render.run+ (CausalPS.amplify 0.2 .+ CtrlPS.processCtrlRate 128+ (lfoSineCausal+ (Chebyshev.parameterCausalA TypeNum.d5 FiltR.Lowpass $<# 0.5))+ $* SigPS.noise 0 0.3)+++upsample :: IO ()+upsample =+ (SVL.writeFile "speedtest.f32" . asMono . SVL.take 10000000 =<<) $+ fmap ($ SVL.chunkSize 100000) $+ Render.run+ (let reduct = 128 :: Exp Float+ in Sig.interpolateConstant reduct+ (Sig.osci Wave.sine 0 (reduct*0.1/44100)))+++filterSweepControlRateCausal ::+ Causal.T+ (Stereo.T (MultiValue.T Float))+ (Stereo.T (MultiValue.T Float))+filterSweepControlRateCausal =+ Causal.amplifyStereo 0.3 <<< BandPass.causal+ $< (let reduct = 128 :: Exp Float+ in Sig.interpolateConstant reduct+ (Causal.map (BandPass.parameter 100) .+ Causal.map (\x -> 0.01 * exp (2*x))+ $* Sig.osci Wave.sine 0 (reduct*0.1/44100)))++{- |+Trigonometric functions are very slow in LLVM+because they are translated to calls to C's math library.+Thus it is advantageous to compute filter parameters+at a lower rate and interpolate constantly.+-}+filterSweepControlRate :: IO ()+filterSweepControlRate =+ (SVL.writeFile "speedtest.f32" . asStereo . SVL.take 10000000 =<<) $+ fmap ($ SVL.chunkSize 100000) $+ Render.run+ (Stereo.multiValue <$> filterSweepControlRateCausal $* chord 0.005)+++filterSweepMusic :: IO ()+filterSweepMusic = do+ proc <-+ Render.run $ \music ->+ Stereo.multiValue ^<< Causal.amplifyStereo 20 .+ filterSweepControlRateCausal <<^ Stereo.unMultiValue $* music+ music <- SV.readFile "lichter.f32"+ SVL.writeFile "speedtest.f32" . asStereo+ =<< proc (SVL.chunkSize 100000) music+++playFilterSweepMusicLazy :: IO ()+playFilterSweepMusicLazy = do+ proc <-+ Render.run $ \vol music ->+ Stereo.multiValue ^<< Causal.amplifyStereo vol .+ filterSweepControlRateCausal <<^ Stereo.unMultiValue $* music+ IO.withFile "lichter.f32" IO.ReadMode $ \h ->+ playStereoVector . proc (SVL.chunkSize 100000) (20::Float) {-1.125-} . snd+ =<< SVL.hGetContentsAsync (SVL.chunkSize 4321) h++playFilterSweepMusicCausal :: IO ()+playFilterSweepMusicCausal = do+ proc <-+ CausalRender.run $+ Stereo.multiValue ^<< Causal.amplifyStereo 20 .+ filterSweepControlRateCausal <<^ Stereo.unMultiValue+ music <- SV.readFile "lichter.f32"+ void $ SoxPlay.simple SV.hPut SoxOption.none 44100 =<<+ pioApplyStrict proc music++playFilterSweepMusicCausalLazy :: IO ()+playFilterSweepMusicCausalLazy = do+ proc <-+ CausalRender.run $+ Stereo.multiValue ^<< Causal.amplifyStereo 20 .+ filterSweepControlRateCausal <<^ Stereo.unMultiValue+ IO.withFile "lichter.f32" IO.ReadMode $ \h ->+ playStereoVector =<< pioApply proc . snd+ =<< SVL.hGetContentsAsync (SVL.chunkSize 43210) h+++deinterleaveProc ::+ IO (Float ->+ PIO.T+ (SV.Vector (StereoInt.T D4 Float))+ (Zip.T+ (SV.Vector (StereoInt.T D4 Float))+ (SV.Vector (StereoInt.T D4 Float))))+deinterleaveProc =+ CausalRender.run deinterleaveCausal++deinterleaveCausal ::+ Exp Float ->+ Causal.T+ (StereoInt.Value D4 Float)+ (StereoInt.Value D4 Float, StereoInt.Value D4 Float)+deinterleaveCausal freq =+ Func.withArgs $ \input ->+ let env =+ Func.fromSignal $+ 0.5 * (1 + SigPS.osci (Wave.triangleSquarePower 4) 0 freq)+ in (Causal.zipWith StereoInt.envelope $& env &|& input)+ &|&+ (Causal.zipWith StereoInt.envelope $& (1-env) &|& input)++deinterleave :: IO ()+deinterleave = do+ proc <- deinterleaveProc+ runSplitProcess (proc (2/44100))+++disturbProc, disturbFMProc ::+ IO (PIO.T+ (SV.Vector (StereoInt.T D4 Float))+ (Zip.T+ (SV.Vector (StereoInt.T D4 Float))+ (SV.Vector (StereoInt.T D4 Float))))+disturbProc =+ CausalRender.run $ crossMix disturbCausal++disturbCausal, disturbFMCausal ::+ Causal.T (StereoInt.Value D4 Float) (StereoInt.Value D4 Float)+disturbCausal =+ Func.withArgs $ \inputInt ->+ let tone = Func.fromSignal $ SigPS.osci Wave.triangle 0 (440/44100)+ getEnvelope x =+ Filt1.lowpassCausalPacked $&+ (Func.fromSignal $+ Sig.constant $ Filt1Core.parameter (1/44100))+ &|&+ (Causal.map abs $& x)+ envelopedTone x = getEnvelope x * tone+ in Causal.map StereoInt.interleave $&+ CausalPS.amplifyStereo 5 $&+ Stereo.liftApplicative envelopedTone+ (Causal.map StereoInt.deinterleave $& inputInt)++disturbFMProc =+ CausalRender.run $ crossMix disturbFMCausal++disturbFMCausal =+ Func.withArgs $ \inputInt ->+ let getEnvelope x =+ Filt1.lowpassCausalPacked $&+ (Func.fromSignal $+ Sig.constant $ Filt1Core.parameter (1/44100))+ &|&+ (Causal.map abs $& x)+ modulatedTone x =+ getEnvelope x *+ (CausalPS.osci Wave.triangle $&+ NP.zero+ &|&+ 10 * getEnvelope (CausalPS.differentiate 0 $& x))+ in Causal.map StereoInt.interleave $&+ CausalPS.amplifyStereo 5 $&+ Stereo.liftApplicative modulatedTone+ (Causal.map StereoInt.deinterleave $& inputInt)++disturb :: IO ()+disturb =+ runSplitProcess =<< disturbFMProc+++wowFlutterProc ::+ IO (PIO.T+ (SV.Vector (StereoInt.T D4 Float))+ (Zip.T+ (SV.Vector (StereoInt.T D4 Float))+ (SV.Vector (StereoInt.T D4 Float))))+wowFlutterProc =+ CausalRender.run $ crossMix wowFlutterCausal++wowFlutterCausal ::+ Causal.T (StereoInt.Value D4 Float) (StereoInt.Value D4 Float)+wowFlutterCausal =+ Func.withArgs $ \inputInt ->+ let freq =+ Func.fromSignal $ (44100*) $+ 0.01 * (1 + SigPS.osci Wave.triangle 0 (1/44100 :: Exp Float)) ++ 0.01 * (1 + SigPS.osci Wave.approxSine2+ 0 (1.23/44100 :: Exp Float))+ modulatedTone x =+ CausalPS.pack+ (Causal.delayControlledInterpolated Interpolation.linear+ (0 :: Exp Float) (441*2*2+10))+ $&+ freq &|& x+ in Causal.map StereoInt.interleave $&+ Stereo.liftApplicative modulatedTone+ (Causal.map StereoInt.deinterleave $& inputInt)++crossMix ::+ Causal.T (StereoInt.Value D4 Float) (StereoInt.Value D4 Float) ->+ Causal.T+ (StereoInt.Value D4 Float)+ (StereoInt.Value D4 Float, StereoInt.Value D4 Float)+crossMix proc =+ ((fst NP.+ snd) &&& (fst NP.- snd))+ .+ (id &&& proc)+ .+ Causal.map (StereoInt.amplify 0.5)+++wowFlutter :: IO ()+wowFlutter =+ runSplitProcess =<< wowFlutterProc++++scrambleProc0, scrambleProc1 ::+ IO (Float ->+ PIO.T+ (SV.Vector (StereoInt.T D4 Float))+ (Zip.T+ (SV.Vector (StereoInt.T D4 Float))+ (SV.Vector (StereoInt.T D4 Float))))+scrambleProc0 =+ CausalRender.run $ \freq ->+ deinterleaveCausal freq NP.++ (id &&& NP.negate id) .+ Causal.map (StereoInt.amplify 0.5) . wowFlutterCausal++scrambleProc1 =+ CausalRender.run $ \freq ->+ deinterleaveCausal freq NP.++ (id &&& NP.negate id) .+ Causal.map (StereoInt.amplify 0.3) .+ (wowFlutterCausal NP.+ disturbFMCausal)++scramble :: IO ()+scramble = do+ proc <- scrambleProc1+ runSplitProcess (proc (2/44100))+++runSplitProcess ::+ (Storable a) =>+ PIO.T (SV.Vector a) (Zip.T (SV.Vector a) (SV.Vector a)) ->+ IO ()+runSplitProcess proc = do+ void $+ IO.withFile "/tmp/test.f32" IO.ReadMode $ \h ->+ IO.withFile "/tmp/even.f32" IO.WriteMode $ \h0 ->+ IO.withFile "/tmp/odd.f32" IO.WriteMode $ \h1 ->++ case proc of+ PIO.Cons next create delete ->+ {-+ Is the use of 'bracket' correct?+ I think 'delete' must be called with the final state,+ not with the initial one.+ -}+ bracket create delete $+ let chunkSize = 543210+ loop s0 = do+ chunk <- SV.hGet h chunkSize+ (Zip.Cons y0 y1, s1) <- next chunk s0+ SV.hPut h0 y0+ SV.hPut h1 y1+ when+ (SV.length y0 >= SV.length chunk &&+ SV.length y1 >= SV.length chunk &&+ SV.length chunk >= chunkSize)+ (loop s1)+ in loop+++antimixProc ::+ IO (SVL.Vector (StereoInt.T D4 Float) ->+ PIO.T+ (SV.Vector (StereoInt.T D4 Float))+ (Zip.T+ (SV.Vector (StereoInt.T D4 Float))+ (SV.Vector (StereoInt.T D4 Float))))+antimixProc =+ CausalRender.run $ \xs -> crossMix $+ Causal.map (StereoInt.amplify 0.5) . Causal.fromSignal xs++antimix :: IO ()+antimix = do+ proc <- antimixProc+ void $+ IO.withFile "/tmp/test.f32" IO.ReadMode $ \h ->+ IO.withFile "/tmp/even.f32" IO.WriteMode $ \h0 ->+ IO.withFile "/tmp/odd.f32" IO.WriteMode $ \h1 -> do+ let chunkSize = SVL.chunkSize 543210+ input <- fmap snd $ SVL.hGetContentsAsync chunkSize h+ let vectorSize = 4+ additive = SVL.drop (div 44100 vectorSize) input+{-+ additive =+ case SVL.splitAt (div 44100 vectorSize) input of+ (prefix, suffix) ->+ SVL.append suffix $+ SVL.replicate chunkSize (SVL.length prefix) StereoInt.zero+-}+{-+ additive =+ case SVL.splitAt (div 44100 vectorSize) input of+ (prefix, suffix) -> SVL.append suffix prefix+-}++ case proc additive of+ PIO.Cons next create delete ->+ {-+ Is the use of 'bracket' correct?+ I think 'delete' must be called with the final state,+ not with the initial one.+ -}+ bracket create delete $ \state ->+ let loop cs0 s0 =+ case cs0 of+ [] -> return ()+ c : cs -> do+ (Zip.Cons y0 y1, s1) <- next c s0+ SV.hPut h0 y0+ SV.hPut h1 y1+ when+ (SV.length y0 >= SV.length c &&+ SV.length y1 >= SV.length c)+ (loop cs s1)+ in loop (SVL.chunks input) state+++arrangeLazy :: IO ()+arrangeLazy = do+ IO.hSetBuffering IO.stdout IO.NoBuffering+ arrange <- SigStL.makeArranger+ print $+ arrange (SVL.chunkSize 2) $+ EventList.fromPairList $+ (0, SVL.pack (SVL.chunkSize 2) [1,2::Double]) :+ (0, SVL.pack (SVL.chunkSize 2) [3,4,5,6]) :+ (2, SVL.pack (SVL.chunkSize 2) [7,8,9,10]) :+ -- repeat (2, SVL.empty)+-- (2, SVL.empty) :+-- (2, SVL.empty) :+-- (2::NonNeg.Int, error "undefined sound") :+ error "end of list"+ -- []+++{- |+This is inefficient because pingSig is compiled by LLVM+for every occurence of the sound!++randomTones :: IO ()+randomTones = do+ playMonoVector $+ SigStL.arrange (SVL.chunkSize 12345) $+ EventList.fromPairList $ zip+ (cycle $ map (flip div 16 . (44100*)) [1,2,3])+ (cycle $ map (SVL.take 44100 . Sig.renderChunky (SVL.chunkSize 54321) .+ pingSig . (0.01*))+ [1,1.25,1.5,2])+-}++{-+{- |+So far we have not managed to compile signals+that depend on parameters.+Thus in order to avoid much recompilation,+we compile and render a few sounds in advance.+-}+pingTones :: [SVL.Vector Float]+pingTones =+ map (SVL.take 44100 . Sig.renderChunky (SVL.chunkSize 4321) .+ pingSig . (0.01*))+ [1,1.25,1.5,2]+-}++pingTonesIO :: IO [SVL.Vector Float]+pingTonesIO =+ fmap+ (\pingVec ->+ map+ (SVL.take 44100 .+ pingVec (SVL.chunkSize 4321) .+ (0.01*))+ [1,1.25,1.5,2::Float])+ (Render.run pingSigP)++{-+Arrange itself does not seem to have a space leak with temporary data.+However it may leak sound data.+This is not very likely because this would result in a large memory leak.++Generate random tones in order to see whether generated sounds leak.+How does 'arrange' compare with 'concat'?+-}++{-+cycleTones :: IO ()+cycleTones = do+-- playMono $+ pings <- pingTonesIO+ SVL.writeFile "test.f32" $+-- Play.auto (0.01::Double) 44100 $+ asMono $+{-+after 13min runtime memory consumption increased from 2.5 to 3.9+and we get lot of buffer underruns with this implementation of amplification+(renderChunky . amplify . fromStorableVector)+-}+ Sig.renderChunky (SVL.chunkSize 432109) $+ Sig.amplify 0.1 $+ Sig.fromStorableVectorLazy $+{-+after 20min memory consumption increased from 2.5 to 3.4+and we get lot of buffer underruns with applyStorableChunky+-}+{-+applyStorableChunky applied to concatenated zero vectors+starts with memory consumption 1.0 and after an hour, it's still 1.1+without buffer underruns.+-}+{-+ CausalP.applyStorableChunky (CausalP.amplify $# (0.1::Float)) () $+ asMono $+-}+{-+with chunksize 12345678+after 50min runtime the memory consumption increased from 12.0 to 26.2++with chunksize 123+after 25min runtime the memory consumption is constant 7.4+however at start time there 5 buffer underruns, but no more+probably due to initial LLVM compilation++with chunksize 1234567 and SVL.replicate instead of pingTones+we get memory consumption from 1.3 to 3.2 in 15min,+while producing lots of buffer underruns.+After 45min in total, it is still 3.2 of memory consumption.+Is this a memory leak, or isn't it?++with chunksize 12345678 and SVL.replicate+we get from 5.6 to 10.2 in 3min+to 14.9 after total 13min.+-}+{-+ SigStL.arrange (SVL.chunkSize 12345678) $+ EventList.fromPairList $ zip+ (repeat (div 44100 8))+-- (cycle $ map (flip div 4 . (44100*)) [1,2,3])+-}+{-+With plain concatenation of those zero vectors+we stay constantly at 0.4 memory consumption and no buffer underruns over 30min.+-}+ SVL.concat+ (cycle pings)+-- (repeat $ SVL.replicate (SVL.chunkSize 44100) 44100 0)+ return ()+-}+++tonesChunkSize :: SVL.ChunkSize+numTones :: Int++{-+For one-time-compiled fill functions,+larger chunks have no relevant effect on the processing speed.+-}+(tonesChunkSize, numTones) =+ (SVL.chunkSize 441, 200)+-- (SVL.chunkSize 44100, 200)++fst :: Arrow arrow => arrow (a,b) a+fst = arr P.fst++snd :: Arrow arrow => arrow (a,b) b+snd = arr P.snd+++{-# NOINLINE makePing #-}+makePing :: IO (Float -> Float -> SVL.Vector Float)+makePing =+ fmap ($ tonesChunkSize) $+ Render.run $ \halfLife freq ->+ Causal.envelope+ $< Sig.exponential2 halfLife 1+ $* Sig.osci Wave.saw 0.5 freq++tonesDown :: IO ()+tonesDown = do+ let dist = div 44100 10+ pingp <- makePing+ arrange <- SigStL.makeArranger+ amplify <- CausalRender.run Causal.amplify+ playMonoVector =<<+ (pioApply (amplify (0.03::Float)) $+ arrange tonesChunkSize $+ EventList.fromPairList $+ zip+ (repeat (NonNeg.fromNumber dist))+ (map (SVL.take (numTones * dist) . pingp 50000) $+ iterate (0.999*) 0.01))+++vibes :: (Exp Float, Exp Float) -> Sig.MV Float+vibes (modDepth, freq) =+ let halfLife = 5000+ -- sine = Wave.sine+ sine = Wave.approxSine4+ in Causal.envelope+ $< Sig.exponential2 halfLife 1+ $* (((Causal.osci sine+ $< (Causal.envelope+ $< Sig.exponential2 halfLife modDepth+ $* (Causal.osci sine $* Sig.constant (0, 2*freq))))+ <<<+ Causal.amplify freq+ <<<+ (Causal.osci sine * 0.01 + 1))+ $* Sig.constant (0, 0.0001))++makeVibes :: IO ((Float,Float) -> SVL.Vector Float)+makeVibes = fmap ($ tonesChunkSize) $ Render.run vibes++vibesCycleVector :: ((Float,Float) -> SVL.Vector Float) -> IO (SVL.Vector Float)+vibesCycleVector pingp =+ (\evs -> fmap (\arrange -> arrange tonesChunkSize evs) SigStL.makeArranger) $+ EventList.fromPairList $ zip+ (repeat 5000)+ (map (SVL.take 50000 . pingp) $+ zip+ (map (\k -> 0.5 * (1 - cos k)) $ iterate (0.05+) 0)+ (cycle $ map (0.01*) [1, 1.25, 1.5, 2]))++pioApply ::+ (Storable a, Storable b) =>+ PIO.T (SV.Vector a) (SV.Vector b) -> SVL.Vector a -> IO (SVL.Vector b)+pioApply proc sig = do+ act <- PIO.runStorableChunkyCont proc+ return $ act (const SVL.empty) sig++pioApplyStrict ::+ (Storable a, Storable b) =>+ PIO.T (SV.Vector a) (SV.Vector b) -> SV.Vector a -> IO (SV.Vector b)+pioApplyStrict proc sig = do+ act <- PIO.runCont proc+ return $+ case act (const []) [sig] of+ chunk : _ -> chunk+ [] -> SV.empty++vibesCycle :: IO ()+vibesCycle = do+ sig <- vibesCycleVector =<< makeVibes+ proc <- CausalRender.run Causal.amplify+ playMonoVector =<< pioApply (proc (0.2::Float)) sig++vibesEcho :: IO ()+vibesEcho = do+ sig <- vibesCycleVector =<< makeVibes+ proc <-+ CausalRender.run (\vol -> Causal.amplify vol <<< Causal.comb 0.5 7000)+ playMonoVector =<< pioApply (proc (0.2::Float)) sig++vibesReverb :: IO ()+vibesReverb = do+ sig <- vibesCycleVector =<< makeVibes+ proc <-+ CausalRender.run+ (\params -> Causal.amplify 0.3 <<< Causal.reverbExplicit params)+ playMonoVector =<<+ pioApply+ (proc (Causal.reverbParams (mkStdGen 142)+ TypeNum.d16 (0.9,0.97) (400,1000)))+ sig++vibesReverbStereo :: IO ()+vibesReverbStereo = do+ sig <- vibesCycleVector =<< makeVibes+ proc <-+ CausalRender.run+ (\params ->+ Stereo.multiValue+ ^<<+ Causal.amplifyStereo 0.3+ <<<+ Causal.stereoFromMonoParameterized Causal.reverbExplicit params+ <<^+ (\x -> Stereo.cons x x))+ playStereoVector =<<+ pioApply+ (proc+ (fmap+ (\seed ->+ Causal.reverbParams (mkStdGen seed)+ TypeNum.d16 (0.9,0.97) (400,1000))+ (Stereo.cons 142 857)))+ sig+++stair :: IO ()+stair =+ (SVL.writeFile "speedtest.f32" . asMono . SVL.take 10000000 =<<) $+ fmap+ (\f ->+ f tonesChunkSize $+ EventListBT.fromPairList $+ zip (iterate (/2) 1) (iterate (2*) (1::NonNeg.Integer))) $+ Render.run Const.flatten+++filterBass :: IO ()+filterBass = do+ proc <-+ Render.run $ \xs ->+ (fmap Stereo.multiValue BandPass.causal+ <<<+ CausalClass.feedSnd+ (liftA2 Stereo.cons+ (Sig.osci Wave.saw 0 (frequency 0.001499))+ (Sig.osci Wave.saw 0 (frequency 0.001501)))+ <<<+ Causal.map (BandPass.parameter 100))+ $*+ Const.flatten xs++ playStereoVector $ proc tonesChunkSize $+ EventListBT.fromPairList $+ zip+ (map (((0.01::Float)*) . (2**) . (/12) . fromInteger) $+ randomRs (0,24) (mkStdGen 998))+ (repeat (6300::NonNeg.Int))+++mixVectorStereo ::+ SVL.Vector (Stereo.T Float) ->+ SVL.Vector (Stereo.T Float) ->+ SVL.Vector (Stereo.T Float)+mixVectorStereo = Unsafe.performIO mixVectorStereoIO++mixVectorStereoIO ::+ IO (SVL.Vector (Stereo.T Float) ->+ SVL.Vector (Stereo.T Float) ->+ SVL.Vector (Stereo.T Float))+mixVectorStereoIO =+ (\proc xs ys -> Unsafe.performIO $ pioApply (proc xs) ys)+ <$>+ CausalRender.run (\xs -> Causal.mix $< xs)++{-+slightly slower than mixVectorParam+-}+mixVectorHaskell :: SVL.Vector Float -> SVL.Vector Float -> SVL.Vector Float+mixVectorHaskell = SVL.zipWith (+)++toneMix :: IO ()+toneMix = do+ pingp <- makePing+ mix <- CausalRender.run $ \x -> Causal.mix $< x+ amplify <- CausalRender.run (Causal.amplify 0.1)+ playMonoVector+ =<< pioApply amplify+ =<< ((\(x:xs) -> Fold.foldlM (pioApply . mix) x xs) $ take numTones $+ map (pingp 1000000) $ iterate (*(2/3)) 0.01)++fadeEnvelope :: Exp Word -> Exp Word -> Sig.MV Float+fadeEnvelope intro len =+ Sig.parabolaFadeIn intro+ <>+ (Causal.take len $* 1)+ <>+ Sig.parabolaFadeOut intro++fadeEnvelopeWrite :: IO ()+fadeEnvelopeWrite =+ (SVL.writeFile "speedtest.f32" . asMono =<<) $+ fmap ($ SVL.chunkSize 1234) $+ Render.run $ fadeEnvelope 100000 200000+++-- | normalize a list of numbers, such that they have a specific average+-- Cf. haskore-supercollider/src/Haskore/Interface/SuperCollider/Example.hs+normalizeLevel :: (Field.C a) => a -> [a] -> [a]+normalizeLevel newAvrg xs =+ let avrg = sum xs / fromIntegral (length xs)+ in map ((newAvrg-avrg)+) xs++stereoOsciParams ::+ (TypeNum.Integer n) =>+ Proxy n -> Float -> (Float, Stereo.T (MultiValue.Array n (Float,Float)))+stereoOsciParams np freq =+ let n = TypeNum.integralFromProxy np+ volume :: Float+ volume = recip $ sqrt $ TypeNum.integralFromProxy np+ detunes :: [Float]+ detunes =+ normalizeLevel 1 $ take (2*n) $+ randomRs (0,0.03) $ mkStdGen 912+ phases :: [Float]+ phases = randomRs (0,1) $ mkStdGen 54+ in (,) volume $+ fmap MultiValue.Array $+ uncurry Stereo.cons $ splitAt n $+ zipWith+ (\phase detune -> (phase, detune*freq))+ phases detunes++stereoOsciSawP ::+ (TypeNum.Natural n) =>+ (TypeNum.Natural arrSize, arrSize ~ (n :*: LLVM.UnknownSize)) =>+ (TypeNum.Natural stereoSize, stereoSize ~ (D2 :*: arrSize)) =>+ Exp Float -> Stereo.T (Exp (MultiValue.Array n (Float,Float))) ->+ Sig.MV (Stereo.T Float)+stereoOsciSawP volume =+ fmap Stereo.multiValue+ .+ stereoFromMonoParameterizedSignal+ (\params ->+ Causal.amplify volume+ $* multiMixSignal+ (\phaseFreq ->+ Sig.osci Wave.saw+ (Expr.fst phaseFreq)+ (Expr.snd phaseFreq))+ params)++stereoFromMonoParameterizedSignal ::+ (Marshal.C x) =>+ (D2 :*: LLVM.SizeOf (Marshal.Struct x) ~ arrSize,+ TypeNum.Natural arrSize) =>+ (Exp x -> Sig.MV Float) ->+ Stereo.T (Exp x) -> Sig.T (Stereo.T (MultiValue.T Float))+stereoFromMonoParameterizedSignal f ps =+ Causal.toSignal $+ Causal.stereoFromMonoParameterized (Causal.fromSignal . f) ps+ <<^+ (\() -> Stereo.cons () ())++multiMixSignal ::+ (TypeNum.Natural n, Marshal.C x,+ n :*: LLVM.SizeOf (Marshal.Struct x) ~ arraySize,+ TypeNum.Natural arraySize,+ Tuple.Undefined a, Tuple.Phi a, A.Additive a) =>+ (Exp x -> Sig.T a) ->+ Exp (MultiValue.Array n x) -> Sig.T a+multiMixSignal f =+ Causal.toSignal . multiMix (Causal.fromSignal . f)++multiMix ::+ (TypeNum.Natural n, Marshal.C x,+ n :*: LLVM.SizeOf (Marshal.Struct x) ~ arraySize,+ TypeNum.Natural arraySize,+ Tuple.Undefined b, Tuple.Phi b, A.Additive b) =>+ (Exp x -> Causal.T a b) ->+ Exp (MultiValue.Array n x) -> Causal.T a b+multiMix f ps =+ Causal.replicateControlledParam (\x -> Causal.mix <<< first (f x)) ps+ <<^+ (\a -> (a, A.zero))++stereoOsciSawVector :: Float -> SVL.Vector (Stereo.T Float)+stereoOsciSawVector freq =+ Unsafe.performIO $+ (\f -> uncurry (f tonesChunkSize) (stereoOsciParams TypeNum.d5 freq))+ <$>+ Render.run stereoOsciSawP++stereoOsciSawChord :: NonEmpty.T [] Float -> SVL.Vector (Stereo.T Float)+stereoOsciSawChord =+ NonEmpty.foldBalanced mixVectorStereo . fmap stereoOsciSawVector++stereoOsciSawPad :: Word -> NonEmpty.T [] Float -> SVL.Vector (Stereo.T Float)+stereoOsciSawPad dur pitches =+ let attack = 20000+ in Unsafe.performIO $+ fmap+ (\f ->+ Unsafe.performIO $+ pioApply (f attack (dur-attack)) (stereoOsciSawChord pitches)) $+ CausalRender.run+ (\intro len ->+ Stereo.multiValue <$>+ (Causal.envelopeStereo $< fadeEnvelope intro len)+ <<^ Stereo.unMultiValue)++a0, as0, b0, c1, cs1, d1, ds1, e1, f1, fs1, g1, gs1,+ a1, as1, b1, c2, cs2, d2, ds2, e2, f2, fs2, g2, gs2,+ a2, as2, b2, c3, cs3, d3, ds3, e3, f3, fs3, g3, gs3,+ a3, as3, b3, c4, cs4, d4, ds4, e4, f4, fs4, g4, gs4 :: Float+a0 : as0 : b0 : c1 : cs1 : d1 : ds1 : e1 : f1 : fs1 : g1 : gs1 :+ a1 : as1 : b1 : c2 : cs2 : d2 : ds2 : e2 : f2 : fs2 : g2 : gs2 :+ a2 : as2 : b2 : c3 : cs3 : d3 : ds3 : e3 : f3 : fs3 : g3 : gs3 :+ a3 : as3 : b3 : c4 : cs4 : d4 : ds4 : e4 : f4 : fs4 : g4 : gs4 : _ =+ iterate ((2 ** recip 12) *) (55/44100)+++chordSequence :: [(Word, NonEmpty.T [] Float)]+chordSequence =+ (2, f1 !: f2 : a2 : c3 : []) :+ (1, g1 !: g2 : b2 : d3 : []) :+ (2, c2 !: g2 : c3 : e3 : []) :+ (1, f1 !: a2 : c3 : f3 : []) :+ (2, g1 !: g2 : b2 : d3 : []) :+ (1, gs1 !: gs2 : b2 : e3 : []) :+ (2, a1 !: e2 : a2 : c3 : []) :+ (1, g1 !: g2 : b2 : d3 : []) :+ (3, c2 !: g2 : c3 : e3 : []) :++ (2, f1 !: f2 : a2 : c3 : []) :+ (1, g1 !: g2 : b2 : d3 : []) :+ (2, c2 !: g2 : c3 : e3 : []) :+ (1, f1 !: a2 : c3 : f3 : []) :+ (2, g1 !: g2 : b2 : d3 : []) :+ (1, gs1 !: gs2 : b2 : e3 : []) :+ (2, a1 !: e2 : a2 : c3 : []) :+ (1, g1 !: g2 : b2 : e3 : []) :+ (3, c2 !: e2 : g2 : c3 : []) :+ []+++withDur :: (Word -> a -> v) -> Word -> a -> (v, NonNeg.Int)+withDur f d ps =+ let dur = d*30000+ in (f dur ps, NonNeg.fromNumber $ fromIntegral dur)+++padMusic :: IO ()+padMusic = do+ arrange <- SigStL.makeArranger+ amplify <-+ CausalRender.run $ \volume ->+ Stereo.multiValue ^<<+ Causal.amplifyStereo volume <<^+ Stereo.unMultiValue+ (playStereoVector =<<) $+ pioApply (amplify (0.1::Float)) $+ arrange tonesChunkSize $+ EventListTM.switchTimeR const $+ EventListMT.consTime 0 $+ EventListBT.fromPairList $+ map (\(d,ps) -> withDur stereoOsciSawPad d ps)+ chordSequence+++lowpassSweepControlRateCausal ::+ Causal.T+ (Stereo.T (MultiValue.T Float))+ (Stereo.T (MultiValue.T Float))+lowpassSweepControlRateCausal =+-- Causal.stereoFromVector $+ Causal.stereoFromMono $+ UniFilter.lowpass ^<<+ Ctrl.processCtrlRate 128+ (lfoSine (UniFilter.parameter (10::Exp Float)))+++moogSweepControlRateCausal ::+ Causal.T+ (Stereo.T (MultiValue.T Float))+ (Stereo.T (MultiValue.T Float))+moogSweepControlRateCausal =+-- Causal.stereoFromVector $+ Causal.stereoFromMono $+ Ctrl.processCtrlRate 128+ (lfoSine (Moog.parameter TypeNum.d8 (10::Exp Float)))+++filterMusic :: IO ()+filterMusic = do+ arrange <- SigStL.makeArranger+ pad <- stereoOsciSawPadIO+ proc <-+ CausalRender.run $ \volume ->+ Stereo.multiValue ^<<+ Causal.amplifyStereo volume <<<+ moogSweepControlRateCausal <<^+ Stereo.unMultiValue+ (playStereoVector =<<) $+ pioApply (proc (0.05::Float)) $+ arrange tonesChunkSize $+ EventListTM.switchTimeR const $+ EventListMT.consTime 0 $+ EventListBT.fromPairList $+ map (\(d,ps) -> withDur pad d ps)+ chordSequence++++stereoOsciSawVectorIO :: IO (Float -> SVL.Vector (Stereo.T Float))+stereoOsciSawVectorIO =+ (\f freq -> uncurry (f tonesChunkSize) (stereoOsciParams TypeNum.d5 freq))+ <$>+ Render.run stereoOsciSawP++applyFadeEnvelopeIO ::+ IO (Word -> SVL.Vector (Stereo.T Float) -> SVL.Vector (Stereo.T Float))+applyFadeEnvelopeIO =+ let attack = 20000 in+ fmap+ (\f dur sig ->+ Unsafe.performIO $ pioApply (f attack (dur-attack)) sig) $+ CausalRender.run+ (\intro len ->+ Stereo.multiValue <$>+ (Causal.envelopeStereo $< fadeEnvelope intro len)+ <<^ Stereo.unMultiValue)++stereoOsciSawChordIO :: IO (NonEmpty.T [] Float -> SVL.Vector (Stereo.T Float))+stereoOsciSawChordIO = do+ sawv <- stereoOsciSawVectorIO+ mix <- mixVectorStereoIO+ return (NonEmpty.foldBalanced mix . fmap sawv)++stereoOsciSawPadIO ::+ IO (Word -> NonEmpty.T [] Float -> SVL.Vector (Stereo.T Float))+stereoOsciSawPadIO = do+ chrd <- stereoOsciSawChordIO+ envelope <- applyFadeEnvelopeIO+ return $+ \ dur pitches -> envelope dur (chrd pitches)++padMusicIO :: IO ()+padMusicIO = do+ arrange <- SigStL.makeArranger+ pad <- stereoOsciSawPadIO+ amplify <-+ CausalRender.run $ \volume ->+ Stereo.multiValue ^<<+ Causal.amplifyStereo volume <<^+ Stereo.unMultiValue+ (playStereoVector =<<) $+ pioApply (amplify (0.08::Float)) $+ arrange tonesChunkSize $+ EventListTM.switchTimeR const $+ EventListMT.consTime 0 $+ EventListBT.fromPairList $+ map (uncurry (withDur pad)) $+ chordSequence++{-+Apply the envelope separately to each tone of the chord+and mix all tones by 'arrange'.+-}+padMusicSeparate :: IO ()+padMusicSeparate = do+ arrange <- SigStL.makeArranger+ osci <- stereoOsciSawVectorIO+ env <- applyFadeEnvelopeIO+ amplify <-+ CausalRender.run $ \volume ->+ Stereo.multiValue ^<<+ Causal.amplifyStereo volume <<^+ Stereo.unMultiValue+ (playStereoVector =<<) $+ pioApply (amplify (0.08::Float)) $+ arrange tonesChunkSize $+ EventList.flatten $+ EventListTM.switchTimeR const $+ EventListMT.consTime 0 $+ EventListBT.fromPairList $+ map (uncurry (withDur (\d ps ->+ map (\p -> env d (osci p)) $ NonEmpty.flatten ps))) $+ chordSequence+++delay :: IO ()+delay =+ (SVL.writeFile "speedtest.f32" . asMono =<<) $+ fmap (\f -> f tonesChunkSize (0::Word) (10000::Word)) $+ Render.run $ \del dur ->+ Causal.delayZero del . Causal.take dur+ $*+ Sig.osci Wave.saw 0 (frequency 0.01)++delayStereo :: IO ()+delayStereo =+ (SVL.writeFile "speedtest.f32" . asStereo =<<) $+ fmap (\f -> f tonesChunkSize (7::Word) (10000::Word)) $+ Render.run $ \del dur ->+ Causal.take dur . liftA2 Stereo.consMultiValue id (Causal.delayZero del)+ $*+ Sig.osci Wave.saw 0 (frequency 0.01)++delayPhaser :: IO ()+delayPhaser =+ (SVL.writeFile "speedtest.f32" . asStereo =<<) $+ fmap (\f -> f tonesChunkSize (40000::Word)) $+ Render.run $ \dur ->+ Func.compileSignal $+ let osci = Func.fromSignal $ Sig.osci Wave.saw 0 (frequency 0.01)+ ctrl =+ Func.fromSignal $+ Sig.osci Wave.triangle 0 $ frequency (1/20000)+ in Causal.take dur $&+ liftA2 Stereo.consMultiValue+ osci+ (Causal.delayControlledInterpolated Interpolation.cubic 0 100+ $&+ (50+50*ctrl) &|& osci)++++allpassControl ::+ (TypeNum.Natural n) =>+ Proxy n -> Exp Float ->+ Sig.T (Allpass.CascadeParameter n (MultiValue.T Float))+allpassControl order reduct =+ Sig.interpolateConstant reduct $+ lfoSine (Allpass.flangerParameter order) reduct++allpassPhaserCausal, allpassPhaserPipeline ::+ Exp Float ->+ Sig.MV Float ->+ Sig.MV Float+allpassPhaserCausal reduct xs =+ let order = TypeNum.d16+ in 0.5 * Allpass.phaser $< allpassControl order reduct $* xs++allpassPhaserPipeline reduct xs =+ let order = TypeNum.d16+ in (nest (TypeNum.integralFromProxy order) Sig.tail) $+ -- Sig.drop+ -- (TypeNum.integralFromProxy order)+ (0.5 * Allpass.phaserPipeline $< allpassControl order reduct $* xs)++allpassPhaser :: IO ()+allpassPhaser =+ (SVL.writeFile "speedtest.f32" . asMono . SVL.take 10000000 =<<) $+ fmap (\f -> f (SVL.chunkSize 100000) (128::Float)) $+ Render.run $+ \reduct ->+-- allpassPhaserCausal reduct $+ allpassPhaserPipeline reduct $+ Sig.osci Wave.saw 0 (frequency 0.01)++noise :: IO ()+noise =+ (SVL.writeFile "speedtest.f32" . asMono . SVL.take 10000000 =<<) $+ fmap ($ SVL.chunkSize 100000) $+ Render.run $+ Sig.noise 0 0.3++noisePacked :: IO ()+noisePacked =+ (SVL.writeFile "speedtest.f32" . asMonoPacked+ . SVL.take (div 10000000 4) =<<) $+ fmap ($ SVL.chunkSize 100000) $+ Render.run $+ SigPS.noise 0 0.3+-- SigPS.pack (SigP.noise 0 0.3)+-- SigPS.packSmall (SigP.noise 0 0.3)++frequencyModulationStorable :: IO ()+frequencyModulationStorable = do+ sample <- Render.run $ Sig.osci Wave.saw 0 (frequency 0.01)+ f <-+ Render.run $ \smp ->+ Causal.frequencyModulationLinear smp $* 0.3+ SVL.writeFile "speedtest.f32" . asMono $+ f (SVL.chunkSize 100000) $ SVL.take 1000000 $ sample (SVL.chunkSize 1000)+++frequencyModulation :: IO ()+frequencyModulation =+ (SVL.writeFile "speedtest.f32" . asMono . SVL.take 10000000 =<<) $+ fmap ($ SVL.chunkSize 100000) $+ Render.run+ (Causal.frequencyModulationLinear (Sig.osci Wave.saw 0 (frequency 0.01))+ $* Sig.exponential2 500000 1)++frequencyModulationStereo :: IO ()+frequencyModulationStereo = do+ sample <- Render.run $ Sig.osci Wave.saw 0 (frequency 0.01)+ f <-+ Render.run $ \smp ->+ Stereo.multiValue ^<<+ Causal.stereoFromMono (Causal.frequencyModulationLinear smp)+ $* Sig.constant (Stereo.cons 0.2999 0.3001)+ SVL.writeFile "speedtest.f32" . asStereo $+ f (SVL.chunkSize 100000) $ SVL.take 1000000 $ sample (SVL.chunkSize 1000)++frequencyModulationProcess :: IO ()+frequencyModulationProcess = do+ proc <-+ CausalRender.run+ (Causal.frequencyModulationLinear+ (Causal.take 50000 $* Sig.osci Wave.saw 0 (frequency 0.01)))+ sample <- Render.run (1 + 0.1 * Sig.osci Wave.approxSine2 0 0.0001)+ SVL.writeFile "speedtest.f32" . asMono =<<+ pioApply proc (sample (SVL.chunkSize 512))++++quantize :: IO ()+quantize =+{-+ SV.writeFile "speedtest.f32" $+ asMono $+ (\xs -> SigP.render xs 10000000 ()) $+-}+ (SVL.writeFile "speedtest.f32" . asMono =<<) $+ fmap (SVL.take 10000000) $+ fmap ($ SVL.chunkSize 100000) $+ Render.run $+ (Causal.quantizeLift id+ $<# (5.5::Float)+ $* Sig.osci Wave.saw 0 (frequency 0.01))++quantizedFilterControl :: IO ()+quantizedFilterControl =+ (SVL.writeFile "speedtest.f32" . asMono =<<) $+ fmap (SVL.take 10000000) $+ fmap ($ SVL.chunkSize 100000) $+ Render.run+ (0.3 * (UniFilter.lowpass ^<< Ctrl.process)+ $< (Causal.quantizeLift+ (Causal.map (UniFilter.parameter 100) <<<+ -- (Causal.map (Moog.parameter TypeNum.d8 100) <<<+ Causal.map (\x -> 0.01 * exp (2 * x)))+ $<# (128::Float)+ $* Sig.osci Wave.approxSine2 0 (frequency (0.1/44100)))+ $* Sig.osci Wave.saw 0 (frequency 0.01))+++arrowNonShared :: IO ()+arrowNonShared =+ (SVL.writeFile "speedtest.f32" . asStereo =<<) $+ fmap (SVL.take 10000000) $+ fmap ($ SVL.chunkSize 100000) $+ Render.run+ (let osci = Causal.osci Wave.approxSine2+ in liftA2 Stereo.consMultiValue osci osci $* Sig.constant (0, 0.01))++arrowShared :: IO ()+arrowShared =+ (SVL.writeFile "speedtest.f32" . asStereo =<<) $+ fmap (SVL.take 10000000) $+ fmap ($ SVL.chunkSize 100000) $+ Render.run+ (let osci = Func.lift $ Causal.osci Wave.approxSine2+ in Func.compile (liftA2 Stereo.consMultiValue osci osci) $*+ Sig.constant (0, 0.01))++arrowIndependent :: IO ()+arrowIndependent =+ (SVL.writeFile "speedtest.f32" . asStereo =<<) $+ fmap (SVL.take 10000000) $+ fmap ($ SVL.chunkSize 100000) $+ Render.run+ (let osci = Causal.osci Wave.approxSine2+ in Func.compile+ (uncurry Stereo.consMultiValue <$>+ (osci *** osci $& Func.lift id)) $*+ Sig.constant ((0, 0.01), (0.25, 0.01001)))+++rampDown :: Int -> SV.Vector Float+rampDown n =+ SigS.toStrictStorableSignal n $+ CtrlS.line n (1, 0)++impulses :: Int -> Float -> SVL.Vector Float+impulses n x =+ SVL.fromChunks $+ concatMap (\k -> [SV.singleton x, SV.replicate k 0]) $+ take n $ iterate (2*) 1++convolution :: IO ()+convolution =+ (SVL.writeFile "speedtest.f32" . asMono =<<) $+ ((\f ->+ pioApply (f $ Render.buffer $ rampDown 1000) (impulses 18 0.1)) =<<) $+ CausalRender.run FiltNR.convolve++convolutionPacked :: IO ()+convolutionPacked = do+ pack <- Render.run SigPS.pack+ impulsesPacked <- pack SVL.defaultChunkSize $ impulses 18 0.1+ (SVL.writeFile "speedtest.f32" . asMonoPacked =<<) $+ ((\f ->+ pioApply (f $ Render.buffer $ rampDown 1000) impulsesPacked) =<<) $+ CausalRender.run FiltNR.convolvePacked+++helixSaw :: IO ()+helixSaw = do+ let srcFreq = 0.01+ srcLength :: Word+ srcLength = 40000+ osci <- Render.run $ \dur -> Sig.osci Wave.saw 0 srcFreq * (1-Sig.ramp dur)+ let perc =+ asMono $ osci (fromIntegral srcLength) srcLength+ SV.writeFile "osci-saw.f32" perc+ stretched <-+ Render.run $ \dur sig ->+ Func.compileSignal $+ (Helix.static Interpolation.cubic Interpolation.cubic+ 100 (recip srcFreq) sig+ $&+ (Func.fromSignal $ Sig.amplify (fromIntegral srcLength) $ Sig.ramp dur)+ &|&+ (Causal.osciCore $& 0 &|& 0.01))+ SVL.writeFile "osci-stretched.f32" . asMono =<<+ stretched SVL.defaultChunkSize (80000::Word) (Render.buffer perc)+++loadTomato :: IO (Float, SVL.Vector Float)+loadTomato = do+ let Sample.Info name _sampleRate positions = Sample.tomatensalat+ word <- Sample.load (Default.sampleDirectory </> name)+ return (Sample.period $ head positions, word)++helixOsci :: Exp Float -> Func.T a (MultiValue.T Float)+helixOsci period =+ Causal.osciCore $& 0 &|& Func.fromSignal (Sig.constant (recip period))++helixSpeechStaticSig ::+ Func.T () (MultiValue.T Float) ->+ Exp (Source.StorableVector Float) ->+ Exp Float ->+ Sig.MV Float+helixSpeechStaticSig shape word period =+ Func.compileSignal+ (Helix.static Interpolation.linear Interpolation.linear+ (Expr.roundToIntFast period) period word+ $&+ shape+ &|&+ helixOsci period)++helixSpeechStaticSpeed ::+ Exp Float ->+ Exp (Source.StorableVector Float) ->+ Exp Float ->+ Sig.MV Float+helixSpeechStaticSpeed speed word =+ helixSpeechStaticSig+ (Func.fromSignal+ (Causal.takeWhile+ (Expr.fromIntegral (Source.storableVectorLength word) >*)+ $*+ Sig.rampSlope speed))+ word++helixSpeechStatic :: IO ()+helixSpeechStatic = do+ smp <- loadTomato+ stretched <-+ Render.run $ \speed (period, word) ->+ helixSpeechStaticSpeed speed word period+ (SVL.writeFile "speech-stretched.f32" . asMono =<<) $+ stretched SVL.defaultChunkSize (0.5::Float) $+ mapSnd (Render.buffer . SV.concat . SVL.chunks) smp++helixSpeechDynamicSig ::+ Func.T () (MultiValue.T Float) ->+ Sig.MV Float ->+ Exp Float ->+ Sig.MV Float+helixSpeechDynamicSig shape word period =+ Func.compileSignal+ (Helix.dynamicLimited Interpolation.linear Interpolation.linear+ (Expr.roundToIntFast period) period word+ $&+ shape+ &|&+ helixOsci period)++helixSpeechDynamicSpeed ::+ Exp Float ->+ Sig.MV Float ->+ Exp Float ->+ Sig.MV Float+helixSpeechDynamicSpeed speed =+ helixSpeechDynamicSig (Func.fromSignal $ Sig.constant speed)++helixSpeechDynamic :: IO ()+helixSpeechDynamic = do+ smp <- loadTomato+ stretched <-+ Render.run $ \speed (period, word) ->+ helixSpeechDynamicSpeed speed word period+ SVL.writeFile "speech-stretched.f32" $ asMono $+ stretched SVL.defaultChunkSize (0.5::Float) smp++helixSpeechCompare :: IO ()+helixSpeechCompare = do+ (per,smp) <- loadTomato+ stretched <-+ Render.run $ \speed period word wordBuffer ->+ fmap Stereo.multiValue $+ sequenceA $+ Stereo.cons+ (helixSpeechStaticSpeed speed wordBuffer period)+ (helixSpeechDynamicSpeed speed word period)+ SVL.writeFile "speech-stretched.f32" $ asStereo $+ stretched SVL.defaultChunkSize (0.5::Float)+ per smp (Render.buffer . SV.concat . SVL.chunks $ smp)++helixSpeechVariCompare :: IO ()+helixSpeechVariCompare = do+ (per,smp) <- loadTomato+ stretched <-+ Render.run $ \period word wordBuffer ->+ fmap Stereo.multiValue $+ sequenceA $+ let speed =+ Func.fromSignal $ Sig.cycle $+ Sig.fromArray $ Expr.cons $+ (MultiValue.Array [0.2, 0.5, 1, 1.5, 1.8]+ :: MultiValue.Array TypeNum.D5 Float)+ in Stereo.cons+ (helixSpeechStaticSig+ (Causal.integrateZero $& speed)+ wordBuffer period)+ (helixSpeechDynamicSig speed word period)+ SVL.writeFile "speech-stretched.f32" $ asStereo $+ stretched SVL.defaultChunkSize+ per smp (Render.buffer . SV.concat . SVL.chunks $ smp)++helixLimited :: IO ()+helixLimited = do+ let period = 100+ srcLength :: Int+ srcLength = 500+ dstLength = 5000+ speed :: Exp Float+ speed = 0.5+ osci =+ 0.5+ *+ Sig.ramp (fromIntegral srcLength)+ *+ Sig.osci Wave.approxSine2 0 (recip period)+ renderOsci <- Render.run osci+ let osciVec = renderOsci srcLength+ SV.writeFile "helix-orig.f32" $ asMono osciVec++ let stretchedStatic osciBuffer =+ Helix.static Interpolation.linear Interpolation.linear+ (Expr.roundToIntFast period) period osciBuffer+ $&+ Func.fromSignal (Sig.rampSlope speed)+ &|&+ helixOsci period+ stretchedDynamic =+ Helix.dynamic Interpolation.linear Interpolation.linear+ (Expr.roundToIntFast period) period osci+ $&+ Func.fromSignal (Sig.constant speed)+ &|&+ helixOsci period+ stretched osciBuffer =+ liftA2 Stereo.consMultiValue+ (stretchedStatic osciBuffer) stretchedDynamic+ renderHelix <- Render.run $ Func.compileSignal . stretched+ SV.writeFile "helix-stretched.f32" $ asStereo $+ renderHelix dstLength (Render.buffer osciVec)++cycleRamp :: IO ()+cycleRamp =+ SVL.writeFile "speedtest.f32" . asMono .+ (\f -> f SVL.defaultChunkSize (10000::Word)) =<<+ Render.run+ (\dur ->+ Causal.take 100000 $*+ Sig.cycle (Sig.append (Sig.ramp dur) (1 - Sig.ramp dur)))++zigZag :: IO ()+zigZag =+ SVL.writeFile "speedtest.f32" . asMono .+ (\f -> f SVL.defaultChunkSize (-3::Float)) =<<+ Render.run+ (\start -> Causal.take 100000 $* (Helix.zigZag start $* 0.0001))++zigZagPacked :: IO ()+zigZagPacked =+ SVL.writeFile "speedtest.f32" . asMonoPacked .+ (\f -> f SVL.defaultChunkSize (-3::Float)) =<<+ Render.run+ (\start ->+ let vectorSize = 4+ in Causal.take (fromInteger $ div 100000 vectorSize) $*+ (Helix.zigZagPacked start $* 0.0001))+++trigger :: IO ()+trigger =+ (SVL.writeFile "speedtest.f32" . asMono =<<) $+ fmap ($ SVL.defaultChunkSize) $+ Render.run+ (let pause len =+ CausalClass.applyConst (Causal.take len) Maybe.nothing+ pulse :: Float -> Exp Word -> Sig.T (Maybe.T (MultiValue.T Float))+ pulse freq len =+ Causal.take len .+ arr (flip Maybe.fromBool (MultiValue.cons freq) . unbool) .+ Causal.delay1 Expr.true $*# False+ in (Causal.zipWith ExprMaybe.select+ $> Sig.noise 0 (0.01 :: Exp Float)) $*+ (Causal.trigger (\freq -> Causal.take 150000 $* pingSigP freq) $*+ pause 50000 <>+ pulse 0.004 100000 <>+ pulse 0.005 200000 <>+ pulse 0.006 400000))++-- FixMe: duplicate of CausalExp.ProcessPrivate+unbool :: MultiValue.T Bool -> LLVM.Value Bool+unbool (MultiValue.Cons b) = b+++triggerLFO :: Sig.MV Float+triggerLFO =+ Sig.osci Wave.approxSine2 0 0.00015+ ++ Sig.osci Wave.approxSine2 0 0.000037++trackZeros :: Causal.MV Float Bool+trackZeros =+ Causal.zipWith (\x y -> x &&* Expr.not y) .+ (id &&& Causal.delay1 Expr.false) .+ Causal.map (>* 0)++fmPingSig :: Exp Float -> Exp Float -> Sig.MV Float+fmPingSig freq depth =+ Sig.exponential2 5000 1+ *+ ((Causal.osci Wave.approxSine2 $> Sig.constant freq)+ $*+ (Sig.constant depth * Sig.osci Wave.approxSine2 0 (2*freq)))++sweepTrigger :: IO ()+sweepTrigger =+ (SVL.writeFile "speedtest.f32" . asMono =<<) $+ fmap ($ SVL.defaultChunkSize) $+ Render.run+ ((Causal.zipWith ExprMaybe.select $> Sig.noise 0 0.01) $*+ (Causal.trigger (fmPingSig 0.005) $*+ liftA2 (Maybe.fromBool . unbool)+ (Causal.take 10000000 . trackZeros $* triggerLFO)+ (5 * Sig.osci Wave.approxSine2 0 0.00001))) main :: IO ()
example/Synthesizer/LLVM/TestALSA.hs view
@@ -2,6 +2,11 @@ import qualified Synthesizer.LLVM.LNdW2011 as LNdW +import Control.Monad (when) + main :: IO ()-main = LNdW.flyPacked+main = do+ when True LNdW.flyPacked+ when False LNdW.modulation+ when False LNdW.bubblesPacked
jack/Synthesizer/LLVM/Server/JACK.hs view
@@ -13,13 +13,16 @@ import qualified Synthesizer.MIDI.CausalIO.Process as MIO import qualified Synthesizer.CausalIO.Process as PIO -import qualified Synthesizer.LLVM.CausalParameterized.ProcessPacked as CausalPS-import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP+import qualified Synthesizer.LLVM.Causal.Render as CausalRender+import qualified Synthesizer.LLVM.Causal.ProcessPacked as CausalPS+import qualified Synthesizer.LLVM.Causal.Process as Causal import qualified Synthesizer.LLVM.Storable.Signal as SigStL import qualified Synthesizer.LLVM.Frame.StereoInterleaved as StereoInt import qualified Synthesizer.LLVM.Frame.Stereo as Stereo +import qualified Type.Data.Num.Decimal as TypeNum+ import qualified Data.StorableVector as SV import qualified Data.StorableVector.Base as SVB import Foreign.Marshal.Array (copyArray)@@ -47,9 +50,8 @@ import qualified System.Path.PartClass as PathClass import qualified System.Path as Path -import Control.Arrow ((<<<), (^<<), arr)+import Control.Arrow (arr, (<<<), (^<<)) import Control.Category (id)-import Control.Applicative (pure) import qualified System.Random as Random import qualified Numeric.NonNegative.Wrapper as NonNegW@@ -205,11 +207,11 @@ keyboardMultiChannel = do opt <- Option.get proc <- keyboardDetuneFMCore (Option.sampleDirectory opt)- mix <- CausalP.processIO CausalP.mix+ mix <- CausalRender.run Causal.mix playStereoFromEvents opt $ \ sampleRate -> foldl1- (\x y -> mix () <<< Zip.arrowFanout x y)+ (\x y -> mix <<< Zip.arrowFanout x y) (map (\chan -> proc (ChannelMsg.toChannel chan) (VoiceMsg.toProgram 0)@@ -232,24 +234,29 @@ voderMaskSeparated :: IO () voderMaskSeparated = do opt <- Option.get- let postProcessing =+ let postProcessing params = if True then- let reverb seed =- CausalP.reverb- (pure $ Random.mkStdGen seed) 16 (pure (0.92,0.98))- (fmap (\(SampleRate rate) -> (round (rate/200), round (rate/40))) id)- in CausalPS.pack (Stereo.arrowFromChannels (reverb 42) (reverb 23))+ CausalPS.pack+ (Stereo.arrowFromChannels+ (Causal.reverbExplicit $ Stereo.left params)+ (Causal.reverbExplicit $ Stereo.right params)) else id proc <- Arrange.voderMaskSeparated- (arr unconsStereo <<< postProcessing)+ (\reverbParams -> unconsStereo ^<< postProcessing reverbParams) (Option.sampleDirectory opt) - playStereoFromEvents opt $ \ sampleRate ->+ playStereoFromEvents opt $ \ sampleRate@(SampleRate rate) -> proc (Option.channel opt) (Option.extraChannel opt) (VoiceMsg.toProgram 4) sampleRate+ (fmap+ (\seed ->+ Causal.reverbParams+ (Random.mkStdGen seed) TypeNum.d16 (0.92,0.98)+ (round (rate/200), round (rate/40)))+ (Stereo.cons 42 23)) main :: IO ()
render/Synthesizer/LLVM/Server/Render.hs view
@@ -7,6 +7,7 @@ import qualified Synthesizer.LLVM.Server.Option as Option import qualified Synthesizer.LLVM.Frame.Stereo as Stereo+import Synthesizer.LLVM.Server.CausalPacked.Common (chopEvents) import Synthesizer.LLVM.Server.Common import qualified Synthesizer.CausalIO.Process as PIO@@ -59,7 +60,7 @@ render :: Option.T -> IO (MidiFile.T -> SVL.Vector (Stereo.T Real)) render opt = do proc <-- case 0::Int of+ case fromInteger 0 :: Int of 0 -> Arrange.keyboardMultiChannel $ Option.sampleDirectory opt _ -> Arrange.voderMaskMulti $ Option.sampleDirectory opt run <- PIO.runCont $ proc $ fmap fromIntegral $ Option.sampleRate opt
server/Synthesizer/LLVM/Server/CausalPacked/Arrange.hs view
@@ -1,6 +1,7 @@ module Synthesizer.LLVM.Server.CausalPacked.Arrange where -import Synthesizer.LLVM.Server.CommonPacked (VectorSize, Vector, VectorValue, stair)+import Synthesizer.LLVM.Server.CommonPacked+ (VectorSize, Vector, VectorValue, stair) import qualified Sound.MIDI.Controller as Ctrl @@ -18,8 +19,10 @@ import qualified Synthesizer.PiecewiseConstant.Signal as PC import qualified Synthesizer.LLVM.Plug.Output as POut-import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP-import qualified Synthesizer.LLVM.CausalParameterized.ProcessPacked as CausalPS+import qualified Synthesizer.LLVM.Causal.Render as CausalRender+import qualified Synthesizer.LLVM.Causal.ProcessPacked as CausalPS+import qualified Synthesizer.LLVM.Causal.Process as Causal+import qualified Synthesizer.LLVM.Generator.Render as Render import qualified Synthesizer.LLVM.Storable.Process as CausalSt import qualified Synthesizer.LLVM.Storable.Signal as SigStL @@ -42,14 +45,13 @@ import qualified System.Path.PartClass as PathClass import qualified System.Path as Path -import Control.Arrow (Arrow, arr, first, (<<<), (^<<))+import Control.Arrow (Arrow, arr, (***), (<<<), (^<<), (<<^)) import Control.Category (id) import Control.Applicative ((<*>)) import qualified Data.List.HT as ListHT-import Data.Maybe.HT (toMaybe)- import qualified Data.Map as Map+import Data.Maybe.HT (toMaybe) import qualified Number.DimensionTerm as DN import qualified Algebra.DimensionTerm as Dim@@ -72,12 +74,12 @@ PIO.T (MIO.Events msg) (SV.Vector Vector)) keyboard = do arrange <- CausalSt.makeArranger- amp <- CausalP.processIO (CausalPS.amplify 0.2)+ amp <- CausalRender.run (CausalPS.amplify 0.2) ping <- Instr.pingRelease return $ \ chan sampleRate ->- amp ()+ amp <<< arrange <<<@@ -117,19 +119,19 @@ keyboardFM :: (Check.C msg, POut.Default b) =>- CausalP.T () (Stereo.T VectorValue) (POut.Element b) ->+ Causal.T (Stereo.T VectorValue) (POut.Element b) -> ChannelMsg.Channel -> IO (SampleRate Real -> PIO.T (MIO.Events msg) b) keyboardFM emitStereo chan = do arrange <- CausalSt.makeArranger amp <-- CausalP.processIO- (emitStereo <<< CausalPS.amplifyStereo 0.2)+ CausalRender.run+ (emitStereo <<< CausalPS.amplifyStereo 0.2 <<^ Stereo.unMultiValue) ping <- Instr.pingStereoReleaseFM return $ \ sampleRate ->- amp ()+ amp <<< arrange <<<@@ -201,19 +203,19 @@ keyboardDetuneFMCore :: (PathClass.AbsRel ar, Check.C msg, POut.Default b) =>- CausalP.T () (Stereo.T VectorValue) (POut.Element b) ->+ Causal.T (Stereo.T VectorValue) (POut.Element b) -> Path.Dir ar -> IO (ChannelMsg.Channel -> VoiceMsg.Program -> SampleRate Real -> PIO.T (MIO.Events msg) b) keyboardDetuneFMCore emitStereo smpDir = do arrange <- keyboardDetuneFMConstVolume smpDir amp <-- CausalP.processIO+ CausalRender.run (emitStereo <<<- CausalP.envelopeStereo <<<- first (CausalP.mapSimple Serial.upsample))+ Causal.envelopeStereo <<<+ Causal.map Serial.upsample *** arr Stereo.unMultiValue) return $ \chan initPgm rate ->- amp ()+ amp <<< MIO.controllerExponential chan controllerVolume (0.001, 1) (0.2::Float) &+&@@ -433,15 +435,15 @@ keyboardMultiChannel smpDir = do proc <- keyboardDetuneFMCore- (CausalP.mapSimple StereoInt.interleave)+ (Causal.map StereoInt.interleave) smpDir- mix <- CausalP.processIO CausalP.mix+ mix <- CausalRender.run Causal.mix return $ \ sampleRate -> arr SigStL.unpackStereoStrict <<< foldl1- (\x y -> mix () <<< Zip.arrowFanout x y)+ (\x y -> mix <<< Zip.arrowFanout x y) (map (\chan -> proc (ChannelMsg.toChannel chan) (VoiceMsg.toProgram 0)@@ -485,18 +487,18 @@ voder :: (PathClass.AbsRel ar, Check.C msg, Construct.C msg, POut.Default b) =>- CausalP.T () (Stereo.T VectorValue) (POut.Element b) ->+ Causal.T (Stereo.T VectorValue) (POut.Element b) -> Speech.VowelSynth -> Path.Dir ar -> IO (ChannelMsg.Channel -> VoiceMsg.Program -> SampleRate Real -> PIO.T (MIO.Events msg) b) voder emitStereo voice smpDir = do- carrier <- keyboardDetuneFMCore id smpDir+ carrier <- keyboardDetuneFMCore (arr Stereo.multiValue) smpDir arrange <- CausalSt.makeArranger- interleave <- CausalP.processIO emitStereo+ interleave <- CausalRender.run (emitStereo <<^ Stereo.unMultiValue) return $ \chan initPgm sampleRate ->- interleave ()+ interleave <<< arrange <<<@@ -512,7 +514,7 @@ voderBand :: (PathClass.AbsRel ar, Check.C msg, Construct.C msg, POut.Default b) =>- CausalP.T () (Stereo.T VectorValue) (POut.Element b) ->+ Causal.T (Stereo.T VectorValue) (POut.Element b) -> Path.Dir ar -> IO (ChannelMsg.Channel -> VoiceMsg.Program -> SampleRate Real -> PIO.T (MIO.Events msg) b)@@ -522,7 +524,7 @@ voderMask :: (PathClass.AbsRel ar, Check.C msg, Construct.C msg, POut.Default b) =>- CausalP.T () (Stereo.T VectorValue) (POut.Element b) ->+ Causal.T (Stereo.T VectorValue) (POut.Element b) -> Path.Dir ar -> IO (ChannelMsg.Channel -> VoiceMsg.Program -> SampleRate Real -> PIO.T (MIO.Events msg) b)@@ -538,7 +540,7 @@ voderEnv :: (PathClass.AbsRel ar, Check.C msg, Construct.C msg, POut.Default b) =>- CausalP.T () (Stereo.T VectorValue) (POut.Element b) ->+ Causal.T (Stereo.T VectorValue) (POut.Element b) -> Speech.VowelSynthEnv -> Path.Dir ar -> IO (ChannelMsg.Channel -> VoiceMsg.Program ->@@ -547,13 +549,13 @@ carrier <- keyboardDetuneFMConstVolume smpDir arrange <- CausalSt.makeArranger amp <-- CausalP.processIO+ CausalRender.run (emitStereo <<<- CausalP.envelopeStereo <<<- first (CausalP.mapSimple Serial.upsample))+ Causal.envelopeStereo <<<+ Causal.map Serial.upsample *** arr Stereo.unMultiValue) return $ \chan initPgm sampleRate ->- amp ()+ amp <<< MIO.controllerExponential chan controllerVolume (0.001, 1) (0.2::Float) &+&@@ -574,7 +576,7 @@ voderMaskEnv :: (PathClass.AbsRel ar, Check.C msg, Construct.C msg, POut.Default b) =>- CausalP.T () (Stereo.T VectorValue) (POut.Element b) ->+ Causal.T (Stereo.T VectorValue) (POut.Element b) -> Path.Dir ar -> IO (ChannelMsg.Channel -> VoiceMsg.Program -> SampleRate Real -> PIO.T (MIO.Events msg) b)@@ -584,23 +586,24 @@ voderSeparated ::- (PathClass.AbsRel ar, Check.C msg, Construct.C msg, POut.Default b) =>- CausalP.T (SampleRate Real) (Stereo.T VectorValue) (POut.Element b) ->+ (PathClass.AbsRel ar, Render.RunArg p,+ Check.C msg, Construct.C msg, POut.Default b) =>+ (Render.DSLArg p -> Causal.T (Stereo.T VectorValue) (POut.Element b)) -> Speech.VowelSynthEnv -> Path.Dir ar -> IO (ChannelMsg.Channel -> ChannelMsg.Channel -> VoiceMsg.Program ->- SampleRate Real -> PIO.T (MIO.Events msg) b)+ SampleRate Real -> p -> PIO.T (MIO.Events msg) b) voderSeparated emitStereo voice smpDir = do- carrier <- keyboardDetuneFMCore id smpDir+ carrier <- keyboardDetuneFMCore (arr Stereo.multiValue) smpDir arrange <- CausalSt.makeArranger amp <-- CausalP.processIO- (emitStereo <<<- CausalP.envelopeStereo <<<- first (CausalP.mapSimple Serial.upsample))+ CausalRender.run $ \p ->+ (emitStereo p <<<+ Causal.envelopeStereo <<<+ Causal.map Serial.upsample *** arr Stereo.unMultiValue) - return $ \carrierChan phonemeChan initPgm sampleRate ->- amp sampleRate+ return $ \carrierChan phonemeChan initPgm sampleRate p ->+ amp p <<< MIO.controllerExponential phonemeChan controllerVolume (0.001, 1) (0.2::Float) &+&@@ -618,11 +621,12 @@ (carrier carrierChan initPgm sampleRate))) voderMaskSeparated ::- (PathClass.AbsRel ar, Check.C msg, Construct.C msg, POut.Default b) =>- CausalP.T (SampleRate Real) (Stereo.T VectorValue) (POut.Element b) ->+ (PathClass.AbsRel ar, Render.RunArg p,+ Check.C msg, Construct.C msg, POut.Default b) =>+ (Render.DSLArg p -> Causal.T (Stereo.T VectorValue) (POut.Element b)) -> Path.Dir ar -> IO (ChannelMsg.Channel -> ChannelMsg.Channel -> VoiceMsg.Program ->- SampleRate Real -> PIO.T (MIO.Events msg) b)+ SampleRate Real -> p -> PIO.T (MIO.Events msg) b) voderMaskSeparated emitStereo smpDir = do voice <- Speech.phonemeMask <*> Speech.loadMasksGrouped voderSeparated emitStereo voice smpDir@@ -633,22 +637,22 @@ IO (SampleRate Real -> PIO.T (MIO.Events msg) (SV.Vector (Stereo.T Real))) voderMaskMulti smpDir = do- mix <- CausalP.processIO CausalP.mix+ mix <- CausalRender.run Causal.mix proc <- voderMaskSeparated- (CausalP.mapSimple StereoInt.interleave)+ (const $ Causal.map StereoInt.interleave) smpDir return $ \ sampleRate -> arr SigStL.unpackStereoStrict <<< foldl1- (\x y -> mix () <<< Zip.arrowFanout x y)+ (\x y -> mix <<< Zip.arrowFanout x y) (map (\chan -> proc (ChannelMsg.toChannel chan) (ChannelMsg.toChannel $ succ chan) (VoiceMsg.toProgram 4)- sampleRate)+ sampleRate ()) [0, 2, 4, 6])
src/Synthesizer/LLVM/Causal/Controlled.hs view
@@ -2,6 +2,7 @@ {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE UndecidableInstances #-} {- | This module provides a type class that automatically selects a filter@@ -10,9 +11,13 @@ because there may be different ways to specify the filter parameters but there is only one implementation of the filter itself. -}-module Synthesizer.LLVM.Causal.Controlled (C(..)) where+module Synthesizer.LLVM.Causal.Controlled (+ C(..),+ processCtrlRate,+ ) where -import qualified Synthesizer.LLVM.Filter.ComplexFirstOrderPacked as ComplexFiltPack+import qualified Synthesizer.LLVM.Filter.ComplexFirstOrderPacked+ as ComplexFiltPack import qualified Synthesizer.LLVM.Filter.ComplexFirstOrder as ComplexFilt import qualified Synthesizer.LLVM.Filter.Allpass as Allpass import qualified Synthesizer.LLVM.Filter.FirstOrder as Filt1@@ -22,30 +27,48 @@ import qualified Synthesizer.LLVM.Filter.Moog as Moog import qualified Synthesizer.LLVM.Filter.Universal as UniFilter -import qualified Synthesizer.LLVM.Causal.Process as Causal+import qualified Synthesizer.LLVM.Causal.Private as Causal+import qualified Synthesizer.LLVM.Generator.Signal as Sig import qualified Synthesizer.LLVM.Frame.Stereo as Stereo +import Synthesizer.Causal.Class (($<))++import qualified LLVM.DSL.Expression as Expr+import LLVM.DSL.Expression (Exp)++import qualified LLVM.Extra.Multi.Value.Marshal as Marshal+import qualified LLVM.Extra.Multi.Value as MultiValue+import qualified LLVM.Extra.Multi.Vector as MultiVector import qualified LLVM.Extra.Memory as Memory-import qualified LLVM.Extra.ScalarOrVector as SoV-import qualified LLVM.Extra.Vector as Vector import qualified LLVM.Extra.Arithmetic as A import qualified LLVM.Core as LLVM-import LLVM.Core (Value, IsConst) import qualified Type.Data.Num.Decimal as TypeNum import Type.Data.Num.Decimal.Number ((:*:)) +import qualified Algebra.Module as Module +++processCtrlRate ::+ (C parameter a b, Memory.C parameter) =>+ (Marshal.C r, MultiValue.IntegerConstant r,+ MultiValue.Additive r, MultiValue.Comparison r) =>+ Exp r -> (Exp r -> Sig.T parameter) -> Causal.T a b+processCtrlRate reduct ctrlGen =+ process $< Sig.interpolateConstant reduct (ctrlGen reduct)++ {- | A filter parameter type uniquely selects a filter function. However it does not uniquely determine the input and output type, since the same filter can run on mono and stereo signals. -} class (a ~ Input parameter b, b ~ Output parameter a) => C parameter a b where- type Input parameter b :: *- type Output parameter a :: *- process :: (Causal.C process) => process (parameter, a) b+ type Input parameter b+ type Output parameter a+ process :: Causal.T (parameter, a) b {-@@ -54,7 +77,7 @@ -} instance- (a ~ A.Scalar v, A.PseudoModule v, A.IntegerConstant a,+ (Module.C ae ve, Expr.Aggregate ae a, Expr.Aggregate ve v, Memory.C a, Memory.C v) => C (Filt1.Parameter a) v (Filt1.Result v) where type Input (Filt1.Parameter a) (Filt1.Result v) = v@@ -70,27 +93,25 @@ process = Filt2.causal instance- (Vector.Arithmetic a, SoV.RationalConstant a,- Memory.C (Value (Filt2P.State a))) =>- C (Filt2P.Parameter a)- (Value a) (Value a) where- type Input (Filt2P.Parameter a) (Value a) = Value a- type Output (Filt2P.Parameter a) (Value a) = Value a+ (Marshal.C a, Marshal.Vector TypeNum.D4 a, MultiVector.PseudoRing a) =>+ C (Filt2P.Parameter a) (MultiValue.T a) (MultiValue.T a) where+ type Input (Filt2P.Parameter a) (MultiValue.T a) = MultiValue.T a+ type Output (Filt2P.Parameter a) (MultiValue.T a) = MultiValue.T a process = Filt2P.causal instance- (LLVM.IsSized v, SoV.PseudoModule v, SoV.Scalar v ~ a,- LLVM.IsSized a, SoV.IntegerConstant a,- TypeNum.Natural n,- TypeNum.Positive (n :*: LLVM.UnknownSize)) =>- C (Cascade.ParameterValue n a) (Value v) (Value v) where- type Input (Cascade.ParameterValue n a) (Value v) = Value v- type Output (Cascade.ParameterValue n a) (Value v) = Value v+ (a ~ MultiValue.Scalar v, MultiValue.PseudoModule v,+ Marshal.C a, MultiValue.IntegerConstant a, Marshal.C v,+ TypeNum.Natural n, TypeNum.Positive (n :*: LLVM.UnknownSize),+ inp ~ MultiValue.T v, out ~ MultiValue.T v) =>+ C (Cascade.ParameterValue n a) inp out where+ type Input (Cascade.ParameterValue n a) out = out+ type Output (Cascade.ParameterValue n a) inp = inp process = Cascade.causal instance- (a ~ A.Scalar v, A.PseudoModule v, A.RationalConstant a,+ (Module.C ae ve, Expr.Aggregate ae a, Expr.Aggregate ve v, Memory.C a, Memory.C v) => C (Allpass.Parameter a) v v where type Input (Allpass.Parameter a) v = v@@ -98,9 +119,8 @@ process = Allpass.causal instance- (a ~ A.Scalar v, A.PseudoModule v, A.RationalConstant a,- Memory.C a, Memory.C v,- TypeNum.Natural n) =>+ (Module.C ae ve, Expr.Aggregate ae a, Expr.Aggregate ve v,+ Memory.C a, Memory.C v, TypeNum.Natural n) => C (Allpass.CascadeParameter n a) v v where type Input (Allpass.CascadeParameter n a) v = v type Output (Allpass.CascadeParameter n a) v = v@@ -108,7 +128,7 @@ instance- (A.PseudoModule v, A.Scalar v ~ a, A.IntegerConstant a,+ (Module.C ae ve, Expr.Aggregate ae a, Expr.Aggregate ve v, Memory.C v, TypeNum.Natural n) => C (Moog.Parameter n a) v v where type Input (Moog.Parameter n a) v = v@@ -117,7 +137,7 @@ instance- (a ~ A.Scalar v, A.PseudoModule v, A.RationalConstant a,+ (A.PseudoModule v, A.Scalar v ~ a, A.RationalConstant a, Memory.C a, Memory.C v) => C (UniFilter.Parameter a) v (UniFilter.Result v) where type Input (UniFilter.Parameter a) (UniFilter.Result v) = v@@ -132,10 +152,9 @@ process = ComplexFilt.causal instance- (Vector.Arithmetic a, IsConst a,- Memory.C (Value (Filt2P.State a))) =>- C (ComplexFiltPack.Parameter a)- (Stereo.T (Value a)) (Stereo.T (Value a)) where- type Input (ComplexFiltPack.Parameter a) (Stereo.T (Value a)) = Stereo.T (Value a)- type Output (ComplexFiltPack.Parameter a) (Stereo.T (Value a)) = Stereo.T (Value a)+ (Marshal.Vector n a, n ~ TypeNum.D3, MultiVector.PseudoRing a,+ inp ~ MultiValue.T a, out ~ MultiValue.T a) =>+ C (ComplexFiltPack.ParameterMV a) (Stereo.T inp) (Stereo.T out) where+ type Input (ComplexFiltPack.ParameterMV a) (Stereo.T out) = Stereo.T out+ type Output (ComplexFiltPack.ParameterMV a) (Stereo.T inp) = Stereo.T inp process = ComplexFiltPack.causal
src/Synthesizer/LLVM/Causal/ControlledPacked.hs view
@@ -2,47 +2,73 @@ {-# LANGUAGE TypeOperators #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE UndecidableInstances #-} {- |-This is like "Synthesizer.LLVM.Causal.Controlled"+This is like "Synthesizer.LLVM.CausalExp.Controlled" but for vectorised signals. -}-module Synthesizer.LLVM.Causal.ControlledPacked (C(..)) where+module Synthesizer.LLVM.Causal.ControlledPacked (+ C(..),+ processCtrlRate,+ ) where +import qualified Synthesizer.LLVM.Filter.SecondOrderCascade as Cascade import qualified Synthesizer.LLVM.Filter.Allpass as Allpass import qualified Synthesizer.LLVM.Filter.FirstOrder as Filt1 import qualified Synthesizer.LLVM.Filter.SecondOrder as Filt2-import qualified Synthesizer.LLVM.Filter.SecondOrderCascade as Cascade import qualified Synthesizer.LLVM.Filter.Moog as Moog import qualified Synthesizer.LLVM.Filter.Universal as UniFilter -import qualified Synthesizer.LLVM.Causal.ProcessPacked as CausalS+import qualified Synthesizer.LLVM.Causal.ProcessPacked as CausalP import qualified Synthesizer.LLVM.Causal.Process as Causal-import qualified Synthesizer.LLVM.Frame.SerialVector as Serial+import qualified Synthesizer.LLVM.Generator.Signal as Sig+import qualified Synthesizer.LLVM.Frame.SerialVector.Class as Serial +import Synthesizer.Causal.Class (($<))++import qualified LLVM.DSL.Expression as Expr+import LLVM.DSL.Expression (Exp)++import qualified LLVM.Extra.Multi.Value.Marshal as Marshal+import qualified LLVM.Extra.Multi.Value as MultiValue import qualified LLVM.Extra.Memory as Memory-import qualified LLVM.Extra.ScalarOrVector as SoV import qualified LLVM.Extra.Tuple as Tuple import qualified LLVM.Extra.Arithmetic as A import qualified LLVM.Core as LLVM-import LLVM.Core (IsSized) import qualified Type.Data.Num.Decimal as TypeNum import Type.Data.Num.Decimal.Number ((:*:)) +import qualified Algebra.Module as Module+import qualified NumericPrelude.Numeric as NP+ import Control.Arrow ((<<<), arr, first) ++processCtrlRate ::+ (C parameter av bv, Memory.C parameter,+ Serial.Read av, n ~ Serial.Size av,+ Serial.Write bv, n ~ Serial.Size bv) =>+ (Marshal.C r, MultiValue.RationalConstant r,+ MultiValue.Field r, MultiValue.Comparison r) =>+ Exp r -> (Exp r -> Sig.T parameter) -> Causal.T av bv+processCtrlRate reduct ctrlGen = Serial.withSize $ \n ->+ process $<+ Sig.interpolateConstant (reduct / NP.fromIntegral n) (ctrlGen reduct)++ {- | A filter parameter type uniquely selects a filter function. However it does not uniquely determine the input and output type, since the same filter can run on mono and stereo signals. -}-class (a ~ Input parameter b, b ~ Output parameter a) => C parameter a b where- type Input parameter b :: *- type Output parameter a :: *- process :: (Causal.C process) => process (parameter, a) b+class (Output parameter a ~ b, Input parameter b ~ a) => C parameter a b where+ type Output parameter a+ type Input parameter b+ process :: Causal.T (parameter, a) b {-@@ -51,29 +77,29 @@ -} instance- (Serial.C v, Serial.Element v ~ a,- A.PseudoRing a, A.IntegerConstant a, Memory.C a,- A.PseudoRing v) =>+ (Serial.Write v, Serial.Element v ~ a,+ A.PseudoRing v, A.IntegerConstant v,+ A.PseudoRing a, A.IntegerConstant a, Expr.Aggregate ae a,+ Tuple.Phi a, Tuple.Undefined a, Memory.C a) => C (Filt1.Parameter a) v (Filt1.Result v) where type Input (Filt1.Parameter a) (Filt1.Result v) = v type Output (Filt1.Parameter a) v = Filt1.Result v process = Filt1.causalPacked instance- (Serial.C v, Serial.Element v ~ a,- A.PseudoRing a, A.IntegerConstant a, Memory.C a,- A.PseudoRing v, A.IntegerConstant v, Memory.C v) =>+ (Serial.Write v, Serial.Element v ~ a,+ A.PseudoRing v, A.IntegerConstant v,+ A.PseudoRing a, A.IntegerConstant a, Expr.Aggregate ae a,+ Tuple.Phi a, Tuple.Undefined a, Memory.C a, Memory.C v) => C (Filt2.Parameter a) v v where type Input (Filt2.Parameter a) v = v type Output (Filt2.Parameter a) v = v process = Filt2.causalPacked instance- (LLVM.Value a ~ A.Scalar v, A.PseudoModule v,- Serial.C v, Serial.Element v ~ LLVM.Value a,- SoV.IntegerConstant a,- A.PseudoRing v, A.IntegerConstant v, Memory.C v,- LLVM.IsPrimitive a, IsSized a,+ (Serial.Write v, Serial.Element v ~ MultiValue.T a,+ Memory.C v, A.PseudoRing v, A.IntegerConstant v,+ Marshal.C a, MultiValue.PseudoRing a, MultiValue.IntegerConstant a, TypeNum.Positive (n :*: LLVM.UnknownSize), TypeNum.Natural n) => C (Cascade.ParameterValue n a) v v where@@ -81,11 +107,10 @@ type Output (Cascade.ParameterValue n a) v = v process = Cascade.causalPacked - instance- (Serial.C v, Serial.Element v ~ a,- Memory.C a, A.IntegerConstant a,- A.PseudoRing v, A.PseudoRing a) =>+ (Serial.Write v, Serial.Element v ~ a,+ A.PseudoRing a, A.IntegerConstant a, Memory.C a,+ A.PseudoRing v, A.IntegerConstant v) => C (Allpass.Parameter a) v v where type Input (Allpass.Parameter a) v = v type Output (Allpass.Parameter a) v = v@@ -93,7 +118,7 @@ instance (TypeNum.Natural n,- Serial.C v, Serial.Element v ~ a,+ Serial.Write v, Serial.Element v ~ a, A.PseudoRing a, A.IntegerConstant a, Memory.C a, A.PseudoRing v, A.RationalConstant v) => C (Allpass.CascadeParameter n a) v v where@@ -103,23 +128,22 @@ instance- (Serial.C v, Serial.Element v ~ b, Tuple.Phi a, Tuple.Undefined a,- a ~ A.Scalar b, A.PseudoModule b, A.IntegerConstant a, Memory.C b,- TypeNum.Natural n) =>+ (TypeNum.Natural n,+ Serial.Write v, Serial.Element v ~ b, Memory.C b,+ Tuple.Phi a, Tuple.Undefined a,+ Expr.Aggregate ae a, Expr.Aggregate be b, Module.C ae be) => C (Moog.Parameter n a) v v where type Input (Moog.Parameter n a) v = v type Output (Moog.Parameter n a) v = v- process =- CausalS.pack Moog.causal <<<- first (arr Serial.constant)+ process = CausalP.pack Moog.causal <<< first (arr Serial.constant) instance- (Serial.C v, Serial.Element v ~ b, Tuple.Phi a, Tuple.Undefined a,- a ~ A.Scalar b, A.PseudoModule b, A.IntegerConstant a, Memory.C b) =>+ (Serial.Write v, Serial.Element v ~ b, Memory.C b,+ Tuple.Phi a, Tuple.Undefined a,+ Expr.Aggregate ae a, Expr.Aggregate be b, Module.C ae be) => C (UniFilter.Parameter a) v (UniFilter.Result v) where type Input (UniFilter.Parameter a) (UniFilter.Result v) = v type Output (UniFilter.Parameter a) v = UniFilter.Result v process =- CausalS.pack UniFilter.causal <<<- first (arr Serial.constant)+ CausalP.pack UniFilter.causalExp <<< first (arr Serial.constant)
+ src/Synthesizer/LLVM/Causal/Exponential2.hs view
@@ -0,0 +1,414 @@+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{- |+Exponential curve with controllable delay.+-}+module Synthesizer.LLVM.Causal.Exponential2 (+ Parameter,+ parameter,+ parameterPlain,+ multiValueParameter,+ unMultiValueParameter,+ causal,++ ParameterPacked,+ parameterPacked,+ parameterPackedExp,+ parameterPackedPlain,+ multiValueParameterPacked,+ unMultiValueParameterPacked,+ causalPacked,+ ) where++import qualified Synthesizer.LLVM.Causal.Private as CausalPriv+import qualified Synthesizer.LLVM.Causal.Process as Causal+import qualified Synthesizer.LLVM.Causal.Functional as F+import qualified Synthesizer.LLVM.Frame.SerialVector.Plain as SerialPlain+import qualified Synthesizer.LLVM.Frame.SerialVector.Code as SerialCode+import qualified Synthesizer.LLVM.Frame.SerialVector as Serial+import qualified Synthesizer.LLVM.Frame.SerialVector.Class as SerialOld+import qualified Synthesizer.LLVM.Value as Value++import qualified LLVM.DSL.Expression as Expr+import LLVM.DSL.Expression (Exp)++import qualified LLVM.Extra.Multi.Value.Marshal as MarshalMV+import qualified LLVM.Extra.Multi.Value as MultiValue+import qualified LLVM.Extra.Multi.Vector as MultiVector+import qualified LLVM.Extra.ScalarOrVector as SoV+import qualified LLVM.Extra.Vector as Vector+import qualified LLVM.Extra.Storable as Storable+import qualified LLVM.Extra.Marshal as Marshal+import qualified LLVM.Extra.Memory as Memory+import qualified LLVM.Extra.Tuple as Tuple+import qualified LLVM.Extra.Arithmetic as A++import qualified LLVM.Core as LLVM+import LLVM.Core (CodeGenFunction, Value, IsFloating)++import qualified Type.Data.Num.Decimal as TypeNum++import qualified Foreign.Storable.Traversable as Store+import qualified Foreign.Storable+import Foreign.Storable (Storable)++import qualified Control.Applicative as App+import Control.Applicative (liftA2, pure, (<*>))+import Control.Arrow (arr, (&&&))++import qualified Data.Foldable as Fold+import qualified Data.Traversable as Trav+import Data.Traversable (traverse)++import qualified Algebra.Transcendental as Trans++import NumericPrelude.Numeric+import NumericPrelude.Base+++newtype Parameter a = Parameter a+ deriving (Show, Storable)+++instance Functor Parameter where+ {-# INLINE fmap #-}+ fmap f (Parameter k) = Parameter (f k)++instance App.Applicative Parameter where+ {-# INLINE pure #-}+ pure x = Parameter x+ {-# INLINE (<*>) #-}+ Parameter f <*> Parameter k = Parameter (f k)++instance Fold.Foldable Parameter where+ {-# INLINE foldMap #-}+ foldMap = Trav.foldMapDefault++instance Trav.Traversable Parameter where+ {-# INLINE sequenceA #-}+ sequenceA (Parameter k) = fmap Parameter k+++instance (Tuple.Phi a) => Tuple.Phi (Parameter a) where+ phi = Tuple.phiTraversable+ addPhi = Tuple.addPhiFoldable++instance Tuple.Undefined a => Tuple.Undefined (Parameter a) where+ undef = Tuple.undefPointed++instance Tuple.Zero a => Tuple.Zero (Parameter a) where+ zero = Tuple.zeroPointed++instance (Memory.C a) => Memory.C (Parameter a) where+ type Struct (Parameter a) = Memory.Struct a+ load = Memory.loadNewtype Parameter+ store = Memory.storeNewtype (\(Parameter k) -> k)+ decompose = Memory.decomposeNewtype Parameter+ compose = Memory.composeNewtype (\(Parameter k) -> k)++instance (Marshal.C a) => Marshal.C (Parameter a) where+ pack (Parameter k) = Marshal.pack k+ unpack = Parameter . Marshal.unpack++instance (MarshalMV.C a) => MarshalMV.C (Parameter a) where+ pack (Parameter k) = MarshalMV.pack k+ unpack = Parameter . MarshalMV.unpack++instance (Storable.C a) => Storable.C (Parameter a) where+ load = Storable.loadNewtype Parameter Parameter+ store = Storable.storeNewtype Parameter (\(Parameter k) -> k)++instance (Tuple.Value a) => Tuple.Value (Parameter a) where+ type ValueOf (Parameter a) = Parameter (Tuple.ValueOf a)+ valueOf = Tuple.valueOfFunctor++instance (MultiValue.C a) => MultiValue.C (Parameter a) where+ type Repr (Parameter a) = Parameter (MultiValue.Repr a)+ cons = multiValueParameter . fmap MultiValue.cons+ undef = multiValueParameter $ pure MultiValue.undef+ zero = multiValueParameter $ pure MultiValue.zero+ phi bb =+ fmap multiValueParameter .+ traverse (MultiValue.phi bb) . unMultiValueParameter+ addPhi bb a b =+ Fold.sequence_ $+ liftA2 (MultiValue.addPhi bb)+ (unMultiValueParameter a) (unMultiValueParameter b)++multiValueParameter ::+ Parameter (MultiValue.T a) -> MultiValue.T (Parameter a)+multiValueParameter = MultiValue.Cons . fmap (\(MultiValue.Cons a) -> a)++unMultiValueParameter ::+ MultiValue.T (Parameter a) -> Parameter (MultiValue.T a)+unMultiValueParameter (MultiValue.Cons x) = fmap MultiValue.Cons x+++instance (Value.Flatten a) => Value.Flatten (Parameter a) where+ type Registers (Parameter a) = Parameter (Value.Registers a)+ flattenCode = Value.flattenCodeTraversable+ unfoldCode = Value.unfoldCodeTraversable+++instance (Vector.Simple v) => Vector.Simple (Parameter v) where+ type Element (Parameter v) = Parameter (Vector.Element v)+ type Size (Parameter v) = Vector.Size v+ shuffleMatch = Vector.shuffleMatchTraversable+ extract = Vector.extractTraversable++instance (Vector.C v) => Vector.C (Parameter v) where+ insert = Vector.insertTraversable+++instance+ (Expr.Aggregate exp mv) =>+ Expr.Aggregate (Parameter exp) (Parameter mv) where+ type MultiValuesOf (Parameter exp) = Parameter (Expr.MultiValuesOf exp)+ type ExpressionsOf (Parameter mv) = Parameter (Expr.ExpressionsOf mv)+ bundle (Parameter p) = fmap Parameter $ Expr.bundle p+ dissect (Parameter p) = Parameter $ Expr.dissect p+++parameter ::+ (Trans.C a, SoV.TranscendentalConstant a, IsFloating a) =>+ Value a ->+ CodeGenFunction r (Parameter (Value a))+parameter = Value.unlift1 parameterPlain++parameterPlain ::+ (Trans.C a) =>+ a -> Parameter a+parameterPlain halfLife =+ Parameter $ 0.5 ^? recip halfLife+++causal ::+ (MarshalMV.C a, MultiValue.T a ~ am, MultiValue.PseudoRing a) =>+ Exp a -> Causal.T (Parameter am) am+causal initial =+ Causal.loop initial+ (arr snd &&& CausalPriv.zipWith (\(Parameter a) -> A.mul a))+++data ParameterPacked a =+ ParameterPacked {ppFeedback, ppCurrent :: a}+++instance Functor ParameterPacked where+ {-# INLINE fmap #-}+ fmap f p = ParameterPacked+ (f $ ppFeedback p) (f $ ppCurrent p)++instance App.Applicative ParameterPacked where+ {-# INLINE pure #-}+ pure x = ParameterPacked x x+ {-# INLINE (<*>) #-}+ f <*> p = ParameterPacked+ (ppFeedback f $ ppFeedback p)+ (ppCurrent f $ ppCurrent p)++instance Fold.Foldable ParameterPacked where+ {-# INLINE foldMap #-}+ foldMap = Trav.foldMapDefault++instance Trav.Traversable ParameterPacked where+ {-# INLINE sequenceA #-}+ sequenceA p =+ liftA2 ParameterPacked+ (ppFeedback p) (ppCurrent p)+++instance (Tuple.Phi a) => Tuple.Phi (ParameterPacked a) where+ phi = Tuple.phiTraversable+ addPhi = Tuple.addPhiFoldable++instance Tuple.Undefined a => Tuple.Undefined (ParameterPacked a) where+ undef = Tuple.undefPointed++instance Tuple.Zero a => Tuple.Zero (ParameterPacked a) where+ zero = Tuple.zeroPointed+++{-+storeParameter ::+ Storable a => Store.Dictionary (ParameterPacked a)+storeParameter =+ Store.run $+ liftA2 ParameterPacked+ (Store.element ppFeedback)+ (Store.element ppCurrent)++instance Storable a => Storable (ParameterPacked a) where+ sizeOf = Store.sizeOf storeParameter+ alignment = Store.alignment storeParameter+ peek = Store.peek storeParameter+ poke = Store.poke storeParameter+-}++instance Storable a => Storable (ParameterPacked a) where+ sizeOf = Store.sizeOf+ alignment = Store.alignment+ peek = Store.peekApplicative+ poke = Store.poke+++type ParameterPackedStruct a = LLVM.Struct (a, (a, ()))++memory ::+ (Memory.C a) =>+ Memory.Record r (ParameterPackedStruct (Memory.Struct a)) (ParameterPacked a)+memory =+ liftA2 ParameterPacked+ (Memory.element ppFeedback TypeNum.d0)+ (Memory.element ppCurrent TypeNum.d1)++instance (Memory.C a) => Memory.C (ParameterPacked a) where+ type Struct (ParameterPacked a) = ParameterPackedStruct (Memory.Struct a)+ load = Memory.loadRecord memory+ store = Memory.storeRecord memory+ decompose = Memory.decomposeRecord memory+ compose = Memory.composeRecord memory++instance (Marshal.C a) => Marshal.C (ParameterPacked a) where+ pack (ParameterPacked bend depth) = Marshal.pack (bend, depth)+ unpack = uncurry ParameterPacked . Marshal.unpack++instance (MarshalMV.C a) => MarshalMV.C (ParameterPacked a) where+ pack (ParameterPacked bend depth) = MarshalMV.pack (bend, depth)+ unpack = uncurry ParameterPacked . MarshalMV.unpack++instance (Storable.C a) => Storable.C (ParameterPacked a) where+ load = Storable.loadApplicative+ store = Storable.storeFoldable+++instance (Tuple.Value a) => Tuple.Value (ParameterPacked a) where+ type ValueOf (ParameterPacked a) = ParameterPacked (Tuple.ValueOf a)+ valueOf = Tuple.valueOfFunctor++instance (MultiValue.C a) => MultiValue.C (ParameterPacked a) where+ type Repr (ParameterPacked a) = ParameterPacked (MultiValue.Repr a)+ cons = multiValueParameterPacked . fmap MultiValue.cons+ undef = multiValueParameterPacked $ pure MultiValue.undef+ zero = multiValueParameterPacked $ pure MultiValue.zero+ phi bb =+ fmap multiValueParameterPacked .+ traverse (MultiValue.phi bb) . unMultiValueParameterPacked+ addPhi bb a b =+ Fold.sequence_ $+ liftA2 (MultiValue.addPhi bb)+ (unMultiValueParameterPacked a) (unMultiValueParameterPacked b)++multiValueParameterPacked ::+ ParameterPacked (MultiValue.T a) -> MultiValue.T (ParameterPacked a)+multiValueParameterPacked = MultiValue.Cons . fmap (\(MultiValue.Cons a) -> a)++unMultiValueParameterPacked ::+ MultiValue.T (ParameterPacked a) -> ParameterPacked (MultiValue.T a)+unMultiValueParameterPacked (MultiValue.Cons x) = fmap MultiValue.Cons x+++instance (Value.Flatten a) => Value.Flatten (ParameterPacked a) where+ type Registers (ParameterPacked a) = ParameterPacked (Value.Registers a)+ flattenCode = Value.flattenCodeTraversable+ unfoldCode = Value.unfoldCodeTraversable++instance+ (Expr.Aggregate exp mv) =>+ Expr.Aggregate (ParameterPacked exp) (ParameterPacked mv) where+ type MultiValuesOf (ParameterPacked exp) =+ ParameterPacked (Expr.MultiValuesOf exp)+ type ExpressionsOf (ParameterPacked mv) =+ ParameterPacked (Expr.ExpressionsOf mv)+ bundle p =+ liftA2 ParameterPacked+ (Expr.bundle $ ppFeedback p) (Expr.bundle $ ppCurrent p)+ dissect p =+ ParameterPacked+ (Expr.dissect $ ppFeedback p) (Expr.dissect $ ppCurrent p)+++type instance F.Arguments f (ParameterPacked a) = f (ParameterPacked a)+instance F.MakeArguments (ParameterPacked a) where+ makeArgs = id++++withSize ::+ (TypeNum.Natural n) =>+ (SerialOld.Write v, SerialOld.Size v ~ n, TypeNum.Positive n) =>+ (TypeNum.Singleton n -> m (param v)) ->+ m (param v)+withSize f = f TypeNum.singleton++parameterPacked ::+ (SerialOld.Write v, SerialOld.Element v ~ a,+ A.PseudoRing v, A.RationalConstant v,+ A.Transcendental a, A.RationalConstant a) =>+ a -> CodeGenFunction r (ParameterPacked v)+parameterPacked halfLife = withSize $ \n -> do+ feedback <-+ SerialOld.upsample =<<+ A.pow (A.fromRational' 0.5) =<<+ A.fdiv (A.fromInteger' $ TypeNum.integralFromSingleton n) halfLife+ k <-+ A.pow (A.fromRational' 0.5) =<<+ A.fdiv (A.fromInteger' 1) halfLife+ current <-+ SerialOld.iterate (A.mul k) (A.fromInteger' 1)+ return $ ParameterPacked feedback current+{-+ Value.unlift1 parameterPackedPlain+-}++withSizePlain ::+ (TypeNum.Positive n) =>+ (TypeNum.Singleton n -> param (Serial.T n a)) ->+ param (Serial.T n a)+withSizePlain f = f TypeNum.singleton++parameterPackedPlain ::+ (TypeNum.Positive n, Trans.C a) =>+ a -> ParameterPacked (Serial.T n a)+parameterPackedPlain halfLife =+ withSizePlain $ \n ->+ ParameterPacked+ (SerialPlain.replicate+ (0.5 ^? (fromInteger (TypeNum.integerFromSingleton n) / halfLife)))+ (SerialPlain.iterate (0.5 ^? recip halfLife *) one)++withSizeExp ::+ (TypeNum.Positive n) =>+ (TypeNum.Singleton n -> param (exp (Serial.T n a))) ->+ param (exp (Serial.T n a))+withSizeExp f = f TypeNum.singleton++parameterPackedExp ::+ (TypeNum.Positive n) =>+ (MultiValue.Transcendental a, MultiValue.RationalConstant a) =>+ (MultiVector.C a) =>+ Exp a -> ParameterPacked (Exp (Serial.T n a))+parameterPackedExp halfLife =+ withSizeExp $ \n ->+ ParameterPacked+ (Serial.upsample+ (0.5 ^? (fromInteger (TypeNum.integerFromSingleton n) / halfLife)))+ (Serial.iterate (0.5 ^? recip halfLife *) one)+++causalPacked ::+ (MultiVector.PseudoRing a, MultiValue.IntegerConstant a,+ TypeNum.Positive n, MarshalMV.Vector n a, MarshalMV.C a) =>+ Exp a ->+ Causal.T (ParameterPacked (SerialCode.Value n a)) (SerialCode.Value n a)+causalPacked initial =+ Causal.loop+ (Serial.upsample initial)+ (CausalPriv.map $+ \(p, s0) -> liftA2 (,)+ (A.mul (ppCurrent p) s0)+ (A.mul (ppFeedback p) s0))
+ src/Synthesizer/LLVM/Causal/Functional.hs view
@@ -0,0 +1,519 @@+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE Rank2Types #-}+module Synthesizer.LLVM.Causal.Functional (+ T,+ lift, fromSignal,+ ($&), (&|&),+ compile,+ compileSignal,+ withArgs, MakeArguments, Arguments, makeArgs,+ AnyArg(..),++ Ground(Ground),+ withGroundArgs, MakeGroundArguments, GroundArguments,+ makeGroundArgs,++ Atom(..), atom,+ withGuidedArgs, MakeGuidedArguments, GuidedArguments, PatternArguments,+ makeGuidedArgs,++ PrepareArguments(PrepareArguments), withPreparedArgs, withPreparedArgs2,+ atomArg, stereoArgs, pairArgs, tripleArgs,+ ) where++import qualified Synthesizer.LLVM.Causal.Private as CausalCore+import qualified Synthesizer.LLVM.Causal.Process as Causal+import qualified Synthesizer.LLVM.Generator.Signal as Signal+import qualified Synthesizer.LLVM.Frame.SerialVector.Class as Serial+import qualified Synthesizer.LLVM.Frame.Stereo as Stereo+import qualified Synthesizer.Causal.Class as CausalClass+import Synthesizer.LLVM.Private (getPairPtrs, noLocalPtr)++import qualified LLVM.Extra.Multi.Value as MultiValue+import qualified LLVM.Extra.Tuple as Tuple+import qualified LLVM.Extra.MaybeContinuation as MaybeCont+import qualified LLVM.Extra.Memory as Memory+import qualified LLVM.Extra.Arithmetic as A++import LLVM.Core (CodeGenFunction)+import qualified LLVM.Core as LLVM++import qualified Number.Ratio as Ratio+import qualified Algebra.Transcendental as Trans+import qualified Algebra.Algebraic as Algebraic+import qualified Algebra.Field as Field+import qualified Algebra.Ring as Ring+import qualified Algebra.Additive as Additive++import qualified Control.Monad.Trans.State as State+import qualified Control.Monad.Trans.Class as MT+import Control.Monad.Trans.State (StateT)++import qualified Data.Vault.Lazy as Vault+import Data.Vault.Lazy (Vault)+import qualified Control.Category as Cat+import Control.Arrow (Arrow, (>>^), (&&&), arr, first)+import Control.Category (Category, (.))+import Control.Applicative (Applicative, (<*>), pure, liftA2)++import Data.Tuple.Strict (zipPair)+import Data.Tuple.HT (fst3, snd3, thd3)++import qualified System.Unsafe as Unsafe++import Prelude hiding ((.))+++newtype T inp out = Cons (Code inp out)+++-- | similar to @Causal.T a b@+data Code a b =+ forall global local state.+ (Memory.C global, LLVM.IsSized local, Memory.C state) =>+ Code (forall r c.+ (Tuple.Phi c) =>+ global -> LLVM.Value (LLVM.Ptr local) -> a -> state ->+ StateT Vault (MaybeCont.T r c) (b, state))+ -- compute next value+ (forall r. CodeGenFunction r (global, state))+ -- initial state+ (forall r. global -> CodeGenFunction r ())+ -- cleanup+++instance Category Code where+ id = arr id+ Code nextB startB stopB . Code nextA startA stopA = Code+ (\(globalA, globalB) local a (sa0,sb0) -> do+ (localA,localB) <- MT.lift $ getPairPtrs local+ (b,sa1) <- nextA globalA localA a sa0+ (c,sb1) <- nextB globalB localB b sb0+ return (c, (sa1,sb1)))+ (liftA2 zipPair startA startB)+ (\(globalA, globalB) -> stopA globalA >> stopB globalB)+++instance Arrow Code where+ arr f = Code+ (\() -> noLocalPtr $ \a () -> return (f a, ()))+ (return ((),()))+ (\() -> return ())+ first (Code next start stop) = Code (CausalCore.firstNext next) start stop+++{-+We must not define Category and Arrow instances+because in osci***osci the result of osci would be shared,+although it depends on the particular input.++instance Category T where+ id = tagUnique Cat.id+ Cons a . Cons b = tagUnique (a . b)++instance Arrow T where+ arr f = tagUnique $ arr f+ first (Cons a) = tagUnique $ first a+-}++instance Functor (T inp) where+ fmap f (Cons x) =+ tagUnique $ x >>^ f++instance Applicative (T inp) where+ pure a = tagUnique $ arr (const a)+ f <*> x = fmap (uncurry ($)) $ f &|& x+++lift0 :: (forall r. CodeGenFunction r out) -> T inp out+lift0 f = lift (CausalCore.map (const f))++lift1 :: (forall r. a -> CodeGenFunction r out) -> T inp a -> T inp out+lift1 f x = CausalCore.map f $& x++lift2 ::+ (forall r. a -> b -> CodeGenFunction r out) ->+ T inp a -> T inp b -> T inp out+lift2 f x y = CausalCore.zipWith f $& x&|&y+++instance (A.PseudoRing b, A.Real b, A.IntegerConstant b) => Num (T a b) where+ fromInteger n = pure (A.fromInteger' n)+ (+) = lift2 A.add+ (-) = lift2 A.sub+ (*) = lift2 A.mul+ abs = lift1 A.abs+ signum = lift1 A.signum++instance (A.Field b, A.Real b, A.RationalConstant b) => Fractional (T a b) where+ fromRational x = pure (A.fromRational' x)+ (/) = lift2 A.fdiv+++instance (A.Additive b) => Additive.C (T a b) where+ zero = pure A.zero+ (+) = lift2 A.add+ (-) = lift2 A.sub+ negate = lift1 A.neg++instance (A.PseudoRing b, A.IntegerConstant b) => Ring.C (T a b) where+ one = pure A.one+ fromInteger n = pure (A.fromInteger' n)+ (*) = lift2 A.mul++instance (A.Field b, A.RationalConstant b) => Field.C (T a b) where+ fromRational' x = pure (A.fromRational' $ Ratio.toRational98 x)+ (/) = lift2 A.fdiv++instance (A.Transcendental b, A.RationalConstant b) => Algebraic.C (T a b) where+ sqrt = lift1 A.sqrt+ root n x = lift2 A.pow x (Field.recip $ Ring.fromInteger n)+ x^/r = lift2 A.pow x (Field.fromRational' r)++instance (A.Transcendental b, A.RationalConstant b) => Trans.C (T a b) where+ pi = lift0 A.pi+ sin = lift1 A.sin+ cos = lift1 A.cos+ (**) = lift2 A.pow+ exp = lift1 A.exp+ log = lift1 A.log++ asin _ = error "LLVM missing intrinsic: asin"+ acos _ = error "LLVM missing intrinsic: acos"+ atan _ = error "LLVM missing intrinsic: atan"+++infixr 0 $&++($&) :: Causal.T b c -> T a b -> T a c+f $& (Cons b) =+ tagUnique $ liftCode f . b+++infixr 3 &|&++(&|&) :: T a b -> T a c -> T a (b,c)+Cons b &|& Cons c =+ tagUnique $ b &&& c+++liftCode :: Causal.T inp out -> Code inp out+liftCode (CausalCore.Cons next start stop) =+ Code+ (\p l a state -> MT.lift (next p l a state))+ start stop++lift :: Causal.T inp out -> T inp out+lift = tagUnique . liftCode++fromSignal :: Signal.T out -> T inp out+fromSignal = lift . CausalClass.fromSignal++tag :: Vault.Key out -> Code inp out -> T inp out+tag key (Code next start stop) =+ Cons $+ Code+ (\p l a s0 -> do+ mb <- State.gets (Vault.lookup key)+ case mb of+ Just b -> return (b,s0)+ Nothing -> do+ bs@(b,_) <- next p l a s0+ State.modify (Vault.insert key b)+ return bs)+ start stop++-- dummy for debugging+_tag :: Vault.Key out -> Code inp out -> T inp out+_tag _ = Cons++tagUnique :: Code inp out -> T inp out+tagUnique code =+ Unsafe.performIO $+ fmap (flip tag code) Vault.newKey++initialize :: Code inp out -> Causal.T inp out+initialize (Code next start stop) =+ CausalCore.Cons+ (\p l a state -> State.evalStateT (next p l a state) Vault.empty)+ start stop++compile :: T inp out -> Causal.T inp out+compile (Cons code) = initialize code++compileSignal :: T () out -> Signal.T out+compileSignal f = CausalClass.toSignal $ compile f+++{- |+Using 'withArgs' you can simplify++> let x = F.lift (arr fst)+> y = F.lift (arr (fst.snd))+> z = F.lift (arr (snd.snd))+> in F.compile (f x y z)++to++> withArgs $ \(x,(y,z)) -> f x y z+-}+withArgs ::+ (MakeArguments inp) =>+ (Arguments (T inp) inp -> T inp out) -> Causal.T inp out+withArgs f = withId $ f . makeArgs++withId :: (T inp inp -> T inp out) -> Causal.T inp out+withId f = compile $ f $ lift Cat.id+++type family Arguments (f :: * -> *) arg++class MakeArguments arg where+ makeArgs :: Functor f => f arg -> Arguments f arg+++{-+I have thought about an Arg type, that marks where to stop descending.+This way we can throw away all of these FlexibleContext instances+and the user can freely choose the granularity of arguments.+However this does not work so easily,+because we would need a functional depedency from, say,+@(Arg a, Arg b)@ to @(a,b)@.+This is the opposite direction to the dependency we use currently.+The 'AnyArg' type provides a solution in this spirit.+-}+type instance Arguments f (LLVM.Value a) = f (LLVM.Value a)+instance MakeArguments (LLVM.Value a) where+ makeArgs = id++type instance Arguments f (MultiValue.T a) = f (MultiValue.T a)+instance MakeArguments (MultiValue.T a) where+ makeArgs = id++{- |+Consistent with pair instance.+You may use 'AnyArg' or 'withGuidedArgs'+to stop descending into the stereo channels.+-}+type instance Arguments f (Stereo.T a) = Stereo.T (Arguments f a)+instance (MakeArguments a) => MakeArguments (Stereo.T a) where+ makeArgs = fmap makeArgs . Stereo.sequence++type instance Arguments f (Serial.Constant n a) = f (Serial.Constant n a)+instance MakeArguments (Serial.Constant n a) where+ makeArgs = id++type instance Arguments f () = f ()+instance MakeArguments () where+ makeArgs = id++type instance Arguments f (a,b) = (Arguments f a, Arguments f b)+instance (MakeArguments a, MakeArguments b) =>+ MakeArguments (a,b) where+ makeArgs f = (makeArgs $ fmap fst f, makeArgs $ fmap snd f)++type instance Arguments f (a,b,c) =+ (Arguments f a, Arguments f b, Arguments f c)+instance (MakeArguments a, MakeArguments b, MakeArguments c) =>+ MakeArguments (a,b,c) where+ makeArgs f =+ (makeArgs $ fmap fst3 f, makeArgs $ fmap snd3 f, makeArgs $ fmap thd3 f)+++{- |+You can use this to explicitly stop breaking of composed data types.+It might be more comfortable to do this using 'withGuidedArgs'.+-}+newtype AnyArg a = AnyArg {getAnyArg :: a}++type instance Arguments f (AnyArg a) = f a+instance MakeArguments (AnyArg a) where+ makeArgs = fmap getAnyArg++++{- |+This is similar to 'withArgs'+but it requires to specify the decomposition depth+using constructors in the arguments.+-}+withGroundArgs ::+ (MakeGroundArguments (T inp) args,+ GroundArguments args ~ inp) =>+ (args -> T inp out) -> Causal.T inp out+withGroundArgs f = withId $ f . makeGroundArgs+++newtype Ground f a = Ground (f a)+++type family GroundArguments args++class (Functor f) => MakeGroundArguments f args where+ makeGroundArgs :: f (GroundArguments args) -> args+++type instance GroundArguments (Ground f a) = a+instance (Functor f, f ~ g) => MakeGroundArguments f (Ground g a) where+ makeGroundArgs = Ground++type instance GroundArguments (Stereo.T a) = Stereo.T (GroundArguments a)+instance MakeGroundArguments f a => MakeGroundArguments f (Stereo.T a) where+ makeGroundArgs f =+ Stereo.cons+ (makeGroundArgs $ fmap Stereo.left f)+ (makeGroundArgs $ fmap Stereo.right f)++type instance GroundArguments () = ()+instance (Functor f) => MakeGroundArguments f () where+ makeGroundArgs _ = ()+++type instance+ GroundArguments (a,b) =+ (GroundArguments a, GroundArguments b)+instance+ (MakeGroundArguments f a, MakeGroundArguments f b) =>+ MakeGroundArguments f (a,b) where+ makeGroundArgs f =+ (makeGroundArgs $ fmap fst f,+ makeGroundArgs $ fmap snd f)++type instance+ GroundArguments (a,b,c) =+ (GroundArguments a, GroundArguments b, GroundArguments c)+instance+ (MakeGroundArguments f a, MakeGroundArguments f b,+ MakeGroundArguments f c) =>+ MakeGroundArguments f (a,b,c) where+ makeGroundArgs f =+ (makeGroundArgs $ fmap fst3 f,+ makeGroundArgs $ fmap snd3 f,+ makeGroundArgs $ fmap thd3 f)++++{- |+This is similar to 'withArgs'+but it allows to specify the decomposition depth using a pattern.+-}+withGuidedArgs ::+ (MakeGuidedArguments pat, PatternArguments pat ~ inp) =>+ pat ->+ (GuidedArguments (T inp) pat -> T inp out) -> Causal.T inp out+withGuidedArgs p f = withId $ f . makeGuidedArgs p+++data Atom a = Atom++atom :: Atom a+atom = Atom+++type family GuidedArguments (f :: * -> *) pat+type family PatternArguments pat++class MakeGuidedArguments pat where+ makeGuidedArgs ::+ Functor f =>+ pat -> f (PatternArguments pat) -> GuidedArguments f pat+++type instance GuidedArguments f (Atom a) = f a+type instance PatternArguments (Atom a) = a+instance MakeGuidedArguments (Atom a) where+ makeGuidedArgs Atom = id++type instance GuidedArguments f (Stereo.T a) = Stereo.T (GuidedArguments f a)+type instance PatternArguments (Stereo.T a) = Stereo.T (PatternArguments a)+instance MakeGuidedArguments a => MakeGuidedArguments (Stereo.T a) where+ makeGuidedArgs pat f =+ Stereo.cons+ (makeGuidedArgs (Stereo.left pat) $ fmap Stereo.left f)+ (makeGuidedArgs (Stereo.right pat) $ fmap Stereo.right f)++type instance GuidedArguments f () = f ()+type instance PatternArguments () = ()+instance MakeGuidedArguments () where+ makeGuidedArgs () = id++type instance+ GuidedArguments f (a,b) =+ (GuidedArguments f a, GuidedArguments f b)+type instance+ PatternArguments (a,b) =+ (PatternArguments a, PatternArguments b)+instance (MakeGuidedArguments a, MakeGuidedArguments b) =>+ MakeGuidedArguments (a,b) where+ makeGuidedArgs (pa,pb) f =+ (makeGuidedArgs pa $ fmap fst f,+ makeGuidedArgs pb $ fmap snd f)++type instance+ GuidedArguments f (a,b,c) =+ (GuidedArguments f a, GuidedArguments f b, GuidedArguments f c)+type instance+ PatternArguments (a,b,c) =+ (PatternArguments a, PatternArguments b, PatternArguments c)+instance+ (MakeGuidedArguments a, MakeGuidedArguments b, MakeGuidedArguments c) =>+ MakeGuidedArguments (a,b,c) where+ makeGuidedArgs (pa,pb,pc) f =+ (makeGuidedArgs pa $ fmap fst3 f,+ makeGuidedArgs pb $ fmap snd3 f,+ makeGuidedArgs pc $ fmap thd3 f)++++{- |+Alternative to withGuidedArgs.+This way of pattern construction is even Haskell 98.+-}+withPreparedArgs ::+ PrepareArguments (T inp) inp a ->+ (a -> T inp out) -> Causal.T inp out+withPreparedArgs (PrepareArguments prepare) f = withId $ f . prepare++withPreparedArgs2 ::+ PrepareArguments (T (inp0, inp1)) inp0 a ->+ PrepareArguments (T (inp0, inp1)) inp1 b ->+ (a -> b -> T (inp0, inp1) out) ->+ Causal.T (inp0, inp1) out+withPreparedArgs2 prepareA prepareB f =+ withPreparedArgs (pairArgs prepareA prepareB) (uncurry f)++newtype PrepareArguments f merged separated =+ PrepareArguments (f merged -> separated)++atomArg :: PrepareArguments f a (f a)+atomArg = PrepareArguments id++stereoArgs ::+ (Functor f) =>+ PrepareArguments f a b ->+ PrepareArguments f (Stereo.T a) (Stereo.T b)+stereoArgs (PrepareArguments p) =+ PrepareArguments $ fmap p . Stereo.sequence++pairArgs ::+ (Functor f) =>+ PrepareArguments f a0 b0 ->+ PrepareArguments f a1 b1 ->+ PrepareArguments f (a0,a1) (b0,b1)+pairArgs (PrepareArguments p0) (PrepareArguments p1) =+ PrepareArguments $ \f -> (p0 $ fmap fst f, p1 $ fmap snd f)++tripleArgs ::+ (Functor f) =>+ PrepareArguments f a0 b0 ->+ PrepareArguments f a1 b1 ->+ PrepareArguments f a2 b2 ->+ PrepareArguments f (a0,a1,a2) (b0,b1,b2)+tripleArgs (PrepareArguments p0) (PrepareArguments p1) (PrepareArguments p2) =+ PrepareArguments $ \f ->+ (p0 $ fmap fst3 f, p1 $ fmap snd3 f, p2 $ fmap thd3 f)
+ src/Synthesizer/LLVM/Causal/FunctionalPlug.hs view
@@ -0,0 +1,376 @@+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE FlexibleContexts #-}+module Synthesizer.LLVM.Causal.FunctionalPlug (+ T,+ ($&), (&|&),+ run, runPlugOut,+ fromSignal, plug, askParameter, Input,+ withArgs, withArgsPlugOut,+ MakeArguments, Arguments, makeArgs,+ ) where++import qualified Synthesizer.LLVM.Plug.Input as PIn+import qualified Synthesizer.LLVM.Plug.Output as POut++import qualified Synthesizer.LLVM.Causal.Parameterized as Parameterized+import qualified Synthesizer.LLVM.Causal.Render as CausalRender+import qualified Synthesizer.LLVM.Causal.Private as CausalPriv+import qualified Synthesizer.LLVM.Causal.Process as Causal+import qualified Synthesizer.LLVM.Generator.Signal as Sig++import qualified Synthesizer.Causal.Class as CausalClass+import qualified Synthesizer.CausalIO.Process as PIO+import qualified Synthesizer.Generic.Cut as CutG+import qualified Synthesizer.Zip as Zip++import qualified Data.EventList.Relative.BodyTime as EventListBT+import qualified Data.StorableVector as SV++import LLVM.DSL.Expression (Exp(Exp))++import qualified LLVM.Extra.Multi.Value.Marshal as Marshal+import qualified LLVM.Extra.MaybeContinuation as MaybeCont+import qualified LLVM.Extra.Arithmetic as A+import LLVM.Core (CodeGenFunction)++import Data.IORef (newIORef, readIORef)++import qualified Number.Ratio as Ratio+import qualified Algebra.Transcendental as Trans+import qualified Algebra.Algebraic as Algebraic+import qualified Algebra.Field as Field+import qualified Algebra.Ring as Ring+import qualified Algebra.Additive as Additive++import qualified Control.Monad.Trans.Reader as MR+import qualified Control.Monad.Trans.State as MS+import Control.Monad.IO.Class (liftIO)++import qualified Data.Set as Set+import qualified Data.Vault.Lazy as Vault+import Data.Vault.Lazy (Vault)+import Data.Unique (Unique, newUnique)+import Data.Maybe (fromMaybe)++import Control.Arrow ((^<<), (<<^), arr, first, second)+import Control.Category (id, (.))+import Control.Applicative (Applicative, (<*>), pure, liftA2, liftA3)++import qualified System.Unsafe as Unsafe++import Prelude hiding (id, (.))+++{- |+This data type detects sharing.+-}+{-+There are two levels of the use of keys.+At the top level, in T's State monad,+we store an object id in order to check,+whether we have already seen a certain object.+If we encounter a known object+then we use the Simple constructor+and fetch the stored CausalP output+within the causal process enclosed in Simple.+This and the causal process in the Plugged constructor+are the second level.+These arrows handle a Vault like a state monad+and insert all values they produce into the Vault.+-}+newtype T pp inp out =+ Cons (MS.State (Set.Set Unique) (Core pp inp out))++{-+We need to hide the x and y types+since these types grow when combining Cores,+and then we could not define numeric instances.+-}+data Core pp inp out =+ forall x y. CutG.Read x =>+ Plugged+ (pp -> inp -> x)+ (PIn.T x y)+ (Causal.T (y, Vault) (out, Vault))+ |+ {-+ The Simple constructor is needed for reusing shared CausalP processes+ and for input without external representation. (a Plug.Input)+ -}+ Simple (Causal.T Vault (out, Vault))+++applyCore ::+ Causal.T (a, Vault) (b, Vault) ->+ Core pp inp a ->+ Core pp inp b+applyCore f core =+ case core of+ Plugged prep plg process -> Plugged prep plg (f . process)+ Simple process -> Simple (f . process)++combineCore ::+ Core pp inp a ->+ Core pp inp b ->+ Core pp inp (a,b)+combineCore (Plugged prepA plugA processA) (Plugged prepB plugB processB) =+ Plugged+ (\p -> Zip.arrowFanout (prepA p) (prepB p))+ (PIn.split plugA plugB)+ ((\(a,(b,v)) -> ((a,b), v)) ^<< second processB+ . arr (\((a,v),b) -> (a,(b,v))) .+ first processA <<^ (\((a,b),v) -> ((a,v),b)))+combineCore (Simple processA) (Plugged prepB plugB processB) =+ Plugged prepB plugB+ ((\(b,(a,v)) -> ((a,b), v)) ^<< second processA . processB)+combineCore (Plugged prepA plugA processA) (Simple processB) =+ Plugged prepA plugA+ ((\(a,(b,v)) -> ((a,b), v)) ^<< second processB . processA)+combineCore (Simple processA) (Simple processB) =+ Simple ((\(a,(b,v)) -> ((a,b), v)) ^<< second processB . processA)+++reuseCore :: Vault.Key out -> Core pp inp out+reuseCore key =+ Simple $ arr $ \vault ->+ (fromMaybe (error "key must have been lost") $ Vault.lookup key vault,+ vault)+++tag ::+ Unique -> Vault.Key out ->+ MS.State (Set.Set Unique) (Core pp inp out) ->+ T pp inp out+tag unique key stateCore = Cons $ do+ alreadySeen <- MS.gets (Set.member unique)+ if alreadySeen+ then return $ reuseCore key+ else do+ MS.modify (Set.insert unique)+ fmap (applyCore (arr $ \(a,v) -> (a, Vault.insert key a v))) stateCore++tagUnique ::+ MS.State (Set.Set Unique) (Core pp inp out) ->+ T pp inp out+tagUnique core =+ Unsafe.performIO $+ liftA3 tag newUnique Vault.newKey (pure core)+++infixr 0 $&++($&) ::+ Causal.T a b ->+ T pp inp a ->+ T pp inp b+f $& Cons core =+ tagUnique $ fmap (applyCore $ first f) core+++infixr 3 &|&++(&|&) ::+ T pp inp a ->+ T pp inp b ->+ T pp inp (a,b)+Cons coreA &|& Cons coreB =+ tagUnique $ liftA2 combineCore coreA coreB+++instance Functor (Core pp inp) where+ fmap f (Simple process) = Simple (fmap (first f) process)+ fmap f (Plugged prep plg process) = Plugged prep plg (fmap (first f) process)++instance Applicative (Core pp inp) where+ pure a = lift0Core $ pure a+ f <*> x = fmap (uncurry ($)) $ combineCore f x++lift0Core :: (forall r. CodeGenFunction r out) -> Core pp inp out+lift0Core f = Simple (CausalPriv.map (\v -> fmap (flip (,) v) f))+++instance Functor (T pp inp) where+ fmap f (Cons x) = tagUnique $ fmap (fmap f) x++instance Applicative (T pp inp) where+ pure a = tagUnique $ pure $ pure a+ f <*> x = fmap (uncurry ($)) $ f &|& x+++lift0 :: (forall r. CodeGenFunction r out) -> T pp inp out+lift0 f = tagUnique $ pure $ lift0Core f++lift1 ::+ (forall r. a -> CodeGenFunction r out) ->+ T pp inp a -> T pp inp out+lift1 f x = CausalPriv.map f $& x++lift2 ::+ (forall r. a -> b -> CodeGenFunction r out) ->+ T pp inp a -> T pp inp b -> T pp inp out+lift2 f x y = CausalPriv.zipWith f $& x&|&y+++instance+ (A.PseudoRing b, A.Real b, A.IntegerConstant b) =>+ Num (T pp a b) where+ fromInteger n = pure (A.fromInteger' n)+ (+) = lift2 A.add+ (-) = lift2 A.sub+ (*) = lift2 A.mul+ abs = lift1 A.abs+ signum = lift1 A.signum++instance+ (A.Field b, A.Real b, A.RationalConstant b) =>+ Fractional (T pp a b) where+ fromRational x = pure (A.fromRational' x)+ (/) = lift2 A.fdiv+++instance (A.Additive b) => Additive.C (T pp a b) where+ zero = pure A.zero+ (+) = lift2 A.add+ (-) = lift2 A.sub+ negate = lift1 A.neg++instance (A.PseudoRing b, A.IntegerConstant b) => Ring.C (T pp a b) where+ one = pure A.one+ fromInteger n = pure (A.fromInteger' n)+ (*) = lift2 A.mul++instance (A.Field b, A.RationalConstant b) => Field.C (T pp a b) where+ fromRational' x = pure (A.fromRational' $ Ratio.toRational98 x)+ (/) = lift2 A.fdiv++instance+ (A.Transcendental b, A.RationalConstant b) =>+ Algebraic.C (T pp a b) where+ sqrt = lift1 A.sqrt+ root n x = lift2 A.pow x (Field.recip $ Ring.fromInteger n)+ x^/r = lift2 A.pow x (Field.fromRational' r)++instance+ (A.Transcendental b, A.RationalConstant b) =>+ Trans.C (T pp a b) where+ pi = lift0 A.pi+ sin = lift1 A.sin+ cos = lift1 A.cos+ (**) = lift2 A.pow+ exp = lift1 A.exp+ log = lift1 A.log++ asin _ = error "LLVM missing intrinsic: asin"+ acos _ = error "LLVM missing intrinsic: acos"+ atan _ = error "LLVM missing intrinsic: atan"++++fromSignal :: Sig.T a -> T pp inp a+fromSignal sig =+ tagUnique $ pure $ Simple (CausalClass.feedFst sig)++++type Input pp a = MR.Reader (pp, a)++plug ::+ (CutG.Read b, PIn.Default b) =>+ Input pp a b ->+ T pp a (PIn.Element b)+plug accessor =+ tagUnique $ pure $+ Plugged+ (curry $ MR.runReader accessor)+ PIn.deflt+ id++askParameter :: Input pp a pp+askParameter = MR.asks fst+++runPlugOut ::+ (Marshal.C pl) =>+ (Exp pl -> T pp a x) -> POut.T x b ->+ IO (pp -> pl -> PIO.T a b)+runPlugOut func pout = do+ let name = "FunctionalPlug.runPlugOut"+ ref <- newIORef $ error $ name ++ ": uninitialized parameter reference"+ case func (Exp (liftIO (readIORef ref))) of+ Cons core ->+ case MS.evalState core Set.empty of+ Simple _ -> error $ name ++ ": no substantial input available"+ -- Simple process ->+ -- CausalRender.processIOCore pin process pout+ Plugged prep pin process ->+ fmap (\f pp pl -> f (return (pl, return ())) <<^ prep pp) $+ case fst ^<< process <<^ flip (,) Vault.empty of+ CausalPriv.Cons next start stop ->+ (\paramd ->+ CausalRender.processIOParameterized pin paramd pout) $+ Parameterized.Cons+ (\p global local a state ->+ MaybeCont.lift (Parameterized.loadParam ref p) >>+ next global local a state)+ (\p ->+ Parameterized.loadParam ref p >> start)+ (\p global ->+ Parameterized.loadParam ref p >> stop global)++run ::+ (Marshal.C pl) =>+ (POut.Default b) =>+ (Exp pl -> T pp a (POut.Element b)) ->+ IO (pp -> pl -> PIO.T a b)+run f = runPlugOut f POut.deflt+++{- |+Cf. 'F.withArgs'.+-}+withArgs ::+ (Marshal.C pl) =>+ (MakeArguments a, POut.Default b) =>+ (Arguments (Input pp a) a -> Exp pl -> T pp a (POut.Element b)) ->+ IO (pp -> pl -> PIO.T a b)+withArgs f = withArgsPlugOut f POut.deflt++withArgsPlugOut ::+ (Marshal.C pl) =>+ (MakeArguments a) =>+ (Arguments (Input pp a) a -> Exp pl -> T pp a x) ->+ POut.T x b ->+ IO (pp -> pl -> PIO.T a b)+withArgsPlugOut = withArgsPlugOutStart (MR.asks snd)++withArgsPlugOutStart ::+ (Marshal.C pl) =>+ (MakeArguments a) =>+ Input pp a a ->+ (Arguments (Input pp a) a -> Exp pl -> T pp a x) ->+ POut.T x b ->+ IO (pp -> pl -> PIO.T a b)+withArgsPlugOutStart fid f = runPlugOut (f (makeArgs fid))++++type family Arguments (f :: * -> *) arg++class MakeArguments arg where+ makeArgs :: Functor f => f arg -> Arguments f arg+++type instance Arguments f (EventListBT.T i a) = f (EventListBT.T i a)+instance MakeArguments (EventListBT.T i a) where+ makeArgs = id++type instance Arguments f (SV.Vector a) = f (SV.Vector a)+instance MakeArguments (SV.Vector a) where+ makeArgs = id++type instance Arguments f (Zip.T a b) = (Arguments f a, Arguments f b)+instance (MakeArguments a, MakeArguments b) =>+ MakeArguments (Zip.T a b) where+ makeArgs f = (makeArgs $ fmap Zip.first f, makeArgs $ fmap Zip.second f)
+ src/Synthesizer/LLVM/Causal/Helix.hs view
@@ -0,0 +1,622 @@+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE RebindableSyntax #-}+{- |+<http://arxiv.org/abs/0911.5171>+-}+module Synthesizer.LLVM.Causal.Helix (+ -- * time and phase control based on the helix model+ static,+ staticPacked,+ dynamic,+ dynamicLimited,++ -- * useful control curves+ zigZag,+ zigZagPacked,+ zigZagLong,+ zigZagLongPacked,+ ) where++import qualified Synthesizer.LLVM.Causal.ProcessPacked as CausalPS+import qualified Synthesizer.LLVM.Causal.Private as CausalPriv+import qualified Synthesizer.LLVM.Causal.Process as Causal+import qualified Synthesizer.LLVM.Causal.Functional as Func+import qualified Synthesizer.LLVM.Generator.Source as Source+import qualified Synthesizer.LLVM.Generator.SignalPacked as SigPS+import qualified Synthesizer.LLVM.Generator.Private as SigPriv+import qualified Synthesizer.LLVM.Generator.Signal as Sig+import qualified Synthesizer.LLVM.Causal.RingBufferForward as RingBuffer+import qualified Synthesizer.LLVM.Frame.SerialVector as SerialExp+import qualified Synthesizer.LLVM.Frame.SerialVector.Code as Serial+import qualified Synthesizer.LLVM.Frame.SerialVector.Class as SerialClass+import qualified Synthesizer.LLVM.Interpolation as Ip+import Synthesizer.LLVM.Causal.Functional (($&), (&|&))+import Synthesizer.LLVM.Private (noLocalPtr)++import Synthesizer.Causal.Class (($*), ($<))++import qualified LLVM.DSL.Expression.Vector as ExprVec+import qualified LLVM.DSL.Expression as Expr+import LLVM.DSL.Expression (Exp, (<*), (>=*))++import qualified LLVM.Extra.Multi.Value.Storable as Storable+import qualified LLVM.Extra.Multi.Value.Marshal as Marshal+import qualified LLVM.Extra.Multi.Value.Vector as MultiValueVec+import qualified LLVM.Extra.Multi.Value as MultiValue+import qualified LLVM.Extra.Multi.Vector as MultiVector+import qualified LLVM.Extra.Arithmetic as A+import qualified LLVM.Extra.Memory as Memory++import qualified LLVM.Core as LLVM++import qualified Type.Data.Num.Decimal as TypeNum++import Data.Word (Word)++import Control.Arrow (first, (<<<))+import Control.Category (id)+import Control.Functor.HT (unzip)+import Data.Traversable (mapM)+import Data.Tuple.HT (mapPair, mapFst)++import qualified Algebra.Ring as Ring++import NumericPrelude.Numeric hiding (splitFraction)+import NumericPrelude.Base hiding (unzip, zip, mapM, id)++import Prelude ()+++{- |+Inputs are @(shape, phase)@.++The shape parameter is limited at the beginning and at the end+such that only available data is used for interpolation.+Actually, we allow almost one step less than possible,+since the right boundary of the interval of admissible @shape@ values is open.+-}+static ::+ (Ip.C nodesStep, Ip.C nodesLeap) =>+ (Storable.C vh, MultiValue.T vh ~ v) =>+ (Marshal.C a, MultiValue.Field a, MultiValue.RationalConstant a) =>+ (MultiValue.Fraction a, MultiValue.NativeFloating a ar) =>+ (MultiValueVec.NativeFloating a ar, MultiValue.T a ~ am) =>+ (forall r. Ip.T r nodesLeap am v) ->+ (forall r. Ip.T r nodesStep am v) ->+ Exp Int ->+ Exp a ->+ Exp (Source.StorableVector vh) ->+ Causal.T (am, am) v+static ipLeap ipStep periodInt period vec =+ let periodWord = wordFromInt periodInt+ cellMargin = combineMarginParams ipLeap ipStep periodInt+ in interpolateCell ipLeap ipStep+ <<<+ first (peekCell cellMargin periodWord vec)+ <<<+ flattenShapePhaseProc periodWord period+ <<<+ first+ (limitShape cellMargin periodInt+ (intFromWord $ Source.storableVectorLength vec))++intFromWord :: Exp Word -> Exp Int+intFromWord = Expr.liftReprM LLVM.bitcast++wordFromInt :: Exp Int -> Exp Word+wordFromInt = Expr.liftReprM LLVM.bitcast++staticPacked ::+ (Ip.C nodesStep, Ip.C nodesLeap) =>+ (Storable.C vh, MultiValue.T vh ~ ve, SerialClass.Element v ~ ve) =>+ (SerialClass.Size (nodesLeap (nodesStep v)) ~ n,+ SerialClass.Write (nodesLeap (nodesStep v)),+ SerialClass.Element (nodesLeap (nodesStep v)) ~+ nodesLeap (nodesStep (SerialClass.Element v))) =>+ (TypeNum.Positive n) =>+ (Marshal.C a, MultiVector.Field a, MultiVector.Real a,+ MultiVector.Fraction a, MultiVector.RationalConstant a,+ MultiVector.NativeFloating n a ar) =>+ (forall r. Ip.T r nodesLeap (Serial.Value n a) v) ->+ (forall r. Ip.T r nodesStep (Serial.Value n a) v) ->+ Exp Int ->+ Exp a ->+ Exp (Source.StorableVector vh) ->+ Causal.T (Serial.Value n a, Serial.Value n a) v+staticPacked ipLeap ipStep periodInt period vec =+ let periodWord = wordFromInt periodInt+ cellMargin = combineMarginParams ipLeap ipStep periodInt+ in interpolateCell ipLeap ipStep+ <<<+ first (CausalPS.pack+ (peekCell (elementMargin cellMargin) periodWord vec))+ <<<+ flattenShapePhaseProcPacked periodWord period+ <<<+ first+ (limitShapePacked cellMargin periodInt+ (intFromWord $ Source.storableVectorLength vec))+++{- |+In contrast to 'dynamic' this one ends+when the end of the manipulated signal is reached.+-}+dynamicLimited ::+ (Ip.C nodesStep, Ip.C nodesLeap) =>+ (Marshal.C a, MultiValue.Field a, MultiValue.Fraction a,+ MultiValue.Select a, MultiValue.Comparison a,+ MultiValue.NativeFloating a ar,+ MultiValue.RationalConstant a,+ MultiValueVec.NativeFloating a ar) =>+ (MultiValue.T a ~ am) =>+ (Memory.C v) =>+ (forall r. Ip.T r nodesLeap am v) ->+ (forall r. Ip.T r nodesStep am v) ->+ Exp Int ->+ Exp a ->+ Sig.T v ->+ Causal.T (am, am) v+dynamicLimited ipLeap ipStep periodInt period sig =+ dynamicGen+ (\cellMargin (skips, fracs) ->+ let windows =+ (RingBuffer.trackSkip+ (wordFromInt $ Ip.marginNumberExp cellMargin) sig)+ $& skips+ in (windows,+ Causal.delay1 zero $& skips,+ Causal.delay1 zero $& fracs))+ ipLeap ipStep periodInt period++{- |+If the time control exceeds the end of the input signal,+then the last waveform is locked.+This is analogous to 'static'.+-}+dynamic ::+ (Ip.C nodesStep, Ip.C nodesLeap) =>+ (Marshal.C a, MultiValue.Field a, MultiValue.Fraction a,+ MultiValue.Select a, MultiValue.Comparison a,+ MultiValue.NativeFloating a ar,+ MultiValue.RationalConstant a,+ MultiValueVec.NativeFloating a ar) =>+ (MultiValue.T a ~ am) =>+ (Memory.C v) =>+ (forall r. Ip.T r nodesLeap am v) ->+ (forall r. Ip.T r nodesStep am v) ->+ Exp Int ->+ Exp a ->+ Sig.T v ->+ Causal.T (am, am) v+dynamic ipLeap ipStep periodInt period sig =+ dynamicGen+ (\cellMargin (skips, fracs) ->+ let {-+ For conformance with 'static'+ we stop one step before the definite end.+ We achieve this by using a buffer+ that is one step longer than necessary.+ -}+ ((running, actualSkips), windows) =+ mapFst unzip $ unzip $+ (RingBuffer.trackSkipHold+ (wordFromInt (Ip.marginNumberExp cellMargin) + 1) sig)+ $& skips+ holdFracs =+ Causal.zipWith (\r fr -> Expr.select r fr 1)+ $&+ running &|& (Causal.delay1 zero $& fracs)+ in (windows, actualSkips, holdFracs))+ ipLeap ipStep periodInt period++dynamicGen ::+ (Ip.C nodesStep, Ip.C nodesLeap) =>+ (Marshal.C a, MultiValue.Field a, MultiValue.Fraction a,+ MultiValue.Select a, MultiValue.Comparison a,+ MultiValue.NativeFloating a ar,+ MultiValue.RationalConstant a,+ MultiValueVec.NativeFloating a ar) =>+ (MultiValue.T a ~ am) =>+ (Memory.C v) =>+ (Exp (Ip.Margin (nodesLeap (nodesStep v))) ->+ (Func.T (am, am) (MultiValue.T Word),+ Func.T (am, am) am) ->+ (Func.T (am, am) (RingBuffer.T v),+ Func.T (am, am) (MultiValue.T Word),+ Func.T (am, am) am)) ->+ (forall r. Ip.T r nodesLeap am v) ->+ (forall r. Ip.T r nodesStep am v) ->+ Exp Int ->+ Exp a ->+ Causal.T (am, am) v+dynamicGen limitMaxShape ipLeap ipStep periodInt period =+ let periodWord = wordFromInt periodInt+ cellMargin = combineMarginParams ipLeap ipStep periodInt+ minShape = wordFromInt $ fst $ shapeMargin cellMargin periodInt++ in Func.withArgs $ \(shape, phase) ->+ let (windows, skips, fracs) =+ limitMaxShape cellMargin $+ unzip (integrateFrac $& (limitMinShape minShape $& shape))+ (offsets, shapePhases) =+ unzip+ (flattenShapePhaseProc periodWord period $&+ (constantFromWord minShape + fracs)+ &|&+ (Causal.osciCoreSync $&+ phase+ &|&+ negate+ (Causal.map ((/period)) $&+ (Causal.map Expr.fromIntegral $& skips))))+ in interpolateCell ipLeap ipStep $&+ (CausalPriv.map+ (\(buffer, offset) -> do+ p <- Expr.unExp periodWord+ cellFromBuffer p buffer offset)+ $&+ windows+ &|&+ offsets)+ &|&+ shapePhases++constantFromWord ::+ (MultiValue.NativeFloating a ar) =>+ Exp Word -> Func.T inp (MultiValue.T a)+constantFromWord x =+ Func.fromSignal (Causal.map Expr.fromIntegral $* Sig.constant x)++limitMinShape ::+ (Marshal.C a, MultiValue.Select a, MultiValue.Comparison a,+ MultiValue.NativeFloating a ar) =>+ Exp Word ->+ Causal.T (MultiValue.T a) (MultiValue.T a)+limitMinShape xLim =+ Causal.mapAccum+ (\x lim ->+ Expr.unzip $+ Expr.select (x>=*lim) (Expr.zip (x-lim) zero) (Expr.zip zero (lim-x)))+ (Expr.fromIntegral xLim)++integrateFrac ::+ (Marshal.C a, MultiValue.Additive a,+ MultiValueVec.NativeFloating a ar, LLVM.IsPrimitive ar) =>+ Causal.T (MultiValue.T a) (MultiValue.T Word, MultiValue.T a)+integrateFrac =+ Causal.mapAccum+ (\a frac ->+ let s = ExprVec.splitFractionToInt (a+frac)+ in (s, snd s))+ zero+++interpolateCell ::+ (Ip.C nodesStep, Ip.C nodesLeap) =>+ (forall r. Ip.T r nodesLeap a v) ->+ (forall r. Ip.T r nodesStep a v) ->+ Causal.T (nodesLeap (nodesStep v), (a, a)) v+interpolateCell ipLeap ipStep =+ CausalPriv.map+ (\(nodes, (leap,step)) ->+ ipLeap leap =<< mapM (ipStep step) nodes)++cellFromBuffer ::+ (Memory.C a, Ip.C nodesLeap, Ip.C nodesStep) =>+ MultiValue.T Word ->+ RingBuffer.T a ->+ MultiValue.T Word ->+ LLVM.CodeGenFunction r (nodesLeap (nodesStep a))+cellFromBuffer periodInt buffer offset =+ Ip.indexNodesExp+ (Ip.indexNodesExp (flip RingBuffer.index buffer) A.one)+ periodInt offset++elementMargin ::+ Exp (Ip.Margin (nodesLeap (nodesStep v))) ->+ Exp (Ip.Margin (nodesLeap (nodesStep (SerialClass.Element v))))+elementMargin = Expr.liftReprM return++peekCell ::+ (Storable.C a, MultiValue.T a ~ value, Ip.C nodesLeap, Ip.C nodesStep) =>+ Exp (Ip.Margin (nodesLeap (nodesStep value))) ->+ Exp Word ->+ Exp (Source.StorableVector a) ->+ Causal.T (MultiValue.T Word) (nodesLeap (nodesStep value))+peekCell margin periodWord vec =+ CausalPriv.map+ (\n -> do+ ~(MultiValue.Cons (ptr,_l)) <- Expr.unExp vec+ ~(MultiValue.Cons offset) <-+ Expr.unExp $ intFromWord (Expr.lift0 n) - Ip.marginOffsetExp margin+ perInt <- Expr.unExp $ intFromWord periodWord+ Ip.loadNodesExp (Ip.loadNodesExp Storable.load A.one) perInt+ =<< Storable.advancePtr offset ptr)+++flattenShapePhaseProc ::+ (MultiValue.Field a, MultiValue.RationalConstant a, MultiValue.Fraction a) =>+ (MultiValue.NativeFloating a ar, MultiValueVec.NativeFloating a ar) =>+ Exp Word ->+ Exp a ->+ Causal.T+ (MultiValue.T a, MultiValue.T a)+ (MultiValue.T Word, (MultiValue.T a, MultiValue.T a))+flattenShapePhaseProc periodInt period =+ Causal.map+ (\(shape, phase) -> flattenShapePhase periodInt period shape phase)++_flattenShapePhaseProc ::+ (MultiValue.Field a, MultiValue.RationalConstant a, MultiValue.Fraction a) =>+ (MultiValue.NativeFloating a ar) =>+ Exp Word ->+ Exp a ->+ Causal.T+ (MultiValue.T a, MultiValue.T a)+ (MultiValue.T Word, (MultiValue.T a, MultiValue.T a))+_flattenShapePhaseProc period32 period =+ CausalPriv.map+ (\(shape, phase) -> do+ perInt <- Expr.unExp period32+ per <- Expr.unExp period+ _flattenShapePhase perInt per shape phase)++flattenShapePhaseProcPacked ::+ (TypeNum.Positive n, MultiVector.Field a, MultiVector.RationalConstant a) =>+ (MultiVector.Fraction a, MultiVector.NativeFloating n a ar) =>+ Exp Word ->+ Exp a ->+ Causal.T+ (Serial.Value n a, Serial.Value n a)+ (Serial.Value n Word, (Serial.Value n a, Serial.Value n a))+flattenShapePhaseProcPacked periodInt period =+ Causal.zipWith+ (flattenShapePhase+ (SerialExp.upsample periodInt) (SerialExp.upsample period))++flattenShapePhase ::+ (MultiValue.Field a, MultiValue.RationalConstant a, MultiValue.Fraction a) =>+ (MultiValueVec.NativeFloating a ar, MultiValueVec.NativeInteger i ir) =>+ (LLVM.ShapeOf ir ~ LLVM.ShapeOf ar) =>+ Exp i -> Exp a ->+ Exp a -> Exp a ->+ (Exp i, (Exp a, Exp a))+flattenShapePhase periodInt period shape phase =+ let qLeap = Expr.fraction $ shape/period - phase+ (n,qStep) =+ ExprVec.splitFractionToInt $+ {-+ If 'shape' is correctly limited,+ the value is always non-negative algebraically,+ but maybe not numerically.+ -}+ Expr.max zero $+ shape - qLeap * ExprVec.fromIntegral periodInt+ in (n,(qLeap,qStep))++_flattenShapePhase ::+ (MultiValue.Field a, MultiValue.RationalConstant a, MultiValue.Fraction a) =>+ (MultiValue.NativeFloating a ar, MultiValue.NativeInteger i ir) =>+ MultiValue.T i ->+ MultiValue.T a ->+ MultiValue.T a -> MultiValue.T a ->+ LLVM.CodeGenFunction r (MultiValue.T i, (MultiValue.T a, MultiValue.T a))+_flattenShapePhase = Expr.unliftM4 $ \periodInt period shape phase ->+ let qLeap = Expr.fraction $ shape/period - phase+ (n,qStep) =+ Expr.splitFractionToInt $+ {-+ If 'shape' is correctly limited,+ the value is always non-negative algebraically,+ but maybe not numerically.+ -}+ Expr.max zero $+ shape - qLeap * Expr.fromIntegral periodInt+ in (n,(qLeap,qStep))+++limitShape ::+ (Ip.C nodesStep, Ip.C nodesLeap) =>+ (Marshal.C t, MultiValue.Real t, MultiValue.NativeFloating t tr) =>+ (i ~ Int) =>+ Exp (Ip.Margin (nodesLeap (nodesStep value))) ->+ Exp i -> Exp i -> Causal.MV t t+limitShape margin periodInt len =+ Causal.zipWith Expr.limit+ $<+ limitShapeSignal margin periodInt len++limitShapePacked ::+ (Ip.C nodesStep, Ip.C nodesLeap) =>+ (Marshal.C t, MultiValue.NativeFloating t tr) =>+ (TypeNum.Positive n, MultiVector.Real t) =>+ (i ~ Int) =>+ Exp (Ip.Margin (nodesLeap (nodesStep value))) ->+ Exp i ->+ Exp i ->+ Causal.T (Serial.Value n t) (Serial.Value n t)+limitShapePacked margin periodInt len =+ Causal.zipWith+ (\(minShape,maxShape) shape ->+ SerialExp.limit+ (SerialExp.upsample minShape,+ SerialExp.upsample maxShape)+ shape)+ $<+ limitShapeSignal margin periodInt len++limitShapeSignal ::+ (Ip.C nodesStep, Ip.C nodesLeap) =>+ (Marshal.C t, MultiValue.NativeFloating t tr) =>+ (i ~ Int) =>+ Exp (Ip.Margin (nodesLeap (nodesStep value))) ->+ Exp i ->+ Exp i ->+ Sig.T (MultiValue.T t, MultiValue.T t)+limitShapeSignal margin periodInt len =+ SigPriv.Cons+ (\minMax -> noLocalPtr $ \() -> return (minMax, ()))+ (do+ limits <-+ Expr.bundle+ (mapPair (Expr.fromIntegral, Expr.fromIntegral) $+ shapeLimits margin periodInt len)+ return (limits, ()))+ (const $ return ())+++shapeLimits ::+ (Ip.C nodesLeap, Ip.C nodesStep, Exp Int ~ t) =>+ Exp (Ip.Margin (nodesLeap (nodesStep value))) ->+ t -> t -> (t, t)+shapeLimits margin periodInt len =+ case shapeMargin margin periodInt of+ (leftMargin, rightMargin) -> (leftMargin, len - rightMargin)++shapeMargin ::+ (Ip.C nodesLeap, Ip.C nodesStep, Exp Int ~ i) =>+ Exp (Ip.Margin (nodesLeap (nodesStep value))) ->+ i -> (i, i)+shapeMargin margin periodInt =+ let (marginNumber, marginOffset) =+ Expr.unzip $+ Expr.lift1 (uncurry MultiValue.zip . Ip.unzipMargin) margin+ leftMargin = marginOffset + periodInt+ rightMargin = marginNumber - leftMargin+ in (leftMargin, rightMargin)++_shapeLimits ::+ (Ip.C nodesLeap, Ip.C nodesStep) =>+ (MultiValue.NativeFloating t tr) =>+ (MultiValue.Additive t) =>+ Ip.Margin (nodesLeap (nodesStep value)) ->+ Exp Word -> Exp t -> (Exp t, Exp t)+_shapeLimits margin periodInt len =+ let (leftMargin, rightMargin) = _shapeMargin margin periodInt+ in (Expr.fromIntegral leftMargin, len - Expr.fromIntegral rightMargin)++_shapeMargin ::+ (Ip.C nodesLeap, Ip.C nodesStep, Ring.C i) =>+ Ip.Margin (nodesLeap (nodesStep value)) ->+ i -> (i, i)+_shapeMargin margin periodInt =+ let leftMargin = fromIntegral (Ip.marginOffset margin) + periodInt+ rightMargin = fromIntegral (Ip.marginNumber margin) - leftMargin+ in (leftMargin, rightMargin)++combineMarginParams ::+ (Ip.C nodesStep, Ip.C nodesLeap) =>+ (forall r. Ip.T r nodesLeap a v) ->+ (forall r. Ip.T r nodesStep a v) ->+ Exp Int ->+ Exp (Ip.Margin (nodesLeap (nodesStep v)))+combineMarginParams ipLeap ipStep periodInt =+ let marginLeap = Ip.toMargin ipLeap in+ let marginStep = Ip.toMargin ipStep in+ Expr.lift2 Ip.zipMargin+ (fromIntegral (Ip.marginNumber marginStep) ++ fromIntegral (Ip.marginNumber marginLeap) * periodInt)+ (fromIntegral (Ip.marginOffset marginStep) ++ fromIntegral (Ip.marginOffset marginLeap) * periodInt)++_combineMargins ::+ Ip.Margin (nodesLeap value) ->+ Ip.Margin (nodesStep value) ->+ Int ->+ Ip.Margin (nodesLeap (nodesStep value))+_combineMargins marginLeap marginStep periodInt =+ Ip.Margin {+ Ip.marginNumber =+ Ip.marginNumber marginStep ++ Ip.marginNumber marginLeap * periodInt,+ Ip.marginOffset =+ Ip.marginOffset marginStep ++ Ip.marginOffset marginLeap * periodInt+ }+++{- |+@zigZagLong loopStart loopLength@+creates a curve that starts at 0+and is linear until it reaches @loopStart+loopLength@.+Then it begins looping in a ping-pong manner+between @loopStart+loopLength@ and @loopStart@.+It is useful as @shape@ control for looping a sound.+Input of the causal process is the slope (or frequency) control.+Slope values must not be negative.++*Main> Sig.renderChunky SVL.defaultChunkSize (Causal.take 25 <<< Helix.zigZagLong 6 10 $* 2) () :: SVL.Vector Float+VectorLazy.fromChunks [Vector.pack [0.0,1.999999,3.9999995,6.0,8.0,10.0,12.0,14.0,15.999999,14.000001,12.0,10.0,7.999999,6.0,8.0,10.0,12.0,14.0,16.0,14.0,11.999999,9.999998,7.999998,6.0000024,8.000002]]+-}+zigZagLong ::+ (Marshal.C a) =>+ (MultiValue.Select a, MultiValue.Comparison a, MultiValue.Fraction a) =>+ (MultiValue.Field a, MultiValue.RationalConstant a) =>+ Exp a -> Exp a -> Causal.MV a a+zigZagLong =+ zigZagLongGen (Causal.fromSignal . Sig.constant) zigZag++zigZagLongPacked ::+ (Marshal.Vector n a) =>+ (MultiVector.Field a, MultiVector.Fraction a) =>+ (MultiVector.RationalConstant a) =>+ (MultiVector.Select a, MultiVector.Comparison a) =>+ Exp a -> Exp a -> Causal.T (Serial.Value n a) (Serial.Value n a)+zigZagLongPacked =+ zigZagLongGen (Causal.fromSignal . SigPS.constant) zigZagPacked++zigZagLongGen ::+ (MultiValue.RationalConstant a, MultiValue.Field a) =>+ (A.RationalConstant al, A.Field al) =>+ (Exp a -> Causal.T al al) ->+ (Exp a -> Causal.T al al) ->+ Exp a -> Exp a -> Causal.T al al+zigZagLongGen constant zz prefix loop =+ zz (negate $ prefix/loop) * constant loop + constant prefix+ <<<+ id / constant loop++{- |+@zigZag start@ creates a zig-zag curve with values between 0 and 1, inclusively,+that is useful as @shape@ control for looping a sound.+Input of the causal process is the slope (or frequency) control.+Slope values must not be negative.+The start value must be at most 2 and may be negative.+-}+zigZag ::+ (Marshal.C a) =>+ (MultiValue.Select a, MultiValue.Comparison a, MultiValue.Fraction a) =>+ (MultiValue.Field a, MultiValue.RationalConstant a) =>+ Exp a -> Causal.MV a a+zigZag start =+ Causal.map (\x -> 1 - abs (1-x))+ <<<+ Causal.mapAccum+ (\d t0 -> let t1 = t0+d in (t0, wrap Expr.select (0<*) t1))+ start++zigZagPacked ::+ (TypeNum.Positive n) =>+ (Marshal.C a) =>+ (MultiVector.Field a, MultiVector.Fraction a) =>+ (MultiVector.RationalConstant a) =>+ (MultiVector.Select a, MultiVector.Comparison a) =>+ Exp a -> Causal.T (Serial.Value n a) (Serial.Value n a)+zigZagPacked start =+ Causal.map (\x -> 1 - abs (1-x))+ <<<+ Causal.mapAccum+ (\d t0 ->+ let (t1,cum) = SerialExp.cumulate t0 d+ in (wrap SerialExp.select (SerialExp.cmp LLVM.CmpLT zero) cum, t1))+ start++wrap ::+ (MultiValue.Field a, MultiValue.Fraction a, MultiValue.RationalConstant a) =>+ (Exp b -> Exp a -> Exp a -> Exp a) ->+ (Exp a -> Exp b) ->+ Exp a -> Exp a+wrap select positive a = select (positive a) (2 * Expr.fraction (a/2)) a
+ src/Synthesizer/LLVM/Causal/Parameterized.hs view
@@ -0,0 +1,67 @@+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE Rank2Types #-}+module Synthesizer.LLVM.Causal.Parameterized where++import qualified Synthesizer.LLVM.Causal.Private as Causal++import LLVM.DSL.Expression (Exp(Exp))++import qualified LLVM.Extra.Multi.Value.Marshal as Marshal+import qualified LLVM.Extra.Multi.Value as MultiValue+import qualified LLVM.Extra.Memory as Memory+import qualified LLVM.Extra.MaybeContinuation as MaybeCont+import qualified LLVM.Extra.Tuple as Tuple++import qualified LLVM.Core as LLVM++import Control.Monad.IO.Class (liftIO)++import Data.IORef (IORef, newIORef, readIORef, writeIORef)+++data T p a b =+ forall global local state.+ (Memory.C global, LLVM.IsSized local, Memory.C state) =>+ Cons (forall r c.+ (Tuple.Phi c) =>+ p -> global -> LLVM.Value (LLVM.Ptr local) ->+ a -> state -> MaybeCont.T r c (b, state))+ (forall r. p -> LLVM.CodeGenFunction r (global, state))+ (forall r. p -> global -> LLVM.CodeGenFunction r ())+++fromProcess :: String -> (Exp p -> Causal.T a b) -> IO (T (MultiValue.T p) a b)+fromProcess name f = do+ ref <- newIORef $ error $ name ++ ": uninitialized parameter reference"+ return $+ case f (Exp (liftIO (readIORef ref))) of+ Causal.Cons next start stop ->+ Cons+ (\p global local a state ->+ liftIO (writeIORef ref p) >> next global local a state)+ (\p -> liftIO (writeIORef ref p) >> start)+ (\p global -> liftIO (writeIORef ref p) >> stop global)+++fromProcessPtr ::+ (Marshal.C p) =>+ String -> (Exp p -> Causal.T a b) ->+ IO (T (LLVM.Value (LLVM.Ptr (Marshal.Struct p))) a b)+fromProcessPtr name f = do+ ref <- newIORef $ error $ name ++ ": uninitialized parameter reference"+ return $+ case f (Exp (liftIO (readIORef ref))) of+ Causal.Cons next start stop ->+ Cons+ (\p global local a state ->+ MaybeCont.lift (loadParam ref p) >> next global local a state)+ (\p -> loadParam ref p >> start)+ (\p global -> loadParam ref p >> stop global)++loadParam ::+ (Marshal.C param) =>+ IORef (MultiValue.T param) ->+ LLVM.Value (LLVM.Ptr (Marshal.Struct param)) ->+ LLVM.CodeGenFunction r ()+loadParam ref ptr = liftIO . writeIORef ref =<< Memory.load ptr
+ src/Synthesizer/LLVM/Causal/Private.hs view
@@ -0,0 +1,301 @@+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE Rank2Types #-}+module Synthesizer.LLVM.Causal.Private where++import qualified Synthesizer.LLVM.Generator.Private as Sig+import Synthesizer.LLVM.Private (getPairPtrs, noLocalPtr, unbool)++import qualified Synthesizer.Causal.Class as CausalClass+import qualified Synthesizer.Causal.Utility as ArrowUtil+import Synthesizer.Causal.Class (($>))++import qualified LLVM.DSL.Expression as Expr+import LLVM.DSL.Expression (Exp)++import qualified LLVM.Extra.Multi.Value.Marshal as Marshal+import qualified LLVM.Extra.Multi.Value as MultiValue+import qualified LLVM.Extra.Memory as Memory+import qualified LLVM.Extra.MaybeContinuation as MaybeCont+import qualified LLVM.Extra.Control as C+import qualified LLVM.Extra.Arithmetic as A+import qualified LLVM.Extra.Tuple as Tuple++import qualified LLVM.Core as LLVM+import LLVM.Core (CodeGenFunction)++import qualified Type.Data.Num.Decimal as TypeNum++import qualified Control.Category as Cat+import Control.Arrow (Arrow, arr, first, (&&&), (<<<))+import Control.Category (Category)+import Control.Applicative (Applicative, pure, liftA2, (<*>), (<$>))++import Data.Tuple.Strict (mapFst, zipPair)+import Data.Word (Word)++import qualified Number.Ratio as Ratio+import qualified Algebra.Field as Field+import qualified Algebra.Ring as Ring+import qualified Algebra.Additive as Additive++import NumericPrelude.Base hiding (map, zip, zipWith, init)++import qualified Prelude as P+++data T a b =+ forall global local state.+ (Memory.C global, LLVM.IsSized local, Memory.C state) =>+ Cons (forall r c.+ (Tuple.Phi c) =>+ global -> LLVM.Value (LLVM.Ptr local) ->+ a -> state -> MaybeCont.T r c (b, state))+ -- compute next value+ (forall r. CodeGenFunction r (global, state))+ -- initial state+ (forall r. global -> CodeGenFunction r ())+ -- cleanup+++type instance CausalClass.ProcessOf Sig.T = T++instance CausalClass.C T where+ type SignalOf T = Sig.T+ toSignal (Cons next start stop) = Sig.Cons+ (\global local -> next global local ())+ start+ stop+ fromSignal (Sig.Cons next start stop) = Cons+ (\global local _ -> next global local)+ start+ stop+++noGlobal ::+ (LLVM.IsSized local, Memory.C state) =>+ (forall r c.+ (Tuple.Phi c) =>+ LLVM.Value (LLVM.Ptr local) -> a -> state -> MaybeCont.T r c (b, state)) ->+ (forall r. CodeGenFunction r state) ->+ T a b+noGlobal next start =+ Cons (const next) (fmap ((,) ()) start) return++simple ::+ (Memory.C state) =>+ (forall r c. (Tuple.Phi c) => a -> state -> MaybeCont.T r c (b, state)) ->+ (forall r. CodeGenFunction r state) ->+ T a b+simple next start = noGlobal (noLocalPtr next) start++mapAccum ::+ (Memory.C state) =>+ (forall r. a -> state -> CodeGenFunction r (b, state)) ->+ (forall r. CodeGenFunction r state) ->+ T a b+mapAccum next =+ simple (\a s -> MaybeCont.lift $ next a s)++map ::+ (forall r. a -> CodeGenFunction r b) ->+ T a b+map f =+ mapAccum (\a s -> fmap (flip (,) s) $ f a) (return ())++zipWith ::+ (forall r. a -> b -> CodeGenFunction r c) ->+ T (a,b) c+zipWith f = map (uncurry f)+++instance Category T where+ id = map return+ Cons nextB startB stopB . Cons nextA startA stopA = Cons+ (\(globalA, globalB) local a (sa0,sb0) -> do+ (localA,localB) <- getPairPtrs local+ (b,sa1) <- nextA globalA localA a sa0+ (c,sb1) <- nextB globalB localB b sb0+ return (c, (sa1,sb1)))+ (liftA2 zipPair startA startB)+ (\(globalA, globalB) -> stopA globalA >> stopB globalB)++instance Arrow T where+ arr f = map (return . f)+ first (Cons next start stop) = Cons (firstNext next) start stop++firstNext ::+ (Functor m) =>+ (global -> local -> a -> s -> m (b, s)) ->+ global -> local -> (a, c) -> s -> m ((b, c), s)+firstNext next global local (b,d) s0 =+ fmap+ (\(c,s1) -> ((c,d), s1))+ (next global local b s0)+++instance Functor (T a) where+ fmap = flip (>>^)++instance Applicative (T a) where+ pure = ArrowUtil.pure+ (<*>) = ArrowUtil.apply+++infixr 1 >>^, ^>>++(>>^) :: T a b -> (b -> c) -> T a c+Cons next start stop >>^ f =+ Cons+ (\global local a state -> mapFst f <$> next global local a state)+ start stop++(^>>) :: (a -> b) -> T b c -> T a c+f ^>> Cons next start stop =+ Cons+ (\global local -> next global local . f)+ start stop+++mapProc ::+ (forall r. b -> CodeGenFunction r c) ->+ T a b -> T a c+mapProc f x = map f <<< x++zipProcWith ::+ (forall r. b -> c -> CodeGenFunction r d) ->+ T a b -> T a c -> T a d+zipProcWith f x y = zipWith f <<< x&&&y+++instance (A.Additive b) => Additive.C (T a b) where+ zero = pure A.zero+ negate = mapProc A.neg+ (+) = zipProcWith A.add+ (-) = zipProcWith A.sub++instance (A.PseudoRing b, A.IntegerConstant b) => Ring.C (T a b) where+ one = pure A.one+ fromInteger n = pure (A.fromInteger' n)+ (*) = zipProcWith A.mul++instance (A.Field b, A.RationalConstant b) => Field.C (T a b) where+ fromRational' x = pure (A.fromRational' $ Ratio.toRational98 x)+ (/) = zipProcWith A.fdiv+++instance (A.PseudoRing b, A.Real b, A.IntegerConstant b) => P.Num (T a b) where+ fromInteger n = pure (A.fromInteger' n)+ negate = mapProc A.neg+ (+) = zipProcWith A.add+ (-) = zipProcWith A.sub+ (*) = zipProcWith A.mul+ abs = mapProc A.abs+ signum = mapProc A.signum++instance+ (A.Field b, A.Real b, A.RationalConstant b) => P.Fractional (T a b) where+ fromRational x = pure (A.fromRational' x)+ (/) = zipProcWith A.fdiv+++{- |+Not quite the loop of ArrowLoop+because we need a delay of one time step+and thus an initialization value.++For a real ArrowLoop.loop, that is a zero-delay loop,+we would formally need a MonadFix instance of CodeGenFunction.+But this will not become reality, since LLVM is not able to re-order code+in a way that allows to access a result before creating the input.+-}+loop ::+ (Memory.C c) =>+ (forall r. CodeGenFunction r c) -> T (a,c) (b,c) -> T a b+loop initial (Cons next start stop) = Cons+ (\global local a0 (c0,s0) -> do+ ((b1,c1), s1) <- next global local (a0,c0) s0+ return (b1,(c1,s1)))+ (liftA2 (\ini (global,s) -> (global,(ini,s))) initial start)+ stop+++replicateSerial ::+ (Tuple.Undefined a, Tuple.Phi a) =>+ Exp Word -> T a a -> T a a+replicateSerial n proc =+ (\a -> ((),a)) ^>> replicateControlled n (snd^>>proc)++replicateControlled ::+ (Tuple.Undefined a, Tuple.Phi a) =>+ Exp Word -> T (c,a) a -> T (c,a) a+replicateControlled n (Cons next start stop) = Cons+ (\(len,globalStates) local (c,a) () ->+ MaybeCont.fromMaybe $ fmap (\(_,ms) -> flip (,) () <$> ms) $+ MaybeCont.arrayLoop len globalStates a $+ \globalStatePtr a0 -> do+ (global, s0) <- MaybeCont.lift $ Memory.load globalStatePtr+ (a1,s1) <- next global local (c,a0) s0+ MaybeCont.lift $+ Memory.store s1 =<<+ LLVM.getElementPtr0 globalStatePtr (TypeNum.d1, ())+ return a1)+ (do+ MultiValue.Cons len <- Expr.unExp n+ globalStates <- LLVM.arrayMalloc len+ C.arrayLoop len globalStates () $ \globalStatePtr () ->+ flip Memory.store globalStatePtr =<< start+ return ((len,globalStates), ()))+ (\(len,globalStates) -> do+ C.arrayLoop len globalStates () $ \globalStatePtr () ->+ stop =<< Memory.load+ =<< LLVM.getElementPtr0 globalStatePtr (TypeNum.d0, ())+ LLVM.free globalStates)++{-+We can implement 'replicateControlled' in terms of 'replicateSerial'+but this adds constraints @(Tuple.Undefined c, Tuple.Phi c)@.+-}+replicateControlledAlt ::+ (Tuple.Undefined a, Tuple.Phi a) =>+ (Tuple.Undefined c, Tuple.Phi c) =>+ Exp Word -> T (c,a) a -> T (c,a) a+replicateControlledAlt n proc =+ replicateSerial n (arr fst &&& proc) >>^ snd++replicateParallel ::+ (Tuple.Undefined b, Tuple.Phi b) =>+ Exp Word -> Sig.T b -> T (b,b) b -> T a b -> T a b+replicateParallel n z cum p =+ replicateControlled n (cum <<< first p) $> z+++quantizeLift ::+ (Memory.C b, Marshal.C c, MultiValue.IntegerConstant c,+ MultiValue.Additive c, MultiValue.Comparison c) =>+ T a b -> T (MultiValue.T c, a) b+quantizeLift (Cons next start stop) = Cons+ (\global local (k, a0) yState0 -> do+ (yState1, frac1) <-+ MaybeCont.fromBool $+ C.whileLoop+ (LLVM.valueOf True, yState0)+ (\(cont1, (_, frac0)) ->+ LLVM.and cont1 . unbool+ =<< MultiValue.cmp LLVM.CmpLE frac0 A.zero)+ (\(_,((_,state01), frac0)) ->+ MaybeCont.toBool $ liftA2 (,)+ (next global local a0 state01)+ (MaybeCont.lift $ A.add frac0 k))++ frac2 <- MaybeCont.lift $ A.sub frac1 A.one+ return (fst yState1, (yState1, frac2)))+{- using this initialization code we would not need undefined values+ (do (global,s) <- start+ (a,_) <- next s+ return (global, ((a,s), A.zero))+-}+ (do+ (global,s) <- start+ return (global, ((Tuple.undef, s), A.zero)))+ stop
src/Synthesizer/LLVM/Causal/Process.hs view
@@ -1,756 +1,787 @@ {-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE ExistentialQuantification #-}-{-# LANGUAGE Rank2Types #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE ForeignFunctionInterface #-}-module Synthesizer.LLVM.Causal.Process (- C(simple, replicateControlled),- T,- amplify,- amplifyStereo,- apply,- applyFst,- applySnd,- applyConst,- applyConstFst,- applyConstSnd,- (CausalClass.$<), (CausalClass.$>), (CausalClass.$*),- ($<#), ($>#), ($*#),- feedFst,- feedSnd,- feedConstFst,- feedConstSnd,- first,- envelope,- envelopeStereo,- fromModifier,- fromSignal,- toSignal,- loopConst,- loopZero,- delay1Zero,- feedbackControlledZero,- map,- mapAccum,- zipWith,- mapProc,- zipProcWith,- mix,- takeWhile,- pipeline,- stereoFromVector,- vectorize,- replaceChannel,- arrayElement,- element,- osciCoreSync,- osciCore,- osci,- shapeModOsci,- skip,- foldChunks,- foldChunksPartial,- frequencyModulation,- interpolateConstant,- quantizeLift,- applyStorable,- applyStorableChunky,- runStorableChunky,- ) where--import Synthesizer.LLVM.Causal.ProcessPrivate--import qualified Synthesizer.LLVM.Simple.SignalPrivate as Sig-import qualified Synthesizer.LLVM.Simple.Value as Value-import qualified Synthesizer.LLVM.Fold as Fold-import qualified Synthesizer.LLVM.Frame.Stereo as Stereo-import qualified Synthesizer.LLVM.Frame as Frame-import qualified Synthesizer.LLVM.ForeignPtr as ForeignPtr--import qualified Synthesizer.Plain.Modifier as Modifier-import qualified Synthesizer.Causal.Class as CausalClass--import qualified Data.StorableVector.Lazy as SVL-import qualified Data.StorableVector as SV-import qualified Data.StorableVector.Base as SVB--import qualified LLVM.DSL.Execution as Exec--import qualified LLVM.Extra.Multi.Vector as MultiVector-import qualified LLVM.Extra.Multi.Value as MultiValue-import qualified LLVM.Extra.Control as C-import qualified LLVM.Extra.Tuple as Tuple-import qualified LLVM.Extra.Arithmetic as A-import qualified LLVM.Extra.ScalarOrVector as SoV-import qualified LLVM.Extra.MaybeContinuation as MaybeCont-import qualified LLVM.Extra.Maybe as Maybe-import qualified LLVM.Extra.Storable as Storable-import qualified LLVM.Extra.Marshal as Marshal-import qualified LLVM.Extra.Memory as Memory--import qualified LLVM.Core as LLVM-import LLVM.Core- (CodeGenFunction, ret, Value, valueOf,- IsConst, IsFirstClass, IsArithmetic, IsPrimitive)--import qualified Type.Data.Num.Decimal as TypeNum-import Type.Base.Proxy (Proxy)-import Type.Data.Num.Decimal (D2, (:<:))--import qualified Control.Arrow as Arr-import Control.Monad.Trans.State (runState)-import Control.Arrow (arr, (<<<), (>>>), (&&&))-import Control.Monad (liftM2)-import Control.Applicative (liftA3, (<$>))--import qualified Data.List as List-import Data.Tuple.HT (swap)-import Data.Word (Word)--import Foreign.Ptr (Ptr)-import Control.Exception (bracket)-import qualified System.Unsafe as Unsafe--import Prelude hiding (and, map, zip, zipWith, init, takeWhile)----fromModifier ::- (C process) =>- (Value.Flatten ah, Value.Registers ah ~ al,- Value.Flatten bh, Value.Registers bh ~ bl,- Value.Flatten ch, Value.Registers ch ~ cl,- Value.Flatten sh, Value.Registers sh ~ sl,- Memory.C sl) =>- Modifier.Simple sh ch ah bh -> process (cl,al) bl-fromModifier (Modifier.Simple initial step) =- mapAccum- (\(c,a) s ->- Value.flatten $- runState- (step (Value.unfold c) (Value.unfold a))- (Value.unfold s))- (Value.flatten initial)---apply :: T a b -> Sig.T a -> Sig.T b-apply = CausalClass.apply--feedFst :: Sig.T a -> T b (a,b)-feedFst = CausalClass.feedFst--feedSnd :: Sig.T a -> T b (b,a)-feedSnd = CausalClass.feedSnd--feedConstFst :: (Tuple.Value a, Tuple.ValueOf a ~ al) => a -> T b (al,b)-feedConstFst = CausalClass.feedConstFst . Tuple.valueOf--feedConstSnd :: (Tuple.Value a, Tuple.ValueOf a ~ al) => a -> T b (b,al)-feedConstSnd = CausalClass.feedConstSnd . Tuple.valueOf---applyFst :: T (a,b) c -> Sig.T a -> T b c-applyFst = CausalClass.applyFst--applySnd :: T (a,b) c -> Sig.T b -> T a c-applySnd = CausalClass.applySnd--applyConst ::- (Tuple.Value a, Tuple.ValueOf a ~ al) =>- T al b -> a -> Sig.T b-applyConst proc =- CausalClass.applyConst proc . Tuple.valueOf--applyConstFst ::- (Tuple.Value a, Tuple.ValueOf a ~ al) =>- T (al,b) c -> a -> T b c-applyConstFst proc =- CausalClass.applyConstFst proc . Tuple.valueOf--applyConstSnd ::- (Tuple.Value b, Tuple.ValueOf b ~ bl) =>- T (a,bl) c -> b -> T a c-applyConstSnd proc =- CausalClass.applyConstSnd proc . Tuple.valueOf---infixl 0 $<#, $>#, $*#--{- |-provide constant input in a comfortable way--}-($*#) ::- (C process, CausalClass.SignalOf process ~ signal,- Tuple.Value ah, Tuple.ValueOf ah ~ a) =>- process a b -> ah -> signal b-proc $*# x = CausalClass.applyConst proc $ Tuple.valueOf x--($<#) ::- (C process, Tuple.Value ah, Tuple.ValueOf ah ~ a) =>- process (a,b) c -> ah -> process b c-proc $<# x = CausalClass.applyConstFst proc $ Tuple.valueOf x--($>#) ::- (C process, Tuple.Value bh, Tuple.ValueOf bh ~ b) =>- process (a,b) c -> bh -> process a c-proc $># x = CausalClass.applyConstSnd proc $ Tuple.valueOf x----{- |-You may also use '(+)'.--}-mix ::- (C process, A.Additive a) =>- process (a, a) a-mix = zipWith Frame.mix---{- |-You may also use '(*)'.--}-envelope ::- (C process, A.PseudoRing a) =>- process (a, a) a-envelope = zipWith Frame.amplifyMono--envelopeStereo ::- (C process, A.PseudoRing a) =>- process (a, Stereo.T a) (Stereo.T a)-envelopeStereo = zipWith Frame.amplifyStereo--amplify ::- (C process, IsArithmetic a, IsConst a) =>- a -> process (Value a) (Value a)-amplify x =- map (Frame.amplifyMono (valueOf x))--amplifyStereo ::- (C process, IsArithmetic a, IsConst a) =>- a -> process (Stereo.T (Value a)) (Stereo.T (Value a))-amplifyStereo x =- map (Frame.amplifyStereo (valueOf x))----loopConst ::- (C process, Memory.C c) =>- c -> process (a,c) (b,c) -> process a b-loopConst init =- alter- (\(Core next start stop) ->- Core- (loopNext next)- (fmap ((,) init) . start)- (stop . snd))--{- |-Like 'Synthesizer.LLVM.CausalParameterized.loop'-but uses zero as initial value-and it does not need a zero as Haskell value.--}-loopZero ::- (C process, A.Additive c, Memory.C c) =>- process (a,c) (b,c) -> process a b-loopZero = loopConst A.zero--delay1Zero ::- (C process, A.Additive a, Memory.C a) =>- process a a-delay1Zero = loopZero (arr swap)---{- |-This allows to compute a chain of equal processes efficiently,-if all of these processes can be bundled in one vectorial process.-Applications are an allpass cascade or an FM operator cascade.--The function expects that the vectorial input process-works like parallel scalar processes.-The different pipeline stages may be controlled by different parameters,-but the structure of all pipeline stages must be equal.-Our function feeds the input of the pipelined process-to the zeroth element of the Vector.-The result of processing the i-th element (the i-th channel, so to speak)-is fed to the (i+1)-th element.-The (n-1)-th element of the vectorial process is emitted-as output of the pipelined process.--The pipeline necessarily introduces a delay of (n-1) values.-For simplification we extend this to n values delay.-If you need to combine the resulting signal from the pipeline-with another signal in a 'zip'-like way,-you may delay that signal with @pipeline id@.-The first input values in later stages of the pipeline-are initialized with zero.-If this is not appropriate for your application,-then we may add a more sensible initialization.--}-pipeline ::- (C process,- TypeNum.Positive n, MultiVector.C x,- v ~ MultiVector.T n x,- a ~ MultiValue.T x,- Tuple.Zero v, Memory.C v) =>- process v v -> process a a-pipeline vectorProcess =- loopConst MultiVector.zero $- map (uncurry MultiVector.shiftUp)- >>>- Arr.second vectorProcess---feedbackControlledZero ::- (C process, A.Additive c, Memory.C c) =>- process ((ctrl,a),c) b -> process (ctrl,b) c -> process (ctrl,a) b-feedbackControlledZero forth back =- loopZero (feedbackControlledAux forth back)---{--In order to let this work we have to give the disable-mmx option somewhere,-but where?--}-stereoFromVector ::- (C process, IsPrimitive a, IsPrimitive b) =>- process (Value (LLVM.Vector D2 a)) (Value (LLVM.Vector D2 b)) ->- process (Stereo.T (Value a)) (Stereo.T (Value b))-stereoFromVector proc =- map Frame.stereoFromVector <<<- proc <<<- map Frame.vectorFromStereo---{--insert and extract instructions will be in opposite order,-no matter whether we use foldr or foldl-and independent from the order of proc and channel in replaceChannel.-However, LLVM neglects the order anyway.--}-vectorize ::- (C process,- TypeNum.Positive n,- MultiVector.C x, MultiValue.T x ~ a, MultiVector.T n x ~ va,- MultiVector.C y, MultiValue.T y ~ b, MultiVector.T n y ~ vb) =>- process a b -> process va vb-vectorize proc =- withSize $ \n ->- foldl- (\acc i -> replaceChannel i proc acc)- (arr (const $ Tuple.undef)) $- List.take (TypeNum.integralFromSingleton n) [0 ..]--withSize ::- (TypeNum.Positive n, MultiVector.T n a ~ v) =>- (TypeNum.Singleton n -> f v) ->- f v-withSize f = f TypeNum.singleton--{- |-Given a vector process, replace the i-th output by output-that is generated by a scalar process from the i-th input.--}-replaceChannel ::- (C process,- TypeNum.Positive n,- MultiVector.C x, MultiValue.T x ~ a, MultiVector.T n x ~ va,- MultiVector.C y, MultiValue.T y ~ b, MultiVector.T n y ~ vb) =>- Int -> process a b -> process va vb -> process va vb-replaceChannel i channel proc =- let li = valueOf $ fromIntegral i- in zipWith (MultiVector.insert li) <<<- (channel <<< map (MultiVector.extract li)) &&&- proc--{- |-Read the i-th element from each array.--}-arrayElement ::- (C process, IsFirstClass a,- TypeNum.Natural index, TypeNum.Natural dim,- index :<: dim) =>- Proxy index -> process (Value (LLVM.Array dim a)) (Value a)-arrayElement i =- map (\array -> LLVM.extractvalue array i)--{- |-Read the i-th element from an aggregate type.--}-element ::- (C process, IsFirstClass a, LLVM.GetValue agg index,- LLVM.ValueType agg index ~ a) =>- index -> process (Value agg) (Value a)-element i =- map (\array -> LLVM.extractvalue array i)----{- |-Compute the phases from phase distortions and frequencies.--It's like integrate but with wrap-around performed by @fraction@.-For FM synthesis we need also negative phase distortions,-thus we use 'A.addToPhase' which supports that.--}-osciCore, _osciCore, osciCoreSync ::- (C process, Memory.C t, A.Fraction t) =>- process (t, t) (t)-_osciCore =- zipWith A.addToPhase <<<- Arr.second- (mapAccum- (\a s -> do- b <- A.incPhase a s- return (s,b))- (return A.zero))--{--This could be implemented using a generalized frequencyModulation,-however, osciCoreSync allows for negative phase differences.--}-osciCoreSync =- zipWith A.addToPhase <<<- Arr.second- (mapAccum- (\a s -> do- b <- A.incPhase a s- return (b,b))- (return A.zero))--osciCore =- zipWith A.addToPhase <<<- Arr.second (loopZero (arr snd &&& zipWith A.incPhase))--osci ::- (C process, Memory.C t, A.Fraction t) =>- (forall r. t -> CodeGenFunction r y) ->- process (t, t) y-osci wave =- map wave <<< osciCore--shapeModOsci ::- (C process, Memory.C t, A.Fraction t) =>- (forall r. c -> t -> CodeGenFunction r y) ->- process (c, (t, t)) y-shapeModOsci wave =- zipWith wave <<< Arr.second osciCore---{- |-Feeds a signal into a causal process while holding or skipping signal elements-according to the process input.-The skip happens after a value is passed from the fed signal.--@skip x $* 0@ repeats the first signal value in the output.-@skip x $* 1@ feeds the signal to the output as is.-@skip x $* 2@ feeds the signal to the output with double speed.--}-skip ::- (C process, CausalClass.SignalOf process ~ signal,- Tuple.Undefined a, Tuple.Phi a, Memory.C a) =>- signal a -> process (Value Word) a-skip =- alterSignal- (\(Sig.Core next start stop) -> Core- (\context n1 (yState0,n0) -> do- yState1@(y,_) <-- MaybeCont.fromMaybe $ fmap snd $- MaybeCont.fixedLengthLoop n0 yState0 $- next context . snd- return (y, (yState1,n1)))- (fmap (\s -> ((Tuple.undef, s), A.one)) . start)- (\((_y,state),_k) -> stop state))--{- |-The input of the process is a sequence of chunk sizes.-The signal is chopped into chunks of these sizes-and each chunk is folded using-the given initial value and the accumulation function.-A trailing incomplete chunk will be ignored.--}-foldChunks ::- (C process, CausalClass.SignalOf process ~ signal, Tuple.Undefined b, Tuple.Phi b) =>- Fold.T a b -> signal a -> process (Value Word) b-foldChunks (Fold.Cons accum initial) =- alterSignal- (\(Sig.Core next start stop) -> Core- (\context n state ->- MaybeCont.fromMaybe $ fmap snd $- MaybeCont.fixedLengthLoop n (initial,state) $ \(b0,state0) -> do- (a,state1) <- next context state0- b1 <- MaybeCont.lift $ accum b0 a- return (b1,state1))- start- stop)--{- |-Like 'foldChunks' but an incomplete chunk at the end-is treated like a complete one.--}-foldChunksPartial ::- (C process, CausalClass.SignalOf process ~ signal,- Tuple.Undefined a, Tuple.Phi a, Tuple.Undefined b, Tuple.Phi b) =>- Fold.T a b -> signal a -> process (Value Word) b-foldChunksPartial (Fold.Cons accum initial) =- alterSignal- (\(Sig.Core next start stop) -> Core- (\context n runState0 -> do- ((i,b), runState1) <-- MaybeCont.lift $- C.whileLoopShared ((n, initial), runState0) $- \((i0,b0), (run,s0)) ->- (A.and run =<< A.cmp LLVM.CmpGT i0 A.zero,- do mas1 <- MaybeCont.toMaybe $ next context s0- Maybe.run mas1- (return ((i0,b0), (valueOf False, s0)))- (\(a,s1) -> do- b1 <- accum b0 a- i1 <- A.dec i0- return ((i1,b1), (valueOf True, s1))))- MaybeCont.guard =<< MaybeCont.lift (A.cmp LLVM.CmpLT i n)- return (b, runState1))- (fmap ((,) (valueOf True)) . start)- (stop . snd))--{--It is quite similar to quantizeLift but the control is the reciprocal.-This is especially a problem since we need the fractional part for interpolation.--}-frequencyModulation ::- (C process, CausalClass.SignalOf process ~ signal,- SoV.IntegerConstant a, LLVM.IsFloating a,- LLVM.CmpRet a, LLVM.CmpResult a ~ Bool, LLVM.IsSized a,- Tuple.Undefined nodes, Tuple.Phi nodes, Memory.C nodes) =>- (forall r. Value a -> nodes -> CodeGenFunction r v) ->- signal nodes -> process (Value a) v-frequencyModulation ip =- alterSignal (\(Sig.Core next start stop) -> Core- (\context k yState0 -> do- ((nodes2,state2), ss2) <-- MaybeCont.fromBool $- C.whileLoop- (valueOf True, yState0)- (\(cont0, (_, ss0)) ->- LLVM.and cont0 =<< A.fcmp LLVM.FPOGE ss0 A.one)- (\(_,((_,state0), ss0)) ->- MaybeCont.toBool $ liftM2 (,)- (next context state0)- (MaybeCont.lift $ A.sub ss0 A.one))-- MaybeCont.lift $ do- y <- ip ss2 nodes2- ss3 <- A.add ss2 k- return (y, ((nodes2, state2), ss3)))- (fmap (\sa -> ((Tuple.undef, sa), A.one)) . start)- (\((_y01,state),_ss) -> stop state))---{- |-Stretch signal in time by a time-varying factor.--}-interpolateConstant ::- (C process, CausalClass.SignalOf process ~ signal,- Memory.C a, LLVM.IsSized b, SoV.IntegerConstant b,- LLVM.IsFloating b, LLVM.CmpRet b, LLVM.CmpResult b ~ Bool) =>- signal a -> process (Value b) a-interpolateConstant xs =- quantizeLift (CausalClass.fromSignal xs) $># ()---quantizeLift ::- (C process, Memory.C b,- SoV.IntegerConstant c, LLVM.IsFloating c,- LLVM.CmpRet c, LLVM.CmpResult c ~ Bool, LLVM.IsSized c) =>- process a b ->- process (Value c, a) b-quantizeLift = alter (\(Core next start stop) -> Core- (\context (k, a0) yState0 -> do- (yState1, frac1) <-- MaybeCont.fromBool $- C.whileLoop- (LLVM.valueOf True, yState0)- (\(cont1, (_, frac0)) ->- LLVM.and cont1 =<< A.fcmp LLVM.FPOLE frac0 A.zero)- (\(_,((_,state01), frac0)) ->- MaybeCont.toBool $ liftM2 (,)- (next context a0 state01)- (MaybeCont.lift $ A.add frac0 k))-- frac2 <- MaybeCont.lift $ A.sub frac1 A.one- return (fst yState1, (yState1, frac2)))-{- using this initialization code we would not need undefined values- (do sa <- start- (a,_) <- next sa- return (sa, a, A.zero))--}- (\p -> do- s <- start p- return ((Tuple.undef, s), A.zero))- (\((_, s), _) -> stop s))----foreign import ccall safe "dynamic" derefFillPtr ::- Exec.Importer- (LLVM.Ptr paramStruct -> Word -> Ptr a -> Ptr b -> IO Word)---compile ::- (Storable.C a, Tuple.ValueOf a ~ aValue,- Storable.C b, Tuple.ValueOf b ~ bValue,- Memory.C param, Memory.Struct param ~ paramStruct,- Tuple.Phi state, Tuple.Undefined state) =>- (forall r z. (Tuple.Phi z) =>- param -> local -> aValue -> state -> MaybeCont.T r z (bValue, state)) ->- (forall r. CodeGenFunction r local) ->- (forall r. param -> CodeGenFunction r state) ->- IO (LLVM.Ptr paramStruct -> Word -> Ptr a -> Ptr b -> IO Word)-compile next alloca start =- Exec.compile "causal" $- Exec.createFunction derefFillPtr "fillprocessblock" $- \ paramPtr size alPtr blPtr -> do- param <- Memory.load paramPtr- s <- start param- local <- alloca- (pos,_) <-- Storable.arrayLoopMaybeCont2 size alPtr blPtr s $- \ aPtri bPtri s0 -> do- a <- MaybeCont.lift $ Storable.load aPtri- (b,s1) <- next param local a s0- MaybeCont.lift $ Storable.store b bPtri- return s1- ret pos---applyStorable ::- (Storable.C a, Tuple.ValueOf a ~ valueA,- Storable.C b, Tuple.ValueOf b ~ valueB) =>- T valueA valueB -> SV.Vector a -> SV.Vector b-applyStorable proc = Unsafe.performIO $ runStorable proc--runStorable ::- (Storable.C a, Tuple.ValueOf a ~ valueA,- Storable.C b, Tuple.ValueOf b ~ valueB) =>- T valueA valueB -> IO (SV.Vector a -> SV.Vector b)-runStorable proc = (Unsafe.performIO .) <$> runStorableIO proc--runStorableIO ::- (Storable.C a, Tuple.ValueOf a ~ valueA,- Storable.C b, Tuple.ValueOf b ~ valueB) =>- T valueA valueB -> IO (SV.Vector a -> IO (SV.Vector b))-runStorableIO- (Cons next alloca start createIOContext deleteIOContext) = do-- fill <- compile next alloca start- return $ \as ->- bracket createIOContext (deleteIOContext . fst) $ \ (_ioContext, params) ->- SVB.withStartPtr as $ \ aPtr len ->- SVB.createAndTrim len $ \ bPtr ->- Marshal.with params $ \paramPtr ->- fmap (fromIntegral :: Word -> Int) $- fill paramPtr (fromIntegral len) aPtr bPtr---foreign import ccall safe "dynamic" derefStartPtr ::- Exec.Importer (LLVM.Ptr b -> IO (LLVM.Ptr a))--foreign import ccall safe "dynamic" derefStopPtr ::- Exec.Importer (LLVM.Ptr a -> IO ())--foreign import ccall safe "dynamic" derefChunkPtr ::- Exec.Importer- (LLVM.Ptr paramStruct -> LLVM.Ptr stateStruct -> Word ->- Ptr a -> Ptr b -> IO Word)---compileChunky ::- (Storable.C a, Tuple.ValueOf a ~ aValue,- Storable.C b, Tuple.ValueOf b ~ bValue,- Memory.C param, Memory.Struct param ~ paramStruct,- Memory.C state, Memory.Struct state ~ stateStruct) =>- (forall r z. (Tuple.Phi z) =>- param -> local -> aValue -> state -> MaybeCont.T r z (bValue, state)) ->- (forall r. CodeGenFunction r local) ->- (forall r.- param -> CodeGenFunction r state) ->- IO (LLVM.Ptr paramStruct -> IO (LLVM.Ptr stateStruct),- Exec.Finalizer stateStruct,- LLVM.Ptr paramStruct -> LLVM.Ptr stateStruct ->- Word -> Ptr a -> Ptr b -> IO Word)-compileChunky next alloca start =- Exec.compile "causal-chunky" $- liftA3 (,,)- (Exec.createFunction derefStartPtr "startprocess" $- \paramPtr -> do- pptr <- LLVM.malloc- param <- Memory.load paramPtr- flip Memory.store pptr =<< start param- ret pptr)- (Exec.createFinalizer derefStopPtr "stopprocess" $- \ pptr -> LLVM.free pptr >> ret ())- (Exec.createFunction derefChunkPtr "fillprocess" $- \paramPtr sptr loopLen aPtr bPtr -> do- sInit <- Memory.load sptr- param <- Memory.load paramPtr- local <- alloca- (pos,sExit) <-- Storable.arrayLoopMaybeCont2 loopLen aPtr bPtr sInit $- \ aPtri bPtri s0 -> do- a <- MaybeCont.lift $ Storable.load aPtri- (b,s1) <- next param local a s0- MaybeCont.lift $ Storable.store b bPtri- return s1- Memory.store (Maybe.fromJust sExit) sptr- ret pos)---traverseChunks ::- (Storable.C a, Storable.C b) =>- (LLVM.Ptr paramStruct -> LLVM.Ptr stateStruct ->- Word -> Ptr a -> Ptr b -> IO Word) ->- ForeignPtr.MemoryPtr paramStruct ->- ForeignPtr.MemoryPtr stateStruct ->- SVL.Vector a -> IO [SVB.Vector b]-traverseChunks fill paramFPtr statePtr =- let go xt =- Unsafe.interleaveIO $- case xt of- [] -> return []- x:xs -> SVB.withStartPtr x $ \aPtr size -> do- v <-- ForeignPtr.with paramFPtr $ \paramPtr ->- ForeignPtr.with statePtr $ \sptr ->- SVB.createAndTrim size $- fmap (fromIntegral :: Word -> Int) .- fill paramPtr sptr (fromIntegral size) aPtr- (if SV.length v > 0- then fmap (v:)- else id) $- (if SV.length v < size- then return []- else go xs)- in go . SVL.chunks---runStorableChunky ::- (Storable.C a, Tuple.ValueOf a ~ valueA,- Storable.C b, Tuple.ValueOf b ~ valueB) =>- T valueA valueB -> IO (SVL.Vector a -> SVL.Vector b)-runStorableChunky- (Cons next alloca start createIOContext deleteIOContext) = do-- (startFunc, stopFunc, fill) <- compileChunky next alloca start- return $ \sig -> SVL.fromChunks $ Unsafe.performIO $ do- (ioContext, params) <- createIOContext- paramPtr <- ForeignPtr.new (deleteIOContext ioContext) params- statePtr <-- ForeignPtr.newInit stopFunc $ ForeignPtr.with paramPtr startFunc- traverseChunks fill paramPtr statePtr sig---applyStorableChunky ::- (Storable.C a, Tuple.ValueOf a ~ valueA,- Storable.C b, Tuple.ValueOf b ~ valueB) =>- T valueA valueB -> SVL.Vector a -> SVL.Vector b-applyStorableChunky = Unsafe.performIO . runStorableChunky+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE Rank2Types #-}+module Synthesizer.LLVM.Causal.Process (+ Causal.T, MV,+ CausalClass.fromSignal,+ CausalClass.toSignal,+ (CausalClass.$<), (CausalClass.$>), (CausalClass.$*),+ ($<#), ($>#), ($*#),+ map,+ zipWith,+ takeWhile,+ take,+ mix,+ raise,+ envelope,+ envelopeStereo,+ amplify,+ amplifyStereo,+ mapLinear,+ mapExponential,+ loop,+ loopZero,+ integrate,+ integrateZero,+ delay1,+ delayControlled,+ delayControlledInterpolated,+ differentiate,+ feedbackControlled,+ feedbackControlledZero,+ mapAccum,+ fromModifier,+ osciCoreSync,+ osciCore,+ osci,+ shapeModOsci,+ skip,+ frequencyModulation,+ frequencyModulationLinear,+ Causal.quantizeLift,+ track,+ delay,+ delayZero,+ Causal.replicateControlled,+ replicateControlledParam,+ stereoFromMono,+ stereoFromMonoControlled,+ stereoFromMonoParameterized,+ comb,+ combStereo,+ reverbExplicit,+ reverbParams,+ trigger,+ arrayElement,+ vectorize,+ pipeline,+ ) where++import qualified Synthesizer.LLVM.Causal.Parameterized as Parameterized+import qualified Synthesizer.LLVM.Causal.Private as Causal+import qualified Synthesizer.LLVM.Generator.Private as SigPriv+import qualified Synthesizer.LLVM.Generator.Signal as Sig+import qualified Synthesizer.LLVM.RingBuffer as RingBuffer+import qualified Synthesizer.LLVM.Interpolation as Interpolation+import qualified Synthesizer.LLVM.Frame.Stereo as Stereo+import qualified Synthesizer.LLVM.Frame as Frame+import Synthesizer.LLVM.Generator.Private (arraySize)+import Synthesizer.LLVM.Private (noLocalPtr, unbool)++import qualified Synthesizer.Plain.Modifier as Modifier+import qualified Synthesizer.Causal.Class as CausalClass+import Synthesizer.Causal.Class (($*), ($<))++import qualified LLVM.DSL.Expression as Expr+import LLVM.DSL.Expression (Exp)++import qualified LLVM.Extra.Multi.Vector as MultiVector+import qualified LLVM.Extra.Multi.Value.Marshal as Marshal+import qualified LLVM.Extra.Multi.Value as MultiValue+import qualified LLVM.Extra.Memory as Memory+import qualified LLVM.Extra.MaybeContinuation as MaybeCont+import qualified LLVM.Extra.Maybe as Maybe+import qualified LLVM.Extra.Tuple as Tuple+import qualified LLVM.Extra.Iterator as Iter+import qualified LLVM.Extra.Control as C+import qualified LLVM.Extra.Arithmetic as A++import qualified LLVM.Core as LLVM++import qualified Type.Data.Num.Decimal as TypeNum+import Type.Data.Num.Decimal ((:<:))+import Type.Base.Proxy (Proxy(Proxy))++import qualified Data.List as List+import Data.Traversable (sequenceA)+import Data.Tuple.HT (mapSnd, swap)+import Data.Word (Word)++import qualified Control.Arrow as Arrow+import qualified Control.Category as Cat+import qualified Control.Monad.Trans.State as MS+import qualified Control.Functor.HT as FuncHT+import qualified Control.Applicative.HT as App+import Control.Arrow (Arrow, arr, (<<<), (^<<), (<<^), (>>>), (***), (&&&))+import Control.Applicative (pure, liftA2, liftA3, (<$>))++import qualified System.Unsafe as Unsafe+import System.Random (Random, RandomGen, randomR)++import qualified Algebra.Additive as Additive+import NumericPrelude.Numeric+import NumericPrelude.Base hiding (map, zipWith, takeWhile, take)+import Prelude ()+++type MV a b = Causal.T (MultiValue.T a) (MultiValue.T b)+++infixl 0 $<#, $>#, $*#++{- |+provide constant input in a comfortable way+-}+($*#) ::+ (CausalClass.C process, CausalClass.SignalOf process ~ signal,+ MultiValue.C a) =>+ process (MultiValue.T a) b -> a -> signal b+proc $*# x = CausalClass.applyConst proc $ MultiValue.cons x++($<#) ::+ (CausalClass.C process, MultiValue.C a) =>+ process (MultiValue.T a, b) c -> a -> process b c+proc $<# x = CausalClass.applyConstFst proc $ MultiValue.cons x++($>#) ::+ (CausalClass.C process, MultiValue.C b) =>+ process (a, MultiValue.T b) c -> b -> process a c+proc $># x = CausalClass.applyConstSnd proc $ MultiValue.cons x++++map ::+ (Expr.Aggregate ae a, Expr.Aggregate be b) =>+ (ae -> be) -> Causal.T a b+map f = Causal.map (\a -> Expr.bundle (f (Expr.dissect a)))++zipWith ::+ (Expr.Aggregate ae a, Expr.Aggregate be b, Expr.Aggregate ce c) =>+ (ae -> be -> ce) -> Causal.T (a,b) c+zipWith f = map (uncurry f)++takeWhile :: (Expr.Aggregate ae a) => (ae -> Exp Bool) -> Causal.T a a+takeWhile p = Causal.simple+ (\a () -> do+ MaybeCont.guard . unbool =<< MaybeCont.lift (Expr.unliftM1 p a)+ return (a,()))+ (return ())++take :: Exp Word -> Causal.T a a+take len =+ arr snd $< (takeWhile (0 Expr.<*) $* Sig.iterate (subtract 1) len)+++{- |+You may also use '(+)'.+-}+mix :: (A.Additive a) => Causal.T (a,a) a+mix = Causal.zipWith Frame.mix++{- |+You may also use '(+)' and a 'Sig.constant' signal or a number literal.+-}+raise :: (Marshal.C a, MultiValue.Additive a) => Exp a -> MV a a+raise x = mix $< Sig.constant x+++{- |+You may also use '(*)'.+-}+envelope :: (A.PseudoRing a) => Causal.T (a, a) a+envelope = Causal.zipWith Frame.amplifyMono++envelopeStereo :: (A.PseudoRing a) => Causal.T (a, Stereo.T a) (Stereo.T a)+envelopeStereo = Causal.zipWith Frame.amplifyStereo++{- |+You may also use '(*)' and a 'Sig.constant' signal or a number literal.+-}+amplify ::+ (Expr.Aggregate ea a, Memory.C a, A.PseudoRing a) =>+ ea -> Causal.T a a+amplify x = envelope $< Sig.constant x++amplifyStereo ::+ (Marshal.C a, MultiValue.PseudoRing a, Stereo.T (MultiValue.T a) ~ stereo) =>+ Exp a -> Causal.T stereo stereo+amplifyStereo x = envelopeStereo $< Sig.constant x+++mapLinear ::+ (Marshal.C a, MultiValue.T a ~ am,+ MultiValue.PseudoRing a, MultiValue.IntegerConstant a) =>+ Exp a -> Exp a -> Causal.T am am+mapLinear depth center = map (\x -> center + depth*x)++-- ToDo: use base 2+mapExponential ::+ (Marshal.C a, MultiValue.T a ~ am,+ MultiValue.Transcendental a, MultiValue.RationalConstant a) =>+ Exp a -> Exp a -> Causal.T am am+mapExponential depth center =+ let logDepth = log depth+ in map (\x -> center * exp (logDepth * x))+++loop ::+ (Expr.Aggregate ce c, Memory.C c) =>+ ce -> Causal.T (a,c) (b,c) -> Causal.T a b+loop initial = Causal.loop (Expr.bundle initial)++loopZero ::+ (A.Additive c, Memory.C c) =>+ Causal.T (a,c) (b,c) -> Causal.T a b+loopZero = Causal.loop (return A.zero)++loopConst ::+ (Memory.C c) =>+ c -> Causal.T (a,c) (b,c) -> Causal.T a b+loopConst c = Causal.loop (return c)+++integrate ::+ (Expr.Aggregate ae a, A.Additive a, Memory.C a) => ae -> Causal.T a a+integrate initial = loop initial (arr snd &&& Causal.zipWith A.add)++integrateZero :: (A.Additive a, Memory.C a) => Causal.T a a+integrateZero = loopZero (arr snd &&& Causal.zipWith A.add)+++feedbackControlledAux ::+ (Arrow arrow) =>+ arrow ((ctrl,a),c) b ->+ arrow (ctrl,b) c ->+ arrow ((ctrl,a),c) (b,c)+feedbackControlledAux forth back =+ arr snd &&& back <<< arr (fst.fst) &&& forth++feedbackControlled ::+ (Expr.Aggregate ce c, Memory.C c) =>+ ce -> Causal.T ((ctrl,a),c) b -> Causal.T (ctrl,b) c -> Causal.T (ctrl,a) b+feedbackControlled initial forth back =+ loop initial (feedbackControlledAux forth back)++feedbackControlledZero ::+ (A.Additive c, Memory.C c) =>+ Causal.T ((ctrl,a),c) b -> Causal.T (ctrl,b) c -> Causal.T (ctrl,a) b+feedbackControlledZero forth back =+ loopZero (feedbackControlledAux forth back)+++arrayPtr ::+ (TypeNum.Natural n, LLVM.IsSized a) =>+ LLVM.Value (LLVM.Ptr a) ->+ LLVM.CodeGenFunction r (LLVM.Value (LLVM.Ptr (LLVM.Array n a)))+arrayPtr = LLVM.bitcast++replicateControlledParam ::+ (TypeNum.Natural n) =>+ (Tuple.Undefined a, Tuple.Phi a) =>+ (Marshal.C b, (n TypeNum.:*: LLVM.SizeOf (Marshal.Struct b)) ~ bSize,+ TypeNum.Natural bSize) =>+ (Exp b -> Causal.T (c,a) a) ->+ Exp (MultiValue.Array n b) -> Causal.T (c,a) a+replicateControlledParam f ps = Unsafe.performIO $ do+ let n :: Word+ n = TypeNum.integralFromProxy $ arraySize ps+ paramd <- Parameterized.fromProcessPtr "Causal.replicateControlledParam" f+ return $+ case paramd of+ Parameterized.Cons next start stop ->+ Causal.Cons+ (\(bPtr,globalPtr) localPtr (c,a0) statePtr -> do+ a1 <-+ MaybeCont.fromBool $+ Iter.mapWhileState_+ (\(biPtr,globalIPtr,localIPtr,stateIPtr)+ (_cont,ai0) -> do+ global <- Memory.load globalIPtr+ local <- Memory.load localIPtr+ state0 <- Memory.load stateIPtr+ (conti,(ai1,state1)) <-+ MaybeCont.toBool $+ next biPtr global local (c,ai0) state0+ flip LLVM.store stateIPtr =<< Memory.compose state1+ return (conti,(conti,ai1)))+ (Iter.take (LLVM.valueOf n) $+ App.lift4 (,,,)+ (Iter.arrayPtrs bPtr)+ (Iter.arrayPtrs globalPtr)+ (Iter.arrayPtrs localPtr)+ (Iter.arrayPtrs statePtr))+ (LLVM.valueOf True, a0)+ return (a1, statePtr))+ (do+ bArr <- Expr.unExp ps+ bPtr <- LLVM.arrayMalloc n+ Memory.store bArr =<< arrayPtr bPtr+ {-+ ToDo:+ Instead of a pointer to a malloced with dynamic length+ we could use LLVM.Array.+ However, we would have to establish the constraint+ Natural (n :*: LLVM.SizeOf (Marshal.Struct a))+ This is pretty cumbersome+ with current decimal number representation.+ It would be feasible with type-level natural numbers, though.+ -}+ globalPtr <- LLVM.arrayMalloc n+ statePtr <- LLVM.arrayMalloc n+ Iter.mapM_+ (\(biPtr,globalIPtr,stateIPtr) -> do+ (global,state) <- start biPtr+ flip LLVM.store globalIPtr =<< Memory.compose global+ flip LLVM.store stateIPtr =<< Memory.compose state)+ (Iter.take (LLVM.valueOf n) $+ liftA3 (,,)+ (Iter.arrayPtrs bPtr)+ (Iter.arrayPtrs globalPtr)+ (Iter.arrayPtrs statePtr))+ return ((bPtr,globalPtr), statePtr))+ (\(bPtr,globalPtr) ->+ Iter.mapM_+ (\(biPtr,globalIPtr) -> do+ stop biPtr =<< Memory.load globalIPtr)+ (Iter.take (LLVM.valueOf n) $+ liftA2 (,)+ (Iter.arrayPtrs bPtr)+ (Iter.arrayPtrs globalPtr)))+++{- |+Run a causal process independently on each stereo channel.+-}+stereoFromMono ::+ (Tuple.Phi a, Tuple.Undefined a, Tuple.Phi b, Tuple.Undefined b) =>+ Causal.T a b -> Causal.T (Stereo.T a) (Stereo.T b)+stereoFromMono proc =+ snd+ ^<<+ Causal.replicateSerial 2+ ((\((x,a),b) -> (Stereo.swap a, Stereo.cons (Stereo.right b) x))+ ^<<+ Arrow.first ((proc <<^ Stereo.left) &&& Cat.id))+ <<^+ (\a -> (a, Tuple.undef))++stereoFromMonoControlled ::+ (Tuple.Phi a, Tuple.Phi b, Tuple.Phi c,+ Tuple.Undefined a, Tuple.Undefined b, Tuple.Undefined c) =>+ Causal.T (c,a) b -> Causal.T (c, Stereo.T a) (Stereo.T b)+stereoFromMonoControlled proc =+ stereoFromMono proc <<^ (\(c,sa) -> (,) c <$> sa)++arrayFromStereo ::+ (Marshal.C a) =>+ Stereo.T (MultiValue.T a) ->+ LLVM.CodeGenFunction r (MultiValue.T (MultiValue.Array TypeNum.D2 a))+arrayFromStereo a =+ MultiValue.insertArrayValue TypeNum.d0 (Stereo.left a) =<<+ MultiValue.insertArrayValue TypeNum.d1 (Stereo.right a) MultiValue.undef++stereoFromMonoParameterized ::+ (Marshal.C x,+ Tuple.Phi a, Tuple.Undefined a, Tuple.Phi b, Tuple.Undefined b) =>+ ((TypeNum.D2 TypeNum.:*: LLVM.SizeOf (Marshal.Struct x)) ~ xSize,+ TypeNum.Natural xSize) =>+ (Exp x -> Causal.T a b) ->+ Stereo.T (Exp x) -> Causal.T (Stereo.T a) (Stereo.T b)+stereoFromMonoParameterized f sx =+ snd+ ^<<+ replicateControlledParam+ (\x ->+ (\((y,a),b) -> (Stereo.swap a, Stereo.cons (Stereo.right b) y))+ ^<<+ Arrow.first ((f x <<^ Stereo.left) &&& Cat.id)+ <<^+ snd)+ (Expr.liftM arrayFromStereo sx)+ <<^+ (\a -> ((),(a,Tuple.undef)))+++mapAccum ::+ (Expr.Aggregate state statel, Memory.C statel,+ Expr.Aggregate a al, Expr.Aggregate b bl) =>+ (a -> state -> (b, state)) -> state -> Causal.T al bl+mapAccum next start =+ Causal.mapAccum+ (\a s -> Expr.bundle $ next (Expr.dissect a) (Expr.dissect s))+ (Expr.bundle start)++fromModifier ::+ (Expr.Aggregate ae al,+ Expr.Aggregate be bl,+ Expr.Aggregate ce cl,+ Expr.Aggregate se sl, Memory.C sl) =>+ Modifier.Simple se ce ae be -> Causal.T (cl,al) bl+fromModifier (Modifier.Simple initial step) =+ mapAccum (\(c,a) -> MS.runState (step c a)) initial+++delay1 :: (Expr.Aggregate ae a, Memory.C a) => ae -> Causal.T a a+delay1 initial = loop initial (arr swap)++differentiate ::+ (A.Additive a, Expr.Aggregate ae a, Memory.C a) => ae -> Causal.T a a+differentiate initial = Cat.id - delay1 initial+++{- |+Compute the phases from phase distortions and frequencies.++It's like integrate but with wrap-around performed by @fraction@.+For FM synthesis we need also negative phase distortions,+thus we use 'A.addToPhase' which supports that.+-}+osciCore, _osciCore, osciCoreSync ::+ (Memory.C t, A.Fraction t) => Causal.T (t, t) t+_osciCore =+ Causal.zipWith A.addToPhase <<<+ Arrow.second+ (Causal.mapAccum+ (\a s -> do+ b <- A.incPhase a s+ return (s,b))+ (return A.zero))++{-+This could be implemented using a generalized frequencyModulation,+however, osciCoreSync allows for negative phase differences.+-}+osciCoreSync =+ Causal.zipWith A.addToPhase <<<+ Arrow.second+ (Causal.mapAccum+ (\a s -> do+ b <- A.incPhase a s+ return (b,b))+ (return A.zero))++osciCore =+ Causal.zipWith A.addToPhase <<<+ Arrow.second (loopZero (arr snd &&& Causal.zipWith A.incPhase))++osci ::+ (Memory.C t, A.Fraction t) =>+ (forall r. t -> LLVM.CodeGenFunction r y) ->+ Causal.T (t, t) y+osci wave = Causal.map wave <<< osciCore++shapeModOsci ::+ (Memory.C t, A.Fraction t) =>+ (forall r. c -> t -> LLVM.CodeGenFunction r y) ->+ Causal.T (c, (t, t)) y+shapeModOsci wave = Causal.zipWith wave <<< Arrow.second osciCore+++{- |+Feeds a signal into a causal process while holding or skipping signal elements+according to the process input.+The skip happens after a value is passed from the fed signal.++@skip x $* 0@ repeats the first signal value in the output.+@skip x $* 1@ feeds the signal to the output as is.+@skip x $* 2@ feeds the signal to the output with double speed.+-}+skip ::+ (Tuple.Undefined a, Tuple.Phi a, Memory.C a) =>+ Sig.T a -> Causal.T (MultiValue.T Word) a+skip (SigPriv.Cons next start stop) = Causal.Cons+ (\global local n1 (yState0, MultiValue.Cons n0) -> do+ yState1@(y,_) <-+ MaybeCont.fromMaybe $ fmap snd $+ MaybeCont.fixedLengthLoop n0 yState0 $+ next global local . snd+ return (y, (yState1,n1)))+ (mapSnd (\s -> ((Tuple.undef, s), A.one)) <$> start)+ stop++frequencyModulation ::+ (Marshal.C a,+ MultiValue.IntegerConstant a,+ MultiValue.Additive a,+ MultiValue.Comparison a,+ Tuple.Undefined nodes, Tuple.Phi nodes, Memory.C nodes) =>+ (forall r. MultiValue.T a -> nodes -> LLVM.CodeGenFunction r v) ->+ SigPriv.T nodes -> Causal.T (MultiValue.T a) v+frequencyModulation ip (SigPriv.Cons next start stop) = Causal.Cons+ (\global local k yState0 -> do+ ((nodes2,state2), ss2) <-+ MaybeCont.fromBool $+ C.whileLoop+ (LLVM.valueOf True, yState0)+ (\(cont0, (_, ss0)) ->+ LLVM.and cont0 . unbool =<< MultiValue.cmp LLVM.CmpGE ss0 A.one)+ (\(_,((_,state0), ss0)) ->+ MaybeCont.toBool $ liftA2 (,)+ (next global local state0)+ (MaybeCont.lift $ A.sub ss0 A.one))++ MaybeCont.lift $ do+ y <- ip ss2 nodes2+ ss3 <- A.add ss2 k+ return (y, ((nodes2, state2), ss3)))+ (fmap (\(global,sa) -> (global, ((Tuple.undef, sa), A.one))) start)+ stop++frequencyModulationLinear ::+ (MultiValue.PseudoRing a, MultiValue.IntegerConstant a,+ MultiValue.Comparison a, Marshal.C a) =>+ Sig.MV a -> MV a a+frequencyModulationLinear sig =+ frequencyModulation Interpolation.linear (Sig.adjacentNodes02 sig)+++track ::+ (Expr.Aggregate ae al, Memory.C al) =>+ ae -> Exp Word -> Causal.T al (RingBuffer.T al)+track initial time = Causal.Cons+ (\(size0,ptr) -> noLocalPtr $ \a remain0 -> MaybeCont.lift $ do+ Memory.store a =<< LLVM.getElementPtr ptr (remain0, ())+ cont <- A.cmp LLVM.CmpGT remain0 A.zero+ remain1 <- C.ifThenSelect cont size0 (A.dec remain0)+ size1 <- A.inc size0+ return (RingBuffer.Cons ptr size1 remain0 remain1, remain1))+ (do+ MultiValue.Cons size0 <- Expr.unExp time+ size1 <- A.inc size0+ ptr <- LLVM.arrayMalloc size1+ a <- Expr.bundle initial+ -- cf. LLVM.Storable.Signal.fill+ C.arrayLoop size1 ptr () $ \ ptri () -> Memory.store a ptri+ return ((size0,ptr), size0))+ (LLVM.free . snd)++{- |+Delay time must be non-negative.+-}+delay ::+ (Expr.Aggregate ae al, Memory.C al) =>+ ae -> Exp Word -> Causal.T al al+delay initial time = Causal.map RingBuffer.oldest <<< track initial time++delayZero ::+ (Expr.Aggregate ae al, Additive.C ae, Memory.C al) =>+ Exp Word -> Causal.T al al+delayZero = delay zero++{- |+Delay time must be greater than zero!+-}+comb ::+ (Marshal.C a, MultiValue.PseudoRing a) =>+ Exp a -> Exp Word -> MV a a+comb gain time =+ loopZero (mix >>> (Cat.id &&& (delayZero (time-1) >>> amplify gain)))++combStereo ::+ (Marshal.C a, MultiValue.PseudoRing a, Stereo.T (MultiValue.T a) ~ stereo) =>+ Exp a -> Exp Word -> Causal.T stereo stereo+combStereo gain time =+ loopZero (mix >>> (Cat.id &&& (delayZero (time-1) >>> amplifyStereo gain)))++reverbExplicit ::+ (TypeNum.Natural n, (n TypeNum.:*: LLVM.UnknownSize) ~ paramSize,+ TypeNum.Natural paramSize) =>+ (Marshal.C a,+ MultiValue.Field a, MultiValue.Real a, MultiValue.IntegerConstant a) =>+ Exp (MultiValue.Array n (a,Word)) -> MV a a+reverbExplicit params =+ amplify (Expr.recip $ TypeNum.integralFromProxy $ arraySize params)+ <<<+ replicateControlledParam+ (\p -> Arrow.first (comb (Expr.fst p) (Expr.snd p)) >>> mix)+ params+ <<^+ (\a -> (a,a))++reverbParams ::+ (RandomGen g, TypeNum.Integer n, Random a) =>+ g -> Proxy n -> (a,a) -> (Word, Word) -> MultiValue.Array n (a, Word)+reverbParams rnd Proxy gainRange timeRange =+ flip MS.evalState rnd $+ sequenceA $ pure $+ liftA2 (,)+ (MS.state (randomR gainRange))+ (MS.state (randomR timeRange))+++{- |+Delay by a variable amount of samples.+The momentum delay must be between @0@ and @maxTime@, inclusively.+How about automated clipping?+-}+delayControlled ::+ (Expr.Aggregate ae al, Memory.C al) =>+ ae -> Exp Word -> Causal.T (MultiValue.T Word, al) al+delayControlled initial maxTime =+ Causal.zipWith RingBuffer.index+ <<<+ arr (\(MultiValue.Cons i) -> i) *** track initial maxTime++{- |+Delay by a variable fractional amount of samples.+Non-integer delays are achieved by interpolation.+The momentum delay must be between @0@ and @maxTime@, inclusively.+-}+delayControlledInterpolated ::+ (Interpolation.C nodes) =>+ (MultiValue.T a ~ am) =>+ (MultiValue.NativeFloating a ar, MultiValue.Additive a) =>+ (Expr.Aggregate ve v, Memory.C v) =>+ (forall r. Interpolation.T r nodes am v) ->+ ve -> Exp Word -> Causal.T (am, v) v+delayControlledInterpolated ip initial maxTime =+ let margin = Interpolation.toMargin ip+ in Causal.zipWith+ (\del buf -> do+ let offset =+ A.fromInteger' $ fromIntegral $+ Interpolation.marginOffset margin+ n <- A.max offset =<< MultiValue.truncateToInt del+ k <- A.sub del =<< MultiValue.fromIntegral n+ ~(MultiValue.Cons m) <- A.sub n (offset :: MultiValue.T Word)+ ip k =<<+ Interpolation.indexNodes (flip RingBuffer.index buf) A.one m)+ <<<+ Arrow.second+ (track initial+ (fromIntegral (Interpolation.marginNumber margin) + maxTime))+++{- |+This allows to compute a chain of equal processes efficiently,+if all of these processes can be bundled in one vectorial process.+Applications are an allpass cascade or an FM operator cascade.++The function expects that the vectorial input process+works like parallel scalar processes.+The different pipeline stages may be controlled by different parameters,+but the structure of all pipeline stages must be equal.+Our function feeds the input of the pipelined process+to the zeroth element of the Vector.+The result of processing the i-th element (the i-th channel, so to speak)+is fed to the (i+1)-th element.+The (n-1)-th element of the vectorial process is emitted+as output of the pipelined process.++The pipeline necessarily introduces a delay of (n-1) values.+For simplification we extend this to n values delay.+If you need to combine the resulting signal from the pipeline+with another signal in a 'zip'-like way,+you may delay that signal with @pipeline id@.+The first input values in later stages of the pipeline+are initialized with zero.+If this is not appropriate for your application,+then we may add a more sensible initialization.+-}+pipeline ::+ (TypeNum.Positive n, MultiVector.C x,+ v ~ MultiVector.T n x,+ a ~ MultiValue.T x,+ Tuple.Zero v, Memory.C v) =>+ Causal.T v v -> Causal.T a a+pipeline vectorProcess =+ loopConst MultiVector.zero $+ Causal.map (uncurry MultiVector.shiftUp)+ >>>+ Arrow.second vectorProcess+++{-+insert and extract instructions will be in opposite order,+no matter whether we use foldr or foldl+and independent from the order of proc and channel in replaceChannel.+However, LLVM neglects the order anyway.+-}+vectorize ::+ (TypeNum.Positive n,+ MultiVector.C x, MultiValue.T x ~ a, MultiVector.T n x ~ va,+ MultiVector.C y, MultiValue.T y ~ b, MultiVector.T n y ~ vb) =>+ Causal.T a b -> Causal.T va vb+vectorize proc =+ withSize $ \n ->+ foldl+ (\acc i -> replaceChannel i proc acc)+ (arr (const Tuple.undef)) $+ List.take (TypeNum.integralFromSingleton n) [0 ..]++withSize ::+ (TypeNum.Positive n, MultiVector.T n a ~ v) =>+ (TypeNum.Singleton n -> f v) ->+ f v+withSize f = f TypeNum.singleton++{- |+Given a vector process, replace the i-th output by output+that is generated by a scalar process from the i-th input.+-}+replaceChannel ::+ (TypeNum.Positive n,+ MultiVector.C x, MultiValue.T x ~ a, MultiVector.T n x ~ va,+ MultiVector.C y, MultiValue.T y ~ b, MultiVector.T n y ~ vb) =>+ Int -> Causal.T a b -> Causal.T va vb -> Causal.T va vb+replaceChannel i channel proc =+ let li = LLVM.valueOf $ fromIntegral i+ in Causal.zipWith (MultiVector.insert li) <<<+ (channel <<< Causal.map (MultiVector.extract li)) &&&+ proc+++{- |+Read the i-th element from each array.+-}+arrayElement ::+ (Marshal.C a, Marshal.Struct a ~ aStruct, LLVM.IsFirstClass aStruct,+ TypeNum.Natural i, TypeNum.Natural n, i :<: n) =>+ Proxy i -> Causal.T (MultiValue.T (MultiValue.Array n a)) (MultiValue.T a)+arrayElement i = Causal.map (MultiValue.extractArrayValue i)+++{- |+@trigger fill signal@ sends @signal@ to the output+and restarts it whenever the process input is 'Just'.+Before the Arrow.first occurrence of 'Just'+and between instances of the signal the output is filled with 'Maybe.nothing'.+-}+trigger ::+ (Marshal.C a, Tuple.Undefined b, Tuple.Phi b) =>+ (Exp a -> Sig.T b) ->+ Causal.T (Maybe.T (MultiValue.T a)) (Maybe.T b)+trigger f = Unsafe.performIO $ do+ paramd <-+ Parameterized.fromProcess "Causal.trigger" (CausalClass.fromSignal . f)+ return $+ case paramd of+ Parameterized.Cons next start stop -> Causal.Cons+ (\globalPtr local ma ms0 -> MaybeCont.lift $ do+ ms1 <-+ Maybe.run ma+ (return ms0)+ (\a -> do+ stopAndFree stop globalPtr+ (global2,state2) <- start a+ Memory.store (Maybe.just (a,global2)) globalPtr+ return $ Maybe.just state2)+ mc1 <- Memory.load globalPtr+ mcs1 <- Maybe.lift2 (,) mc1 ms1+ as2 <-+ Maybe.run mcs1 (return Maybe.nothing) $ \((p1,c1),s1) ->+ MaybeCont.toMaybe $ next p1 c1 local () s1+ return $ FuncHT.unzip as2)+ (do+ globalPtr <- LLVM.malloc+ Memory.store (nothingFromFunc f stop) globalPtr+ return (globalPtr, Maybe.nothing))+ (\globalPtr -> do+ stopAndFree stop globalPtr+ LLVM.free globalPtr)++stopAndFree ::+ (Memory.C global, Memory.C am) =>+ (am -> global -> LLVM.CodeGenFunction r ()) ->+ LLVM.Value (LLVM.Ptr (Memory.Struct (Maybe.T (am, global)))) ->+ LLVM.CodeGenFunction r ()+stopAndFree stop globalPtr = do+ maybeGlobal <- Memory.load globalPtr+ Maybe.for maybeGlobal $ \(a,global) -> stop a global++nothingFromFunc ::+ (MultiValue.C a, Tuple.Undefined global) =>+ (Exp a -> Sig.T b) ->+ (ap -> global -> code) ->+ Maybe.T (MultiValue.T a, global)+nothingFromFunc _ _ = Maybe.nothing
src/Synthesizer/LLVM/Causal/ProcessPacked.hs view
@@ -1,76 +1,83 @@-{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE Rank2Types #-} {-# LANGUAGE TypeOperators #-}+{-# LANGUAGE Rank2Types #-} module Synthesizer.LLVM.Causal.ProcessPacked where +import qualified Synthesizer.LLVM.Causal.Private as CausalPriv import qualified Synthesizer.LLVM.Causal.Process as Causal-import Synthesizer.LLVM.Causal.ProcessPrivate (Core(Core), alter)- import qualified Synthesizer.LLVM.Frame.SerialVector as Serial+import qualified Synthesizer.LLVM.Frame.SerialVector.Code as SerialCode+import qualified Synthesizer.LLVM.Frame.SerialVector.Class as SerialClass+import qualified Synthesizer.LLVM.Frame.Stereo as Stereo+import qualified Synthesizer.LLVM.Frame as Frame -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.DSL.Expression as Expr+import LLVM.DSL.Expression (Exp)++import qualified LLVM.Extra.Multi.Vector as MultiVector+import qualified LLVM.Extra.Multi.Value.Marshal as Marshal+import qualified LLVM.Extra.Multi.Value as MultiValue import qualified LLVM.Extra.Tuple as Tuple-import qualified LLVM.Extra.Arithmetic as A+import qualified LLVM.Extra.MaybeContinuation as Maybe import qualified LLVM.Extra.Control as C--import qualified LLVM.Core as LLVM-import LLVM.Core- (CodeGenFunction, Value, valueOf,- IsSized, IsFirstClass)+import qualified LLVM.Extra.Arithmetic as A import qualified Type.Data.Num.Decimal as TypeNum import Type.Data.Num.Decimal ((:<:)) import Type.Base.Proxy (Proxy) +import qualified LLVM.Core as LLVM++import qualified Control.Arrow as Arrow+import qualified Control.Category as Cat import qualified Control.Monad.Trans.Class as MT import qualified Control.Monad.Trans.State as MS-import qualified Control.Arrow as Arr import Control.Arrow ((<<<)) +import Data.Tuple.HT (swap) import Data.Word (Word) import NumericPrelude.Numeric-import NumericPrelude.Base+import NumericPrelude.Base hiding (map, zipWith, takeWhile)+import Prelude () +type Serial n a = MultiValue.T (Serial.T n a)++ {- | 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 ::- (Causal.C process,- Serial.Read va, n ~ Serial.Size va, a ~ Serial.Element va,- Serial.C vb, n ~ Serial.Size vb, b ~ Serial.Element vb) =>- process a b -> process va vb-pack = alter (\(Core next start stop) -> Core- (\param a s -> do- r <- Maybe.lift $ Serial.readStart a+ (SerialClass.Read va, n ~ SerialClass.Size va, a ~ SerialClass.Element va,+ SerialClass.Write vb, n ~ SerialClass.Size vb, b ~ SerialClass.Element vb)+ =>+ Causal.T a b -> Causal.T va vb+pack (CausalPriv.Cons next start stop) = CausalPriv.Cons+ (\global local a s -> do+ r <- Maybe.lift $ SerialClass.readStart a ((_,w2),(_,s2)) <- Maybe.fromBool $ C.whileLoop- (valueOf True,+ (LLVM.valueOf True, let w = Tuple.undef- in ((r,w),- (valueOf (fromIntegral $ Serial.sizeOfIterator w :: Word), s)))+ in ((r,w),+ (LLVM.valueOf (SerialClass.sizeOfIterator w :: Word), s))) (\(cont,(_rw0,(i0,_s0))) ->- A.and cont =<<- A.cmp LLVM.CmpGT i0 A.zero)+ 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+ (ai,r1) <- Maybe.lift $ SerialClass.readNext r0+ (bi,s1) <- next global local ai s0 Maybe.lift $ do- w1 <- Serial.writeNext bi w0+ w1 <- SerialClass.writeNext bi w0 i1 <- A.dec i0 return ((r1,w1),(i1,s1)))- b <- Maybe.lift $ Serial.writeStop w2+ b <- Maybe.lift $ SerialClass.writeStop w2 return (b, s2)) start- stop)+ stop {- | Like 'pack' but duplicates the code for the scalar process.@@ -79,100 +86,95 @@ This is efficient only for simple input processes. -} packSmall ::- (Causal.C process,- Serial.Read va, n ~ Serial.Size va, a ~ Serial.Element va,- Serial.C vb, n ~ Serial.Size vb, b ~ Serial.Element vb) =>- process a b -> process va vb-packSmall = alter (\(Core next start stop) -> Core- (\param a ->+ (SerialClass.Read va, n ~ SerialClass.Size va, a ~ SerialClass.Element va,+ SerialClass.Write vb, n ~ SerialClass.Size vb, b ~ SerialClass.Element vb)+ =>+ Causal.T a b -> Causal.T va vb+packSmall (CausalPriv.Cons next start stop) = CausalPriv.Cons+ (\global local a -> MS.runStateT $- (MT.lift . Maybe.lift . Serial.assemble)+ MT.lift . Maybe.lift . SerialClass.assemble =<<- mapM (MS.StateT . next param)+ mapM (MS.StateT . next global local) =<<- (MT.lift $ Maybe.lift $ Serial.extractAll a))+ (MT.lift $ Maybe.lift $ SerialClass.dissect a)) start- stop)+ stop -{- |-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 ::- (Causal.C process,- Serial.Zero va, n ~ Serial.Size va, a ~ Serial.Element va,- Serial.Read vb, n ~ Serial.Size vb, b ~ Serial.Element vb,- Memory.C va, Memory.C ita, ita ~ Serial.WriteIt va,- Memory.C vb, Memory.C itb, itb ~ Serial.ReadIt vb) =>- process va vb -> process a b-unpack = alter (\(Core next start stop) -> Core- (\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))))- (\s -> do- s1 <- start s- w <- Serial.writeZero- return ((w, Tuple.undef), (valueOf (0::Word), s1)))- (\(_wr,(_i,state)) -> stop state))+raise ::+ (TypeNum.Positive n, MultiVector.Additive a) =>+ Exp a -> Causal.T (Serial n a) (Serial n a)+raise x =+ CausalPriv.map+ (\y -> Expr.unExp (Serial.upsample x) >>= flip Frame.mix y) +amplify ::+ (TypeNum.Positive n, MultiVector.PseudoRing a) =>+ Exp a -> Causal.T (Serial n a) (Serial n a)+amplify x =+ CausalPriv.map+ (\y -> Expr.unExp (Serial.upsample x) >>= flip Frame.amplifyMono y) +amplifyStereo ::+ (TypeNum.Positive n, MultiVector.PseudoRing a) =>+ Exp a -> Causal.T (Stereo.T (Serial n a)) (Stereo.T (Serial n a))+amplifyStereo x =+ CausalPriv.map+ (\y -> Expr.unExp (Serial.upsample x) >>= flip Frame.amplifyStereo y)+++delay1 ::+ (LLVM.Positive n, Marshal.C a,+ MultiVector.C a, SerialCode.Value n a ~ v) =>+ Exp a -> Causal.T v v+delay1 initial =+ Causal.loop initial $+ Causal.map (swap . uncurry Serial.shiftUp . swap)++differentiate ::+ (LLVM.Positive n, Marshal.C a,+ MultiVector.Additive a, SerialCode.Value n a ~ v) =>+ Exp a -> Causal.T v v+differentiate initial = Cat.id - delay1 initial++integrate ::+ (LLVM.Positive n, Marshal.C a,+ MultiVector.Additive a, SerialCode.Value n a ~ v) =>+ Exp a -> Causal.T v v+integrate =+ Causal.mapAccum (\a acc0 -> swap $ Serial.cumulate acc0 a)++ osciCore ::- (Causal.C process,- IsSized t, Vector.Real t, SoV.Fraction t, LLVM.IsFloating t,- TypeNum.Positive n) =>- process (Serial.Value n t, Serial.Value n t) (Serial.Value n t)+ (TypeNum.Positive n, Marshal.C t, MultiVector.Fraction t) =>+ Causal.T (Serial n t, Serial n t) (Serial n t) osciCore =- Causal.zipWith A.addToPhase <<<- Arr.second+ CausalPriv.zipWith A.addToPhase <<<+ Arrow.second (Causal.mapAccum- (\a phase0 -> do- (phase1,b1) <- Serial.cumulate phase0 a- phase2 <- A.signedFraction phase1- return (b1,phase2))- (return A.zero))+ (\a phase0 ->+ let (phase1,b1) = Serial.cumulate phase0 a+ in (b1, Expr.liftM A.signedFraction phase1))+ Expr.zero) osci ::- (Causal.C process,- IsSized t, Vector.Real t, SoV.Fraction t, LLVM.IsFloating t,- TypeNum.Positive n) =>- (forall r. Serial.Value n t -> CodeGenFunction r y) ->- process (Serial.Value n t, Serial.Value n t) y-osci wave =- Causal.map wave <<< osciCore+ (TypeNum.Positive n, Marshal.C t, MultiVector.Fraction t) =>+ (forall r. Serial n t -> LLVM.CodeGenFunction r y) ->+ Causal.T (Serial n t, Serial n t) y+osci wave = CausalPriv.map wave <<< osciCore shapeModOsci ::- (Causal.C process,- IsSized t, Vector.Real t, SoV.Fraction t, LLVM.IsFloating t,- TypeNum.Positive n) =>- (forall r. c -> Serial.Value n t -> CodeGenFunction r y) ->- process (c, (Serial.Value n t, Serial.Value n t)) y-shapeModOsci wave =- Causal.zipWith wave <<< Arr.second osciCore-+ (TypeNum.Positive n, Marshal.C t, MultiVector.Fraction t) =>+ (forall r. c -> Serial n t -> LLVM.CodeGenFunction r y) ->+ Causal.T (c, (Serial n t, Serial n t)) y+shapeModOsci wave = CausalPriv.zipWith wave <<< Arrow.second osciCore arrayElement ::- (Causal.C process,- IsFirstClass a, LLVM.Value a ~ Serial.Element v, Serial.C v,- TypeNum.Natural index, TypeNum.Natural dim,- index :<: dim) =>- Proxy index -> process (Value (LLVM.Array dim a)) v-arrayElement i =- Causal.map Serial.upsample <<< Causal.arrayElement i+ (TypeNum.Positive n,+ MultiVector.C a, Marshal.C a,+ Marshal.Struct a ~ aStruct, LLVM.IsFirstClass aStruct,+ TypeNum.Natural i, TypeNum.Natural d, i :<: d) =>+ Proxy i -> Causal.T (MultiValue.T (MultiValue.Array d a)) (Serial n a)+arrayElement i = Causal.map Serial.upsample <<< Causal.arrayElement i
− src/Synthesizer/LLVM/Causal/ProcessPrivate.hs
@@ -1,306 +0,0 @@-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE ExistentialQuantification #-}-{-# LANGUAGE Rank2Types #-}-module Synthesizer.LLVM.Causal.ProcessPrivate where--import qualified Synthesizer.LLVM.Simple.SignalPrivate as Sig-import qualified Synthesizer.Causal.Class as CausalClass-import qualified Synthesizer.Causal.Utility as ArrowUtil--import qualified LLVM.Extra.Tuple as Tuple-import qualified LLVM.Extra.Arithmetic as A-import qualified LLVM.Extra.MaybeContinuation as MaybeCont-import qualified LLVM.Extra.Marshal as Marshal-import qualified LLVM.Extra.Memory as Memory--import LLVM.Core (CodeGenFunction, Value)--import System.Random (Random, RandomGen, randomR)--import qualified Control.Arrow as Arr-import qualified Control.Category as Cat-import qualified Control.Monad.Trans.State as MS-import Control.Arrow (Arrow, arr, (<<<), (>>>), (&&&))-import Control.Monad (liftM2, replicateM)-import Control.Applicative (Applicative, pure, (<*>))--import qualified Number.Ratio as Ratio-import qualified Algebra.Field as Field-import qualified Algebra.Ring as Ring-import qualified Algebra.Additive as Additive--import NumericPrelude.Numeric-import NumericPrelude.Base hiding (and, map, zip, zipWith, init)--import qualified Prelude as P---data Core context initState exitState a b =- forall state.- (Memory.C state) =>- Core (forall r c.- (Tuple.Phi c) =>- context ->- a -> state -> MaybeCont.T r c (b, state))- -- compute next value- (forall r.- initState ->- CodeGenFunction r state)- -- initial state- (state -> exitState)- -- extract final state for cleanup---class- (CausalClass.C process, Sig.C (CausalClass.SignalOf process)) =>- C process where- simple ::- (Memory.C state) =>- (forall r c.- (Tuple.Phi c) =>- a -> state -> MaybeCont.T r c (b, state)) ->- (forall r. CodeGenFunction r state) ->- process a b-- alter ::- (forall contextLocal initState exitState.- Core contextLocal initState exitState a0 b0 ->- Core contextLocal initState exitState a1 b1) ->- process a0 b0 -> process a1 b1-- replicateControlled ::- (Tuple.Undefined x, Tuple.Phi x) =>- Int -> process (c,x) x -> process (c,x) x---alterSignal ::- (C process, CausalClass.SignalOf process ~ signal) =>- (forall contextLocal initState exitState.- Sig.Core contextLocal initState exitState a0 ->- Core contextLocal initState exitState a1 b1) ->- signal a0 -> process a1 b1-alterSignal f =- alter (\(Core next start stop) -> f (Sig.Core (\c -> next c ()) start stop))- .- CausalClass.fromSignal----data T a b =- forall state local ioContext parameters.- (Marshal.C parameters, Memory.C state) =>- Cons (forall r c.- (Tuple.Phi c) =>- Tuple.ValueOf parameters -> local ->- a -> state -> MaybeCont.T r c (b, state))- -- compute next value- (forall r.- CodeGenFunction r local)- -- allocate temporary variables before a loop- (forall r.- Tuple.ValueOf parameters ->- CodeGenFunction r state)- -- initial state- (IO (ioContext, parameters))- -- initialization from IO monad- (ioContext -> IO ())- -- finalization from IO monad---type instance CausalClass.ProcessOf Sig.T = T--instance CausalClass.C T where- type SignalOf T = Sig.T- toSignal = toSignal- fromSignal = fromSignal--instance C T where- simple next start =- Cons- (const $ \ () -> next)- (return ())- (const start)- (return ((),()))- (const $ return ())-- alter f (Cons next0 alloca start0 create delete) =- case f (Core (uncurry next0) start0 id) of- Core next1 start1 _ ->- Cons (curry next1) alloca start1 create delete-- {-- Could be implemented with a machine code loop like in CausalParameterized.- But to this end we would need a 'stop' function.- -}- replicateControlled = CausalClass.replicateControlled---toSignal :: T () a -> Sig.T a-toSignal (Cons next alloca start createIOContext deleteIOContext) = Sig.Cons- (\ioContext local -> next ioContext local ())- alloca- start- createIOContext deleteIOContext--fromSignal :: Sig.T b -> T a b-fromSignal (Sig.Cons next alloca start createIOContext deleteIOContext) = Cons- (\ioContext local _ -> next ioContext local)- alloca- start- createIOContext deleteIOContext---map ::- (C process) =>- (forall r. a -> CodeGenFunction r b) ->- process a b-map f =- mapAccum (\a s -> fmap (flip (,) s) $ f a) (return ())--mapAccum ::- (C process, Memory.C state) =>- (forall r.- a -> state -> CodeGenFunction r (b, state)) ->- (forall r. CodeGenFunction r state) ->- process a b-mapAccum next =- simple (\a s -> MaybeCont.lift $ next a s)--zipWith ::- (C process) =>- (forall r. a -> b -> CodeGenFunction r c) ->- process (a,b) c-zipWith f = map (uncurry f)---mapProc ::- (C process) =>- (forall r. b -> CodeGenFunction r c) ->- process a b ->- process a c-mapProc f x = map f <<< x--zipProcWith ::- (C process) =>- (forall r. b -> c -> CodeGenFunction r d) ->- process a b ->- process a c ->- process a d-zipProcWith f x y = zipWith f <<< x&&&y---takeWhile ::- (C process) =>- (forall r. a -> CodeGenFunction r (Value Bool)) ->- process a a-takeWhile p =- simple- (\a () -> do- MaybeCont.guard =<< MaybeCont.lift (p a)- return (a,()))- (return ())---compose :: T a b -> T b c -> T a c-compose- (Cons nextA allocaA startA createIOContextA deleteIOContextA)- (Cons nextB allocaB startB createIOContextB deleteIOContextB) = Cons- (\(paramA, paramB) (localA, localB) a (sa0,sb0) -> do- (b,sa1) <- nextA paramA localA a sa0- (c,sb1) <- nextB paramB localB b sb0- return (c, (sa1,sb1)))- (liftM2 (,) allocaA allocaB)- (Sig.combineStart startA startB)- (Sig.combineCreate createIOContextA createIOContextB)- (Sig.combineDelete deleteIOContextA deleteIOContextB)---first :: (C process) => process b c -> process (b, d) (c, d)-first = alter (\(Core next start stop) -> Core (firstNext next) start stop)---instance Cat.Category T where- id = map return- (.) = flip compose--instance Arr.Arrow T where- arr f = map (return . f)- first = first----instance Functor (T a) where- fmap = ArrowUtil.map--instance Applicative (T a) where- pure = ArrowUtil.pure- (<*>) = ArrowUtil.apply---instance (A.Additive b) => Additive.C (T a b) where- zero = pure A.zero- negate = mapProc A.neg- (+) = zipProcWith A.add- (-) = zipProcWith A.sub--instance (A.PseudoRing b, A.IntegerConstant b) => Ring.C (T a b) where- one = pure A.one- fromInteger n = pure (A.fromInteger' n)- (*) = zipProcWith A.mul--instance (A.Field b, A.RationalConstant b) => Field.C (T a b) where- fromRational' x = pure (A.fromRational' $ Ratio.toRational98 x)- (/) = zipProcWith A.fdiv---instance (A.PseudoRing b, A.Real b, A.IntegerConstant b) => P.Num (T a b) where- fromInteger n = pure (A.fromInteger' n)- negate = mapProc A.neg- (+) = zipProcWith A.add- (-) = zipProcWith A.sub- (*) = zipProcWith A.mul- abs = mapProc A.abs- signum = mapProc A.signum--instance (A.Field b, A.Real b, A.RationalConstant b) => P.Fractional (T a b) where- fromRational x = pure (A.fromRational' x)- (/) = zipProcWith A.fdiv----firstNext ::- (Functor m) =>- (context -> a -> s -> m (b, s)) ->- context -> (a, c) -> s -> m ((b, c), s)-firstNext next context (b,d) s0 =- fmap- (\(c,s1) -> ((c,d), s1))- (next context b s0)--loopNext ::- (Monad m) =>- (context -> (a,c) -> state -> m ((b,c), state)) ->- context -> a -> (c, state) -> m (b, (c, state))-loopNext next ctx a0 (c0,s0) = do- ((b1,c1), s1) <- next ctx (a0,c0) s0- return (b1,(c1,s1))--feedbackControlledAux ::- Arrow arrow =>- arrow ((ctrl,a),c) b ->- arrow (ctrl,b) c ->- arrow ((ctrl,a),c) (b,c)-feedbackControlledAux forth back =- arr (fst.fst) &&& forth >>> arr snd &&& back---reverbParams ::- (RandomGen g, Random a) =>- g -> Int -> (a, a) -> (Int, Int) -> [(a, Int)]-reverbParams rnd num gainRange timeRange =- flip MS.evalState rnd $- replicateM num $- liftM2 (,)- (MS.state (randomR gainRange))- (MS.state (randomR timeRange))
src/Synthesizer/LLVM/Causal/ProcessValue.hs view
@@ -1,50 +1,46 @@-{- |-This module provides functions similar to-"Synthesizer.LLVM.Causal.Process"-but expects functions that operate on 'Value.T'.-This way you can use common arithmetic operators-instead of LLVM assembly functions.--}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE Rank2Types #-} module Synthesizer.LLVM.Causal.ProcessValue (- map, zipWith, mapAccum, takeWhile,+ Causal.T,+ mapAccum,+ fromModifier, ) where -import qualified Synthesizer.LLVM.Causal.Process as Causal-import qualified Synthesizer.LLVM.Simple.Value as Value+import qualified Synthesizer.LLVM.Causal.Private as Causal +import qualified Synthesizer.LLVM.Value as Value++import qualified Synthesizer.Plain.Modifier as Modifier++import qualified LLVM.Extra.MaybeContinuation as MaybeCont import qualified LLVM.Extra.Memory as Memory+ import qualified LLVM.Core as LLVM -import Prelude (Bool)+import Control.Monad.Trans.State (runState) -map ::- (Causal.C process) =>- (Value.T a -> Value.T b) ->- process a b-map f =- Causal.map (Value.unlift1 f) -zipWith ::- (Causal.C process) =>- (Value.T a -> Value.T b -> Value.T c) ->- process (a,b) c-zipWith f =- Causal.zipWith (Value.unlift2 f)- mapAccum ::- (Causal.C process, Memory.C s) =>- (Value.T a -> Value.T s -> (Value.T b, Value.T s)) ->- Value.T s ->- process a b-mapAccum next start =- Causal.mapAccum- (Value.unlift2 next)- (Value.unlift0 start)+ (Memory.C state) =>+ (forall r. a -> state -> LLVM.CodeGenFunction r (b, state)) ->+ (forall r. LLVM.CodeGenFunction r state) ->+ Causal.T a b+mapAccum next = Causal.simple (\a s -> MaybeCont.lift $ next a s) -takeWhile ::- (Causal.C process) =>- (Value.T a -> Value.T (LLVM.Value Bool)) ->- process a a-takeWhile p =- Causal.takeWhile (Value.unlift1 p)+fromModifier ::+ (Value.Flatten ah, Value.Registers ah ~ al,+ Value.Flatten bh, Value.Registers bh ~ bl,+ Value.Flatten ch, Value.Registers ch ~ cl,+ Value.Flatten sh, Value.Registers sh ~ sl,+ Memory.C sl) =>+ Modifier.Simple sh ch ah bh -> Causal.T (cl,al) bl+fromModifier (Modifier.Simple initial step) =+ mapAccum+ (\(c,a) s ->+ Value.flatten $+ runState+ (step (Value.unfold c) (Value.unfold a))+ (Value.unfold s))+ (Value.flatten initial)
+ src/Synthesizer/LLVM/Causal/Render.hs view
@@ -0,0 +1,364 @@+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE ForeignFunctionInterface #-}+module Synthesizer.LLVM.Causal.Render where++import qualified Synthesizer.LLVM.Causal.Parameterized as Parameterized+import Synthesizer.LLVM.Causal.Private (T(Cons))+import Synthesizer.LLVM.Generator.Render+ (Triple, tripleStruct,+ derefStartPtr, derefStopPtr,+ RunArg, DSLArg, BuildArg(BuildArg), buildArg)++import qualified Synthesizer.LLVM.Plug.Input as PIn+import qualified Synthesizer.LLVM.Plug.Output as POut++import qualified Synthesizer.CausalIO.Process as PIO+import qualified Synthesizer.Generic.Cut as Cut++import qualified LLVM.DSL.Execution as Exec+import qualified LLVM.DSL.Expression as Expr+import LLVM.DSL.Expression (Exp(Exp))++import qualified LLVM.Extra.Multi.Value.Storable as Storable+import qualified LLVM.Extra.Multi.Value.Marshal as Marshal+import qualified LLVM.Extra.Multi.Value as MultiValue+import qualified LLVM.Extra.Memory as Memory+import qualified LLVM.Extra.MaybeContinuation as MaybeCont+import qualified LLVM.Extra.Maybe as Maybe+import qualified LLVM.Extra.Tuple as Tuple++import qualified LLVM.Core as LLVM++import qualified Type.Data.Num.Decimal as TypeNum++import qualified Data.StorableVector.Base as SVB+import qualified Data.StorableVector as SV++import Control.Monad (when, join)+import Control.Applicative (liftA3)++import Foreign.Ptr (Ptr)++import Data.Tuple.HT (snd3)+import Data.Word (Word)++++foreign import ccall safe "dynamic" derefFillPtr ::+ Exec.Importer (LLVM.Ptr global -> Word -> Ptr a -> Ptr b -> IO Word)+++compile ::+ (Storable.C a, MultiValue.T a ~ al,+ Storable.C b, MultiValue.T b ~ bl,+ Marshal.C param, Marshal.Struct param ~ paramStruct) =>+ (Exp param -> T al bl) ->+ IO (LLVM.Ptr paramStruct -> Word -> Ptr a -> Ptr b -> IO Word)+compile proc =+ Exec.compile "process" $+ Exec.createFunction derefFillPtr "fill" $ \paramPtr size aPtr bPtr ->+ case proc (Exp (Memory.load paramPtr)) of+ Cons next start stop -> do+ (global,s) <- start+ local <- LLVM.alloca+ (pos,_) <- Storable.arrayLoopMaybeCont2 size aPtr bPtr s $+ \aPtri bPtri s0 -> do+ a <- MaybeCont.lift $ Storable.load aPtri+ (b,s1) <- next global local a s0+ MaybeCont.lift $ Storable.store b bPtri+ return s1+ stop global+ return pos++runAux ::+ (Marshal.C p,+ Storable.C a, MultiValue.T a ~ al,+ Storable.C b, MultiValue.T b ~ bl) =>+ (Exp p -> T al bl) ->+ IO (IO () -> p -> SV.Vector a -> IO (SV.Vector b))+runAux proc = do+ fill <- compile proc+ return $ \final param as ->+ Marshal.with param $ \paramPtr ->+ SVB.withStartPtr as $ \ aPtr len ->+ SVB.createAndTrim len $ \bPtr -> do+ n <- fill paramPtr (fromIntegral len) aPtr bPtr+ final+ return $ fromIntegral n++run_ ::+ (Marshal.C p,+ Storable.C a, MultiValue.T a ~ al,+ Storable.C b, MultiValue.T b ~ bl) =>+ (Exp p -> T al bl) -> IO (p -> SV.Vector a -> IO (SV.Vector b))+run_ = fmap ($ return ()) . runAux++++foreign import ccall safe "dynamic" derefChunkPtr ::+ Exec.Importer (LLVM.Ptr globalState -> Word -> Ptr a -> Ptr b -> IO Word)++compileChunky ::+ (LLVM.IsSized paramStruct, LLVM.Value (LLVM.Ptr paramStruct) ~ pPtr,+ Memory.C state, Memory.Struct state ~ stateStruct,+ Memory.C global, Memory.Struct global ~ globalStruct,+ Triple paramStruct globalStruct stateStruct ~ triple,+ LLVM.IsSized local,+ Storable.C a, MultiValue.T a ~ valueA,+ Storable.C b, MultiValue.T b ~ valueB) =>+ (forall r z. (Tuple.Phi z) =>+ pPtr ->+ global -> LLVM.Value (LLVM.Ptr local) ->+ valueA -> state -> MaybeCont.T r z (valueB, state)) ->+ (forall r. pPtr -> LLVM.CodeGenFunction r (global, state)) ->+ (forall r. pPtr -> global -> LLVM.CodeGenFunction r ()) ->+ IO (LLVM.Ptr paramStruct -> IO (LLVM.Ptr triple),+ Exec.Finalizer triple,+ LLVM.Ptr triple -> Word -> Ptr a -> Ptr b -> IO Word)+compileChunky next start stop =+ Exec.compile "process-chunky" $+ liftA3 (,,)+ (Exec.createFunction derefStartPtr "startprocess" $+ \paramPtr -> do+ paramGlobalStatePtr <- LLVM.malloc+ (global,state) <- start paramPtr+ flip LLVM.store paramGlobalStatePtr =<<+ join+ (liftA3 tripleStruct+ (LLVM.load paramPtr)+ (Memory.compose global)+ (Memory.compose state))+ return paramGlobalStatePtr)+ (Exec.createFinalizer derefStopPtr "stopprocess" $+ \paramGlobalStatePtr -> do+ paramPtr <-+ LLVM.getElementPtr0 paramGlobalStatePtr (TypeNum.d0, ())+ stop paramPtr =<<+ Memory.load =<<+ LLVM.getElementPtr0 paramGlobalStatePtr (TypeNum.d1, ())+ LLVM.free paramGlobalStatePtr)+ (Exec.createFunction derefChunkPtr "fillprocess" $+ \paramGlobalStatePtr loopLen aPtr bPtr -> do+ paramPtr <-+ LLVM.getElementPtr0 paramGlobalStatePtr (TypeNum.d0, ())+ globalPtr <-+ LLVM.getElementPtr0 paramGlobalStatePtr (TypeNum.d1, ())+ statePtr <-+ LLVM.getElementPtr0 paramGlobalStatePtr (TypeNum.d2, ())+ global <- Memory.load globalPtr+ sInit <- Memory.load statePtr+ local <- LLVM.alloca+ (pos,sExit) <-+ Storable.arrayLoopMaybeCont2 loopLen aPtr bPtr sInit $+ \ aPtri bPtri s0 -> do+ a <- MaybeCont.lift $ Storable.load aPtri+ (b,s1) <- next paramPtr global local a s0+ MaybeCont.lift $ Storable.store b bPtri+ return s1+ Memory.store (Maybe.fromJust sExit) statePtr+ return pos)+++foreign import ccall safe "dynamic" derefChunkPluggedPtr ::+ Exec.Importer+ (LLVM.Ptr globalStateStruct -> Word ->+ LLVM.Ptr inp -> LLVM.Ptr out -> IO Word)++compilePlugged ::+ (Tuple.Undefined stateIn, Tuple.Phi stateIn) =>+ (Tuple.Undefined stateOut, Tuple.Phi stateOut) =>+ (LLVM.IsSized paramStruct, LLVM.Value (LLVM.Ptr paramStruct) ~ pPtr,+ Memory.C state, Memory.Struct state ~ stateStruct,+ Memory.C global, Memory.Struct global ~ globalStruct,+ Triple paramStruct globalStruct stateStruct ~ triple) =>+ (LLVM.IsSized local) =>+ (Memory.C paramIn, Memory.Struct paramIn ~ inStruct) =>+ (Memory.C paramOut, Memory.Struct paramOut ~ outStruct) =>+ (forall r.+ paramIn -> stateIn -> LLVM.CodeGenFunction r (valueA, stateIn)) ->+ (forall r.+ paramIn -> LLVM.CodeGenFunction r stateIn) ->+ (forall r z. (Tuple.Phi z) =>+ pPtr -> global -> LLVM.Value (LLVM.Ptr local) ->+ valueA -> state -> MaybeCont.T r z (valueB, state)) ->+ (forall r. pPtr -> LLVM.CodeGenFunction r (global, state)) ->+ (forall r. pPtr -> global -> LLVM.CodeGenFunction r ()) ->+ (forall r.+ paramOut -> valueB -> stateOut -> LLVM.CodeGenFunction r stateOut) ->+ (forall r.+ paramOut -> LLVM.CodeGenFunction r stateOut) ->+ IO (LLVM.Ptr paramStruct -> IO (LLVM.Ptr triple),+ LLVM.Ptr triple -> IO (),+ LLVM.Ptr triple ->+ Word -> LLVM.Ptr inStruct -> LLVM.Ptr outStruct -> IO Word)+compilePlugged nextIn startIn next start stop nextOut startOut =+ Exec.compile "process-plugged" $+ liftA3 (,,)+ (Exec.createFunction derefStartPtr "startprocess" $+ \paramPtr -> do+ paramGlobalStatePtr <- LLVM.malloc+ (global,state) <- start paramPtr+ flip LLVM.store paramGlobalStatePtr =<<+ join+ (liftA3 tripleStruct+ (LLVM.load paramPtr)+ (Memory.compose global)+ (Memory.compose state))+ return paramGlobalStatePtr)+ (Exec.createFunction derefStopPtr "stopprocess" $+ \paramGlobalStatePtr -> do+ paramPtr <-+ LLVM.getElementPtr0 paramGlobalStatePtr (TypeNum.d0, ())+ stop paramPtr =<<+ Memory.load =<<+ LLVM.getElementPtr0 paramGlobalStatePtr (TypeNum.d1, ())+ LLVM.free paramGlobalStatePtr)+ (Exec.createFunction derefChunkPluggedPtr "fillprocess" $+ \paramGlobalStatePtr loopLen inPtr outPtr -> do+ paramPtr <-+ LLVM.getElementPtr0 paramGlobalStatePtr (TypeNum.d0, ())+ globalPtr <-+ LLVM.getElementPtr0 paramGlobalStatePtr (TypeNum.d1, ())+ statePtr <-+ LLVM.getElementPtr0 paramGlobalStatePtr (TypeNum.d2, ())+ global <- Memory.load globalPtr+ sInit <- Memory.load statePtr+ inParam <- Memory.load inPtr+ outParam <- Memory.load outPtr+ inInit <- startIn inParam+ outInit <- startOut outParam+ local <- LLVM.alloca+ (pos,sExit) <-+ MaybeCont.fixedLengthLoop loopLen (inInit, sInit, outInit) $+ \ (in0,s0,out0) -> do+ (a,in1) <- MaybeCont.lift $ nextIn inParam in0+ (b,s1) <- next paramPtr global local a s0+ out1 <- MaybeCont.lift $ nextOut outParam b out0+ return (in1, s1, out1)+ Memory.store (snd3 $ Maybe.fromJust sExit) statePtr+ return pos)+++{-+I liked to write something with signature++> import qualified Synthesizer.Causal.Process as Causal+>+> liftStorableChunk ::+> (Exp param -> T valueA valueB) ->+> IO (param -> Causal.T (SV.Vector a) (SV.Vector b))++but it does not quite work this way.+@Causal.T@ from @synthesizer-core@ uses an immutable state internally,+whereas @T@ uses mutable states.+In principle the immutable state of @Causal.T@+could be used for breaking the processing of a stream+and continue it on two different streams in parallel.+I have no function that makes use of this feature,+and thus an @ST@ monad might be a way out.++With this function we can convert an LLVM causal process to a causal IO arrow.+We also need the plugs in order+to read and write LLVM values from and to Haskell data chunks.++In a second step we could convert this to a processor of lazy lists,+and thus to a processor of chunky storable vectors.+-}+processIOParameterized ::+ (Marshal.C p, Cut.Read a, x ~ LLVM.Value (LLVM.Ptr (Marshal.Struct p))) =>+ PIn.T a b -> Parameterized.T x b c -> POut.T c d ->+ IO (IO (p, IO ()) -> PIO.T a d)+processIOParameterized+ (PIn.Cons nextIn startIn createIn deleteIn)+ paramd+ (POut.Cons nextOut startOut createOut deleteOut) = do+ case paramd of+ Parameterized.Cons next start stop -> do+ (startFunc, stopFunc, fill) <-+ compilePlugged+ nextIn startIn+ next start stop+ nextOut startOut+ return $ \createContext -> PIO.Cons+ (\a s@(_,statePtr) -> do+ let maximumSize = Cut.length a+ (contextIn, paramIn) <- createIn a+ (contextOut,paramOut) <- createOut maximumSize+ actualSize <-+ Marshal.with paramIn $ \inptr ->+ Marshal.with paramOut $ \outptr ->+ fill statePtr (fromIntegral maximumSize) inptr outptr+ -- print actualSize+ when (fromIntegral actualSize > maximumSize) $+ error $ "CausalParametrized.Process: " +++ "output size " ++ show actualSize +++ " > input size " ++ show maximumSize+ deleteIn contextIn+ b <- deleteOut (fromIntegral actualSize) contextOut+ return (b, s))+ (do+ (p, deleteContext) <- createContext+ ptr <- Marshal.with p startFunc+ return (deleteContext, ptr))+ (\(deleteContext, ptr) -> stopFunc ptr >> deleteContext)++processIOCore ::+ (Marshal.C p, Cut.Read a) =>+ PIn.T a b -> (Exp p -> T b c) -> POut.T c d ->+ IO (IO (p, IO ()) -> PIO.T a d)+processIOCore pin proc pout = do+ paramd <- Parameterized.fromProcessPtr "Causal.process" proc+ processIOParameterized pin paramd pout++processIO ::+ (Marshal.C p, Cut.Read a, PIn.Default a, POut.Default d) =>+ (Exp p -> T (PIn.Element a) (POut.Element d)) ->+ IO (p -> PIO.T a d)+processIO proc =+ fmap (\f p -> f (return (p, return ()))) $+ processIOCore PIn.deflt proc POut.deflt+++class Run f where+ type DSL f a b+ type In f+ type Out f+ build ::+ (Marshal.C p) =>+ PIn.T (In f) a -> (Exp p -> DSL f a b) -> POut.T b (Out f) ->+ IO (IO (p, IO ()) -> f)++instance (Cut.Read a) => Run (PIO.T a b) where+ type DSL (PIO.T a b) al bl = T al bl+ type In (PIO.T a b) = a+ type Out (PIO.T a b) = b+ build = processIOCore++instance (RunArg a, Run f) => Run (a -> f) where+ type DSL (a -> f) al bl = DSLArg a -> DSL f al bl+ type In (a -> f) = In f+ type Out (a -> f) = Out f+ build pin sig pout =+ case buildArg of+ BuildArg pass createA -> do+ f <- build pin (Expr.uncurry $ \p -> sig p . pass) pout+ return $ \createP av ->+ f (do (p,finalP) <- createP+ (pa,finalA) <- createA av+ return ((p,pa), finalA >> finalP))+++runPlugged :: (Run f) => PIn.T (In f) a -> DSL f a b -> POut.T b (Out f) -> IO f+runPlugged pin sig pout = do+ act <- build pin (const sig) pout+ return $ act (return ((), return ()))++run ::+ (Run f) =>+ (In f ~ a, PIn.Default a, PIn.Element a ~ al) =>+ (Out f ~ b, POut.Default b, POut.Element b ~ bl) =>+ DSL f al bl -> IO f+run sig = runPlugged PIn.deflt sig POut.deflt
+ src/Synthesizer/LLVM/Causal/RingBufferForward.hs view
@@ -0,0 +1,281 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE Rank2Types #-}+module Synthesizer.LLVM.Causal.RingBufferForward (+ T, track, trackSkip, trackSkipHold,+ index, mapIndex,+ ) where++import qualified Synthesizer.LLVM.Causal.Private as CausalPriv+import qualified Synthesizer.LLVM.Causal.Process as Causal+import qualified Synthesizer.LLVM.Generator.Private as Sig+import Synthesizer.LLVM.RingBuffer (MemoryPtr)++import Synthesizer.LLVM.Causal.Process (($*#))+import Synthesizer.Causal.Class (($<), ($*))++import qualified LLVM.DSL.Expression as Expr+import LLVM.DSL.Expression (Exp)++import qualified LLVM.Extra.Multi.Value as MultiValue+import qualified LLVM.Extra.MaybeContinuation as MaybeCont+import qualified LLVM.Extra.Maybe as Maybe+import qualified LLVM.Extra.Memory as Memory+import qualified LLVM.Extra.Control as C+import qualified LLVM.Extra.Arithmetic as A+import qualified LLVM.Extra.Tuple as Tuple++import qualified LLVM.Core as LLVM+import LLVM.Core (CodeGenFunction, Value)++import qualified Control.Arrow as Arrow+import Control.Arrow ((<<<), (<<^))+import Data.Tuple.HT (mapSnd, mapPair)++import Data.Word (Word)++import Prelude hiding (length)++++{- |+This type is very similar to 'Synthesizer.LLVM.RingBuffer.T'+but differs in several details:++* It stores values in time order,+ whereas 'Synthesizer.LLVM.RingBuffer.T' stores in opposite order.++* Since it stores future values it is not causal+ and can only track signal generators.++* There is no need for an initial value.++* It stores one value less than 'Synthesizer.LLVM.RingBuffer.T'+ since it is meant to provide infixes of the signal+ rather than providing the basis for a delay line.++Those differences in detail would not justify a new type,+you could achieve the same by a combination of+'Synthesizer.LLVM.RingBuffer.track'+and+'Synthesizer.LLVM.CausalParameterized.Process.skip'.+The fundamental problem of this combination is+that it requires to keep the ring buffer alive+longer than the providing signal exists.+This is not possible with the current design.+That's why we provide the combination of @track@ and @skip@+in a way that does not suffer from that problem.+This functionality is critical for+'Synthesizer.LLVM.CausalParameterized.Helix.dynamic'.+-}+data T a =+ Cons {+ buffer :: Value (MemoryPtr a),+ length :: Value Word,+ current :: Value Word+ }++{- |+This function does not check for range violations.+If the ring buffer was generated by @track time@,+then the minimum index is zero and the maximum index is @time-1@.+Index zero refers to the current sample+and index @time-1@ refers to the one that is farthermost in the future.+-}+index :: (Memory.C a) => MultiValue.T Word -> T a -> CodeGenFunction r a+index (MultiValue.Cons i) rb = do+ k <- flip A.irem (length rb) =<< A.add (current rb) i+ Memory.load =<< LLVM.getElementPtr (buffer rb) (k, ())++mapIndex :: (Memory.C a) => Exp Word -> Causal.T (T a) a+mapIndex k = CausalPriv.map (\buf -> flip index buf =<< Expr.unExp k)+++{- |+@track time signal@ bundles @time@ successive values of @signal@.+The values can be accessed using 'index' with indices+ranging from 0 to @time-1@.++The @time@ parameter must be non-negative.+-}+track :: (Memory.C a) => Exp Word -> Sig.T a -> Sig.T (T a)+track time input = trackSkip time input $* 1++{- |+@trackSkip time input $* skips@+is like+@Process.skip (track time input) $* skips@+but this composition would require a @Memory@ constraint for 'T'+which we cannot provide.+-}+trackSkip ::+ (Memory.C a) =>+ Exp Word -> Sig.T a -> Causal.T (MultiValue.T Word) (T a)+trackSkip time (Sig.Cons next start stop) =+ CausalPriv.Cons+ (trackNext next)+ (trackStart start time)+ (trackStop stop)+ <<^+ (\(MultiValue.Cons skip) -> skip)++{- |+Like @trackSkip@ but repeats the last buffer content+when the end of the input signal is reached.+The returned 'Bool' flag is 'True' if a skip could be performed completely+and it is 'False' if the skip exceeds the end of the input.+That is, once a 'False' is returned all following values are tagged with 'False'.+The returned 'Word' value is the number of actually skipped values.+This lags one step behind the input of skip values.+The number of an actual number of skips+is at most the number of requested skips.+If the flag is 'False', then the number of actual skips is zero.+The converse does not apply.++If the input signal is too short, the output is undefined.+(Before the available data the buffer will be filled with arbitrary values.)+We could fill the buffer with zeros,+but this would require an Arithmetic constraint+and the generated signal would not be very meaningful.+We could also return an empty signal if the input is too short.+However this would require a permanent check.+-}+trackSkipHold ::+ (Memory.C a) =>+ Exp Word -> Sig.T a ->+ Causal.T (MultiValue.T Word) ((MultiValue.T Bool, MultiValue.T Word), T a)+trackSkipHold time xs =+ Arrow.first+ (Arrow.second clearFirst <<^ mapPair (MultiValue.Cons, MultiValue.Cons))+ <<<+ trackSkipHold_ time xs+ <<^+ (\(MultiValue.Cons skip) -> skip)++clearFirst ::+ (MultiValue.PseudoRing a, MultiValue.Real a,+ MultiValue.IntegerConstant a, MultiValue.Select a) =>+ Causal.MV a a+clearFirst =+ Causal.zipWith (\b x -> Expr.select b x 0)+ $< (Causal.delay1 Expr.false $*# True)++trackSkipHold_ ::+ (Memory.C a) =>+ Exp Word -> Sig.T a ->+ Causal.T (Value Word) ((Value Bool, Value Word), T a)+trackSkipHold_ time (Sig.Cons next start stop) =+ CausalPriv.Cons+ (trackNextHold next)+ (trackStartHold start time)+ (trackStopHold stop)+++trackNext ::+ (Memory.C al, Tuple.Phi z,+ Tuple.Phi state, Tuple.Undefined state) =>+ (forall z0. (Tuple.Phi z0) =>+ context -> local -> state -> MaybeCont.T r z0 (al, state)) ->+ (context, (Value Word, Value (MemoryPtr al))) -> local ->+ Value Word ->+ (Value Word, (state, Value Word)) ->+ MaybeCont.T r z (T al, (Value Word, (state, Value Word)))+trackNext next (context, (size0,ptr)) local n1 (n0, statePos) = do+ (state3, pos3) <-+ MaybeCont.fromMaybe $ fmap snd $+ MaybeCont.fixedLengthLoop n0 statePos $ \(state0, pos0) -> do+ (a, state1) <- next context local state0+ MaybeCont.lift $+ fmap ((,) state1) $ storeNext (size0,ptr) a pos0+ return (Cons ptr size0 pos3, (n1, (state3, pos3)))++trackStart ::+ (LLVM.IsSized am, Tuple.Phi state, Tuple.Undefined state) =>+ CodeGenFunction r (context, state) ->+ Exp Word ->+ CodeGenFunction r+ ((context, (Value Word, Value (LLVM.Ptr am))),+ (Value Word, (state, Value Word)))+trackStart start size = do+ (context, state) <- start+ ~(MultiValue.Cons size0) <- Expr.unExp size+ ptr <- LLVM.arrayMalloc size0+ return ((context, (size0,ptr)), (size0, (state, A.zero)))++trackStop ::+ (LLVM.IsType am) =>+ (context -> CodeGenFunction r ()) ->+ (context, (tl, Value (LLVM.Ptr am))) ->+ CodeGenFunction r ()+trackStop stop (context, (_size,ptr)) = do+ LLVM.free ptr+ stop context+++trackNextHold ::+ (Memory.C al, Tuple.Phi z,+ Tuple.Phi state, Tuple.Undefined state) =>+ (forall z0. (Tuple.Phi z0) =>+ context -> local -> state -> MaybeCont.T r z0 (al, state)) ->+ (context, (Value Word, Value (MemoryPtr al))) -> local ->+ Value Word ->+ (Value Word, (Maybe.T state, Value Word)) ->+ MaybeCont.T r z+ (((Value Bool, Value Word), T al),+ (Value Word, (Maybe.T state, Value Word)))+trackNextHold next (context, (size0,ptr)) local nNext (n0, (mstate0, pos0)) =+ MaybeCont.lift $ do+ (n3, (pos3, state3)) <-+ Maybe.run mstate0+ (return (n0, (pos0, mstate0)))+ (\state0 ->+ Maybe.loopWithExit (n0, (state0, pos0))+ (\(n1, (state1, pos1)) -> do+ cont <- A.cmp LLVM.CmpGT n1 A.zero+ fmap (mapSnd ((,) n1 . (,) pos1)) $+ C.ifThen cont+ (Maybe.nothing, Maybe.just state1)+ (do aState <-+ MaybeCont.toMaybe $ next context local state1+ return (aState, fmap snd aState)))+ (\((a,state), (n1, (pos1, _mstate))) -> do+ pos2 <- storeNext (size0,ptr) a pos1+ n2 <- A.dec n1+ return (n2, (state, pos2))))+ skipped <- A.sub n0 n3+ return (((Maybe.isJust state3, skipped), Cons ptr size0 pos3),+ (nNext, (state3, pos3)))++storeNext ::+ (Memory.C al) =>+ (Value Word, Value (MemoryPtr al)) ->+ al -> Value Word -> CodeGenFunction r (Value Word)+storeNext (size0,ptr) a pos0 = do+ Memory.store a =<< LLVM.getElementPtr ptr (pos0, ())+ pos1 <- A.inc pos0+ cont <- A.cmp LLVM.CmpLT pos1 size0+ C.select cont pos1 A.zero+++trackStartHold ::+ (LLVM.IsSized am,+ Tuple.Phi state, Tuple.Undefined state) =>+ CodeGenFunction r (context, state) ->+ Exp Word ->+ CodeGenFunction r+ ((context, (Value Word, Value (LLVM.Ptr am))),+ (Value Word, (Maybe.T state, Value Word)))+trackStartHold start size = do+ (context, state) <- start+ ~(MultiValue.Cons size0) <- Expr.unExp size+ ptr <- LLVM.arrayMalloc size0+ return ((context, (size0,ptr)), (size0, (Maybe.just state, A.zero)))++trackStopHold ::+ (LLVM.IsType am) =>+ (context -> CodeGenFunction r ()) ->+ (context, (Value Word, Value (LLVM.Ptr am))) ->+ CodeGenFunction r ()+trackStopHold stop (context, (_size,ptr)) = do+ LLVM.free ptr+ stop context
− src/Synthesizer/LLVM/CausalParameterized/Controlled.hs
@@ -1,41 +0,0 @@-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE FlexibleContexts #-}-{- |-This module provides a type class that automatically selects a filter-for a given parameter type.-We choose the dependency this way-because there may be different ways to specify the filter parameters-but there is only one implementation of the filter itself.--}-module Synthesizer.LLVM.CausalParameterized.Controlled (- Ctrl.process,- processCtrlRate,- ) where--import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP-import qualified Synthesizer.LLVM.Causal.Controlled as Ctrl-import qualified Synthesizer.LLVM.Parameterized.Signal as SigP--import qualified LLVM.DSL.Parameter as Param--import qualified LLVM.Extra.Tuple as Tuple-import qualified LLVM.Extra.Marshal as Marshal-import qualified LLVM.Extra.Memory as Memory-import qualified LLVM.Extra.ScalarOrVector as SoV--import qualified LLVM.Core as LLVM-import LLVM.Core (Value, IsFloating)---processCtrlRate ::- (Ctrl.C parameter a b,- Memory.C parameter,- Marshal.C r, Tuple.ValueOf r ~ Value r,- IsFloating r, SoV.IntegerConstant r,- LLVM.CmpRet r, LLVM.IsPrimitive r) =>- Param.T p r ->- (Param.T p r -> SigP.T p parameter) ->- CausalP.T p a b-processCtrlRate reduct ctrlGen =- CausalP.applyFst Ctrl.process- (SigP.interpolateConstant reduct (ctrlGen reduct))
− src/Synthesizer/LLVM/CausalParameterized/ControlledPacked.hs
@@ -1,48 +0,0 @@-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE FlexibleContexts #-}-{- |-This is like "Synthesizer.LLVM.CausalParameterized.Controlled"-but for vectorised signals.--}-module Synthesizer.LLVM.CausalParameterized.ControlledPacked (- CtrlS.process,- processCtrlRate,- ) where--import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP-import qualified Synthesizer.LLVM.Causal.ControlledPacked as CtrlS-import qualified Synthesizer.LLVM.Parameterized.Signal as SigP-import qualified Synthesizer.LLVM.Frame.SerialVector as Serial--import qualified LLVM.DSL.Parameter as Param--import qualified LLVM.Extra.Tuple as Tuple-import qualified LLVM.Extra.Marshal as Marshal-import qualified LLVM.Extra.Memory as Memory-import qualified LLVM.Extra.ScalarOrVector as SoV--import qualified LLVM.Core as LLVM-import LLVM.Core (Value, IsFloating)--import qualified Algebra.Field as Field--import NumericPrelude.Numeric-import NumericPrelude.Base-import Prelude ()---processCtrlRate ::- (CtrlS.C parameter av bv,- Serial.Read av, n ~ Serial.Size av,- Serial.C bv, n ~ Serial.Size bv,- Memory.C parameter,- Marshal.C r, Field.C r, IsFloating r, SoV.IntegerConstant r,- Tuple.ValueOf r ~ Value r, LLVM.CmpRet r, LLVM.IsPrimitive r) =>- Param.T p r ->- (Param.T p r -> SigP.T p parameter) ->- CausalP.T p av bv-processCtrlRate reduct ctrlGen = Serial.withSize $ \n ->- CausalP.applyFst CtrlS.process- (SigP.interpolateConstant- (fmap (/ fromIntegral n) reduct)- (ctrlGen reduct))
− src/Synthesizer/LLVM/CausalParameterized/Functional.hs
@@ -1,531 +0,0 @@-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE ExistentialQuantification #-}-{-# LANGUAGE Rank2Types #-}-module Synthesizer.LLVM.CausalParameterized.Functional (- T,- lift, fromSignal,- ($&), (&|&),- compile,- compileSignal,- withArgs, MakeArguments, Arguments, makeArgs,- AnyArg(..),-- Ground(Ground),- withGroundArgs, MakeGroundArguments, GroundArguments,- makeGroundArgs,-- Atom(..), atom,- withGuidedArgs, MakeGuidedArguments, GuidedArguments, PatternArguments,- makeGuidedArgs,-- PrepareArguments(PrepareArguments), withPreparedArgs, withPreparedArgs2,- atomArg, stereoArgs, pairArgs, tripleArgs,- ) where--import qualified Synthesizer.LLVM.CausalParameterized.ProcessPrivate as CausalP-import qualified Synthesizer.LLVM.Causal.ProcessPrivate as Causal-import qualified Synthesizer.LLVM.Parameterized.Signal as Signal-import qualified Synthesizer.LLVM.Frame.SerialVector as Serial-import qualified Synthesizer.LLVM.Frame.Stereo as Stereo--import qualified LLVM.Extra.Tuple as Tuple-import qualified LLVM.Extra.MaybeContinuation as Maybe-import qualified LLVM.Extra.Marshal as Marshal-import qualified LLVM.Extra.Memory as Memory-import qualified LLVM.Extra.Arithmetic as A--import LLVM.Core (CodeGenFunction)-import qualified LLVM.Core as LLVM--import qualified Number.Ratio as Ratio-import qualified Algebra.Transcendental as Trans-import qualified Algebra.Algebraic as Algebraic-import qualified Algebra.Field as Field-import qualified Algebra.Ring as Ring-import qualified Algebra.Additive as Additive--import qualified Control.Monad.Trans.State as State-import qualified Control.Monad.Trans.Class as Trans-import Control.Monad.Trans.State (StateT)--import qualified Data.Vault.Lazy as Vault-import Data.Vault.Lazy (Vault)-import qualified Control.Category as Cat-import Control.Arrow (Arrow, (>>^), (&&&), arr, first)-import Control.Category (Category, (.))-import Control.Applicative (Applicative, (<*>), pure, liftA2)--import Data.Tuple.HT (fst3, snd3, thd3)--import qualified System.Unsafe as Unsafe--import Prelude hiding ((.))---newtype T p inp out = Cons (Code p inp out)----- | similar to @CausalP.T p a b@-data Code p a b =- forall context local state ioContext parameters.- (Marshal.C parameters,- Memory.C context,- Memory.C state) =>- Code- (forall r c.- (Tuple.Phi c) =>- context -> local -> a -> state ->- StateT Vault (Maybe.T r c) (b, state))- -- compute next value- (forall r.- CodeGenFunction r local)- -- allocate temporary variables before a loop- (forall r.- Tuple.ValueOf parameters ->- CodeGenFunction r (context, state))- -- initial state- (forall r.- context -> state ->- CodeGenFunction r ())- -- cleanup- (p -> IO (ioContext, parameters))- {- initialization from IO monad- This will be run within Unsafe.performIO,- so no observable In/Out actions please!- -}- (ioContext -> IO ())- -- finalization from IO monad, also run within Unsafe.performIO----instance Category (Code p) where- id = arr id- Code nextB allocaB startB stopB createIOContextB deleteIOContextB .- Code nextA allocaA startA stopA createIOContextA deleteIOContextA = Code- (CausalP.composeNext- (State.mapStateT . Maybe.onFail)- stopA stopB nextA nextB)- (liftA2 (,) allocaA allocaB)- (CausalP.composeStart startA startB)- (CausalP.composeStop stopA stopB)- (CausalP.composeCreate createIOContextA createIOContextB)- (CausalP.composeDelete deleteIOContextA deleteIOContextB)---instance Arrow (Code p) where- arr f = Code- (\ _p () a () -> return (f a, ()))- (return ())- (\() -> return ((),()))- (\() () -> return ())- (const $ return ((),()))- (const $ return ())- first (Code next alloca start stop create delete) = Code- (curry $ Causal.firstNext $ uncurry next) alloca start stop- create delete---{--We must not define Category and Arrow instances-because in osci***osci the result of osci would be shared,-although it depends on the particular input.--instance Category (T p) where- id = tagUnique Cat.id- Cons a . Cons b = tagUnique (a . b)--instance Arrow (T p) where- arr f = tagUnique $ arr f- first (Cons a) = tagUnique $ first a--}--instance Functor (T p inp) where- fmap f (Cons x) =- tagUnique $ x >>^ f--instance Applicative (T p inp) where- pure a = tagUnique $ arr (const a)- f <*> x = fmap (uncurry ($)) $ f &|& x---lift0 :: (forall r. CodeGenFunction r out) -> T p inp out-lift0 f = lift (CausalP.mapSimple (const f))--lift1 :: (forall r. a -> CodeGenFunction r out) -> T p inp a -> T p inp out-lift1 f x = CausalP.mapSimple f $& x--lift2 :: (forall r. a -> b -> CodeGenFunction r out) -> T p inp a -> T p inp b -> T p inp out-lift2 f x y = CausalP.zipWithSimple f $& x&|&y---instance (A.PseudoRing b, A.Real b, A.IntegerConstant b) => Num (T p a b) where- fromInteger n = pure (A.fromInteger' n)- (+) = lift2 A.add- (-) = lift2 A.sub- (*) = lift2 A.mul- abs = lift1 A.abs- signum = lift1 A.signum--instance (A.Field b, A.Real b, A.RationalConstant b) => Fractional (T p a b) where- fromRational x = pure (A.fromRational' x)- (/) = lift2 A.fdiv---instance (A.Additive b) => Additive.C (T p a b) where- zero = pure A.zero- (+) = lift2 A.add- (-) = lift2 A.sub- negate = lift1 A.neg--instance (A.PseudoRing b, A.IntegerConstant b) => Ring.C (T p a b) where- one = pure A.one- fromInteger n = pure (A.fromInteger' n)- (*) = lift2 A.mul--instance (A.Field b, A.RationalConstant b) => Field.C (T p a b) where- fromRational' x = pure (A.fromRational' $ Ratio.toRational98 x)- (/) = lift2 A.fdiv--instance (A.Transcendental b, A.RationalConstant b) => Algebraic.C (T p a b) where- sqrt = lift1 A.sqrt- root n x = lift2 A.pow x (Field.recip $ Ring.fromInteger n)- x^/r = lift2 A.pow x (Field.fromRational' r)--instance (A.Transcendental b, A.RationalConstant b) => Trans.C (T p a b) where- pi = lift0 A.pi- sin = lift1 A.sin- cos = lift1 A.cos- (**) = lift2 A.pow- exp = lift1 A.exp- log = lift1 A.log-- asin _ = error "LLVM missing intrinsic: asin"- acos _ = error "LLVM missing intrinsic: acos"- atan _ = error "LLVM missing intrinsic: atan"---infixr 0 $&--($&) :: CausalP.T p b c -> T p a b -> T p a c-f $& (Cons b) =- tagUnique $ liftCode f . b---infixr 3 &|&--(&|&) :: T p a b -> T p a c -> T p a (b,c)-Cons b &|& Cons c =- tagUnique $ b &&& c---liftCode :: CausalP.T p inp out -> Code p inp out-liftCode (CausalP.Cons next alloca start stop create delete) =- Code- (\p l a state -> Trans.lift (next p l a state))- alloca start stop create delete--lift :: CausalP.T p inp out -> T p inp out-lift = tagUnique . liftCode--fromSignal :: Signal.T p out -> T p inp out-fromSignal = lift . CausalP.fromSignal--tag :: Vault.Key out -> Code p inp out -> T p inp out-tag key (Code next alloca start stop create delete) =- Cons $- Code- (\p l a s0 -> do- mb <- State.gets (Vault.lookup key)- case mb of- Just b -> return (b,s0)- Nothing -> do- bs@(b,_) <- next p l a s0- State.modify (Vault.insert key b)- return bs)- alloca start stop create delete---- dummy for debugging-_tag :: Vault.Key out -> Code p inp out -> T p inp out-_tag _ = Cons--tagUnique :: Code p inp out -> T p inp out-tagUnique code =- Unsafe.performIO $- fmap (flip tag code) Vault.newKey--initialize :: Code p inp out -> CausalP.T p inp out-initialize (Code next alloca start stop create delete) =- CausalP.Cons- (\p l a state -> State.evalStateT (next p l a state) Vault.empty)- alloca start stop create delete--compile :: T p inp out -> CausalP.T p inp out-compile (Cons code) = initialize code--compileSignal :: T p () out -> Signal.T p out-compileSignal f = CausalP.toSignal $ compile f---{- |-Using 'withArgs' you can simplify--> let x = F.lift (arr fst)-> y = F.lift (arr (fst.snd))-> z = F.lift (arr (snd.snd))-> in F.compile (f x y z)--to--> withArgs $ \(x,(y,z)) -> f x y z--}-withArgs ::- (MakeArguments inp) =>- (Arguments (T p inp) inp -> T p inp out) -> CausalP.T p inp out-withArgs f = withId $ f . makeArgs--withId :: (T p inp inp -> T p inp out) -> CausalP.T p inp out-withId f = compile $ f $ lift Cat.id---type family Arguments (f :: * -> *) (arg :: *)--class MakeArguments arg where- makeArgs :: Functor f => f arg -> Arguments f arg---{--I have thought about an Arg type, that marks where to stop descending.-This way we can throw away all of these FlexibleContext instances-and the user can freely choose the granularity of arguments.-However this does not work so easily,-because we would need a functional depedency from, say,-@(Arg a, Arg b)@ to @(a,b)@.-This is the opposite direction to the dependency we use currently.-The 'AnyArg' type provides a solution in this spirit.--}-type instance Arguments f (LLVM.Value a) = f (LLVM.Value a)-instance MakeArguments (LLVM.Value a) where- makeArgs = id--{- |-Consistent with pair instance.-You may use 'AnyArg' or 'withGuidedArgs'-to stop descending into the stereo channels.--}-type instance Arguments f (Stereo.T a) = Stereo.T (Arguments f a)-instance (MakeArguments a) => MakeArguments (Stereo.T a) where- makeArgs = fmap makeArgs . Stereo.sequence--type instance Arguments f (Serial.T v) = f (Serial.T v)-instance MakeArguments (Serial.T v) where- makeArgs = id--type instance Arguments f () = f ()-instance MakeArguments () where- makeArgs = id--type instance Arguments f (a,b) = (Arguments f a, Arguments f b)-instance (MakeArguments a, MakeArguments b) =>- MakeArguments (a,b) where- makeArgs f = (makeArgs $ fmap fst f, makeArgs $ fmap snd f)--type instance Arguments f (a,b,c) = (Arguments f a, Arguments f b, Arguments f c)-instance (MakeArguments a, MakeArguments b, MakeArguments c) =>- MakeArguments (a,b,c) where- makeArgs f = (makeArgs $ fmap fst3 f, makeArgs $ fmap snd3 f, makeArgs $ fmap thd3 f)---{- |-You can use this to explicitly stop breaking of composed data types.-It might be more comfortable to do this using 'withGuidedArgs'.--}-newtype AnyArg a = AnyArg {getAnyArg :: a}--type instance Arguments f (AnyArg a) = f a-instance MakeArguments (AnyArg a) where- makeArgs = fmap getAnyArg----{- |-This is similar to 'withArgs'-but it requires to specify the decomposition depth-using constructors in the arguments.--}-withGroundArgs ::- (MakeGroundArguments (T p inp) args,- GroundArguments args ~ inp) =>- (args -> T p inp out) -> CausalP.T p inp out-withGroundArgs f = withId $ f . makeGroundArgs---newtype Ground f a = Ground (f a)---type family GroundArguments args--class (Functor f) => MakeGroundArguments f args where- makeGroundArgs :: f (GroundArguments args) -> args---type instance GroundArguments (Ground f a) = a-instance (Functor f, f ~ g) => MakeGroundArguments f (Ground g a) where- makeGroundArgs = Ground--type instance GroundArguments (Stereo.T a) = Stereo.T (GroundArguments a)-instance MakeGroundArguments f a => MakeGroundArguments f (Stereo.T a) where- makeGroundArgs f =- Stereo.cons- (makeGroundArgs $ fmap Stereo.left f)- (makeGroundArgs $ fmap Stereo.right f)--type instance GroundArguments () = ()-instance (Functor f) => MakeGroundArguments f () where- makeGroundArgs _ = ()---type instance- GroundArguments (a,b) =- (GroundArguments a, GroundArguments b)-instance- (MakeGroundArguments f a, MakeGroundArguments f b) =>- MakeGroundArguments f (a,b) where- makeGroundArgs f =- (makeGroundArgs $ fmap fst f,- makeGroundArgs $ fmap snd f)--type instance- GroundArguments (a,b,c) =- (GroundArguments a, GroundArguments b, GroundArguments c)-instance- (MakeGroundArguments f a, MakeGroundArguments f b, MakeGroundArguments f c) =>- MakeGroundArguments f (a,b,c) where- makeGroundArgs f =- (makeGroundArgs $ fmap fst3 f,- makeGroundArgs $ fmap snd3 f,- makeGroundArgs $ fmap thd3 f)----{- |-This is similar to 'withArgs'-but it allows to specify the decomposition depth using a pattern.--}-withGuidedArgs ::- (MakeGuidedArguments pat, PatternArguments pat ~ inp) =>- pat ->- (GuidedArguments (T p inp) pat -> T p inp out) -> CausalP.T p inp out-withGuidedArgs p f = withId $ f . makeGuidedArgs p---data Atom a = Atom--atom :: Atom a-atom = Atom---type family GuidedArguments (f :: * -> *) pat-type family PatternArguments pat--class MakeGuidedArguments pat where- makeGuidedArgs ::- Functor f =>- pat -> f (PatternArguments pat) -> GuidedArguments f pat---type instance GuidedArguments f (Atom a) = f a-type instance PatternArguments (Atom a) = a-instance MakeGuidedArguments (Atom a) where- makeGuidedArgs Atom = id--type instance GuidedArguments f (Stereo.T a) = Stereo.T (GuidedArguments f a)-type instance PatternArguments (Stereo.T a) = Stereo.T (PatternArguments a)-instance MakeGuidedArguments a => MakeGuidedArguments (Stereo.T a) where- makeGuidedArgs pat f =- Stereo.cons- (makeGuidedArgs (Stereo.left pat) $ fmap Stereo.left f)- (makeGuidedArgs (Stereo.right pat) $ fmap Stereo.right f)--type instance GuidedArguments f () = f ()-type instance PatternArguments () = ()-instance MakeGuidedArguments () where- makeGuidedArgs () = id--type instance- GuidedArguments f (a,b) =- (GuidedArguments f a, GuidedArguments f b)-type instance- PatternArguments (a,b) =- (PatternArguments a, PatternArguments b)-instance (MakeGuidedArguments a, MakeGuidedArguments b) =>- MakeGuidedArguments (a,b) where- makeGuidedArgs (pa,pb) f =- (makeGuidedArgs pa $ fmap fst f,- makeGuidedArgs pb $ fmap snd f)--type instance- GuidedArguments f (a,b,c) =- (GuidedArguments f a, GuidedArguments f b, GuidedArguments f c)-type instance- PatternArguments (a,b,c) =- (PatternArguments a, PatternArguments b, PatternArguments c)-instance- (MakeGuidedArguments a, MakeGuidedArguments b, MakeGuidedArguments c) =>- MakeGuidedArguments (a,b,c) where- makeGuidedArgs (pa,pb,pc) f =- (makeGuidedArgs pa $ fmap fst3 f,- makeGuidedArgs pb $ fmap snd3 f,- makeGuidedArgs pc $ fmap thd3 f)----{- |-Alternative to withGuidedArgs.-This way of pattern construction is even Haskell 98.--}-withPreparedArgs ::- PrepareArguments (T p inp) inp a ->- (a -> T p inp out) -> CausalP.T p inp out-withPreparedArgs (PrepareArguments prepare) f = withId $ f . prepare--withPreparedArgs2 ::- PrepareArguments (T p (inp0, inp1)) inp0 a ->- PrepareArguments (T p (inp0, inp1)) inp1 b ->- (a -> b -> T p (inp0, inp1) out) ->- CausalP.T p (inp0, inp1) out-withPreparedArgs2 prepareA prepareB f =- withPreparedArgs (pairArgs prepareA prepareB) (uncurry f)--newtype PrepareArguments f merged separated =- PrepareArguments (f merged -> separated)--atomArg :: PrepareArguments f a (f a)-atomArg = PrepareArguments id--stereoArgs ::- (Functor f) =>- PrepareArguments f a b ->- PrepareArguments f (Stereo.T a) (Stereo.T b)-stereoArgs (PrepareArguments p) =- PrepareArguments $ fmap p . Stereo.sequence--pairArgs ::- (Functor f) =>- PrepareArguments f a0 b0 ->- PrepareArguments f a1 b1 ->- PrepareArguments f (a0,a1) (b0,b1)-pairArgs (PrepareArguments p0) (PrepareArguments p1) =- PrepareArguments $ \f -> (p0 $ fmap fst f, p1 $ fmap snd f)--tripleArgs ::- (Functor f) =>- PrepareArguments f a0 b0 ->- PrepareArguments f a1 b1 ->- PrepareArguments f a2 b2 ->- PrepareArguments f (a0,a1,a2) (b0,b1,b2)-tripleArgs (PrepareArguments p0) (PrepareArguments p1) (PrepareArguments p2) =- PrepareArguments $ \f ->- (p0 $ fmap fst3 f, p1 $ fmap snd3 f, p2 $ fmap thd3 f)
− src/Synthesizer/LLVM/CausalParameterized/FunctionalPlug.hs
@@ -1,339 +0,0 @@-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE ExistentialQuantification #-}-{-# LANGUAGE Rank2Types #-}-{-# LANGUAGE FlexibleContexts #-}-module Synthesizer.LLVM.CausalParameterized.FunctionalPlug (- T,- ($&), (&|&),- run, runPlugOut,- fromSignal, plug, askParameter, Input,- withArgs, withArgsPlugOut,- MakeArguments, Arguments, makeArgs,- ) where--import qualified Synthesizer.LLVM.Plug.Input as PIn-import qualified Synthesizer.LLVM.Plug.Output as POut--import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP-import qualified Synthesizer.LLVM.Parameterized.Signal as Sig--import qualified Synthesizer.CausalIO.Process as PIO-import qualified Synthesizer.Generic.Cut as CutG-import qualified Synthesizer.Zip as Zip--import qualified Data.EventList.Relative.BodyTime as EventListBT-import qualified Data.StorableVector as SV--import qualified LLVM.Extra.Arithmetic as A-import LLVM.Core (CodeGenFunction)--import qualified Number.Ratio as Ratio-import qualified Algebra.Transcendental as Trans-import qualified Algebra.Algebraic as Algebraic-import qualified Algebra.Field as Field-import qualified Algebra.Ring as Ring-import qualified Algebra.Additive as Additive--import qualified Control.Monad.Trans.Reader as MR-import qualified Control.Monad.Trans.State as MS--import qualified Data.Set as Set-import qualified Data.Vault.Lazy as Vault-import Data.Vault.Lazy (Vault)-import Data.Unique (Unique, newUnique)-import Data.Maybe (fromMaybe)--import Control.Arrow ((^<<), (<<^), arr, first, second)-import Control.Category (id, (.))-import Control.Applicative (Applicative, (<*>), pure, liftA2, liftA3)--import qualified System.Unsafe as Unsafe--import Prelude hiding (id, (.))---{- |-This data type detects sharing.--}-{--There are two levels of the use of keys.-At the top level, in T's State monad,-we store an object id in order to check,-whether we have already seen a certain object.-If we encounter a known object-then we use the Simple constructor-and fetch the stored CausalP output-within the causal process enclosed in Simple.-This and the causal process in the Plugged constructor-are the second level.-These arrows handle a Vault like a state monad-and insert all values they produce into the Vault.--}-newtype T pp pl inp out =- Cons (MS.State (Set.Set Unique) (Core pp pl inp out))--{--We need to hide the x and y types-since these types grow when combining Cores,-and then we could not define numeric instances.--}-data Core pp pl inp out =- forall x y. CutG.Read x =>- Plugged- (pp -> inp -> x)- (PIn.T x y)- (CausalP.T pl (y, Vault) (out, Vault))- |- {-- The Simple constructor is needed for reusing shared CausalP processes- and for input without external representation. (a Plug.Input)- -}- Simple (CausalP.T pl Vault (out, Vault))---applyCore ::- CausalP.T pl (a, Vault) (b, Vault) ->- Core pp pl inp a ->- Core pp pl inp b-applyCore f core =- case core of- Plugged prep plg process -> Plugged prep plg (f . process)- Simple process -> Simple (f . process)--combineCore ::- Core pp pl inp a ->- Core pp pl inp b ->- Core pp pl inp (a,b)-combineCore (Plugged prepA plugA processA) (Plugged prepB plugB processB) =- Plugged- (\p -> Zip.arrowFanout (prepA p) (prepB p))- (PIn.split plugA plugB)- ((\(a,(b,v)) -> ((a,b), v)) ^<< second processB- . arr (\((a,v),b) -> (a,(b,v))) .- first processA <<^ (\((a,b),v) -> ((a,v),b)))-combineCore (Simple processA) (Plugged prepB plugB processB) =- Plugged prepB plugB- ((\(b,(a,v)) -> ((a,b), v)) ^<< second processA . processB)-combineCore (Plugged prepA plugA processA) (Simple processB) =- Plugged prepA plugA- ((\(a,(b,v)) -> ((a,b), v)) ^<< second processB . processA)-combineCore (Simple processA) (Simple processB) =- Simple ((\(a,(b,v)) -> ((a,b), v)) ^<< second processB . processA)---reuseCore :: Vault.Key out -> Core pp pl inp out-reuseCore key =- Simple $ arr $ \vault ->- (fromMaybe (error "key must have been lost") $ Vault.lookup key vault,- vault)---tag ::- Unique -> Vault.Key out ->- MS.State (Set.Set Unique) (Core pp pl inp out) ->- T pp pl inp out-tag unique key stateCore = Cons $ do- alreadySeen <- MS.gets (Set.member unique)- if alreadySeen- then return $ reuseCore key- else do- MS.modify (Set.insert unique)- fmap (applyCore (arr $ \(a,v) -> (a, Vault.insert key a v))) stateCore--tagUnique ::- MS.State (Set.Set Unique) (Core pp pl inp out) ->- T pp pl inp out-tagUnique core =- Unsafe.performIO $- liftA3 tag newUnique Vault.newKey (pure core)---infixr 0 $&--($&) ::- CausalP.T pl a b ->- T pp pl inp a ->- T pp pl inp b-f $& Cons core =- tagUnique $ fmap (applyCore $ first f) core---infixr 3 &|&--(&|&) ::- T pp pl inp a ->- T pp pl inp b ->- T pp pl inp (a,b)-Cons coreA &|& Cons coreB =- tagUnique $ liftA2 combineCore coreA coreB---instance Functor (Core pp pl inp) where- fmap f (Simple process) = Simple (fmap (first f) process)- fmap f (Plugged prep plg process) = Plugged prep plg (fmap (first f) process)--instance Applicative (Core pp pl inp) where- pure a = lift0Core $ pure a- f <*> x = fmap (uncurry ($)) $ combineCore f x--lift0Core :: (forall r. CodeGenFunction r out) -> Core pp pl inp out-lift0Core f = Simple (CausalP.mapSimple (\v -> fmap (flip (,) v) f))---instance Functor (T pp pl inp) where- fmap f (Cons x) = tagUnique $ fmap (fmap f) x--instance Applicative (T pp pl inp) where- pure a = tagUnique $ pure $ pure a- f <*> x = fmap (uncurry ($)) $ f &|& x---lift0 :: (forall r. CodeGenFunction r out) -> T pp pl inp out-lift0 f = tagUnique $ pure $ lift0Core f--lift1 :: (forall r. a -> CodeGenFunction r out) -> T pp pl inp a -> T pp pl inp out-lift1 f x = CausalP.mapSimple f $& x--lift2 :: (forall r. a -> b -> CodeGenFunction r out) -> T pp pl inp a -> T pp pl inp b -> T pp pl inp out-lift2 f x y = CausalP.zipWithSimple f $& x&|&y---instance (A.PseudoRing b, A.Real b, A.IntegerConstant b) => Num (T pp pl a b) where- fromInteger n = pure (A.fromInteger' n)- (+) = lift2 A.add- (-) = lift2 A.sub- (*) = lift2 A.mul- abs = lift1 A.abs- signum = lift1 A.signum--instance (A.Field b, A.Real b, A.RationalConstant b) => Fractional (T pp pl a b) where- fromRational x = pure (A.fromRational' x)- (/) = lift2 A.fdiv---instance (A.Additive b) => Additive.C (T pp pl a b) where- zero = pure A.zero- (+) = lift2 A.add- (-) = lift2 A.sub- negate = lift1 A.neg--instance (A.PseudoRing b, A.IntegerConstant b) => Ring.C (T pp pl a b) where- one = pure A.one- fromInteger n = pure (A.fromInteger' n)- (*) = lift2 A.mul--instance (A.Field b, A.RationalConstant b) => Field.C (T pp pl a b) where- fromRational' x = pure (A.fromRational' $ Ratio.toRational98 x)- (/) = lift2 A.fdiv--instance (A.Transcendental b, A.RationalConstant b) => Algebraic.C (T pp pl a b) where- sqrt = lift1 A.sqrt- root n x = lift2 A.pow x (Field.recip $ Ring.fromInteger n)- x^/r = lift2 A.pow x (Field.fromRational' r)--instance (A.Transcendental b, A.RationalConstant b) => Trans.C (T pp pl a b) where- pi = lift0 A.pi- sin = lift1 A.sin- cos = lift1 A.cos- (**) = lift2 A.pow- exp = lift1 A.exp- log = lift1 A.log-- asin _ = error "LLVM missing intrinsic: asin"- acos _ = error "LLVM missing intrinsic: acos"- atan _ = error "LLVM missing intrinsic: atan"----fromSignal ::- Sig.T pl a ->- T pp pl inp a-fromSignal sig =- tagUnique $ pure $ Simple (CausalP.feedFst sig)----type Input pp a = MR.Reader (pp, a)--plug ::- (CutG.Read b, PIn.Default b) =>- Input pp a b ->- T pp pl a (PIn.Element b)-plug accessor =- tagUnique $ pure $- Plugged- (curry $ MR.runReader accessor)- PIn.deflt- id--askParameter :: Input pp a pp-askParameter = MR.asks fst---runPlugOut ::- T pp pl a x -> POut.T x b ->- IO (pp -> pl -> PIO.T a b)-runPlugOut (Cons core) pout =- case MS.evalState core Set.empty of- Plugged prep pin process ->- fmap (\f pp pl -> f pl <<^ prep pp) $- CausalP.processIOCore- pin- (fst ^<< process <<^ flip (,) Vault.empty)- pout- Simple _ ->- error "FunctionalPlug.runPlugOut: no substantial input available"- -- Simple process ->- -- CausalP.processIOCore pin process pout--run ::- (POut.Default b) =>- T pp pl a (POut.Element b) ->- IO (pp -> pl -> PIO.T a b)-run f = runPlugOut f POut.deflt---{- |-Cf. 'F.withArgs'.--}-withArgs ::- (MakeArguments a, POut.Default b) =>- (Arguments (Input pp a) a -> T pp pl a (POut.Element b)) ->- IO (pp -> pl -> PIO.T a b)-withArgs f = withArgsPlugOut f POut.deflt--withArgsPlugOut ::- (MakeArguments a) =>- (Arguments (Input pp a) a -> T pp pl a x) ->- POut.T x b ->- IO (pp -> pl -> PIO.T a b)-withArgsPlugOut = withArgsPlugOutStart (MR.asks snd)--withArgsPlugOutStart ::- (MakeArguments a) =>- Input pp a a ->- (Arguments (Input pp a) a -> T pp pl a x) ->- POut.T x b ->- IO (pp -> pl -> PIO.T a b)-withArgsPlugOutStart fid f = runPlugOut (f (makeArgs fid))----type family Arguments (f :: * -> *) (arg :: *)--class MakeArguments arg where- makeArgs :: Functor f => f arg -> Arguments f arg---type instance Arguments f (EventListBT.T i a) = f (EventListBT.T i a)-instance MakeArguments (EventListBT.T i a) where- makeArgs = id--type instance Arguments f (SV.Vector a) = f (SV.Vector a)-instance MakeArguments (SV.Vector a) where- makeArgs = id--type instance Arguments f (Zip.T a b) = (Arguments f a, Arguments f b)-instance (MakeArguments a, MakeArguments b) =>- MakeArguments (Zip.T a b) where- makeArgs f = (makeArgs $ fmap Zip.first f, makeArgs $ fmap Zip.second f)
− src/Synthesizer/LLVM/CausalParameterized/Helix.hs
@@ -1,636 +0,0 @@-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE Rank2Types #-}-{- |-<http://arxiv.org/abs/0911.5171>--}-module Synthesizer.LLVM.CausalParameterized.Helix (- -- * time and phase control based on the helix model- static,- staticPacked,- dynamic,- dynamicLimited,-- -- * useful control curves- zigZag,- zigZagPacked,- zigZagLong,- zigZagLongPacked,- ) where--import qualified Synthesizer.LLVM.CausalParameterized.ProcessValue as CausalPV-import qualified Synthesizer.LLVM.CausalParameterized.ProcessPacked as CausalPS-import qualified Synthesizer.LLVM.CausalParameterized.ProcessPrivate- as CausalPrivP-import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP-import qualified Synthesizer.LLVM.CausalParameterized.Functional as Func-import qualified Synthesizer.LLVM.Parameterized.SignalPacked as SigPS-import qualified Synthesizer.LLVM.Parameterized.SignalPrivate as SigP-import qualified Synthesizer.LLVM.CausalParameterized.RingBufferForward as RingBuffer-import qualified Synthesizer.LLVM.Frame.SerialVector as Serial-import qualified Synthesizer.LLVM.Simple.Value as Value-import qualified Synthesizer.LLVM.Interpolation as Ip-import Synthesizer.LLVM.CausalParameterized.Functional (($&), (&|&))-import Synthesizer.LLVM.CausalParameterized.Process (($*), ($<))-import Synthesizer.LLVM.Simple.Value ((%>), (%>=), (?), (??))--import qualified Synthesizer.LLVM.Storable.Vector as SVU-import qualified Data.StorableVector as SV--import qualified LLVM.DSL.Parameter as Param--import qualified LLVM.Extra.ScalarOrVector as SoV-import qualified LLVM.Extra.Vector as Vector-import qualified LLVM.Extra.Arithmetic as A-import qualified LLVM.Extra.Storable as Storable-import qualified LLVM.Extra.Marshal as Marshal-import qualified LLVM.Extra.Memory as Memory-import qualified LLVM.Extra.Tuple as Tuple-import qualified LLVM.Extra.MaybeContinuation as MaybeCont--import qualified LLVM.Core as LLVM-import LLVM.Core (CodeGenFunction, Value, IsSized, IsFloating)--import qualified Type.Data.Num.Decimal as TypeNum--import Data.Word (Word)--import Foreign.ForeignPtr (touchForeignPtr)--import Control.Arrow (first, (<<<), (^<<), (<<^))-import Control.Category (id)-import Control.Applicative (liftA2)-import Control.Functor.HT (unzip)-import Data.Traversable (mapM)-import Data.Tuple.HT (mapFst)--import qualified Algebra.Field as Field-import qualified Algebra.Ring as Ring--import NumericPrelude.Numeric hiding (splitFraction)-import NumericPrelude.Base hiding (unzip, zip, mapM, id)--import Prelude ()---{- |-Inputs are @(shape, phase)@.--The shape parameter is limited at the beginning and at the end-such that only available data is used for interpolation.-Actually, we allow almost one step less than possible,-since the right boundary of the interval of admissible @shape@ values is open.--}-static ::- (Storable.C vh, Tuple.ValueOf vh ~ v,- Ip.C nodesStep, Ip.C nodesLeap,- SoV.RationalConstant a, SoV.Fraction a,- Marshal.C a, Tuple.ValueOf a ~ Value a, LLVM.IsPrimitive a) =>- (forall r. Ip.T r nodesLeap (Value a) v) ->- (forall r. Ip.T r nodesStep (Value a) v) ->- Param.T p Int ->- Param.T p a ->- Param.T p (SV.Vector vh) ->- CausalP.T p (Value a, Value a) v-static ipLeap ipStep periodInt period vec =- let period32 = Param.wordInt periodInt- cellMargin = combineMarginParams ipLeap ipStep periodInt- in interpolateCell ipLeap ipStep- <<<- first (peekCell cellMargin period32 vec)- <<<- flattenShapePhaseProc period32 period- <<<- first- (limitShape cellMargin period32- (Param.wordInt $ fmap SV.length vec))---staticPacked ::- (Storable.C vh, Tuple.ValueOf vh ~ ve, Serial.Element v ~ ve,- Ip.C nodesStep, Ip.C nodesLeap,- Serial.Size (nodesLeap (nodesStep v)) ~ n,- Serial.C (nodesLeap (nodesStep v)),- Serial.Element (nodesLeap (nodesStep v)) ~- nodesLeap (nodesStep (Serial.Element v)),- TypeNum.Positive n,- SoV.RationalConstant a, SoV.Fraction a, Vector.Real a,- Marshal.C a, Tuple.ValueOf a ~ Value a, LLVM.IsPrimitive a) =>- (forall r. Ip.T r nodesLeap (Serial.Value n a) v) ->- (forall r. Ip.T r nodesStep (Serial.Value n a) v) ->- Param.T p Int ->- Param.T p a ->- Param.T p (SV.Vector vh) ->- CausalP.T p (Serial.Value n a, Serial.Value n a) v-staticPacked ipLeap ipStep periodInt period vec =- let period32 = Param.wordInt periodInt- cellMargin = combineMarginParams ipLeap ipStep periodInt- in interpolateCell ipLeap ipStep- <<<- first (CausalPS.pack- (peekCell (fmap elementMargin cellMargin) period32 vec))- <<<- flattenShapePhaseProcPacked period32 period- <<<- first- (limitShapePacked cellMargin period32- (Param.wordInt $ fmap SV.length vec))---{- |-In contrast to 'dynamic' this one ends-when the end of the manipulated signal is reached.--}-dynamicLimited ::- (Ip.C nodesStep, Ip.C nodesLeap,- A.Additive v, Memory.C v,- SoV.RationalConstant a, SoV.Fraction a,- Marshal.C a, Tuple.ValueOf a ~ Value a, LLVM.IsPrimitive a, LLVM.CmpRet a) =>- (forall r. Ip.T r nodesLeap (Value a) v) ->- (forall r. Ip.T r nodesStep (Value a) v) ->- Param.T p Int ->- Param.T p a ->- SigP.T p v ->- CausalP.T p (Value a, Value a) v-dynamicLimited ipLeap ipStep periodInt period sig =- dynamicGen- (\cellMargin (skips, fracs) ->- let windows =- RingBuffer.trackSkip (fmap Ip.marginNumber cellMargin) sig $& skips- in (windows,- CausalP.delay1Zero $& skips,- CausalP.delay1Zero $& fracs))- ipLeap ipStep periodInt period--{- |-If the time control exceeds the end of the input signal,-then the last waveform is locked.-This is analogous to 'static'.--}-dynamic ::- (Ip.C nodesStep, Ip.C nodesLeap,- A.Additive v, Memory.C v,- SoV.RationalConstant a, SoV.Fraction a,- Marshal.C a, Tuple.ValueOf a ~ Value a, LLVM.IsPrimitive a, LLVM.CmpRet a) =>- (forall r. Ip.T r nodesLeap (Value a) v) ->- (forall r. Ip.T r nodesStep (Value a) v) ->- Param.T p Int ->- Param.T p a ->- SigP.T p v ->- CausalP.T p (Value a, Value a) v-dynamic ipLeap ipStep periodInt period sig =- dynamicGen- (\cellMargin (skips, fracs) ->- let {-- For conformance with 'static'- we stop one step before the definite end.- We achieve this by using a buffer- that is one step longer than necessary.- -}- ((running, actualSkips), windows) =- mapFst unzip $ unzip $- RingBuffer.trackSkipHold- (fmap (succ . Ip.marginNumber) cellMargin) sig $& skips- holdFracs =- CausalPV.zipWithSimple (\r fr -> r ? (fr, 1))- $&- running &|& (CausalP.delay1Zero $& fracs)- in (windows, actualSkips, holdFracs))- ipLeap ipStep periodInt period--dynamicGen ::- (Ip.C nodesStep, Ip.C nodesLeap,- A.Additive v, Memory.C v,- SoV.RationalConstant a, SoV.Fraction a,- Marshal.C a, Tuple.ValueOf a ~ Value a, LLVM.IsPrimitive a, LLVM.CmpRet a) =>- (Param.T p (Ip.Margin (nodesLeap (nodesStep v))) ->- (Func.T p (Value a, Value a) (Value Word),- Func.T p (Value a, Value a) (Value a)) ->- (Func.T p (Value a, Value a) (RingBuffer.T v),- Func.T p (Value a, Value a) (Value Word),- Func.T p (Value a, Value a) (Value a))) ->- (forall r. Ip.T r nodesLeap (Value a) v) ->- (forall r. Ip.T r nodesStep (Value a) v) ->- Param.T p Int ->- Param.T p a ->- CausalP.T p (Value a, Value a) v-dynamicGen limitMaxShape ipLeap ipStep periodInt period =- let period32 = Param.wordInt periodInt- cellMargin = combineMarginParams ipLeap ipStep periodInt- minShape =- Param.wordInt $ fmap fst $- liftA2 shapeMargin cellMargin periodInt-- in Func.withArgs $ \(shape, phase) ->- let (windows, skips, fracs) =- limitMaxShape cellMargin $- unzip (integrateFrac $& (limitMinShape minShape $& shape))- (offsets, shapePhases) =- unzip- (flattenShapePhaseProc period32 period $&- (constantFromWord32 minShape + fracs)- &|&- (CausalP.osciCoreSync $&- phase- &|&- negate- (CausalPV.map (flip (/)) period $&- (CausalP.mapSimple LLVM.inttofp $& skips))))- in interpolateCell ipLeap ipStep $&- (CausalP.map (uncurry . cellFromBuffer) period32- $&- windows- &|&- offsets)- &|&- shapePhases--constantFromWord32 ::- (IsFloating a, LLVM.IsPrimitive a) =>- Param.T p Word -> Func.T p inp (Value a)-constantFromWord32 x =- Func.fromSignal- (CausalP.mapSimple LLVM.inttofp $* SigP.constant x)--limitMinShape ::- (IsFloating a, IsSized a, LLVM.IsPrimitive a, LLVM.CmpRet a) =>- Param.T p Word ->- CausalP.T p (Value a) (Value a)-limitMinShape xLim =- CausalPV.mapAccum- (\_ x lim -> (x%>=lim) ? ((x-lim,zero), (zero,lim-x)))- (Value.lift1 LLVM.inttofp) (return ()) xLim--integrateFrac ::- (IsFloating a, IsSized a, LLVM.IsPrimitive a) =>- CausalP.T p (Value a) (Value Word, Value a)-integrateFrac =- CausalP.mapAccumSimple- (\a (_n,frac) -> do- s <- splitFraction =<< A.add a frac- return (s, s))- (return (A.zero, A.zero))---interpolateCell ::- (Ip.C nodesStep, Ip.C nodesLeap) =>- (forall r. Ip.T r nodesLeap a v) ->- (forall r. Ip.T r nodesStep a v) ->- CausalP.T p (nodesLeap (nodesStep v), (a, a)) v-interpolateCell ipLeap ipStep =- CausalP.mapSimple- (\(nodes, (leap,step)) ->- ipLeap leap =<< mapM (ipStep step) nodes)--cellFromBuffer ::- (Memory.C a, Ip.C nodesLeap, Ip.C nodesStep) =>- Value Word ->- RingBuffer.T a ->- Value Word ->- CodeGenFunction r (nodesLeap (nodesStep a))-cellFromBuffer periodInt buffer offset =- Ip.indexNodes- (Ip.indexNodes (flip RingBuffer.index buffer) A.one)- periodInt offset--elementMargin ::- Ip.Margin (nodesLeap (nodesStep v)) ->- Ip.Margin (nodesLeap (nodesStep (Serial.Element v)))-elementMargin (Ip.Margin x y) = Ip.Margin x y--peekCell ::- (Storable.C a, Tuple.ValueOf a ~ value, Ip.C nodesLeap, Ip.C nodesStep) =>- Param.T p (Ip.Margin (nodesLeap (nodesStep value))) ->- Param.T p Word ->- Param.T p (SV.Vector a) ->- CausalP.T p (Value Word) (nodesLeap (nodesStep value))-peekCell margin period32 vec =- Param.withValue (Param.wordInt $ fmap Ip.marginOffset margin) $ \getOffset valueOffset ->- Param.withValue period32 $ \getPeriod valuePeriod -> CausalPrivP.Cons- (\(p,off,per) () n () -> MaybeCont.lift $ do- offset <- LLVM.bitcast =<< A.sub n (valueOffset off)- perInt <- LLVM.bitcast $ valuePeriod per- nodes <-- Ip.loadNodes (Ip.loadNodes Storable.load A.one) perInt- =<< Storable.advancePtr offset p- return (nodes, ()))- (return ())- (return . flip (,) ())- (const $ const $ return ())- (\p ->- let (fp,ptr,_l) = SVU.unsafeToPointers $ Param.get vec p- in return (fp, (ptr, getOffset p, getPeriod p)))- touchForeignPtr---flattenShapePhaseProc ::- (IsFloating a, SoV.Fraction a, SoV.RationalConstant a,- Marshal.C ah, Tuple.ValueOf ah ~ Value a, LLVM.IsPrimitive a) =>- Param.T p Word ->- Param.T p ah ->- CausalP.T p- (Value a, Value a)- (Value Word, (Value a, Value a))-flattenShapePhaseProc period32 period =- CausalP.map- (\(perInt, per) (shape, phase) ->- flattenShapePhase perInt per shape phase)- (liftA2 (,) period32 period)--flattenShapePhaseProcPacked ::- (IsFloating a, Vector.Real a, SoV.RationalConstant a,- Marshal.C ah, Tuple.ValueOf ah ~ Value a, LLVM.IsPrimitive a,- TypeNum.Positive n) =>- Param.T p Word ->- Param.T p ah ->- CausalP.T p- (Serial.Value n a, Serial.Value n a)- (Serial.Value n Word,- (Serial.Value n a, Serial.Value n a))-flattenShapePhaseProcPacked period32 period =- CausalP.map- (\(perInt, per) (Serial.Cons shape, Serial.Cons phase) -> do- perIntVec <- SoV.replicate perInt- perVec <- SoV.replicate per- (i, (leap, step)) <-- flattenShapePhase perIntVec perVec shape phase- return (Serial.Cons i, (Serial.Cons leap, Serial.Cons step)))- (liftA2 (,) period32 period)--flattenShapePhase ::- (IsFloating a, SoV.Fraction a, SoV.RationalConstant a,- LLVM.ShapeOf a ~ LLVM.ShapeOf i, LLVM.IsInteger i) =>- Value i ->- Value a ->- Value a -> Value a ->- CodeGenFunction r (Value i, (Value a, Value a))-flattenShapePhase = Value.unlift4 $ \periodInt period shape phase ->- let qLeap = Value.lift1 A.fraction $ shape/period - phase- (n,qStep) =- unzip $ Value.lift1 splitFraction $- {-- If 'shape' is correctly limited,- the value is always non-negative algebraically,- but maybe not numerically.- -}- Value.max zero $- shape - qLeap * Value.lift1 LLVM.inttofp periodInt- in (n,(qLeap,qStep))--{- |-You must make sure, that the argument is non-negative.--}-splitFraction ::- (IsFloating a, LLVM.IsInteger i, LLVM.ShapeOf a ~ LLVM.ShapeOf i) =>- Value a -> CodeGenFunction r (Value i, Value a)-splitFraction x = do- n <- LLVM.fptoint x- frac <- A.sub x =<< LLVM.inttofp n- return (n, frac)---limitShape ::- (IsSized t, IsFloating t, SoV.Real t,- LLVM.ShapeOf t ~ LLVM.ShapeOf i,- Marshal.C i, Tuple.ValueOf i ~ Value i,- Ring.C i, LLVM.IsInteger i, SoV.IntegerConstant i,- Ip.C nodesStep, Ip.C nodesLeap) =>- Param.T p (Ip.Margin (nodesLeap (nodesStep value))) ->- Param.T p i ->- Param.T p i ->- CausalP.T p (Value t) (Value t)-limitShape margin periodInt len =- CausalPV.zipWithSimple (Value.limit . unzip)- $<- limitShapeSignal margin periodInt len--limitShapePacked ::- (IsSized t, IsFloating t, LLVM.IsPrimitive t, Vector.Real t,- TypeNum.Positive n,- Ip.C nodesStep, Ip.C nodesLeap) =>- Param.T p (Ip.Margin (nodesLeap (nodesStep value))) ->- Param.T p Word ->- Param.T p Word ->- CausalP.T p (Serial.Value n t) (Serial.Value n t)-limitShapePacked margin periodInt len =- CausalPV.zipWithSimple- (\minmax shape ->- let (minShape,maxShape) = unzip minmax- in Value.limit- (Value.lift1 Serial.upsample minShape,- Value.lift1 Serial.upsample maxShape)- shape)- $<- limitShapeSignal margin periodInt len--limitShapeSignal ::- (IsSized t, IsFloating t,- LLVM.ShapeOf t ~ LLVM.ShapeOf i,- Marshal.C i, Tuple.ValueOf i ~ Value i,- Ring.C i, LLVM.IsInteger i, SoV.IntegerConstant i,- Ip.C nodesStep, Ip.C nodesLeap) =>- Param.T p (Ip.Margin (nodesLeap (nodesStep value))) ->- Param.T p i ->- Param.T p i ->- SigP.T p (Value t, Value t)-limitShapeSignal margin periodInt len =- SigP.Cons- (\minMax () () -> return (minMax, ()))- (return ())- (\(minShapeInt, maxShapeInt) -> do- minShape <- LLVM.inttofp minShapeInt- maxShape <- LLVM.inttofp maxShapeInt- return ((minShape, maxShape), ()))- (const $ const $ return ())- (\p -> return ((),- shapeLimits- (Param.get margin p)- (Param.get periodInt p)- (Param.get len p)))- (const $ return ())---_limitShape ::- (Ring.C th, Marshal.C th, Tuple.ValueOf th ~ t, A.Real t,- Ip.C nodesStep, Ip.C nodesLeap) =>- Ip.Margin (nodesLeap (nodesStep value)) ->- Param.T p th ->- Param.T p th ->- CausalP.T p t t-_limitShape margin periodInt len =- CausalPrivP.Cons- (\(minShape,maxShape) () shape () -> MaybeCont.lift $ do- limited <- A.min maxShape =<< A.max minShape shape- return (limited, ()))- (return ())- (\minmax -> return (minmax, ()))- (const $ const $ return ())- (\p ->- return- ((),- shapeLimits margin- (Param.get periodInt p)- (Param.get len p)))- (const $ return ())--shapeLimits ::- (Ip.C nodesLeap, Ip.C nodesStep, Ring.C t) =>- Ip.Margin (nodesLeap (nodesStep value)) ->- t ->- t ->- (t, t)-shapeLimits margin periodInt len =- case shapeMargin margin periodInt of- (leftMargin, rightMargin) ->- (leftMargin, len - rightMargin)--_shapeLimits ::- (Ip.C nodesLeap, Ip.C nodesStep,- IsFloating t, LLVM.ShapeOf t ~ LLVM.ScalarShape) =>- Ip.Margin (nodesLeap (nodesStep value)) ->- Value.T (Value Word) ->- Value.T (Value t) ->- (Value.T (Value t), Value.T (Value t))-_shapeLimits margin periodInt len =- let (leftMargin, rightMargin) = shapeMargin margin periodInt- in (Value.lift1 LLVM.inttofp leftMargin,- len - Value.lift1 LLVM.inttofp rightMargin)--shapeMargin ::- (Ip.C nodesLeap, Ip.C nodesStep, Ring.C i) =>- Ip.Margin (nodesLeap (nodesStep value)) ->- i -> (i, i)-shapeMargin margin periodInt =- let leftMargin = fromIntegral (Ip.marginOffset margin) + periodInt- rightMargin = fromIntegral (Ip.marginNumber margin) - leftMargin- in (leftMargin, rightMargin)--combineMarginParams ::- (Ip.C nodesStep, Ip.C nodesLeap) =>- (forall r. Ip.T r nodesLeap a v) ->- (forall r. Ip.T r nodesStep a v) ->- Param.T p Int ->- Param.T p (Ip.Margin (nodesLeap (nodesStep v)))-combineMarginParams ipLeap ipStep periodInt =- fmap- (combineMargins (Ip.toMargin ipLeap) (Ip.toMargin ipStep))- periodInt--combineMargins ::- Ip.Margin (nodesLeap value) ->- Ip.Margin (nodesStep value) ->- Int ->- Ip.Margin (nodesLeap (nodesStep value))-combineMargins marginLeap marginStep periodInt =- Ip.Margin {- Ip.marginNumber =- Ip.marginNumber marginStep +- Ip.marginNumber marginLeap * periodInt,- Ip.marginOffset =- Ip.marginOffset marginStep +- Ip.marginOffset marginLeap * periodInt- }---{- |-@zigZagLong loopStart loopLength@-creates a curve that starts at 0-and is linear until it reaches @loopStart+loopLength@.-Then it begins looping in a ping-pong manner-between @loopStart+loopLength@ and @loopStart@.-It is useful as @shape@ control for looping a sound.-Input of the causal process is the slope (or frequency) control.-Slope values must not be negative.--*Main> Sig.renderChunky SVL.defaultChunkSize (Causal.take 25 <<< Helix.zigZagLong 6 10 $* 2) () :: SVL.Vector Float-VectorLazy.fromChunks [Vector.pack [0.0,1.999999,3.9999995,6.0,8.0,10.0,12.0,14.0,15.999999,14.000001,12.0,10.0,7.999999,6.0,8.0,10.0,12.0,14.0,16.0,14.0,11.999999,9.999998,7.999998,6.0000024,8.000002]]--}-zigZagLong ::- (Marshal.C a, Tuple.ValueOf a ~ Value a,- SoV.Fraction a, IsFloating a, SoV.RationalConstant a, LLVM.CmpRet a,- Field.C a) =>- Param.T p a ->- Param.T p a ->- CausalP.T p (Value a) (Value a)-zigZagLong =- zigZagLongGen (CausalP.fromSignal . SigP.constant) zigZag--zigZagLongPacked ::- (Marshal.C a, Tuple.ValueOf a ~ Value a,- Marshal.Vector n a, Tuple.VectorValueOf n a ~ Value (LLVM.Vector n a),- SoV.Fraction a, SoV.RationalConstant a, Vector.Real a,- LLVM.IsPrimitive a, Field.C a,- (n TypeNum.:*: LLVM.SizeOf a) ~ asize,- TypeNum.Positive asize,- TypeNum.Positive n) =>- Param.T p a ->- Param.T p a ->- CausalP.T p (Serial.Value n a) (Serial.Value n a)-zigZagLongPacked =- zigZagLongGen (CausalP.fromSignal . SigPS.constant) zigZagPacked--zigZagLongGen ::- (A.RationalConstant al, A.Field al, Field.C a) =>- (Param.T p a -> CausalP.T p al al) ->- (Param.T p a -> CausalP.T p al al) ->- Param.T p a ->- Param.T p a ->- CausalP.T p al al-zigZagLongGen constant zz prefix loop =- zz (negate $ prefix/loop) * constant loop + constant prefix- <<<- id / constant loop--{- |-@zigZag start@ creates a zig-zag curve with values between 0 and 1, inclusively,-that is useful as @shape@ control for looping a sound.-Input of the causal process is the slope (or frequency) control.-Slope values must not be negative.-The start value must be at most 2 and may be negative.--}-zigZag ::- (Marshal.C a, Tuple.ValueOf a ~ Value a,- SoV.Fraction a, IsFloating a, SoV.RationalConstant a, LLVM.CmpRet a) =>- Param.T p a ->- CausalP.T p (Value a) (Value a)-zigZag start =- CausalPV.mapSimple (\x -> 1-abs (1-x))- <<<- CausalPV.mapAccum- (\_ d t0 ->- let t1 = t0+d- in (t0, wrap (curry . (??)) t1))- id (return ()) start--zigZagPacked ::- (Marshal.C a, Tuple.ValueOf a ~ Value a,- SoV.Fraction a, IsFloating a, Vector.Real a, SoV.RationalConstant a,- LLVM.CmpRet a,- TypeNum.Positive n) =>- Param.T p a ->- CausalP.T p (Serial.Value n a) (Serial.Value n a)-zigZagPacked start =- Serial.Cons- ^<<- CausalPV.mapSimple (\x -> 1 - abs (1-x))- <<<- CausalPV.mapAccum- (\_ d t0 ->- let (t1, cum) = unzip $ Value.lift2 Vector.cumulate t0 d- {-- LLVM.select can be replaced by (??)- once vector select is implemented by LLVM.- -}- in (wrap (Value.lift3 LLVM.select) cum, t1))- id (return ()) start- <<^- (\(Serial.Cons v) -> v)--wrap ::- (SoV.RationalConstant a, IsFloating a, SoV.Fraction a, LLVM.CmpRet a) =>- (Value.T (Value (LLVM.CmpResult a)) ->- Value.T (Value a) ->- Value.T (Value a) ->- Value.T (Value a)) ->- Value.T (Value a) -> Value.T (Value a)-wrap select a = select (a%>0) (2 * Value.fraction (a/2)) a
− src/Synthesizer/LLVM/CausalParameterized/Process.hs
@@ -1,1044 +0,0 @@-{-# LANGUAGE NoImplicitPrelude #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE ExistentialQuantification #-}-{-# LANGUAGE Rank2Types #-}-{-# LANGUAGE ForeignFunctionInterface #-}-module Synthesizer.LLVM.CausalParameterized.Process (- T, simple,- fromSignal, toSignal,- mapAccum, map, mapSimple, zipWith, zipWithSimple,- apply, compose, first,- feedFst, feedSnd,- loop, loopZero, take, takeWhile, integrate,-- ($<), ($>), ($*),- applyFst, applySnd,-- reparameterize,-- mapAccumSimple,-- replicateControlled,- replicateParallel,- replicateControlledParam,- feedbackControlled,- Causal.feedbackControlledZero,- Causal.fromModifier,- fromInitializedModifier,- stereoFromMono,- stereoFromMonoControlled,- stereoFromMonoParameterized,- Causal.stereoFromVector,- Causal.vectorize,- Causal.replaceChannel,- Causal.arrayElement,- Causal.element,- Causal.mix,- raise,- Causal.envelope,- Causal.envelopeStereo,- amplify,- amplifyStereo,- mapLinear,- mapExponential,- quantizeLift,- osciSimple,- Causal.osciCore,- Causal.osciCoreSync,- Causal.shapeModOsci,- delay,- delayZero,- delay1,- Causal.delay1Zero,- delayControlled,- delayControlledInterpolated,- differentiate,- comb,- combStereo,- reverbSimple,- reverb,- Causal.pipeline,- Causal.skip,- Causal.frequencyModulation,- frequencyModulationLinear,- trigger,-- runStorable,- applyStorable,- runStorableChunky,- runStorableChunkyCont,- applyStorableChunky,-- processIO,- processIOCore,- ) where--import Synthesizer.LLVM.CausalParameterized.ProcessPrivate-import Synthesizer.LLVM.Causal.ProcessPrivate- (feedbackControlledAux, reverbParams)-import Synthesizer.LLVM.Causal.Process (loopZero, mix)-import qualified Synthesizer.LLVM.Causal.ProcessPrivate as CausalPriv-import qualified Synthesizer.LLVM.Causal.Process as Causal-import qualified Synthesizer.LLVM.Plug.Input as PIn-import qualified Synthesizer.LLVM.Plug.Output as POut-import qualified Synthesizer.CausalIO.Process as PIO--import qualified Synthesizer.LLVM.CausalParameterized.RingBuffer as RingBuffer-import qualified Synthesizer.LLVM.Parameterized.SignalPrivate as SigPPriv-import qualified Synthesizer.LLVM.Parameterized.Signal as SigP-import qualified Synthesizer.LLVM.Simple.SignalPrivate as SigPriv-import qualified Synthesizer.LLVM.Simple.Value as Value-import qualified Synthesizer.LLVM.Interpolation as Interpolation-import qualified Synthesizer.LLVM.Frame.Stereo as Stereo-import qualified Synthesizer.LLVM.Frame as Frame-import qualified Synthesizer.LLVM.ForeignPtr as ForeignPtr--import qualified Synthesizer.Causal.Class as CausalClass-import qualified Synthesizer.Generic.Cut as Cut-import qualified Synthesizer.Plain.Modifier as Modifier--import qualified Data.StorableVector.Lazy as SVL-import qualified Data.StorableVector as SV-import qualified Data.StorableVector.Base as SVB--import qualified LLVM.DSL.Execution as Exec-import qualified LLVM.DSL.Parameter as Param-import LLVM.DSL.Parameter (($#))--import qualified LLVM.Extra.ScalarOrVector as SoV-import qualified LLVM.Extra.Tuple as Tuple-import qualified LLVM.Extra.MaybeContinuation as MaybeCont-import qualified LLVM.Extra.Maybe as Maybe-import qualified LLVM.Extra.Storable as Storable-import qualified LLVM.Extra.Memory as Memory-import qualified LLVM.Extra.Marshal as Marshal-import qualified LLVM.Extra.Control as C-import qualified LLVM.Extra.Arithmetic as A--import qualified LLVM.Core as LLVM-import LLVM.Core- (CodeGenFunction, ret, Value, valueOf,- IsSized, IsConst, IsArithmetic, IsFloating)--import qualified Type.Data.Num.Decimal as TypeNum--import qualified Control.Category as Cat-import Control.Monad.Trans.State (runState)-import Control.Arrow (arr, first, second, (<<<), (<<^), (>>>), (&&&))-import Control.Monad (liftM, when)-import Control.Applicative (liftA2, liftA3, pure, (<*>))-import Control.Functor.HT (void, unzip)-import Control.Exception (bracket)--import qualified Data.List as List-import Data.Traversable (traverse)-import Data.Foldable (sequence_)-import Data.Tuple.HT (swap, mapFst, mapSnd, uncurry3, snd3)-import Data.Word (Word)-import Data.Int (Int8)--import System.Random (Random, RandomGen)--import Foreign.StablePtr- (StablePtr, newStablePtr, freeStablePtr, deRefStablePtr)-import Foreign.ForeignPtr (touchForeignPtr)-import Foreign.Ptr (FunPtr, Ptr, freeHaskellFunPtr)--import qualified System.Unsafe as Unsafe--import qualified LLVM.DSL.Debug.Marshal as DebugSt-import qualified LLVM.DSL.Debug.Counter as DebugCnt--import qualified Algebra.Transcendental as Trans--import NumericPrelude.Numeric-import NumericPrelude.Base hiding- (and, iterate, map, unzip, zip, zipWith, take, takeWhile, sequence_)---infixl 0 $<, $>, $*--- infixr 0 $:* -- can be used together with $--applyFst, ($<) :: T p (a,b) c -> SigP.T p a -> T p b c-applyFst = CausalClass.applyFst--applySnd, ($>) :: T p (a,b) c -> SigP.T p b -> T p a c-applySnd = CausalClass.applySnd--{--These infix operators may become methods of a type class-that can also have synthesizer-core:Causal.Process as instance.--}-($*) :: T p a b -> SigP.T p a -> SigP.T p b-($*) = apply-($<) = applyFst-($>) = applySnd---reparameterize :: Param.T q p -> T p a b -> T q a b-reparameterize p (Cons start alloca stop next create delete) =- Cons start alloca stop next (create . Param.get p) delete---mapAccumSimple ::- (Memory.C s) =>- (forall r. a -> s -> CodeGenFunction r (b,s)) ->- (forall r. CodeGenFunction r s) ->- T p a b-mapAccumSimple f s =- mapAccum (\() -> f) (\() -> s) (return ()) (return ())--fromInitializedModifier ::- (Value.Flatten ah, Value.Registers ah ~ al,- Value.Flatten bh, Value.Registers bh ~ bl,- Value.Flatten ch, Value.Registers ch ~ cl,- Value.Flatten sh, Value.Registers sh ~ sl, Memory.C sl,- Value.Flatten ih, Value.Registers ih ~ il, Memory.C il,- Marshal.C i, Tuple.ValueOf i ~ il) =>- Modifier.Initialized sh ih ch ah bh -> Param.T p i -> T p (cl,al) bl-fromInitializedModifier (Modifier.Initialized initF step) =- mapAccum- (\() (c,a) s ->- Value.flatten $- runState- (step (Value.unfold c) (Value.unfold a))- (Value.unfold s))- (Value.flattenFunction initF)- (return ())---replicateParallel ::- (Tuple.Undefined b, Tuple.Phi b) =>- Param.T p Int -> SigP.T p b -> T p (b,b) b -> T p a b -> T p a b-replicateParallel n z cum p =- replicateControlled n (first p >>> cum) $> z--{--There are several problems:-- * We have to call f on every parameter in the list,- but we have to assume that the generated code is always the same.-- * createIOContext may return different types for every element in the list.- If types are different, the LLVM code cannot be the same, though.--}-replicateControlledParam ::- (Tuple.Undefined x, Tuple.Phi x) =>- (forall q. Param.T q p -> Param.T q a -> T q (c,x) x) ->- Param.T p [a] -> T p (c,x) x-replicateControlledParam f ps =- case f (arr fst) (arr snd) of- Cons next alloca start stop createIOContext deleteIOContext -> Cons- (replicateControlledNext next stop)--- (_replicateControlledNext next)- alloca- (replicateControlledStart start)- (replicateControlledStop stop)- (\p ->- replicateControlledCreate $- mapM- (\a -> createIOContext (p,a))- (Param.get ps p))- (replicateControlledDelete deleteIOContext)----- cf. synthesizer-core:Causal.Process-feedbackControlled ::- (Marshal.C ch, Tuple.ValueOf ch ~ c) =>- Param.T p ch ->- T p ((ctrl,a),c) b -> T p (ctrl,b) c -> T p (ctrl,a) b-feedbackControlled initial forth back =- loop initial (feedbackControlledAux forth back)---{- |-Run a causal process independently on each stereo channel.--}-stereoFromMono ::- (Tuple.Phi a, Tuple.Phi b, Tuple.Undefined b) =>- T p a b -> T p (Stereo.T a) (Stereo.T b)-stereoFromMono- (Cons next alloca start stop createIOContext deleteIOContext) = Cons- (stereoNext stop next)- alloca- (stereoStart start)- (stereoStop stop)- (stereoCreate createIOContext createIOContext)- (composeDelete deleteIOContext deleteIOContext)--stereoFromMonoControlled ::- (Tuple.Phi a, Tuple.Phi b, Tuple.Phi c, Tuple.Undefined b) =>- T p (c,a) b -> T p (c, Stereo.T a) (Stereo.T b)-stereoFromMonoControlled proc =- stereoFromMono proc <<^ (\(c,sa) -> fmap ((,) c) sa)--stereoFromMonoParameterized ::- (Tuple.Phi a, Tuple.Phi b, Tuple.Undefined b) =>- (forall q. Param.T q p -> Param.T q x -> T q a b) ->- Param.T p (Stereo.T x) -> T p (Stereo.T a) (Stereo.T b)-stereoFromMonoParameterized f ps =- case f (arr fst) (arr snd) of- Cons next alloca start stop createIOContext deleteIOContext -> Cons- (stereoNext stop next)- alloca- (stereoStart start)- (stereoStop stop)- (stereoCreate- (\p -> createIOContext (p, Stereo.left $ Param.get ps p))- (\p -> createIOContext (p, Stereo.right $ Param.get ps p)))- (composeDelete deleteIOContext deleteIOContext)--stereoCreate ::- Monad m =>- (p -> m (ioContextA, context)) ->- (p -> m (ioContextB, context)) ->- p -> m ((ioContextA, ioContextB), Stereo.T context)-stereoCreate l r =- liftM (mapSnd $ uncurry Stereo.cons) . composeCreate l r---stereoNext ::- (Tuple.Phi a, Tuple.Phi b, Tuple.Phi c, Tuple.Phi s, Tuple.Phi context,- Tuple.Undefined b, Tuple.Undefined s) =>- (context -> s -> CodeGenFunction r ()) ->- (forall z. (Tuple.Phi z) => context -> local -> a -> s -> MaybeCont.T r z (b, s)) ->- Stereo.T context ->- local ->- Stereo.T a ->- Stereo.T s ->- MaybeCont.T r c (Stereo.T b, Stereo.T s)-stereoNext stop next context local a s0 = MaybeCont.fromMaybe $ do- mbs1 <-- twiceStereo- (MaybeCont.toMaybe . uncurry3 (flip next local))- (liftA3 (,,) context a s0)-- mbs2 <-- if True- then Maybe.lift2 Stereo.cons (Stereo.left mbs1) (Stereo.right mbs1)- else MaybeCont.toMaybe $ traverse (MaybeCont.fromMaybe . return) mbs1-- end <- Maybe.getIsNothing mbs2- C.ifThen end () $- sequence_ $- liftA2- (\mbsi c -> Maybe.for mbsi (stop c . snd))- mbs1 context-- return $ fmap unzip mbs2--stereoStart ::- (Tuple.Phi a, Tuple.Phi b, Tuple.Phi c, Tuple.Undefined b, Tuple.Undefined c) =>- (a -> CodeGenFunction r (c, b)) ->- Stereo.T a -> CodeGenFunction r (Stereo.T c, Stereo.T b)-stereoStart code a =- fmap unzip $ twiceStereo code a--stereoStop ::- (Tuple.Phi context, Tuple.Phi state) =>- (context -> state -> CodeGenFunction r ()) ->- Stereo.T context -> Stereo.T state -> CodeGenFunction r ()-stereoStop code c s = void $ twiceStereo (uncurry code) (liftA2 (,) c s)--twiceStereo ::- (Tuple.Phi a, Tuple.Phi b, Tuple.Undefined b) =>- (a -> CodeGenFunction r b) ->- Stereo.T a -> CodeGenFunction r (Stereo.T b)-twiceStereo code a =- fmap (uncurry Stereo.cons) $- twice code (Stereo.left a, Stereo.right a)--twice ::- (Tuple.Phi a, Tuple.Phi b, Tuple.Undefined b) =>- (a -> CodeGenFunction r b) ->- (a,a) -> CodeGenFunction r (b,b)-twice code a =- fmap snd $- C.fixedLengthLoop (valueOf (2::Int8)) (a, Tuple.undef) $- \((a0,a1), (_,b1)) -> do- b0 <- code a0- return ((a1,a0), (b1,b0))---{- |-You may also use '(+)' and a 'SigP.constant' signal or a number literal.--}-raise ::- (A.Additive al, Marshal.C a, Tuple.ValueOf a ~ al) =>- Param.T p a -> T p al al-raise =- map Frame.mix---{- |-You may also use '(*)' and a 'SigP.constant' signal or a number literal.--}-amplify ::- (A.PseudoRing al, Marshal.C a, Tuple.ValueOf a ~ al) =>- Param.T p a -> T p al al-amplify =- map Frame.amplifyMono--amplifyStereo ::- (A.PseudoRing al, Marshal.C a, Tuple.ValueOf a ~ al) =>- Param.T p a -> T p (Stereo.T al) (Stereo.T al)-amplifyStereo =- map Frame.amplifyStereo----mapLinear ::- (IsArithmetic a, Marshal.C a, Tuple.ValueOf a ~ Value a) =>- Param.T p a -> Param.T p a -> T p (Value a) (Value a)-mapLinear depth center =- map- (\(d,c) x -> A.add c =<< A.mul d x)- (depth&&¢er)--mapExponential ::- (Trans.C a, Marshal.C a, IsFloating a, IsConst a,- SoV.TranscendentalConstant a, Tuple.ValueOf a ~ Value a) =>- Param.T p a -> Param.T p a -> T p (Value a) (Value a)-mapExponential depth center =- map- (\(d,c) x ->- A.mul c =<< A.exp =<< A.mul d x)- (log depth &&& center)---{- |-@quantizeLift k f@ applies the process @f@ to every @k@th sample-and repeats the result @k@ times.--Like 'SigP.interpolateConstant' this function can be used-for computation of filter parameters at a lower rate.-This can be useful, if you have a frequency control signal at sample rate-that shall be used both for an oscillator and a frequency filter.--}-quantizeLift ::- (Memory.C b,- Marshal.C c, Tuple.ValueOf c ~ Value cl,- SoV.IntegerConstant cl, IsFloating cl,- LLVM.CmpRet cl, LLVM.CmpResult cl ~ Bool) =>- Param.T p c ->- T p a b ->- T p a b-quantizeLift k causal =- Causal.quantizeLift causal $< SigP.constant k----- for backwards compatibility-osciSimple ::- (SoV.Fraction t, IsSized t) =>- (forall r. Value t -> CodeGenFunction r y) ->- T p (Value t, Value t) y-osciSimple = Causal.osci---{- |-Delay time must be non-negative.--The initial value is needed in order to determine the ring buffer element type.--}-delay ::- (Marshal.C a, Tuple.ValueOf a ~ al) =>- Param.T p a -> Param.T p Int -> T p al al-delay initial time =- mapSimple RingBuffer.oldest- <<<- RingBuffer.track initial time--delayZero ::- (Memory.C a, A.Additive a) =>- Param.T p Int -> T p a a-delayZero time =- mapSimple RingBuffer.oldest- <<<- RingBuffer.trackConst A.zero time---{- |-Delay by one sample.-For very small delay times (say up to 8)-it may be more efficient to apply 'delay1' several times-or to use a pipeline,-e.g. @pipeline (id :: T (Vector D4 Float) (Vector D4 Float))@-delays by 4 samples in an efficient way.-In principle it would be also possible to use-@unpack (delay1 (pure $ consVector 0 0 0 0))@-but 'unpack' causes an additional delay.-Thus @unpack (id :: T (Vector D4 Float) (Vector D4 Float))@ may do,-what you want.--}-delay1 ::- (Marshal.C a, Tuple.ValueOf a ~ al) =>- Param.T p a -> T p al al-delay1 initial = loop initial (arr swap)---{- |-Delay by a variable amount of samples.-The momentum delay must be between @0@ and @maxTime@, inclusively.--}-delayControlled ::- (Marshal.C a, Tuple.ValueOf a ~ al) =>- Param.T p a -> Param.T p Int -> T p (Value Word, al) al-delayControlled initial maxTime =- zipWithSimple RingBuffer.index- <<<- second (RingBuffer.track initial maxTime)--{- |-Delay by a variable fractional amount of samples.-Non-integer delays are achieved by linear interpolation.-The momentum delay must be between @0@ and @maxTime@, inclusively.--}-delayControlledInterpolated ::- (Interpolation.C nodes,- Marshal.C vh, Tuple.ValueOf vh ~ v,- IsFloating a, LLVM.ShapeOf a ~ LLVM.ScalarShape) =>- (forall r. Interpolation.T r nodes (Value a) v) ->- Param.T p vh -> Param.T p Int -> T p (Value a, v) v-delayControlledInterpolated ip initial maxTime =- let margin = Interpolation.toMargin ip- in zipWithSimple- (\del buf -> do- let offset =- A.fromInteger' $ fromIntegral $- Interpolation.marginOffset margin- n <- A.max offset =<< LLVM.fptoint del- k <- A.sub del =<< LLVM.inttofp n- m <- A.sub n offset- ip k =<<- Interpolation.indexNodes (flip RingBuffer.index buf) A.one m)- <<<- second- (RingBuffer.track initial- (fmap (Interpolation.marginNumber margin +) maxTime))---differentiate ::- (A.Additive al, Marshal.C a, Tuple.ValueOf a ~ al) =>- Param.T p a -> T p al al-differentiate initial =- Cat.id - delay1 initial--{- |-Delay time must be greater than zero!--}-comb ::- (A.PseudoRing al, Marshal.C a, Tuple.ValueOf a ~ al) =>- Param.T p a -> Param.T p Int ->- T p al al-comb gain time =- loopZero (mix >>> (Cat.id &&&- (delayZero (time-1) >>> amplify gain)))--combStereo ::- (A.PseudoRing al, Marshal.C a, Tuple.ValueOf a ~ al) =>- Param.T p a -> Param.T p Int ->- T p (Stereo.T al) (Stereo.T al)-combStereo gain time =- loopZero (mix >>> (Cat.id &&&- (delayZero (time-1) >>> amplifyStereo gain)))--{- |-Example: apply a stereo reverb to a mono sound.--> traverse-> (\seed -> reverbSimple (Random.mkStdGen seed) 16 (0.92,0.98) (200,1000))-> (Stereo.cons 42 23)--There is a serious problem:-The parameters are not of type 'Param.T',-thus they cannot depend e.g. on a dynamic sample rate as required by JACK.--}-reverbSimple ::- (Random a, IsArithmetic a, SoV.RationalConstant a,- Marshal.C a, Tuple.ValueOf a ~ Value a,- RandomGen g) =>- g -> Int -> (a,a) -> (Int,Int) ->- T p (Value a) (Value a)-reverbSimple rnd num gainRange timeRange =- mapSimple (A.mul (A.fromRational' $ recip $ fromIntegral num)) <<<- (foldl (+) zero $- List.map (\(g,t) -> comb $# g $# t) $- reverbParams rnd num gainRange timeRange)--reverb ::- (Random a, Marshal.C a, Tuple.ValueOf a ~ Value a,- SoV.PseudoModule a, SoV.Scalar a ~ s,- IsFloating s, SoV.IntegerConstant s, LLVM.IsPrimitive s,- RandomGen g) =>- Param.T p g -> Param.T p Int -> Param.T p (a,a) -> Param.T p (Int,Int) ->- T p (Value a) (Value a)-reverb rnd num gainRange timeRange =- map- (\n x -> flip A.scale x =<< A.fdiv A.one =<< LLVM.inttofp n)- (Param.wordInt num)- <<<- replicateControlledParam- (\_p p -> first (comb (fmap fst p) (fmap snd p)) >>> mix)- (pure reverbParams <*> rnd <*> num <*> gainRange <*> timeRange)- <<^- (\a -> (a,a))---{- |-Like 'skip' but does not require @Memory@ constraint on the result type.-This way it can be used on a stream of ring buffer states.-The downside is that the result is recomputed (from the previous state)-at every step.--Warning:-This process is actually unsafe.-It fails on signal generators that use mutable variables,-like Signal.storableVectorLazy.--}-_skipVolatile ::- (Causal.C process, CausalClass.SignalOf process ~ signal) =>- signal v -> process (Value Word) v-_skipVolatile =- CausalPriv.alterSignal- (\(SigPriv.Core next start stop) -> CausalPriv.Core- (\context n state0 -> do- y <- fmap fst $ next context state0- state1 <-- MaybeCont.fromMaybe $ fmap snd $- MaybeCont.fixedLengthLoop n state0 $- fmap snd . next context- return (y, state1))- start- stop)---{- |-> frequencyModulationLinear signal--is a causal process mapping from a shrinking factor-to the modulated input @signal@.-Similar to 'Sig.interpolateConstant'-but the factor is reciprocal and controllable-and we use linear interpolation.-The shrinking factor must be non-negative.--}-frequencyModulationLinear ::- (SoV.IntegerConstant a, IsFloating a,- LLVM.CmpRet a, LLVM.CmpResult a ~ Bool, IsSized a) =>- SigP.T p (Value a) -> T p (Value a) (Value a)-frequencyModulationLinear =- Causal.frequencyModulation Interpolation.linear . SigP.adjacentNodes02---type Exporter f = f -> IO (FunPtr f)--foreign import ccall safe "wrapper" callbackCreate ::- Exporter (LLVM.Ptr lparam -> LLVM.Ptr init -> IO (StablePtr ioContext))--foreign import ccall safe "wrapper" callbackDelete ::- Exporter (StablePtr ioContext -> IO ())--stopAndDelete ::- LLVM.Function (StablePtr ioContext -> IO ()) ->- (context -> state -> CodeGenFunction r ()) ->- Maybe.T ((context, state), Value (StablePtr ioContext)) ->- CodeGenFunction r ()-stopAndDelete eraser stop mcsio =- Maybe.for mcsio $ \(cs, io) -> do- uncurry stop cs- void $ LLVM.call eraser io---{- |-@trigger fill signal@ send @signal@ to the output-and restart it whenever the Boolean process input is 'True'.-Before the first occurrence of 'True'-and between instances of the signal the output is filled with 'Maybe.nothing'.--Every restart of the signal needs a call into Haskell code.-Thus it is certainly a good idea, not to trigger the signal too frequently.--}-{--Are exceptions handled correctly?--}-trigger ::- (Marshal.C a, Tuple.ValueOf a ~ al, Tuple.Undefined b, Tuple.Phi b) =>- (forall q. Param.T q p -> Param.T q a -> SigP.T q b) ->- T p (Maybe.T al) (Maybe.T b)-trigger sig =- triggerAux (sig (arr fst) (arr snd))--triggerAux ::- (Marshal.C a, Tuple.ValueOf a ~ al, Tuple.Undefined b, Tuple.Phi b) =>- SigP.T (p,a) b ->- T p (Maybe.T al) (Maybe.T b)-triggerAux- (SigPPriv.Cons next alloca start stop createIOContext deleteIOContext) = Cons- (\(creator, eraser) (local, (param, xPtr)) mx mcsio0 -> MaybeCont.lift $ do- mcsio1 <-- Maybe.run mx- (return mcsio0)- (\x ->- stopAndDelete eraser stop mcsio0- >>- do- Memory.store x xPtr- io <- LLVM.call creator param xPtr- cs <- start =<< Memory.load param- return $ Maybe.just (cs, io))- mcasio2 <-- Maybe.run mcsio1 (return Maybe.nothing) $ \((c1,s1), io1) ->- MaybeCont.toMaybe $ fmap (flip (,) io1 . (,) c1) $ next c1 local s1- return (fmap (fst.snd.fst) mcasio2, fmap (mapFst (mapSnd snd)) mcasio2))- (liftA2 (,) alloca $ liftA2 (,) LLVM.alloca LLVM.alloca)- (\ce -> return (ce, Maybe.nothing))- (\(_creator, eraser) mcsio -> stopAndDelete eraser stop mcsio)- (\p -> do- creator <- callbackCreate $ \paramPtr xPtr -> do- x <- Marshal.peek xPtr- (context, param) <- createIOContext (p,x)- Marshal.poke paramPtr param- newStablePtr context- eraser <- callbackDelete $ \contextPtr -> do- deleteIOContext =<< deRefStablePtr contextPtr- freeStablePtr contextPtr- let ce = (creator, eraser)- return (ce, ce))- (\(creator, eraser) ->- freeHaskellFunPtr creator >>- freeHaskellFunPtr eraser)---{- |-On each restart the parameters of type @b@ are passed to the signal.--triggerParam ::- (Tuple.Value a, Tuple.ValueOf a ~ al,- Tuple.Value b, Tuple.ValueOf b ~ bl) =>- Param.T p a ->- (Param.T p b -> SigP.T p a) ->- T p (Value Bool, bl) al-triggerParam fill sig =--}----foreign import ccall safe "dynamic" derefFillPtr ::- Exec.Importer (LLVM.Ptr param -> Word -> Ptr a -> Ptr b -> IO Word)--runStorable ::- (Storable.C a, Tuple.ValueOf a ~ valueA,- Storable.C b, Tuple.ValueOf b ~ valueB) =>- T p valueA valueB ->- IO (p -> SV.Vector a -> SV.Vector b)-runStorable (Cons next alloca start stop createIOContext deleteIOContext) = do- fill <-- Exec.compile "process" $- Exec.createFunction derefFillPtr "fillprocessblock" $- \paramPtr size alPtr blPtr -> do- param <- Memory.load paramPtr- (c,s) <- start param- local <- alloca- (pos,msExit) <-- Storable.arrayLoopMaybeCont2 size alPtr blPtr s $- \ aPtri bPtri s0 -> do- a <- MaybeCont.lift $ Storable.load aPtri- (b,s1) <- next c local a s0- MaybeCont.lift $ Storable.store b bPtri- return s1- Maybe.for msExit $ stop c- ret pos-- return $ \p as ->- Unsafe.performIO $- bracket (createIOContext p) (deleteIOContext . fst) $- \ (_,params) ->- SVB.withStartPtr as $ \ aPtr len ->- SVB.createAndTrim len $ \ bPtr ->- Marshal.with params $ \paramPtr ->- fmap fromIntegral $- fill paramPtr (fromIntegral len) aPtr bPtr--applyStorable ::- (Storable.C a, Tuple.ValueOf a ~ valueA,- Storable.C b, Tuple.ValueOf b ~ valueB) =>- T p valueA valueB ->- p -> SV.Vector a -> SV.Vector b-applyStorable gen = Unsafe.performIO $ runStorable gen----foreign import ccall safe "dynamic" derefChunkPtr ::- Exec.Importer- (LLVM.Ptr contextStateStruct -> Word -> Ptr a -> Ptr b -> IO Word)---compileChunky ::- (Storable.C a, Tuple.ValueOf a ~ valueA,- Storable.C b, Tuple.ValueOf b ~ valueB,- Memory.C parameters, Memory.Struct parameters ~ paramStruct,- Memory.C context, Memory.C state,- Memory.Struct (context, Maybe.T state) ~ contextStateStruct) =>- (forall r z.- (Tuple.Phi z) =>- context -> local ->- valueA -> state ->- MaybeCont.T r z (valueB, state)) ->- (forall r. CodeGenFunction r local) ->- (forall r.- parameters ->- CodeGenFunction r (context, state)) ->- (forall r.- context -> state ->- CodeGenFunction r ()) ->- IO (LLVM.Ptr paramStruct -> IO (LLVM.Ptr contextStateStruct),- Exec.Finalizer contextStateStruct,- LLVM.Ptr contextStateStruct -> Word -> Ptr a -> Ptr b -> IO Word)-compileChunky next alloca start stop =- Exec.compile "process-chunky" $- liftA3 (,,)- (Exec.createFunction derefStartPtr "startprocess" $- \paramPtr -> do- pptr <- LLVM.malloc- flip Memory.store pptr . mapSnd Maybe.just- =<< start =<< Memory.load paramPtr- ret pptr)- (Exec.createFinalizer derefStopPtr "stopprocess" $- \ contextStatePtr -> do- (c,ms) <- Memory.load contextStatePtr- Maybe.for ms $ stop c- LLVM.free contextStatePtr- ret ())- (Exec.createFunction derefChunkPtr "fillprocess" $- \ contextStatePtr loopLen aPtr bPtr -> do- (param, msInit) <- Memory.load contextStatePtr- local <- alloca- (pos,msExit) <-- Maybe.run msInit (return (A.zero, Maybe.nothing)) $ \sInit ->- Storable.arrayLoopMaybeCont2 loopLen aPtr bPtr sInit $- \ aPtri bPtri s0 -> do- a <- MaybeCont.lift $ Storable.load aPtri- (b,s1) <- next param local a s0- MaybeCont.lift $ Storable.store b bPtri- return s1- sptr <- LLVM.getElementPtr0 contextStatePtr (TypeNum.d1, ())- Memory.store msExit sptr- ret pos)---foreign import ccall safe "dynamic" derefStartPtr ::- Exec.Importer (LLVM.Ptr paramStruct -> IO (LLVM.Ptr contextStateStruct))--foreign import ccall safe "dynamic" derefStopPtr ::- Exec.Importer (LLVM.Ptr contextStateStruct -> IO ())--foreign import ccall safe "dynamic" derefChunkPluggedPtr ::- Exec.Importer- (LLVM.Ptr contextStateStruct -> Word ->- LLVM.Ptr inp -> LLVM.Ptr out -> IO Word)--compilePlugged ::- (Memory.C parameters, Memory.Struct parameters ~ paramStruct,- Memory.C context, Memory.C state,- Memory.Struct (context, Maybe.T state) ~ contextStateStruct,- Tuple.Undefined stateIn, Tuple.Phi stateIn,- Tuple.Undefined stateOut, Tuple.Phi stateOut,- Memory.C paramValueIn, Memory.Struct paramValueIn ~ paramStructIn,- Memory.C paramValueOut, Memory.Struct paramValueOut ~ paramStructOut) =>- (forall r.- paramValueIn ->- stateIn -> LLVM.CodeGenFunction r (valueA, stateIn)) ->- (forall r.- paramValueIn ->- LLVM.CodeGenFunction r stateIn) ->- (forall r z.- (Tuple.Phi z) =>- context -> local ->- valueA -> state ->- MaybeCont.T r z (valueB, state)) ->- (forall r. CodeGenFunction r local) ->- (forall r.- parameters ->- CodeGenFunction r (context, state)) ->- (forall r.- context -> state ->- CodeGenFunction r ()) ->- (forall r.- paramValueOut ->- valueB -> stateOut -> LLVM.CodeGenFunction r stateOut) ->- (forall r.- paramValueOut ->- LLVM.CodeGenFunction r stateOut) ->- IO (LLVM.Ptr paramStruct -> IO (LLVM.Ptr contextStateStruct),- LLVM.Ptr contextStateStruct -> IO (),- LLVM.Ptr contextStateStruct -> Word ->- LLVM.Ptr paramStructIn -> LLVM.Ptr paramStructOut -> IO Word)-compilePlugged nextIn startIn next alloca start stop nextOut startOut =- Exec.compile "process-plugged" $- liftA3 (,,)- (Exec.createFunction derefStartPtr "startprocess" $- \paramPtr -> do- pptr <- LLVM.malloc- flip Memory.store pptr . mapSnd Maybe.just- =<< start =<< Memory.load paramPtr- ret pptr)- (Exec.createFunction derefStopPtr "stopprocess" $- \ contextStatePtr -> do- (c,ms) <- Memory.load contextStatePtr- Maybe.for ms $ stop c- LLVM.free contextStatePtr- ret ())- (Exec.createFunction derefChunkPluggedPtr "fillprocess" $- \ contextStatePtr loopLen inPtr outPtr -> do- (param, msInit) <- Memory.load contextStatePtr- inParam <- Memory.load inPtr- outParam <- Memory.load outPtr- inInit <- startIn inParam- outInit <- startOut outParam- local <- alloca- (pos,msExit) <-- Maybe.run msInit (return (A.zero, Maybe.nothing)) $ \sInit ->- MaybeCont.fixedLengthLoop loopLen (inInit, sInit, outInit) $- \ (in0,s0,out0) -> do- (a,in1) <- MaybeCont.lift $ nextIn inParam in0- (b,s1) <- next param local a s0- out1 <- MaybeCont.lift $ nextOut outParam b out0- return (in1, s1, out1)- sptr <- LLVM.getElementPtr0 contextStatePtr (TypeNum.d1, ())- Memory.store (fmap snd3 msExit) sptr- ret pos)---runStorableChunky ::- (Storable.C a, Tuple.ValueOf a ~ valueA,- Storable.C b, Tuple.ValueOf b ~ valueB) =>- T p valueA valueB ->- IO (p -> SVL.Vector a -> SVL.Vector b)-runStorableChunky proc =- fmap ($ const SVL.empty) $- runStorableChunkyCont proc--{- |-This function should be used-instead of @StorableVector.Lazy.Pattern.splitAt@ and subsequent @append@,-because it does not have the risk of a memory leak.--}-runStorableChunkyCont ::- (Storable.C a, Tuple.ValueOf a ~ valueA,- Storable.C b, Tuple.ValueOf b ~ valueB) =>- T p valueA valueB ->- IO ((SVL.Vector a -> SVL.Vector b) ->- p -> SVL.Vector a -> SVL.Vector b)-runStorableChunkyCont- (Cons next alloca start stop createIOContext deleteIOContext) = do- (startFunc, stopFunc, fill) <- compileChunky next alloca start stop- return $- \ procRest p sig ->- SVL.fromChunks $ Unsafe.performIO $ do- (ioContext, param) <- createIOContext p-- when False $- DebugCnt.next DebugSt.dumpCounter >>=- DebugSt.dump "param" param-- statePtr <- ForeignPtr.newParam stopFunc startFunc param- ioContextPtr <- ForeignPtr.newAux (deleteIOContext ioContext)-- let go xt =- Unsafe.interleaveIO $- case xt of- [] -> return []- x:xs -> SVB.withStartPtr x $ \aPtr size -> do- v <-- ForeignPtr.with statePtr $ \sptr ->- SVB.createAndTrim size $- fmap fromIntegral .- fill sptr (fromIntegral size) aPtr- touchForeignPtr ioContextPtr- (if SV.length v > 0- then fmap (v:)- else id) $- (if SV.length v < size- then return $ SVL.chunks $- procRest $ SVL.fromChunks $- SV.drop (SV.length v) x : xs- else go xs)- go (SVL.chunks sig)--applyStorableChunky ::- (Storable.C a, Tuple.ValueOf a ~ valueA,- Storable.C b, Tuple.ValueOf b ~ valueB) =>- T p valueA valueB ->- p -> SVL.Vector a -> SVL.Vector b-applyStorableChunky gen =- Unsafe.performIO (runStorableChunky gen)---{--I liked to write something with signature--> import qualified Synthesizer.Causal.Process as Causal->-> liftStorableChunk ::-> T p valueA valueB ->-> IO (p -> Causal.T (SV.Vector a) (SV.Vector b))--but it does not quite work this way.-@Causal.T@ from @synthesizer-core@ uses an immutable state internally,-whereas @T@ uses mutable states.-In principle the immutable state of @Causal.T@-could be used for breaking the processing of a stream-and continue it on two different streams in parallel.-I have no function that makes use of this feature,-and thus an @ST@ monad might be a way out.--With this function we can convert an LLVM causal process to an causal IO arrow.-We also need the plugs in order-to read and write LLVM values from and to Haskell data chunks.--In a second step we could convert this to a processor of lazy lists,-and thus to a processor of chunky storable vectors.--}-processIOCore ::- (Cut.Read a) =>- PIn.T a b ->- T p b c ->- POut.T c d ->- IO (p -> PIO.T a d)-processIOCore- (PIn.Cons nextIn startIn createIn deleteIn)- (Cons next alloca start stop createIOContext deleteIOContext)- (POut.Cons nextOut startOut createOut deleteOut) = do- (startFunc, stopFunc, fill) <-- compilePlugged nextIn startIn next alloca start stop nextOut startOut- return $ \p -> PIO.Cons- (\a s@(_, paramPtr) -> do- let maximumSize = Cut.length a- (contextIn, paramIn) <- createIn a- (contextOut,paramOut) <- createOut maximumSize- actualSize <-- Marshal.with paramIn $ \inptr ->- Marshal.with paramOut $ \outptr ->- fill paramPtr (fromIntegral maximumSize) inptr outptr- deleteIn contextIn- b <- deleteOut (fromIntegral actualSize) contextOut- return (b, s))- (do- (ioContext, param) <- createIOContext p-- when False $- DebugCnt.next DebugSt.dumpCounter >>=- DebugSt.dump "param" param- contextStatePtr <- Marshal.with param startFunc-- return (ioContext, contextStatePtr))- (\(ioContext, contextStatePtr) -> do- stopFunc contextStatePtr- deleteIOContext ioContext)--processIO ::- (Cut.Read a, PIn.Default a, POut.Default d) =>- T p (PIn.Element a) (POut.Element d) ->- IO (p -> PIO.T a d)-processIO proc =- processIOCore PIn.deflt proc POut.deflt
− src/Synthesizer/LLVM/CausalParameterized/ProcessPacked.hs
@@ -1,114 +0,0 @@-{-# LANGUAGE NoImplicitPrelude #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE Rank2Types #-}-module Synthesizer.LLVM.CausalParameterized.ProcessPacked (- CausalS.pack,- CausalS.packSmall,- CausalS.unpack,- raise,- amplify,- amplifyStereo,- CausalS.osciCore,- osciSimple,- CausalS.shapeModOsci,- delay1,- differentiate,- integrate,- CausalS.arrayElement,- ) where--import Synthesizer.LLVM.CausalParameterized.ProcessPrivate (T)-import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP-import qualified Synthesizer.LLVM.Causal.ProcessPacked as CausalS-import qualified Synthesizer.LLVM.Causal.Process as Causal-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.DSL.Parameter as Param--import qualified LLVM.Extra.ScalarOrVector as SoV-import qualified LLVM.Extra.Vector as Vector-import qualified LLVM.Extra.Marshal as Marshal-import qualified LLVM.Extra.Tuple as Tuple-import qualified LLVM.Extra.Arithmetic as A--import qualified LLVM.Core as LLVM-import LLVM.Core (CodeGenFunction, Value, IsSized, IsArithmetic, IsPrimitive)--import qualified Type.Data.Num.Decimal as TypeNum--import qualified Control.Category as Cat--import Data.Tuple.HT (swap)--import NumericPrelude.Numeric-import NumericPrelude.Base hiding (and, iterate, map, zip, zipWith)---raise ::- (IsArithmetic a, Marshal.C a, Tuple.ValueOf a ~ Value a, IsPrimitive a,- TypeNum.Positive 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 ::- (IsArithmetic a, Marshal.C a, Tuple.ValueOf a ~ Value a, IsPrimitive a,- TypeNum.Positive 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 ::- (IsArithmetic a, Marshal.C a, Tuple.ValueOf a ~ Value a, IsPrimitive a,- TypeNum.Positive 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)----- for backwards compatibility-osciSimple ::- (Causal.C process,- Vector.Real t, SoV.Fraction t, LLVM.IsFloating t, IsSized t,- TypeNum.Positive n) =>- (forall r. Serial.Value n t -> CodeGenFunction r y) ->- process (Serial.Value n t, Serial.Value n t) y-osciSimple = CausalS.osci---delay1 ::- (Serial.C va, n ~ Serial.Size va, al ~ Serial.Element va,- Marshal.C a, Tuple.ValueOf a ~ al) =>- Param.T p a -> T p va va-delay1 initial =- CausalP.loop initial $- Causal.map (fmap swap . uncurry Serial.shiftUp . swap)--differentiate ::- (Serial.C va, n ~ Serial.Size va, al ~ Serial.Element va,- A.Additive va,- Marshal.C a, Tuple.ValueOf a ~ al) =>- Param.T p a -> T p va va-differentiate initial =- Cat.id - delay1 initial--integrate ::- (Vector.Arithmetic a, Marshal.C a, Tuple.ValueOf a ~ Value a, IsPrimitive a,- TypeNum.Positive 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 ())
− src/Synthesizer/LLVM/CausalParameterized/ProcessPrivate.hs
@@ -1,518 +0,0 @@-{-# LANGUAGE NoImplicitPrelude #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE ExistentialQuantification #-}-{-# LANGUAGE Rank2Types #-}-module Synthesizer.LLVM.CausalParameterized.ProcessPrivate where--import qualified Synthesizer.LLVM.Parameterized.SignalPrivate as Sig-import qualified Synthesizer.LLVM.Causal.ProcessPrivate as CausalPriv-import qualified Synthesizer.LLVM.Causal.Process as Causal-import qualified Synthesizer.LLVM.ForeignPtr as ForeignPtr-import Synthesizer.LLVM.Causal.ProcessPrivate (loopNext)-import Synthesizer.LLVM.Causal.Process (mapProc, zipProcWith)-import Synthesizer.LLVM.Simple.SignalPrivate (proxyFromElement2)--import qualified Synthesizer.Causal.Class as CausalClass-import qualified Synthesizer.Causal.Utility as ArrowUtil--import qualified LLVM.DSL.Parameter as Param--import qualified LLVM.Extra.Tuple as Tuple-import qualified LLVM.Extra.Control as C-import qualified LLVM.Extra.Arithmetic as A-import qualified LLVM.Extra.MaybeContinuation as MaybeCont-import qualified LLVM.Extra.Marshal as Marshal-import qualified LLVM.Extra.Memory as Memory--import qualified LLVM.ExecutionEngine as EE-import qualified LLVM.Core as LLVM-import LLVM.Core (CodeGenFunction, Value, valueOf)--import Type.Data.Num.Decimal (d1)--import qualified Control.Monad.HT as M-import qualified Control.Arrow as Arr-import qualified Control.Category as Cat-import Control.Arrow (arr, (^<<), (<<<), (&&&))-import Control.Applicative (Applicative, pure, (<*>), (<$>))-import Data.Tuple.HT (mapSnd)--import Data.Word (Word)--import Foreign.ForeignPtr (ForeignPtr, touchForeignPtr, mallocForeignPtrBytes)--import qualified System.Unsafe as Unsafe--import qualified Number.Ratio as Ratio-import qualified Algebra.Field as Field-import qualified Algebra.Ring as Ring-import qualified Algebra.Additive as Additive--import NumericPrelude.Numeric-import NumericPrelude.Base hiding (and, iterate, map, zip, zipWith, take, takeWhile, init)--import qualified Prelude as P---data T p a b =- forall context state local ioContext parameters.- (Marshal.C parameters, Memory.C context, Memory.C state) =>- Cons- (forall r c.- (Tuple.Phi c) =>- context -> local ->- a -> state -> MaybeCont.T r c (b, state))- -- compute next value- (forall r.- CodeGenFunction r local)- -- allocate temporary variables before a loop- (forall r.- Tuple.ValueOf parameters ->- CodeGenFunction r (context, state))- -- initial state- (forall r.- context -> state ->- CodeGenFunction r ())- -- cleanup- (p -> IO (ioContext, parameters))- {- initialization from IO monad- This will be run within Unsafe.performIO,- so no observable In/Out actions please!- -}- (ioContext -> IO ())- -- finalization from IO monad, also run within Unsafe.performIO---type instance CausalClass.ProcessOf (Sig.T p) = T p--instance CausalClass.C (T p) where- type SignalOf (T p) = Sig.T p- toSignal = toSignal- fromSignal = fromSignal--instance Causal.C (T p) where- simple next start =- simple (\() -> next) (\() -> fmap ((,) ()) start) (pure ())-- alter f (Cons next0 alloca start0 stop0 create delete) =- case f (CausalPriv.Core (uncurry next0) return id) of- CausalPriv.Core next1 start1 stop1 ->- Cons- (curry next1) alloca- (Sig.withStart start0 start1)- (\c -> stop0 c . stop1)- create delete-- replicateControlled n = replicateControlled $ pure n---simple ::- (Marshal.C parameters, Memory.C context, Memory.C state) =>- (forall r c.- (Tuple.Phi c) =>- context -> a -> state -> MaybeCont.T r c (b, state)) ->- (forall r.- Tuple.ValueOf parameters ->- CodeGenFunction r (context, state)) ->- Param.T p parameters -> T p a b-simple f start param =- Param.withValue param $ \get value ->- Cons- (\context () -> f context)- (return ())- (start . value)- (const $ const $ return ())- (return . (,) () . get)- (const $ return ())---toSignal :: T p () a -> Sig.T p a-toSignal- (Cons next alloca start stop createIOContext deleteIOContext) = Sig.Cons- (\p l -> next p l ())- alloca- start stop- createIOContext deleteIOContext--fromSignal :: Sig.T p b -> T p a b-fromSignal- (Sig.Cons next alloca start stop createIOContext deleteIOContext) = Cons- (\p l _ -> next p l)- alloca- start stop- createIOContext deleteIOContext---mapAccum ::- (Marshal.C pnh, Tuple.ValueOf pnh ~ pnl,- Marshal.C psh, Tuple.ValueOf psh ~ psl,- Memory.C s) =>- (forall r. pnl -> a -> s -> CodeGenFunction r (b,s)) ->- (forall r. psl -> CodeGenFunction r s) ->- Param.T p pnh ->- Param.T p psh ->- T p a b-mapAccum next start selectParamN selectParamS =- simple- (\p a s -> MaybeCont.lift $ next p a s)- (\(n,s) -> fmap ((,) n) $ start s)- (selectParamN &&& selectParamS)---map ::- (Marshal.C ph, Tuple.ValueOf ph ~ pl) =>- (forall r. pl -> a -> CodeGenFunction r b) ->- Param.T p ph ->- T p a b-map f selectParamF =- mapAccum- (\p a s -> fmap (flip (,) s) $ f p a)- (const $ return ())- selectParamF- (return ())--mapSimple ::- (forall r. a -> CodeGenFunction r b) ->- T p a b-mapSimple f =- map (const f) (return ())--zipWith ::- (Marshal.C ph, Tuple.ValueOf ph ~ pl) =>- (forall r. pl -> a -> b -> CodeGenFunction r c) ->- Param.T p ph ->- T p (a,b) c-zipWith f =- map (uncurry . f)--zipWithSimple ::- (forall r. a -> b -> CodeGenFunction r c) ->- T p (a,b) c-zipWithSimple f =- mapSimple (uncurry f)---apply :: T p a b -> Sig.T p a -> Sig.T p b-apply = CausalClass.apply--feedFst :: Sig.T p a -> T p b (a,b)-feedFst = CausalClass.feedFst--feedSnd :: Sig.T p a -> T p b (b,a)-feedSnd = CausalClass.feedSnd---{--Very similar to 'apply',-since 'apply' can be considered being of type-@T p a b -> T p () a -> T p () b@.--}-compose :: T p a b -> T p b c -> T p a c-compose- (Cons nextA allocaA startA stopA createIOContextA deleteIOContextA)- (Cons nextB allocaB startB stopB createIOContextB deleteIOContextB) =- Cons- (composeNext MaybeCont.onFail stopA stopB nextA nextB)- (M.lift2 (,) allocaA allocaB)- (composeStart startA startB)- (composeStop stopA stopB)- (composeCreate createIOContextA createIOContextB)- (composeDelete deleteIOContextA deleteIOContextB)--composeNext ::- (Monad maybe) =>- (forall x. code () -> maybe x -> maybe x) ->- (contextA -> stateA -> code ()) ->- (contextB -> stateB -> code ()) ->- (contextA -> localA -> a -> stateA -> maybe (b, stateA)) ->- (contextB -> localB -> b -> stateB -> maybe (c, stateB)) ->- (contextA, contextB) ->- (localA, localB) ->- a ->- (stateA, stateB) ->- maybe (c, (stateA, stateB))-composeNext onFail stopA stopB nextA nextB- (paramA, paramB) (localA, localB) a (sa0,sb0) = do- (b,sa1) <- onFail (stopB paramB sb0) $ nextA paramA localA a sa0- (c,sb1) <- onFail (stopA paramA sa1) $ nextB paramB localB b sb0- return (c, (sa1,sb1))--composeStart ::- Monad m =>- (paramA -> m (contextA, stateA)) ->- (paramB -> m (contextB, stateB)) ->- (paramA, paramB) -> m ((contextA, contextB), (stateA, stateB))-composeStart = Sig.combineStart--composeStop ::- Monad m =>- (contextA -> stateA -> m ()) ->- (contextB -> stateB -> m ()) ->- (contextA, contextB) -> (stateA, stateB) -> m ()-composeStop = Sig.combineStop--composeCreate ::- Monad m =>- (p -> m (ioContextA, contextA)) ->- (p -> m (ioContextB, contextB)) ->- p -> m ((ioContextA, ioContextB), (contextA, contextB))-composeCreate = Sig.combineCreate--composeDelete ::- (Monad m) =>- (ca -> m ()) -> (cb -> m ()) -> (ca, cb) -> m ()-composeDelete = Sig.combineDelete---{- |-serial replication--But you may also use it for a parallel replication, see 'replicateParallel'.--}-replicateControlled ::- (Tuple.Undefined x, Tuple.Phi x) =>- Param.T p Int -> T p (c,x) x -> T p (c,x) x-replicateControlled- n (Cons next alloca start stop createIOContext deleteIOContext) =- case Param.wordInt n of- n32 -> Cons- (\(len, cs) ->- replicateControlledNext next stop (Param.valueTuple n32 len, cs))- (-- we re-use the temporary variable for all stages)- alloca)- (\(len, param) ->- replicateControlledStart start (Param.valueTuple n32 len, param))- (\(len, cs) ->- replicateControlledStop stop (Param.valueTuple n32 len, cs))- (\p ->- replicateControlledCreate $- M.replicate (Param.get n p) (createIOContext p))- (replicateControlledDelete deleteIOContext)--replicateControlledNext ::- (Memory.C context, Memory.C state,- contextState ~- LLVM.Struct (Memory.Struct context, (Memory.Struct state, ())),- Tuple.Phi z, Tuple.Phi a, Tuple.Undefined a) =>- (forall z0. (Tuple.Phi z0) =>- context -> local -> (ctrl, a) -> state ->- MaybeCont.T r z0 (a, state)) ->- (context -> state -> CodeGenFunction r ()) ->- (Value Word, Value (LLVM.Ptr contextState)) ->- local ->- (ctrl, a) ->- () ->- MaybeCont.T r z (a, ())-replicateControlledNext next stop (len, contextStates) local (c,a) () =- MaybeCont.fromMaybe $ fmap (\(_,ms) -> flip (,) () <$> ms) $- MaybeCont.arrayLoop len contextStates a $- \contextStatePtr a0 -> do- (context, s0) <- MaybeCont.lift $ Memory.load contextStatePtr- (a1,s1) <-- MaybeCont.onFail- (replicateControlledStopExcept- stop len contextStates contextStatePtr) $- next context local (c,a0) s0- MaybeCont.lift $- Memory.store s1 =<< LLVM.getElementPtr0 contextStatePtr (d1, ())- return a1--replicateControlledStopExcept ::- (Memory.C a, Memory.C b,- ab ~ LLVM.Struct (Memory.Struct a, (Memory.Struct b, ()))) =>- (a -> b -> CodeGenFunction r ()) ->- Value Word ->- Value (LLVM.Ptr ab) ->- Value (LLVM.Ptr ab) ->- CodeGenFunction r ()-replicateControlledStopExcept stop len contextStates contextStatePtr =- C.arrayLoop len contextStates () $ \ptr () -> do- b <- A.cmp LLVM.CmpNE ptr contextStatePtr- C.ifThen b () $ uncurry stop =<< Memory.load ptr--_replicateControlledNext ::- (Memory.C context, Memory.C state,- contextState ~- LLVM.Struct (Memory.Struct context, (Memory.Struct state, ())),- Tuple.Phi z, Tuple.Phi a, Tuple.Undefined a) =>- (forall z0. (Tuple.Phi z0) =>- context -> (ctrl, a) -> state ->- MaybeCont.T r z0 (a, state)) ->- (Value Word, Value (LLVM.Ptr contextState)) ->- (ctrl, a) ->- () ->- MaybeCont.T r z (a, ())-_replicateControlledNext next (len, contextStates) (c,a) () =- fmap (flip (,) ()) $ MaybeCont.fromBool $ fmap snd $- C.arrayLoopWithExit len contextStates (valueOf True, a) $- \contextStatePtr (_,a0) -> do- (context, s0) <- Memory.load contextStatePtr- (cont, (a1,s1)) <- MaybeCont.toBool $ next context (c,a0) s0- Memory.store s1 =<< LLVM.getElementPtr0 contextStatePtr (d1, ())- return (cont, (cont,a1))--replicateControlledStart ::- (Memory.C a, Memory.C b) =>- (a -> CodeGenFunction r b) ->- (Value Word, Value (LLVM.Ptr (Memory.Struct a))) ->- CodeGenFunction r ((Value Word, Value (LLVM.Ptr (Memory.Struct b))), ())-replicateControlledStart start (len, params) = do- contextStates <- LLVM.arrayMalloc len- C.arrayLoop2 len params contextStates () $ \paramPtr statePtr () ->- flip Memory.store statePtr =<< start =<< Memory.load paramPtr- return ((len, contextStates), ())--replicateControlledStop ::- (Memory.C a, Memory.C b,- ab ~ LLVM.Struct (Memory.Struct a, (Memory.Struct b, ()))) =>- (a -> b -> CodeGenFunction r ()) ->- (Value Word, Value (LLVM.Ptr ab)) ->- () ->- CodeGenFunction r ()-replicateControlledStop stop (len, contextStates) () = do- C.arrayLoop len contextStates () $ \contextStatePtr () ->- uncurry stop =<< Memory.load contextStatePtr- LLVM.free contextStates---replicateControlledCreate ::- (Monad m, Marshal.C b, Marshal.Struct b ~ struct) =>- m [(a, b)] ->- m (([a], ForeignPtr.MemoryPtr struct), (Word, LLVM.Ptr struct))-replicateControlledCreate createIOContexts = do- (ioContexts, params) <- M.lift unzip createIOContexts- let len = length params- let fptr = Unsafe.performIO $ do- fptr0 <-- mallocForeignPtrBytes $ EE.sizeOfArray (proxyFromElement2 fptr) len- ForeignPtr.with fptr0 $ flip EE.pokeList (fmap Marshal.pack params)- return fptr0- return ((ioContexts, fptr),- (fromIntegral len,- EE.castFromStoredPtr $ Unsafe.foreignPtrToPtr fptr))--replicateControlledDelete ::- (a -> IO ()) ->- ([a], ForeignPtr b) -> IO ()-replicateControlledDelete deleteIOContext (ioContexts, fptr) = do- mapM_ deleteIOContext ioContexts- touchForeignPtr fptr---instance Cat.Category (T p) where- id = mapSimple return- (.) = flip compose--instance Arr.Arrow (T p) where- arr f = mapSimple (return . f)- first = Causal.first---instance Functor (T p a) where- fmap = ArrowUtil.map--instance Applicative (T p a) where- pure = ArrowUtil.pure- (<*>) = ArrowUtil.apply---instance (A.Additive b) => Additive.C (T p a b) where- zero = pure A.zero- negate = mapProc A.neg- (+) = zipProcWith A.add- (-) = zipProcWith A.sub--instance (A.PseudoRing b, A.IntegerConstant b) => Ring.C (T p a b) where- one = pure A.one- fromInteger n = pure (A.fromInteger' n)- (*) = zipProcWith A.mul--instance (A.Field b, A.RationalConstant b) => Field.C (T p a b) where- fromRational' x = pure (A.fromRational' $ Ratio.toRational98 x)- (/) = zipProcWith A.fdiv---instance (A.PseudoRing b, A.Real b, A.IntegerConstant b) => P.Num (T p a b) where- fromInteger n = pure (A.fromInteger' n)- negate = mapProc A.neg- (+) = zipProcWith A.add- (-) = zipProcWith A.sub- (*) = zipProcWith A.mul- abs = mapProc A.abs- signum = mapProc A.signum--instance (A.Field b, A.Real b, A.RationalConstant b) => P.Fractional (T p a b) where- fromRational x = pure (A.fromRational' x)- (/) = zipProcWith A.fdiv---{- |-Not quite the loop of ArrowLoop-because we need a delay of one time step-and thus an initialization value.--For a real ArrowLoop.loop, that is a zero-delay loop,-we would formally need a MonadFix instance of CodeGenFunction.-But this will not become reality, since LLVM is not able to re-order code-in a way that allows to access a result before creating the input.--}-loop ::- (Marshal.C c, Tuple.ValueOf c ~ cl) =>- Param.T p c -> T p (a,cl) (b,cl) -> T p a b-loop initial (Cons next alloca start stop createIOContext deleteIOContext) =- Param.withValue initial $ \getInitial valueInitial -> Cons- (curry $ loopNext $ uncurry next)- alloca- (\(i,p) -> fmap (mapSnd ((,) (valueInitial i))) $ start p)- (loopStop stop)- (\p -> do- (ctx, param) <- createIOContext p- return (ctx, (getInitial p, param)))- deleteIOContext--loopStop :: (context -> state -> m) -> context -> (c, state) -> m-loopStop stop ctx (_c,s) = stop ctx s---takeWhile ::- (Marshal.C ph, Tuple.ValueOf ph ~ pl) =>- (forall r. pl -> a -> CodeGenFunction r (Value Bool)) ->- Param.T p ph ->- T p a a-takeWhile check selectParam = simple- (\p a () -> do- MaybeCont.guard =<< MaybeCont.lift (check p a)- return (a, ()))- (\p -> return (p, ()))- selectParam---take ::- Param.T p Int ->- T p a a-take len =- snd ^<<- Causal.takeWhile (A.cmp LLVM.CmpLT A.zero . fst) <<<- feedFst- (Sig.iterate (const A.dec) (return ())- (Param.wordInt $ max 0 ^<< len))---{- |-The first output value is the initial value.-Thus 'integrate' delays by one sample compared with 'integrateSync'.--}-integrate ::- (Marshal.C a, Tuple.ValueOf a ~ al, A.Additive al) =>- Param.T p a ->- T p al al-integrate =- flip loop (arr snd &&& zipWithSimple A.add)--integrateSync ::- (Marshal.C a, Tuple.ValueOf a ~ al, A.Additive al) =>- Param.T p a ->- T p al al-integrateSync =- flip loop ((\a -> (a,a)) ^<< zipWithSimple A.add)
− src/Synthesizer/LLVM/CausalParameterized/ProcessValue.hs
@@ -1,100 +0,0 @@-{-# LANGUAGE TypeFamilies #-}-{- |-This module provides functions similar to-"Synthesizer.LLVM.CausalParameterized.Process"-but expects functions that operate on 'Value.T'.-This way you can use common arithmetic operators-instead of LLVM assembly functions.--}-module Synthesizer.LLVM.CausalParameterized.ProcessValue (--- simple,- mapAccum, map, mapSimple, zipWith, zipWithSimple,- takeWhile,- ) where--import Synthesizer.LLVM.CausalParameterized.ProcessPrivate (T)-import qualified Synthesizer.LLVM.CausalParameterized.ProcessPrivate as CausalP-import qualified Synthesizer.LLVM.Causal.ProcessValue as CausalV-import qualified Synthesizer.LLVM.Simple.Value as Value--import qualified LLVM.DSL.Parameter as Param--import qualified LLVM.Extra.Tuple as Tuple-import qualified LLVM.Extra.Marshal as Marshal-import qualified LLVM.Extra.Memory as Memory--import qualified LLVM.Core as LLVM--import Prelude hiding (map, zipWith, takeWhile)---{--simple ::- (Storable startParamTuple,- Storable nextParamTuple,- Tuple.Value startParamTuple, Tuple.ValueOf startParamTuple ~ startParamValue,- Tuple.Value nextParamTuple, Tuple.ValueOf nextParamTuple ~ nextParamValue,- Memory.C startParamValue,- Memory.C nextParamValue,- Memory.C state) =>- (Value.T nextParamValue ->- Value.T a -> Value.T state -> Value.Maybe (Value.T b, Value.T state)) ->- (Value.T startParamValue -> Value.T state) ->- Param.T p nextParamTuple ->- Param.T p startParamTuple -> T p a b-simple f start =- CausalP.simple- (\p a s ->- Value.flattenMaybe $- next- (Value.constantValue p)- (Value.constantValue a)- (Value.constantValue s))- (Value.unlift1 start)--}--map ::- (Marshal.C ph, Tuple.ValueOf ph ~ pl) =>- (Value.T pl -> Value.T a -> Value.T b) ->- Param.T p ph ->- T p a b-map f = CausalP.map (Value.unlift2 f)--mapSimple ::- (Value.T a -> Value.T b) ->- T p a b-mapSimple = CausalV.map--zipWith ::- (Marshal.C ph, Tuple.ValueOf ph ~ pl) =>- (Value.T pl -> Value.T a -> Value.T b -> Value.T c) ->- Param.T p ph -> T p (a,b) c-zipWith f =- CausalP.zipWith (Value.unlift3 f)--zipWithSimple ::- (Value.T a -> Value.T b -> Value.T c) ->- T p (a,b) c-zipWithSimple = CausalV.zipWith--mapAccum ::- (Marshal.C pnh, Tuple.ValueOf pnh ~ pnl,- Marshal.C psh, Tuple.ValueOf psh ~ psl,- Memory.C s) =>- (Value.T pnl -> Value.T a -> Value.T s -> (Value.T b, Value.T s)) ->- (Value.T psl -> Value.T s) ->- Param.T p pnh ->- Param.T p psh ->- T p a b-mapAccum next start =- CausalP.mapAccum- (Value.unlift3 next)- (Value.unlift1 start)--takeWhile ::- (Marshal.C ph, Tuple.ValueOf ph ~ pl) =>- (Value.T pl -> Value.T a -> Value.T (LLVM.Value Bool)) ->- Param.T p ph ->- T p a a-takeWhile check =- CausalP.takeWhile (Value.unlift2 check)
− src/Synthesizer/LLVM/CausalParameterized/RingBuffer.hs
@@ -1,59 +0,0 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE TypeFamilies #-}-module Synthesizer.LLVM.CausalParameterized.RingBuffer (- T, track, trackConst,- index, oldest,- ) where--import Synthesizer.LLVM.RingBuffer--import qualified Synthesizer.LLVM.CausalParameterized.ProcessPrivate as CausalP-import qualified LLVM.DSL.Parameter as Param--import qualified LLVM.Extra.Marshal as Marshal-import qualified LLVM.Extra.Memory as Memory-import qualified LLVM.Extra.Tuple as Tuple---{- |-@track initial time@ tracks the last @time@ sample values-including the current one.-The values before the actual input data are filled with @initial@.-The values can be accessed using 'index' with indices-ranging from 0 to @time@.--The @time@ parameter must be non-negative.--The initial value is also needed for determining the ring buffer element type.--}-track ::- (Marshal.C a, Tuple.ValueOf a ~ al) =>- Param.T p a -> Param.T p Int -> CausalP.T p al (T al)-track initial time =- Param.withValue initial $ \getInitial valueInitial ->- Param.withValue (Param.wordInt time) $ \getTime valueTime ->- CausalP.Cons- (trackNext valueTime)- (return ())- (\(x, size) -> trackStart valueTime (valueInitial x, size))- trackStop- (trackCreate getInitial getTime)- trackDelete--{- |-Initialize with zero without the need of a Haskell zero value.--We cannot get rid of the type 'a' so easily,-because we need its Storable instance-for allocating the buffer on the Haskell side.--}-trackConst :: (Memory.C al) => al -> Param.T p Int -> CausalP.T p al (T al)-trackConst initial time =- Param.withValue (Param.wordInt time) $ \getTime valueTime ->- CausalP.Cons- (trackNext valueTime)- (return ())- (\size -> trackStart valueTime (initial, size))- trackStop- (trackConstCreate getTime)- trackDelete
− src/Synthesizer/LLVM/CausalParameterized/RingBufferForward.hs
@@ -1,295 +0,0 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE Rank2Types #-}-module Synthesizer.LLVM.CausalParameterized.RingBufferForward (- T, track, trackSkip, trackSkipHold,- index,- ) where--import qualified Synthesizer.LLVM.CausalParameterized.ProcessPrivate- as CausalPrivP-import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP-import qualified Synthesizer.LLVM.Parameterized.SignalPrivate as SigP-import Synthesizer.LLVM.CausalParameterized.Process (($<), ($*))-import Synthesizer.LLVM.RingBuffer (MemoryPtr)--import qualified LLVM.DSL.Parameter as Param--import qualified LLVM.Extra.MaybeContinuation as MaybeCont-import qualified LLVM.Extra.Maybe as Maybe-import qualified LLVM.Extra.Memory as Memory-import qualified LLVM.Extra.Control as C-import qualified LLVM.Extra.Arithmetic as A-import qualified LLVM.Extra.Tuple as Tuple--import qualified LLVM.Core as LLVM-import LLVM.Core (CodeGenFunction, Value)--import Control.Arrow ((<<<))-import Control.Applicative (pure)-import Data.Tuple.HT (mapSnd)--import Data.Word (Word)--import Prelude hiding (length)---{- |-This type is very similar to 'Synthesizer.LLVM.RingBuffer.T'-but differs in several details:--* It stores values in time order,- whereas 'Synthesizer.LLVM.RingBuffer.T' stores in opposite order.--* Since it stores future values it is not causal- and can only track signal generators.--* There is no need for an initial value.--* It stores one value less than 'Synthesizer.LLVM.RingBuffer.T'- since it is meant to provide infixes of the signal- rather than providing the basis for a delay line.--Those differences in detail would not justify a new type,-you could achieve the same by a combination of-'Synthesizer.LLVM.RingBuffer.track'-and-'Synthesizer.LLVM.CausalParameterized.Process.skip'.-The fundamental problem of this combination is-that it requires to keep the ring buffer alive-longer than the providing signal exists.-This is not possible with the current design.-That's why we provide the combination of @track@ and @skip@-in a way that does not suffer from that problem.-This functionality is critical for-'Synthesizer.LLVM.CausalParameterized.Helix.dynamic'.--}-data T a =- Cons {- buffer :: Value (MemoryPtr a),- length :: Value Word,- current :: Value Word- }--{- |-This function does not check for range violations.-If the ring buffer was generated by @track time@,-then the minimum index is zero and the maximum index is @time-1@.-Index zero refers to the current sample-and index @time-1@ refers to the one that is farthermost in the future.--}-index :: (Memory.C a) => Value Word -> T a -> CodeGenFunction r a-index i rb = do- k <- flip A.irem (length rb) =<< A.add (current rb) i- Memory.load =<< LLVM.getElementPtr (buffer rb) (k, ())---{- |-@track time signal@ bundles @time@ successive values of @signal@.-The values can be accessed using 'index' with indices-ranging from 0 to @time-1@.--The @time@ parameter must be non-negative.--}-track :: (Memory.C a) => Param.T p Int -> SigP.T p a -> SigP.T p (T a)-track time input = trackSkip time input $* 1--{- |-@trackSkip time input $* skips@-is like-@Process.skip (track time input) $* skips@-but this composition would require a @Memory@ constraint for 'T'-which we cannot provide.--}-trackSkip ::- (Memory.C a) =>- Param.T p Int -> SigP.T p a -> CausalP.T p (Value Word) (T a)-trackSkip time (SigP.Cons next alloca start stop create delete) =- Param.withValue (Param.wordInt time) $ \getTime valueTime ->- CausalPrivP.Cons- (trackNext next valueTime)- alloca- (trackStart start valueTime)- (trackStop stop)- (trackCreate create getTime)- (trackDelete delete)--{- |-Like @trackSkip@ but repeats the last buffer content-when the end of the input signal is reached.-The returned 'Bool' flag is 'True' if a skip could be performed completely-and it is 'False' if the skip exceeds the end of the input.-That is, once a 'False' is returned all following values are tagged with 'False'.-The returned 'Word' value is the number of actually skipped values.-This lags one step behind the input of skip values.-The number of an actual number of skips-is at most the number of requested skips.-If the flag is 'False', then the number of actual skips is zero.-The converse does not apply.--If the input signal is too short, the output is undefined.-(Before the available data the buffer will be filled with arbitrary values.)-We could fill the buffer with zeros,-but this would require an Arithmetic constraint-and the generated signal would not be very meaningful.-We could also return an empty signal if the input is too short.-However this would require a permanent check.--}-trackSkipHold, trackSkipHold_ ::- (Memory.C a) =>- Param.T p Int -> SigP.T p a ->- CausalP.T p (Value Word) ((Value Bool, Value Word), T a)-trackSkipHold time xs =- (CausalP.zipWithSimple- (\b ((c,x), buf) -> do- y <- C.select b x A.zero- return ((c, y), buf))- $< (CausalP.delay1 (pure False) $* SigP.constant (pure True)))-{-- (CausalPV.zipWithSimple (\b ((c,x), buf) -> ((c, b ?? (x,0)), buf))- $< (CausalP.delay1 (pure False) $* SigP.constant (pure True)))--}- <<<- trackSkipHold_ time xs--trackSkipHold_ time (SigP.Cons next alloca start stop create delete) =- (Param.withValue (Param.wordInt time) $ \getTime valueTime ->- CausalPrivP.Cons- (trackNextHold next valueTime)- alloca- (trackStartHold start valueTime)- (trackStopHold stop)- (trackCreate create getTime)- (trackDelete delete))---trackNext ::- (Memory.C al, Tuple.Phi z,- Tuple.Phi state, Tuple.Undefined state) =>- (forall z0. (Tuple.Phi z0) =>- context -> local -> state -> MaybeCont.T r z0 (al, state)) ->- (tl -> Value Word) ->- (context, (tl, Value (MemoryPtr al))) -> local ->- Value Word ->- (Value Word, (state, Value Word)) ->- MaybeCont.T r z (T al, (Value Word, (state, Value Word)))-trackNext next valueTime (context, (size,ptr)) local n1 (n0, statePos) = do- let size0 = valueTime size- (state3, pos3) <-- MaybeCont.fromMaybe $ fmap snd $- MaybeCont.fixedLengthLoop n0 statePos $ \(state0, pos0) -> do- (a, state1) <- next context local state0- MaybeCont.lift $- fmap ((,) state1) $ storeNext (size0,ptr) a pos0- return (Cons ptr size0 pos3, (n1, (state3, pos3)))--trackStart ::- (LLVM.IsSized am, Tuple.Phi state, Tuple.Undefined state) =>- (param -> CodeGenFunction r (context, state)) ->- (tl -> Value Word) ->- (param, tl) ->- CodeGenFunction r- ((context, (tl, Value (LLVM.Ptr am))),- (Value Word, (state, Value Word)))-trackStart start valueTime (param, size) = do- (context, state) <- start param- let size0 = valueTime size- ptr <- LLVM.arrayMalloc size0- return ((context, (size,ptr)), (size0, (state, A.zero)))--trackStop ::- (LLVM.IsType am) =>- (context -> state -> CodeGenFunction r ()) ->- (context, (tl, Value (LLVM.Ptr am))) ->- (Value Word, (state, Value Word)) ->- CodeGenFunction r ()-trackStop stop (context, (_size,ptr)) (_n, (state, _remain)) = do- LLVM.free ptr- stop context state---trackNextHold ::- (Memory.C al, Tuple.Phi z,- Tuple.Phi state, Tuple.Undefined state) =>- (forall z0. (Tuple.Phi z0) =>- context -> local -> state -> MaybeCont.T r z0 (al, state)) ->- (tl -> Value Word) ->- (context, (tl, Value (MemoryPtr al))) -> local ->- Value Word ->- (Value Word, (Maybe.T state, Value Word)) ->- MaybeCont.T r z- (((Value Bool, Value Word), T al),- (Value Word, (Maybe.T state, Value Word)))-trackNextHold- next valueTime (context, (size,ptr)) local nNext (n0, (mstate0, pos0)) =- MaybeCont.lift $ do- let size0 = valueTime size- (n3, (pos3, state3)) <-- Maybe.run mstate0- (return (n0, (pos0, mstate0)))- (\state0 ->- Maybe.loopWithExit (n0, (state0, pos0))- (\(n1, (state1, pos1)) -> do- cont <- A.cmp LLVM.CmpGT n1 A.zero- fmap (mapSnd ((,) n1 . (,) pos1)) $- C.ifThen cont- (Maybe.nothing, Maybe.just state1)- (do aState <-- MaybeCont.toMaybe $ next context local state1- return (aState, fmap snd aState)))- (\((a,state), (n1, (pos1, _mstate))) -> do- pos2 <- storeNext (size0,ptr) a pos1- n2 <- A.dec n1- return (n2, (state, pos2))))- skipped <- A.sub n0 n3- return (((Maybe.isJust state3, skipped), Cons ptr size0 pos3),- (nNext, (state3, pos3)))--storeNext ::- (Memory.C al) =>- (Value Word, Value (MemoryPtr al)) ->- al -> Value Word -> CodeGenFunction r (Value Word)-storeNext (size0,ptr) a pos0 = do- Memory.store a =<< LLVM.getElementPtr ptr (pos0, ())- pos1 <- A.inc pos0- cont <- A.cmp LLVM.CmpLT pos1 size0- C.select cont pos1 A.zero---trackStartHold ::- (LLVM.IsSized am,- Tuple.Phi state, Tuple.Undefined state) =>- (param -> CodeGenFunction r (context, state)) ->- (tl -> Value Word) ->- (param, tl) ->- CodeGenFunction r- ((context, (tl, Value (LLVM.Ptr am))),- (Value Word, (Maybe.T state, Value Word)))-trackStartHold start valueTime (param, size) = do- (context, state) <- start param- let size0 = valueTime size- ptr <- LLVM.arrayMalloc size0- return ((context, (size,ptr)), (size0, (Maybe.just state, A.zero)))--trackStopHold ::- (LLVM.IsType am) =>- (context -> state -> CodeGenFunction r ()) ->- (context, (tl, Value (LLVM.Ptr am))) ->- (Value Word, (Maybe.T state, Value Word)) ->- CodeGenFunction r ()-trackStopHold stop (context, (_size,ptr)) (_n, (state, _remain)) = do- LLVM.free ptr- Maybe.for state $ stop context---trackCreate ::- (p -> IO (ioContext, param)) ->- (p -> t) ->- p ->- IO (ioContext, (param, t))-trackCreate create getTime p = do- (context, param) <- create p- return (context, (param, getTime p))--trackDelete :: (ioContext -> IO ()) -> ioContext -> IO ()-trackDelete = id
src/Synthesizer/LLVM/Complex.hs view
@@ -3,25 +3,28 @@ module Synthesizer.LLVM.Complex ( Complex.T(Complex.real, Complex.imag), Struct,- (Complex.+:),+ (+:), Complex.cis, Complex.scale, constOf, unfold, ) where -import qualified Synthesizer.LLVM.Simple.Value as Value+import qualified Synthesizer.LLVM.Value as Value +import qualified LLVM.Extra.Multi.Value.Marshal as Marshal+import qualified LLVM.Extra.Multi.Value as MultiValue import qualified LLVM.Extra.Memory as Memory import qualified LLVM.Extra.Tuple as Tuple import qualified LLVM.Core as LLVM import LLVM.Core (Value, ConstValue, IsConst) -import qualified Type.Data.Num.Decimal as TypeNum+import qualified Type.Data.Num.Decimal as TypeNum import Control.Applicative (liftA2) import qualified Number.Complex as Complex+import Number.Complex ((+:)) type Struct a = LLVM.Struct (a, (a, ()))@@ -38,16 +41,16 @@ Value (Struct a) -> Complex.T (Value.T (Value a)) unfold x = Value.lift0 (LLVM.extractvalue x TypeNum.d0)- Complex.+:+ +: Value.lift0 (LLVM.extractvalue x TypeNum.d1) instance (Tuple.Undefined a) => Tuple.Undefined (Complex.T a) where- undef = (Complex.+:) Tuple.undef Tuple.undef+ undef = Tuple.undef +: Tuple.undef instance (Tuple.Phi a) => Tuple.Phi (Complex.T a) where phi bb v =- liftA2 (Complex.+:)+ liftA2 (+:) (Tuple.phi bb (Complex.real v)) (Tuple.phi bb (Complex.imag v)) addPhi bb x y = do@@ -59,7 +62,7 @@ (Memory.C l) => Memory.Record r (Struct (Memory.Struct l)) (Complex.T l) memory =- liftA2 (Complex.+:)+ liftA2 (+:) (Memory.element Complex.real TypeNum.d0) (Memory.element Complex.imag TypeNum.d1) @@ -69,3 +72,36 @@ store = Memory.storeRecord memory decompose = Memory.decomposeRecord memory compose = Memory.composeRecord memory++++instance (MultiValue.C a) => MultiValue.C (Complex.T a) where+ type Repr (Complex.T a) = Complex.T (MultiValue.Repr a)+ cons x =+ consMV+ (MultiValue.cons $ Complex.real x)+ (MultiValue.cons $ Complex.imag x)+ undef = consMV MultiValue.undef MultiValue.undef+ zero = consMV MultiValue.zero MultiValue.zero+ phi bb a =+ case deconsMV a of+ (a0,a1) -> liftA2 consMV (MultiValue.phi bb a0) (MultiValue.phi bb a1)+ addPhi bb a b =+ case (deconsMV a, deconsMV b) of+ ((a0,a1), (b0,b1)) ->+ MultiValue.addPhi bb a0 b0 >> MultiValue.addPhi bb a1 b1++consMV :: MultiValue.T a -> MultiValue.T a -> MultiValue.T (Complex.T a)+consMV (MultiValue.Cons a) (MultiValue.Cons b) = MultiValue.Cons (a+:b)++deconsMV :: MultiValue.T (Complex.T a) -> (MultiValue.T a, MultiValue.T a)+deconsMV (MultiValue.Cons x) =+ (MultiValue.Cons $ Complex.real x, MultiValue.Cons $ Complex.imag x)+++instance (Marshal.C a) => Marshal.C (Complex.T a) where+ pack x =+ LLVM.consStruct+ (Marshal.pack $ Complex.real x)+ (Marshal.pack $ Complex.imag x)+ unpack = LLVM.uncurryStruct $ \a b -> Marshal.unpack a +: Marshal.unpack b
src/Synthesizer/LLVM/ConstantPiece.hs view
@@ -10,24 +10,15 @@ Struct, parameterMemory, flatten,- piecewiseConstant,- lazySize,+ causalMap, ) where -import qualified Synthesizer.LLVM.Parameterized.SignalPrivate as SigP-import qualified Synthesizer.LLVM.Simple.SignalPrivate as Sig--import qualified Synthesizer.LLVM.Storable.LazySizeIterator as SizeIt-import qualified Data.StorableVector.Lazy.Pattern as SVP--import qualified Synthesizer.LLVM.EventIterator as EventIt-import qualified Data.EventList.Relative.BodyTime as EventList-import qualified Numeric.NonNegative.Wrapper as NonNeg+import qualified Synthesizer.LLVM.Causal.Private as Causal+import qualified Synthesizer.LLVM.Generator.Private as Sig -import qualified LLVM.DSL.Parameter as Param+import qualified LLVM.DSL.Expression as Expr import qualified LLVM.Extra.MaybeContinuation as Maybe-import qualified LLVM.Extra.Marshal as Marshal import qualified LLVM.Extra.Memory as Memory import qualified LLVM.Extra.Tuple as Tuple import qualified LLVM.Extra.Arithmetic as A@@ -38,9 +29,10 @@ import Type.Data.Num.Decimal (d0, d1) +import Data.Tuple.HT (mapSnd) import Data.Word (Word) -import Control.Applicative (liftA2)+import Control.Applicative (liftA2, (<$>)) import NumericPrelude.Numeric () import NumericPrelude.Base@@ -48,6 +40,9 @@ data T a = Cons (Value Word) a +instance Functor T where+ fmap f (Cons len y) = Cons len (f y)+ instance (Tuple.Phi a) => Tuple.Phi (T a) where phi bb (Cons len y) = liftA2 Cons (Tuple.phi bb len) (Tuple.phi bb y)@@ -78,69 +73,24 @@ compose = Memory.composeRecord parameterMemory -flatten ::- (Sig.C signal, Memory.C value) =>- signal (T value) ->- signal value-flatten = Sig.alter (\(Sig.Core next start stop) ->- Sig.Core- (\context state0 -> do+causalMap ::+ (Expr.Aggregate a am, Expr.Aggregate b bm) =>+ (a -> b) -> Causal.T (T am) (T bm)+causalMap f = Causal.map (\(Cons len y) -> Cons len <$> Expr.unliftM1 f y)+++flatten :: (Memory.C a) => Sig.T (T a) -> Sig.T a+flatten (Sig.Cons next start stop) =+ Sig.Cons+ (\global local state0 -> do ~(Cons length1 y1, s1) <- Maybe.fromBool $ whileLoop (valueOf True, state0) (\(cont, (Cons len _y, _s)) -> LLVM.and cont =<< A.cmp LLVM.CmpEQ len A.zero) (\(_cont, (Cons _len _y, s)) ->- Maybe.toBool $ next context s)+ Maybe.toBool $ next global local s) length2 <- Maybe.lift (A.dec length1) return (y1, (Cons length2 y1, s1)))- (fmap ((,) (Cons A.zero Tuple.undef)) . start)- (stop . snd))---piecewiseConstant ::- (Marshal.C a, Tuple.ValueOf a ~ value, Marshal.Struct a ~ struct) =>- Param.T p (EventList.T NonNeg.Int a) ->- SigP.T p (T value)-piecewiseConstant evs = SigP.Cons- (\stable yPtr () -> do- len <- Maybe.lift $ do- nextFn <-- LLVM.staticNamedFunction- "ConstantPiece.piecewiseConstant.nextChunk"- EventIt.nextCallBack- LLVM.call nextFn stable yPtr- Maybe.guard =<<- Maybe.lift (A.cmp LLVM.CmpNE len A.zero)- y <- Maybe.lift $ Memory.load yPtr- return (Cons len y, ()))- LLVM.alloca- return- (const $ const $ return ())- (\p -> do- stable <- EventIt.new (Param.get evs p)- return (stable, (stable, ())))- EventIt.dispose---lazySize ::- Param.T p SVP.LazySize ->- SigP.T p (T ())-lazySize size = SigP.Cons- (\stable () () -> do- len <- Maybe.lift $ do- nextFn <-- LLVM.staticNamedFunction- "ConstantPiece.lazySize.nextChunk"- SizeIt.nextCallBack- LLVM.call nextFn stable- Maybe.guard =<<- Maybe.lift (A.cmp LLVM.CmpNE len A.zero)- return (Cons len (), ()))- (return ())- return- (const $ const $ return ())- (\p -> do- stable <- SizeIt.new (Param.get size p)- return (stable, (stable, ())))- SizeIt.dispose+ (mapSnd ((,) (Cons A.zero Tuple.undef)) <$> start)+ stop
src/Synthesizer/LLVM/EventIterator.hs view
@@ -6,7 +6,7 @@ import qualified Data.EventList.Relative.BodyTime as EventList import qualified Numeric.NonNegative.Wrapper as NonNeg -import qualified LLVM.Extra.Marshal as Marshal+import qualified LLVM.Extra.Multi.Value.Marshal as Marshal import qualified LLVM.Core as LLVM import Foreign.StablePtr@@ -28,10 +28,10 @@ type MarshalPtr a = LLVM.Ptr (Marshal.Struct a) -foreign import ccall "&nextConstant"+foreign import ccall "&nextConstantExp" nextCallBack :: FunPtr (StablePtr (T a) -> MarshalPtr a -> IO Word) -foreign export ccall "nextConstant"+foreign export ccall "nextConstantExp" next :: StablePtr (T a) -> MarshalPtr a -> IO Word
src/Synthesizer/LLVM/Filter/Allpass.hs view
@@ -8,30 +8,28 @@ {-# LANGUAGE DeriveTraversable #-} {-# OPTIONS_GHC -fno-warn-orphans #-} module Synthesizer.LLVM.Filter.Allpass (- Parameter, parameter,- CascadeParameter, flangerParameter, flangerParameterPlain,+ Parameter, Allpass.parameter,+ CascadeParameter(CascadeParameter), flangerParameter,+ cascadeParameterMultiValue, cascadeParameterUnMultiValue, causal, cascade, phaser, cascadePipeline, phaserPipeline, causalPacked, cascadePacked, phaserPacked,-- causalP, cascadeP, phaserP,- causalPackedP, cascadePackedP, phaserPackedP, ) where import Synthesizer.Plain.Filter.Recursive.Allpass (Parameter(Parameter)) import qualified Synthesizer.Plain.Filter.Recursive.Allpass as Allpass import qualified Synthesizer.Plain.Filter.Recursive.FirstOrder as Filt1 -import qualified Synthesizer.Plain.Modifier as Modifier import qualified Synthesizer.LLVM.Filter.FirstOrder as Filt1L -import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP-import qualified Synthesizer.LLVM.CausalParameterized.Functional as F-import qualified Synthesizer.LLVM.Causal.ProcessValue as CausalV+import qualified Synthesizer.LLVM.Causal.Private as CausalPriv import qualified Synthesizer.LLVM.Causal.Process as Causal-import qualified Synthesizer.LLVM.Frame.SerialVector as Serial-import qualified Synthesizer.LLVM.Simple.Value as Value+import qualified Synthesizer.LLVM.Causal.Functional as F+import qualified Synthesizer.LLVM.Frame.SerialVector.Class as Serial +import qualified LLVM.DSL.Expression as Expr++import qualified LLVM.Extra.Multi.Value.Marshal as MarshalMV import qualified LLVM.Extra.Multi.Vector as MultiVector import qualified LLVM.Extra.Multi.Value as MultiValue import qualified LLVM.Extra.Vector as Vector@@ -41,8 +39,6 @@ import qualified LLVM.Extra.Memory as Memory import qualified LLVM.Extra.Tuple as Tuple import qualified LLVM.Extra.Arithmetic as A-import qualified LLVM.Core as LLVM-import LLVM.Core (CodeGenFunction) import qualified Type.Data.Num.Decimal as TypeNum import Type.Base.Proxy (Proxy(Proxy))@@ -55,9 +51,10 @@ import qualified Data.Traversable as Trav import qualified Data.Foldable as Fold-import Data.Tuple.HT (mapPair)+import Data.Tuple.HT (mapFst) import qualified Algebra.Transcendental as Trans+import qualified Algebra.Module as Module import NumericPrelude.Numeric import NumericPrelude.Base@@ -73,6 +70,14 @@ instance Tuple.Zero a => Tuple.Zero (Parameter a) where zero = Tuple.zeroPointed +instance+ (Expr.Aggregate e mv) =>+ Expr.Aggregate (Parameter e) (Parameter mv) where+ type MultiValuesOf (Parameter e) = Parameter (Expr.MultiValuesOf e)+ type ExpressionsOf (Parameter mv) = Parameter (Expr.ExpressionsOf mv)+ bundle = Trav.traverse Expr.bundle+ dissect = fmap Expr.dissect+ instance (Memory.C a) => Memory.C (Parameter a) where type Struct (Parameter a) = Memory.Struct a load = Memory.loadNewtype Parameter@@ -84,19 +89,15 @@ pack (Parameter k) = Marshal.pack k unpack = Parameter . Marshal.unpack +instance (MarshalMV.C a) => MarshalMV.C (Parameter a) where+ pack (Parameter k) = MarshalMV.pack k+ unpack = Parameter . MarshalMV.unpack+ instance (Storable.C a) => Storable.C (Parameter a) where load = Storable.loadNewtype Parameter Parameter store = Storable.storeNewtype Parameter (\(Parameter k) -> k) -{--instance LLVM.ValueTuple a => LLVM.ValueTuple (Parameter a) where- buildTuple f = Class.buildTupleTraversable (LLVM.buildTuple f)--instance LLVM.IsTuple a => LLVM.IsTuple (Parameter a) where- tupleDesc = Class.tupleDescFoldable--}- instance (Tuple.Value a) => Tuple.Value (Parameter a) where type ValueOf (Parameter a) = Parameter (Tuple.ValueOf a) valueOf = Tuple.valueOfFunctor@@ -106,6 +107,7 @@ vectorValueOf = fmap Tuple.vectorValueOf . Trav.sequenceA instance (MultiValue.C a) => MultiValue.C (Allpass.Parameter a) where+ type Repr (Parameter a) = Parameter (MultiValue.Repr a) cons = paramFromPlainValue . MultiValue.cons . Allpass.getParameter undef = paramFromPlainValue MultiValue.undef@@ -121,6 +123,7 @@ (plainFromParamValue b) instance (MultiVector.C a) => MultiVector.C (Allpass.Parameter a) where+ type Repr n (Parameter a) = Parameter (MultiVector.Repr n a) cons = paramFromPlainVector . MultiVector.cons . fmap Allpass.getParameter undef = paramFromPlainVector MultiVector.undef zero = paramFromPlainVector MultiVector.zero@@ -171,12 +174,6 @@ MultiValue.lift1 Allpass.getParameter -instance (Value.Flatten a) => Value.Flatten (Parameter a) where- type Registers (Parameter a) = Parameter (Value.Registers a)- flattenCode = Value.flattenCodeTraversable- unfoldCode = Value.unfoldCodeTraversable-- instance (Vector.Simple v) => Vector.Simple (Parameter v) where type Element (Parameter v) = Parameter (Vector.Element v) type Size (Parameter v) = Vector.Size v@@ -191,12 +188,6 @@ makeArgs = id -parameter ::- (A.Transcendental a, A.RationalConstant a) =>- a -> a -> CodeGenFunction r (Parameter a)-parameter = Value.unlift2 Allpass.parameter-- newtype CascadeParameter n a = CascadeParameter (Allpass.Parameter a) deriving@@ -219,19 +210,15 @@ pack (CascadeParameter k) = Marshal.pack k unpack = CascadeParameter . Marshal.unpack +instance (MarshalMV.C a) => MarshalMV.C (CascadeParameter n a) where+ pack (CascadeParameter k) = MarshalMV.pack k+ unpack = CascadeParameter . MarshalMV.unpack+ instance (Storable.C a) => Storable.C (CascadeParameter n a) where load = Storable.loadNewtype CascadeParameter id store = Storable.storeNewtype CascadeParameter id -{--instance LLVM.ValueTuple a => LLVM.ValueTuple (CascadeParameter n a) where- buildTuple f = Class.buildTupleTraversable (LLVM.buildTuple f)--instance LLVM.IsTuple a => LLVM.IsTuple (CascadeParameter n a) where- tupleDesc = Class.tupleDescFoldable--}- instance (Tuple.Value a) => Tuple.Value (CascadeParameter n a) where type ValueOf (CascadeParameter n a) = Parameter (Tuple.ValueOf a) valueOf (CascadeParameter a) = Tuple.valueOf a@@ -245,6 +232,7 @@ fmap Tuple.vectorValueOf . Trav.traverse (\(CascadeParameter k) -> k) instance (MultiValue.C a) => MultiValue.C (CascadeParameter n a) where+ type Repr (CascadeParameter n a) = Parameter (MultiValue.Repr a) cons (CascadeParameter a) = cascadeFromParamValue $ MultiValue.cons a undef = cascadeFromParamValue MultiValue.undef@@ -259,7 +247,8 @@ (paramFromCascadeValue a) (paramFromCascadeValue b) -instance (MultiVector.C a) => MultiVector.C (CascadeParameter n a) where+instance (MultiVector.C a) => MultiVector.C (CascadeParameter m a) where+ type Repr n (CascadeParameter m a) = Parameter (MultiVector.Repr n a) cons = cascadeFromParamVector . MultiVector.cons . fmap (\(CascadeParameter a) -> a)@@ -308,12 +297,7 @@ MultiValue.T (Allpass.Parameter a) paramFromCascadeValue = MultiValue.lift1 id -instance (Value.Flatten a) => Value.Flatten (CascadeParameter n a) where- type Registers (CascadeParameter n a) = CascadeParameter n (Value.Registers a)- flattenCode = Value.flattenCodeTraversable- unfoldCode = Value.unfoldCodeTraversable - instance (Vector.Simple v) => Vector.Simple (CascadeParameter n v) where type Element (CascadeParameter n v) = CascadeParameter n (Vector.Element v) type Size (CascadeParameter n v) = Vector.Size v@@ -328,76 +312,64 @@ makeArgs = id -flangerParameter ::- (A.Transcendental a, A.RationalConstant a, TypeNum.Natural n) =>- Proxy n -> a ->- CodeGenFunction r (CascadeParameter n a)-flangerParameter order =- Value.unlift1 (flangerParameterPlain order)+instance+ (Expr.Aggregate e mv, n ~ m) =>+ Expr.Aggregate (CascadeParameter n e) (CascadeParameter m mv) where+ type MultiValuesOf (CascadeParameter n e) =+ CascadeParameter n (Expr.MultiValuesOf e)+ type ExpressionsOf (CascadeParameter m mv) =+ CascadeParameter m (Expr.ExpressionsOf mv)+ bundle = Trav.traverse Expr.bundle+ dissect = fmap Expr.dissect -flangerParameterPlain ::++flangerParameter :: (Trans.C a, TypeNum.Natural n) => Proxy n -> a -> CascadeParameter n a-flangerParameterPlain order freq =+flangerParameter order freq = CascadeParameter $ Allpass.flangerParameter (TypeNum.integralFromProxy order) freq -modifier ::- (a ~ A.Scalar v, A.PseudoModule v, A.IntegerConstant a) =>- Modifier.Simple- -- (Allpass.State (Value.T v))- (Value.T v, Value.T v)- (Parameter (Value.T a))- (Value.T v) (Value.T v)-modifier =- Allpass.firstOrderModifier--{--For Allpass cascade you may use the 'Causal.pipeline' function.--} causal ::- (Causal.C process,- A.IntegerConstant a, a ~ A.Scalar v, A.PseudoModule v, Memory.C v) =>- process (Parameter a, v) v-causal =- Causal.fromModifier modifier+ (Module.C ae ve, Expr.Aggregate ae a, Expr.Aggregate ve v, Memory.C v) =>+ Causal.T (Parameter a, v) v+causal = Causal.fromModifier Allpass.firstOrderModifier replicateStage ::- (Causal.C process,- TypeNum.Natural n, Tuple.Phi b, Tuple.Undefined b) =>+ (TypeNum.Natural n) =>+ (Tuple.Phi a, Tuple.Undefined a) =>+ (Tuple.Phi b, Tuple.Undefined b) => Proxy n ->- process (Parameter a, b) b ->- process (CascadeParameter n a, b) b+ Causal.T (Parameter a, b) b ->+ Causal.T (CascadeParameter n a, b) b replicateStage order stg = Causal.replicateControlled (TypeNum.integralFromProxy order) (stg <<< first (arr (\(CascadeParameter p) -> p))) cascade ::- (Causal.C process,- A.RationalConstant a, a ~ A.Scalar v, A.PseudoModule v, Memory.C v,- TypeNum.Natural n) =>- process (CascadeParameter n a, v) v-cascade =- replicateStage Proxy causal+ (TypeNum.Natural n) =>+ (Module.C ae ve, Expr.Aggregate ae a, Expr.Aggregate ve v, Memory.C v) =>+ (Tuple.Phi a, Tuple.Undefined a) =>+ (Tuple.Phi v, Tuple.Undefined v) =>+ Causal.T (CascadeParameter n a, v) v+cascade = replicateStage Proxy causal halfVector ::- (Causal.C process, A.RationalConstant a, a ~ A.Scalar v, A.PseudoModule v) =>- process v v-halfVector = CausalV.map (Value.fromRational' 0.5 *>)+ (A.RationalConstant a, a ~ A.Scalar v, A.PseudoModule v) =>+ Causal.T v v+halfVector = CausalPriv.map (A.scale $ A.fromRational' 0.5) phaser ::- (Causal.C process,- A.RationalConstant a, A.RationalConstant v,- a ~ A.Scalar v, A.PseudoModule v, Memory.C v,- TypeNum.Natural n) =>- process (CascadeParameter n a, v) v-phaser =- Causal.mix <<<- cascade &&& arr snd <<<- second halfVector+ (TypeNum.Natural n) =>+ (Module.C ae ve, Expr.Aggregate ae a, Expr.Aggregate ve v, Memory.C v) =>+ (Tuple.Phi a, Tuple.Undefined a) =>+ (Tuple.Phi v, Tuple.Undefined v) =>+ (A.RationalConstant a, a ~ A.Scalar v, A.PseudoModule v) =>+ Causal.T (CascadeParameter n a, v) v+phaser = (cascade + arr snd) <<< second halfVector paramFromCascadeParam ::@@ -411,12 +383,11 @@ but LLVM-2.6 does not yet do it. -} stage ::- (Causal.C process,- TypeNum.Positive n, MultiVector.C a,+ (TypeNum.Positive n, MultiVector.C a, MultiVector.T n (CascadeParameter n a, a) ~ v, MultiValue.PseudoRing a, MultiValue.IntegerConstant a,- Marshal.C a) =>- Proxy n -> process v v+ MarshalMV.C a) =>+ Proxy n -> Causal.T v v stage _ = Causal.vectorize $ uncurry MultiValue.zip@@ -432,8 +403,8 @@ MultiValue.unzip withSize ::- (Proxy n -> process (MultiValue.T (CascadeParameter n a), b) c) ->- process (MultiValue.T (CascadeParameter n a), b) c+ (Proxy n -> Causal.T (mv (CascadeParameter n a), b) c) ->+ Causal.T (mv (CascadeParameter n a), b) c withSize f = f Proxy {- |@@ -443,12 +414,11 @@ and we get a delay by the number of pipeline stages. -} cascadePipeline ::- (Causal.C process,- TypeNum.Positive n, MultiVector.C a,+ (TypeNum.Positive n, MultiVector.C a, Tuple.ValueOf a ~ ar, MultiValue.PseudoRing a, MultiValue.IntegerConstant a,- Marshal.C a, Marshal.Vector n a) =>- process+ MarshalMV.C a, MarshalMV.Vector n a) =>+ Causal.T (MultiValue.T (CascadeParameter n a), MultiValue.T a) (MultiValue.T a) cascadePipeline = withSize $ \order ->@@ -459,148 +429,82 @@ uncurry MultiValue.zip vectorId ::- (Causal.C process) =>- Proxy n -> process (MultiVector.T n a) (MultiVector.T n a)+ Proxy n -> Causal.T (MultiVector.T n a) (MultiVector.T n a) vectorId _ = Cat.id half ::- (Causal.C process, A.RationalConstant a, A.PseudoRing a) =>- process a a-half = CausalV.map (Value.fromRational' 0.5 *)---multiValue ::- (Tuple.ValueOf a ~ LLVM.Value a) =>- LLVM.Value a -> MultiValue.T a-multiValue = MultiValue.Cons--unmultiValue ::- (Tuple.ValueOf a ~ LLVM.Value a) =>- MultiValue.T a -> LLVM.Value a-unmultiValue (MultiValue.Cons a) = a--multiCascadeParam ::- (Tuple.ValueOf a ~ LLVM.Value a) =>- CascadeParameter n (LLVM.Value a) ->- MultiValue.T (CascadeParameter n a)-multiCascadeParam (CascadeParameter a) =- MultiValue.Cons a--phaserPipeline ::- (Causal.C process,- TypeNum.Positive n,- MultiValue.PseudoRing a, MultiValue.RationalConstant a,- Marshal.C a, Marshal.Vector n a, MultiVector.C a,- Tuple.ValueOf a ~ LLVM.Value a) =>- process- (CascadeParameter n (LLVM.Value a), LLVM.Value a)- (LLVM.Value a)-phaserPipeline =- unmultiValue- ^<<- phaserPipelineMulti- <<^- mapPair (multiCascadeParam, multiValue)---phaserPipelineMulti ::- (Causal.C process,- TypeNum.Positive n,- MultiValue.PseudoRing a, MultiValue.RationalConstant a,- Marshal.C a, Marshal.Vector n a, MultiVector.C a) =>- process- (MultiValue.T (CascadeParameter n a), MultiValue.T a)- (MultiValue.T a)-phaserPipelineMulti = withSize $ \order ->- Causal.mix <<<- cascadePipeline &&&- (Causal.pipeline (vectorId order) <<^ snd) <<<--- (Causal.delay (const zero) (const $ TypeNum.integralFromProxy order) <<^ snd) <<<- second half+ (A.RationalConstant a, A.PseudoRing a) =>+ Causal.T a a+half = CausalPriv.map (A.mul (A.fromRational' 0.5)) causalPacked, causalNonRecursivePacked ::- (Causal.C process,- Serial.C v, Serial.Element v ~ a,- Memory.C a, A.IntegerConstant a,- A.PseudoRing v, A.PseudoRing a) =>- process (Parameter a, v) v+ (Serial.Write v, Serial.Element v ~ a,+ A.PseudoRing a, A.IntegerConstant a, Memory.C a,+ A.PseudoRing v, A.IntegerConstant v) =>+ Causal.T (Parameter a, v) v causalPacked = Filt1L.causalRecursivePacked <<<- (Causal.map- (\(Parameter k, _) ->- fmap Filt1.Parameter $ A.neg k) &&&+ (CausalPriv.map (\(Parameter k, _) -> fmap Filt1.Parameter $ A.neg k) &&& causalNonRecursivePacked) causalNonRecursivePacked =- Causal.mapAccum+ CausalPriv.mapAccum (\(Parameter k, v0) x1 -> do (_,v1) <- Serial.shiftUp x1 v0 y <- A.add v1 =<< A.mul v0 =<< Serial.upsample k- let size = fromIntegral $ Serial.size v0- u0 <- Serial.extract (LLVM.valueOf $ size - 1) v0+ u0 <- Serial.last v0 return (y, u0)) (return A.zero) cascadePacked, phaserPacked ::- (Causal.C process,- TypeNum.Natural n,- Serial.C v, Serial.Element v ~ a,+ (TypeNum.Natural n,+ Serial.Write v, Serial.Element v ~ a, A.PseudoRing a, A.IntegerConstant a, Memory.C a, A.PseudoRing v, A.RationalConstant v) =>- process (CascadeParameter n a, v) v-cascadePacked =- replicateStage Proxy causalPacked+ Causal.T (CascadeParameter n a, v) v+cascadePacked = replicateStage Proxy causalPacked phaserPacked =- Causal.mix <<<- cascadePacked &&& arr snd <<<- second (Causal.map (A.mul (A.fromRational' 0.5)))---+ (cascadePacked + arr snd) <<<+ second (CausalPriv.map (A.mul (A.fromRational' 0.5))) -causalP ::- (A.RationalConstant a, a ~ A.Scalar v, A.PseudoModule v, Memory.C v) =>- CausalP.T p (Parameter a, v) v-causalP = causal--cascadeP ::- (A.RationalConstant a, a ~ A.Scalar v, A.PseudoModule v, Memory.C v,- TypeNum.Natural n) =>- CausalP.T p (CascadeParameter n a, v) v-cascadeP = cascade+-- ToDo: consistent naming with Exponential2+cascadeParameterMultiValue ::+ CascadeParameter n (MultiValue.T a) ->+ MultiValue.T (CascadeParameter n a)+cascadeParameterMultiValue (CascadeParameter k) =+ MultiValue.Cons $ fmap (\(MultiValue.Cons a) -> a) k -phaserP ::- (A.RationalConstant a, A.RationalConstant v,- a ~ A.Scalar v, A.PseudoModule v, Memory.C v,- TypeNum.Natural n) =>- CausalP.T p (CascadeParameter n a, v) v-phaserP = phaser+cascadeParameterUnMultiValue ::+ MultiValue.T (CascadeParameter n a) ->+ CascadeParameter n (MultiValue.T a)+cascadeParameterUnMultiValue (MultiValue.Cons k) =+ CascadeParameter $ fmap MultiValue.Cons k -causalPackedP ::- (Serial.C v, Serial.Element v ~ a,- Memory.C a, A.IntegerConstant a,- A.PseudoRing v, A.PseudoRing a) =>- CausalP.T p (Parameter a, v) v-causalPackedP = causalPacked--cascadePackedP, phaserPackedP ::- (TypeNum.Natural n,- Serial.C v, Serial.Element v ~ a,- A.PseudoRing a, A.IntegerConstant a, Memory.C a,- A.PseudoRing v, A.RationalConstant v) =>- CausalP.T p (CascadeParameter n a, v) v-cascadePackedP = cascadePacked-phaserPackedP = phaserPacked+phaserPipelineMV ::+ (TypeNum.Positive n,+ MultiValue.PseudoRing a, MultiValue.RationalConstant a,+ Marshal.C a, MarshalMV.Vector n a) =>+ Causal.T+ (MultiValue.T (CascadeParameter n a), MultiValue.T a)+ (MultiValue.T a)+phaserPipelineMV = withSize $ \order ->+ Causal.mix <<<+ cascadePipeline &&&+ (Causal.pipeline (vectorId order) <<^ snd) <<<+-- (Causal.delay (const zero) (const $ TypeNum.integralFromProxy order) <<^ snd) <<<+ second half -{-# DEPRECATED causalP "use 'causal' instead" #-}-{-# DEPRECATED cascadeP "use 'cascade' instead" #-}-{-# DEPRECATED phaserP "use 'phaser' instead" #-}-{-# DEPRECATED causalPackedP "use 'causalPacked' instead" #-}-{-# DEPRECATED cascadePackedP "use 'cascadePacked' instead" #-}-{-# DEPRECATED phaserPackedP "use 'phaserPacked' instead" #-}+phaserPipeline ::+ (TypeNum.Positive n,+ MultiValue.PseudoRing a, MultiValue.RationalConstant a,+ Marshal.C a, MarshalMV.Vector n a) =>+ Causal.T+ (CascadeParameter n (MultiValue.T a), MultiValue.T a)+ (MultiValue.T a)+phaserPipeline = phaserPipelineMV <<^ mapFst cascadeParameterMultiValue
src/Synthesizer/LLVM/Filter/Butterworth.hs view
@@ -4,29 +4,28 @@ {-# LANGUAGE FlexibleContexts #-} module Synthesizer.LLVM.Filter.Butterworth ( parameter, parameterCausal, Cascade.ParameterValue,- Cascade.causal, Cascade.causalPacked,- Cascade.causalP, Cascade.causalPackedP,+ Cascade.causal, Cascade.causalPacked, Cascade.fixSize, ) where import qualified Synthesizer.LLVM.Filter.SecondOrderCascade as Cascade import qualified Synthesizer.LLVM.Filter.SecondOrder as Filt2-import qualified Synthesizer.LLVM.Causal.ProcessPrivate as Causal-import qualified Synthesizer.LLVM.Simple.SignalPrivate as Sig-import qualified Synthesizer.LLVM.Simple.Value as Value+import qualified Synthesizer.LLVM.Causal.Private as Causal+import qualified Synthesizer.LLVM.Generator.Private as Sig import qualified Synthesizer.Plain.Filter.Recursive.Butterworth as Butterworth import Synthesizer.Plain.Filter.Recursive (Passband) import Synthesizer.Causal.Class (($<)) -import qualified LLVM.Extra.ScalarOrVector as SoV-import qualified LLVM.Extra.Control as U+import qualified LLVM.DSL.Expression as Expr++import qualified LLVM.Extra.Multi.Value.Marshal as Marshal+import qualified LLVM.Extra.Multi.Value as MultiValue+import qualified LLVM.Extra.Memory as Memory import qualified LLVM.Extra.Arithmetic as A+import qualified LLVM.Extra.Control as U import qualified LLVM.Core as LLVM-import LLVM.Core- (CodeGenFunction, Value, valueOf, constOf,- IsFloating, IsSized, SizeOf) import Data.Word (Word) @@ -43,13 +42,12 @@ parameterCausal ::- (Causal.C process,- Trans.C a, SoV.TranscendentalConstant a, IsFloating a, IsSized a,- TypeNum.Natural n,- TypeNum.Positive (n :*: SizeOf a),- IsSized (Cascade.ParameterStruct n a)) =>+ (TypeNum.Positive (n :*: LLVM.SizeOf (Marshal.Struct a)),+ TypeNum.Natural (n :*: LLVM.UnknownSize),+ TypeNum.Natural n, Trans.C a,+ Marshal.C a, MultiValue.RationalConstant a, MultiValue.Transcendental a) => Proxy n -> Passband ->- process (Value a, Value a) (Cascade.ParameterValue n a)+ Causal.T (MultiValue.T a, MultiValue.T a) (Cascade.ParameterValue n a) parameterCausal n kind = Causal.map (\((psine, ps), (ratio, freq)) ->@@ -58,12 +56,12 @@ Sig.zipWith (curry return) Sig.alloca Sig.alloca parameter ::- (Trans.C a, SoV.TranscendentalConstant a, IsFloating a, IsSized a,- TypeNum.Natural n,- TypeNum.Positive (n :*: SizeOf a),- IsSized (Cascade.ParameterStruct n a)) =>- Proxy n -> Passband -> Value a -> Value a ->- CodeGenFunction r (Cascade.ParameterValue n a)+ (TypeNum.Positive (n :*: LLVM.SizeOf (Marshal.Struct a)),+ TypeNum.Natural (n :*: LLVM.UnknownSize),+ TypeNum.Natural n, Trans.C a,+ Marshal.C a, MultiValue.RationalConstant a, MultiValue.Transcendental a) =>+ Proxy n -> Passband -> MultiValue.T a -> MultiValue.T a ->+ LLVM.CodeGenFunction r (Cascade.ParameterValue n a) parameter n kind ratio freq = do psine <- LLVM.malloc ps <- LLVM.malloc@@ -73,29 +71,30 @@ return pv parameterCore ::- (Trans.C a, SoV.TranscendentalConstant a, IsFloating a, IsSized a,- TypeNum.Natural n,- TypeNum.Positive (n :*: SizeOf a),- IsSized (Cascade.ParameterStruct n a)) =>+ (TypeNum.Positive (n :*: LLVM.SizeOf (Marshal.Struct a)),+ TypeNum.Natural (n :*: LLVM.UnknownSize),+ TypeNum.Natural n, Trans.C a,+ Marshal.C a, MultiValue.RationalConstant a, MultiValue.Transcendental a) => Proxy n -> Passband ->- Value (LLVM.Ptr (LLVM.Array n a)) ->- Value (LLVM.Ptr (Cascade.ParameterStruct n a)) ->- Value a -> Value a ->- CodeGenFunction r (Cascade.ParameterValue n a)+ LLVM.Value (LLVM.Ptr (Marshal.Struct (MultiValue.Array n a))) ->+ LLVM.Value (LLVM.Ptr (Cascade.ParameterStruct n a)) ->+ MultiValue.T a -> MultiValue.T a ->+ LLVM.CodeGenFunction r (Cascade.ParameterValue n a) parameterCore n kind psine ps ratio freq = do let order = 2 * TypeNum.integralFromProxy n- partialRatio <- Value.unlift1 (Butterworth.partialRatio order) ratio- let sines =- Cascade.constArray n $- map constOf $ Butterworth.makeSines order- LLVM.store sines psine- s <- LLVM.getElementPtr0 psine (valueOf (0::Word), ())- p <- LLVM.getElementPtr0 ps (valueOf (0::Word), ())- let len = valueOf $ (TypeNum.integralFromProxy n :: Word)+ partialRatio <- Expr.unliftM1 (Butterworth.partialRatio order) ratio+ let evalSines :: (Trans.C a) => mv a -> Int -> [a]+ evalSines _ = Butterworth.makeSines+ let sines = Cascade.constArray n $ evalSines freq order+ Memory.store sines psine+ s <- LLVM.getElementPtr0 psine (LLVM.valueOf (0::Word), ())+ p <- LLVM.getElementPtr0 ps (LLVM.valueOf (0::Word), ())+ let len = LLVM.valueOf (TypeNum.integralFromProxy n :: Word) _ <- U.arrayLoop len p s $ \ptri si -> do- sinw <- LLVM.load si- flip LLVM.store ptri =<<- Filt2.composeParameter =<<- Value.unlift3 (Butterworth.partialParameter kind) partialRatio sinw freq+ sinw <- Memory.load si+ flip Memory.store ptri =<<+ Filt2.composeParameterMV =<<+ Expr.unliftM3 (Butterworth.partialParameter kind)+ partialRatio sinw freq A.advanceArrayElementPtr si- fmap Cascade.ParameterValue $ LLVM.load ps+ fmap Cascade.ParameterValue $ Memory.load ps
src/Synthesizer/LLVM/Filter/Chebyshev.hs view
@@ -6,38 +6,37 @@ parameterCausalA, parameterCausalB, parameterA, parameterB, Cascade.ParameterValue, Cascade.causal, Cascade.causalPacked,- Cascade.causalP, Cascade.causalPackedP, Cascade.fixSize, ) where import qualified Synthesizer.LLVM.Filter.SecondOrderCascade as Cascade import qualified Synthesizer.LLVM.Filter.SecondOrder as Filt2-import qualified Synthesizer.LLVM.Causal.ProcessPrivate as Causal-import qualified Synthesizer.LLVM.Simple.SignalPrivate as Sig-import qualified Synthesizer.LLVM.Simple.Value as Value+import qualified Synthesizer.LLVM.Causal.Private as Causal+import qualified Synthesizer.LLVM.Generator.Private as Sig import qualified Synthesizer.Plain.Filter.Recursive.Chebyshev as Chebyshev import qualified Synthesizer.Plain.Filter.Recursive.SecondOrder as Filt2Core import Synthesizer.Plain.Filter.Recursive (Passband) import Synthesizer.Causal.Class (($<)) -import qualified LLVM.Extra.ScalarOrVector as SoV-import qualified LLVM.Extra.Control as U+import qualified LLVM.DSL.Expression as Expr++import qualified LLVM.Extra.Multi.Value.Marshal as Marshal+import qualified LLVM.Extra.Multi.Value as MultiValue+import qualified LLVM.Extra.Memory as Memory import qualified LLVM.Extra.Arithmetic as A+import qualified LLVM.Extra.Control as U import qualified LLVM.Core as LLVM-import LLVM.Core- (Value, valueOf, IsSized, SizeOf, IsFloating, CodeGenFunction) import Data.Word (Word) - import qualified Type.Data.Num.Decimal as TypeNum import Type.Data.Num.Decimal.Number ((:*:)) import Type.Base.Proxy (Proxy) -import qualified Synthesizer.LLVM.Complex as ComplexL+import qualified Synthesizer.LLVM.Complex as Complex -import qualified Number.Complex as Complex+import Control.Applicative (liftA2) import qualified Algebra.Transcendental as Trans @@ -53,14 +52,12 @@ because they use stack-based @alloca@ instead of @malloc@. -} parameterCausalA, parameterCausalB ::- (Causal.C process,- Trans.C a, SoV.TranscendentalConstant a, IsFloating a, IsSized a,- TypeNum.Positive n, TypeNum.Natural n,- TypeNum.Positive (n :*: SizeOf a),- IsSized (Cascade.ParameterStruct n a), SizeOf (Cascade.ParameterStruct n a) ~ paramSize,- (n :*: LLVM.UnknownSize) ~ paramSize, TypeNum.Positive paramSize) =>+ (TypeNum.Natural n, Trans.C a,+ Marshal.C a, MultiValue.RationalConstant a, MultiValue.Transcendental a) =>+ (TypeNum.Positive (n :*: LLVM.SizeOf (Marshal.Struct a)),+ TypeNum.Positive (n :*: LLVM.UnknownSize)) => Proxy n -> Passband ->- process (Value a, Value a) (Cascade.ParameterValue n a)+ Causal.T (MultiValue.T a, MultiValue.T a) (Cascade.ParameterValue n a) parameterCausalA n kind = Causal.map (\((psine, ps), (ratio, freq)) ->@@ -79,18 +76,17 @@ allocaArrays allocaArrays ::- (Sig.C signal, IsSized a, IsSized b) =>- signal (Value (LLVM.Ptr a), Value (LLVM.Ptr b))-allocaArrays = Sig.zipWith (curry return) Sig.alloca Sig.alloca+ (LLVM.IsSized a, LLVM.IsSized b) =>+ Sig.T (LLVM.Value (LLVM.Ptr a), LLVM.Value (LLVM.Ptr b))+allocaArrays = liftA2 (,) Sig.alloca Sig.alloca parameterA, parameterB ::- (Trans.C a, SoV.TranscendentalConstant a, IsFloating a, IsSized a,- TypeNum.Positive n, TypeNum.Natural n,- TypeNum.Positive (n :*: SizeOf a),- IsSized (Cascade.ParameterStruct n a), SizeOf (Cascade.ParameterStruct n a) ~ paramSize,- (n :*: LLVM.UnknownSize) ~ paramSize, TypeNum.Positive paramSize) =>- Proxy n -> Passband -> Value a -> Value a ->- CodeGenFunction r (Cascade.ParameterValue n a)+ (TypeNum.Natural n, Trans.C a,+ Marshal.C a, MultiValue.RationalConstant a, MultiValue.Transcendental a) =>+ (TypeNum.Positive (n :*: LLVM.SizeOf (Marshal.Struct a)),+ TypeNum.Positive (n :*: LLVM.UnknownSize)) =>+ Proxy n -> Passband -> MultiValue.T a -> MultiValue.T a ->+ LLVM.CodeGenFunction r (Cascade.ParameterValue n a) parameterA n kind ratio freq = withArrays $ \psine ps -> fmap Cascade.ParameterValue $@@ -104,8 +100,9 @@ withArrays :: (LLVM.IsSized a, LLVM.IsSized b) =>- (Value (LLVM.Ptr a) -> Value (LLVM.Ptr b) -> CodeGenFunction r c) ->- CodeGenFunction r c+ (LLVM.Value (LLVM.Ptr a) -> LLVM.Value (LLVM.Ptr b) ->+ LLVM.CodeGenFunction r c) ->+ LLVM.CodeGenFunction r c withArrays act = do psine <- LLVM.malloc ps <- LLVM.malloc@@ -117,52 +114,43 @@ -- | adjust amplification of the first filter adjustAmplitude ::- (LLVM.IsArithmetic a, IsSized a, SoV.IntegerConstant a,- Filt2.ParameterStruct a ~ filt2, TypeNum.Natural n) =>- Value a -> Value (LLVM.Array n filt2) ->- CodeGenFunction r (Value (LLVM.Array n filt2))-adjustAmplitude ratio pv = do- filt0 <-- Filt2.decomposeParameter =<<- LLVM.extractvalue pv (0::Word)- flip (LLVM.insertvalue pv) (0::Word) =<<- Filt2.composeParameter =<<- Value.flatten- (Filt2Core.amplify (Value.constantValue ratio) (Value.unfold filt0))-+ (TypeNum.Natural n, Filt2.Parameter a ~ filt2,+ Marshal.C a, MultiValue.IntegerConstant a, MultiValue.PseudoRing a) =>+ MultiValue.T a -> MultiValue.T (MultiValue.Array n filt2) ->+ LLVM.CodeGenFunction r (MultiValue.T (MultiValue.Array n filt2))+adjustAmplitude ratio (MultiValue.Cons pv) = do+ filt0 <- Filt2.decomposeParameterMV =<< LLVM.extractvalue pv (0::Word)+ fmap MultiValue.Cons $+ flip (LLVM.insertvalue pv) (0::Word) =<<+ Filt2.composeParameterMV =<<+ Expr.unliftM2 Filt2Core.amplify ratio filt0 parameter ::- (Trans.C a, SoV.RationalConstant a, IsFloating a, IsSized a,- Value.T (Value a) ~ av,- TypeNum.Positive n, TypeNum.Natural n,- TypeNum.Positive (n :*: SizeOf a),- IsSized (Cascade.ParameterStruct n a), SizeOf (Cascade.ParameterStruct n a) ~ paramSize,- (n :*: LLVM.UnknownSize) ~ paramSize, TypeNum.Positive paramSize) =>- (Passband -> Int -> av -> Complex.T av -> av -> Filt2Core.Parameter av) ->+ (TypeNum.Positive (n :*: LLVM.SizeOf (Marshal.Struct a)),+ TypeNum.Positive (n :*: LLVM.UnknownSize),+ TypeNum.Natural n, Trans.C a,+ Marshal.C a, MultiValue.RationalConstant a, MultiValue.Transcendental a,+ Expr.Exp a ~ ae) =>+ (Passband -> Int -> ae -> Complex.T ae -> ae -> Filt2Core.Parameter ae) -> Proxy n -> Passband ->- Value (LLVM.Ptr (LLVM.Array n (ComplexL.Struct a))) ->- Value (LLVM.Ptr (Cascade.ParameterStruct n a)) ->- Value a -> Value a ->- CodeGenFunction r (Value (Cascade.ParameterStruct n a))+ LLVM.Value (LLVM.Ptr (Marshal.Struct (MultiValue.Array n (Complex.T a)))) ->+ LLVM.Value (LLVM.Ptr (Cascade.ParameterStruct n a)) ->+ MultiValue.T a -> MultiValue.T a ->+ LLVM.CodeGenFunction r (MultiValue.T (Cascade.Parameter n a)) parameter partialParameter n kind psine ps ratio freq = do let order = TypeNum.integralFromProxy n- let sines =- Cascade.constArray n $- map ComplexL.constOf $- Chebyshev.makeCirclePoints order- LLVM.store sines psine- s <- LLVM.getElementPtr0 psine (valueOf (0::Word), ())- p <- LLVM.getElementPtr0 ps (valueOf (0::Word), ())- let len = valueOf $ (TypeNum.integralFromProxy n :: Word)+ let evalSines :: (Trans.C a) => mv a -> Int -> [Complex.T a]+ evalSines _ = Chebyshev.makeCirclePoints+ let sines = Cascade.constArray n $ evalSines freq order+ Memory.store sines psine+ s <- LLVM.getElementPtr0 psine (LLVM.valueOf (0::Word), ())+ p <- LLVM.getElementPtr0 ps (LLVM.valueOf (0::Word), ())+ let len = LLVM.valueOf (TypeNum.integralFromProxy n :: Word) _ <- U.arrayLoop len p s $ \ptri si -> do- c <- LLVM.load si- flip LLVM.store ptri =<<- Filt2.composeParameter =<<- Value.flatten- (partialParameter kind order- (Value.constantValue ratio)- (ComplexL.unfold c)- (Value.constantValue freq))+ c <- Memory.load si+ flip Memory.store ptri =<<+ Filt2.composeParameterMV =<<+ Expr.unliftM3 (partialParameter kind order) ratio c freq A.advanceArrayElementPtr si - LLVM.load ps+ Memory.load ps
src/Synthesizer/LLVM/Filter/ComplexFirstOrder.hs view
@@ -1,17 +1,20 @@ {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE MultiParamTypeClasses #-} module Synthesizer.LLVM.Filter.ComplexFirstOrder (- Parameter, parameter,- causal, causalP,+ Parameter(Parameter), parameter, causal,+ parameterCode, causalExp, ) where -import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP-import qualified Synthesizer.LLVM.Causal.Process as Causal-import qualified Synthesizer.LLVM.Simple.Value as Value+import qualified Synthesizer.LLVM.Causal.Process as CausalExp+import qualified Synthesizer.LLVM.Causal.Private as Causal+import qualified Synthesizer.LLVM.Value as Value import qualified Synthesizer.LLVM.Frame.Stereo as Stereo import qualified Synthesizer.LLVM.Complex as Complex +import qualified LLVM.DSL.Expression as Expr+ import qualified LLVM.Extra.Arithmetic as A import qualified LLVM.Extra.Memory as Memory import qualified LLVM.Extra.Tuple as Tuple@@ -27,6 +30,9 @@ import qualified Data.Traversable as Trav import qualified Data.Foldable as Fold +import qualified Algebra.Transcendental as Trans+import qualified Algebra.Ring as Ring+ import NumericPrelude.Numeric import NumericPrelude.Base @@ -91,25 +97,39 @@ flattenCode = Value.flattenCodeTraversable unfoldCode = Value.unfoldCodeTraversable +instance+ (Expr.Aggregate e mv) =>+ Expr.Aggregate (Parameter e) (Parameter mv) where+ type MultiValuesOf (Parameter e) = Parameter (Expr.MultiValuesOf e)+ type ExpressionsOf (Parameter mv) = Parameter (Expr.ExpressionsOf mv)+ bundle = Trav.traverse Expr.bundle+ dissect = fmap Expr.dissect -parameter, _parameter ::++parameterCode, _parameterCode :: (A.Transcendental a, A.RationalConstant a) => a -> a -> CodeGenFunction r (Parameter a)-parameter reson freq =+parameterCode reson freq = let amp = recip $ Value.unfold reson in Value.flatten $ Parameter amp $ Complex.scale (1-amp) $ Complex.cis $- Value.unfold freq * Value.twoPi+ Value.unfold freq * Value.tau -_parameter reson freq = do+_parameterCode reson freq = do amp <- A.fdiv A.one reson k <- A.sub A.one amp- w <- A.mul freq =<< Value.decons Value.twoPi+ w <- A.mul freq =<< Value.decons Value.tau kr <- A.mul k =<< A.cos w ki <- A.mul k =<< A.sin w return (Parameter amp (kr Complex.+: ki)) +parameter :: (Trans.C a) => a -> a -> Parameter a+parameter reson freq =+ let amp = recip reson+ in Parameter amp $+ Complex.scale (1-amp) $ Complex.cis $ freq * 2*pi + {- Synthesizer.Plain.Filter.Recursive.FirstOrderComplex.step cannot be used directly, because Filt1C has complex amplitude@@ -120,15 +140,12 @@ Complex.T a -> CodeGenFunction r (Stereo.T a, Complex.T a) next inp state =- let stereoFromComplex ::- Complex.T a -> Complex.T (Value.T a) ->- Stereo.T (Value.T a)- stereoFromComplex _ c =- Stereo.cons (Complex.real c) (Complex.imag c)+ let stereoFromComplexVal :: Complex.T (Value.T a) -> Stereo.T (Value.T a)+ stereoFromComplexVal = stereoFromComplex (Parameter amp k, x) = Value.unfold inp xc = Stereo.left x Complex.+: Stereo.right x y = Complex.scale amp xc + k * Value.unfold state- in Value.flatten (stereoFromComplex state y, y)+ in Value.flatten (stereoFromComplexVal y, y) _next (Parameter amp k, x) s = do let kr = Complex.real k@@ -151,18 +168,27 @@ return (A.zero Complex.+: A.zero) causal ::- (Causal.C process, A.PseudoRing a, A.IntegerConstant a, Memory.C a) =>- process+ (A.PseudoRing a, A.IntegerConstant a, Memory.C a) =>+ Causal.T (Parameter a, Stereo.T a) (Stereo.T a) causal = Causal.mapAccum next start -{-# DEPRECATED causalP "use causal instead" #-}-causalP ::- (A.PseudoRing a, A.IntegerConstant a, Memory.C a) =>- CausalP.T p- (Parameter a, Stereo.T a)- (Stereo.T a)-causalP =- CausalP.mapAccumSimple next start++stereoFromComplex :: Complex.T a -> Stereo.T a+stereoFromComplex c = Stereo.cons (Complex.real c) (Complex.imag c)++nextPlain ::+ (Ring.C a) =>+ (Parameter a, Stereo.T a) -> Complex.T a -> (Stereo.T a, Complex.T a)+nextPlain (Parameter amp k, x) state =+ let xc = Stereo.left x Complex.+: Stereo.right x+ y = Complex.scale amp xc + k * state+ in (stereoFromComplex y, y)++causalExp ::+ (Ring.C ae, Expr.Aggregate ae a, Memory.C a) =>+ CausalExp.T (Parameter a, Stereo.T a) (Stereo.T a)+causalExp =+ CausalExp.mapAccum nextPlain zero
src/Synthesizer/LLVM/Filter/ComplexFirstOrderPacked.hs view
@@ -2,150 +2,136 @@ {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE Rank2Types #-} module Synthesizer.LLVM.Filter.ComplexFirstOrderPacked (- Parameter, parameter,- causal, causalP,+ Parameter(Parameter), parameterPlain, parameter, causal,+ ParameterMV, ) where -import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP-import qualified Synthesizer.LLVM.Causal.Process as Causal-import qualified Synthesizer.LLVM.Simple.Value as Value+import qualified Synthesizer.LLVM.Filter.ComplexFirstOrder as ComplexFilter +import qualified Synthesizer.LLVM.Causal.Private as Causal+ 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.DSL.Expression as Expr+import LLVM.DSL.Expression (Exp(Exp))++import qualified LLVM.Extra.Multi.Value.Marshal as Marshal+import qualified LLVM.Extra.Multi.Value as MultiValue+import qualified LLVM.Extra.Multi.Vector as MultiVector import qualified LLVM.Extra.Arithmetic as A import qualified LLVM.Extra.Memory as Memory import qualified LLVM.Extra.Tuple as Tuple import qualified LLVM.Core as LLVM-import LLVM.Core- (Value, valueOf, Struct,- IsPrimitive, IsFloating, IsSized,- Vector, insertelement,- CodeGenFunction) -import qualified Type.Data.Num.Decimal as TypeNum-import Type.Data.Num.Decimal (D4, d0, d1, (:*:))+import Type.Data.Num.Decimal (D3, d0, d1) import Control.Applicative (liftA2) +import qualified Algebra.Transcendental as Trans++import qualified Number.Complex as Complex+ import NumericPrelude.Numeric import NumericPrelude.Base --- the pair should also be replaced by a Vector-data Parameter a =- Parameter (Value (Vector D4 a)) (Value (Vector D4 a))+data Parameter a = Parameter (LLVM.Vector D3 a) (LLVM.Vector D3 a) -instance IsPrimitive a => Tuple.Phi (Parameter a) where- phi bb (Parameter r i) = do+data ParameterMV a = ParameterMV (MultiVector.T D3 a) (MultiVector.T D3 a)++instance (MultiVector.C a) => Tuple.Phi (ParameterMV a) where+ phi bb (ParameterMV r i) = do r' <- Tuple.phi bb r i' <- Tuple.phi bb i- return (Parameter r' i')+ return (ParameterMV r' i') addPhi bb- (Parameter r i)- (Parameter r' i') = do+ (ParameterMV r i)+ (ParameterMV r' i') = do Tuple.addPhi bb r r' Tuple.addPhi bb i i' -instance IsPrimitive a => Tuple.Undefined (Parameter a) where- undef = Parameter Tuple.undef Tuple.undef+instance (MultiVector.C a) => Tuple.Undefined (ParameterMV a) where+ undef = ParameterMV Tuple.undef Tuple.undef -type ParameterStruct a = Struct (Vector D4 a, (Vector D4 a, ()))+type ParameterStruct a = Marshal.Struct (LLVM.Vector D3 a, LLVM.Vector D3 a) parameterMemory ::- (IsPrimitive a, IsSized a,- TypeNum.Positive (TypeNum.D4 :*: LLVM.SizeOf a)) =>- Memory.Record r (ParameterStruct a) (Parameter a)+ (Marshal.Vector D3 a) =>+ Memory.Record r (ParameterStruct a) (ParameterMV a) parameterMemory =- liftA2 Parameter- (Memory.element (\(Parameter kr _) -> kr) d0)- (Memory.element (\(Parameter _ ki) -> ki) d1)--{--The complicated Add constraints are caused by the IsType superclass of Memory.--instance (IsPrimitive l, IsSized (Vector D4 l) ss) =>- Memory.C (Parameter l) (Struct (Vector D4 l, (Vector D4 l, ()))) where+ liftA2 ParameterMV+ (Memory.element (\(ParameterMV kr _) -> kr) d0)+ (Memory.element (\(ParameterMV _ ki) -> ki) d1) -Mul constraint seems to be not enough, GHC urges to give constraints in terms of Add-instance (IsPrimitive l, IsSized l s, Mul D4 s ss, Sets.Pos ss) =>- Memory.C (Parameter l) (Struct (Vector D4 l, (Vector D4 l, ()))) where--}-instance- (IsPrimitive a, IsSized a,- TypeNum.Positive (TypeNum.D4 :*: LLVM.SizeOf a)) =>- Memory.C (Parameter a) where- type Struct (Parameter a) = ParameterStruct a+instance (Marshal.Vector D3 a) => Memory.C (ParameterMV a) where+ type Struct (ParameterMV a) = ParameterStruct a load = Memory.loadRecord parameterMemory store = Memory.storeRecord parameterMemory decompose = Memory.decomposeRecord parameterMemory compose = Memory.composeRecord parameterMemory -parameter ::- (SoV.TranscendentalConstant a, IsFloating a, IsPrimitive a) =>- Value a -> Value a -> CodeGenFunction r (Parameter a)-parameter reson freq = do- amp <- A.fdiv A.one reson- k <- A.sub A.one amp- w <- A.mul freq =<< Value.decons Value.twoPi- kr <- A.mul k =<< A.cos w- ki <- A.mul k =<< A.sin w - kin <- A.neg ki- kvr <- Vector.assemble [kr,kin,amp, A.zero]- kvi <- Vector.assemble [ki,kr, amp, A.zero]- return (Parameter kvr kvi)+data ParameterExp a =+ ParameterExp (forall r. LLVM.CodeGenFunction r (ParameterMV a)) +instance Expr.Aggregate (ParameterExp a) (ParameterMV a) where+ type MultiValuesOf (ParameterExp a) = ParameterMV a+ type ExpressionsOf (ParameterMV a) = ParameterExp a+ dissect x = ParameterExp (return x)+ bundle (ParameterExp code) = code -type State a = Vector D4 a -{--The handling of Vector D2 Float in LLVM-2.5 and LLVM-2.6 is at least unexpected.-Because of compatibility reasons, LLVM chooses MMX registers-which requires to call EMMS occasionally.-Thus I choose Vector D4 for Float computations.-Actually, I have now rearranged the data-such that we can make use of SSE4's dot product operation.-This would even require a vector of size 3.--}+parameterPlain :: (Trans.C a) => a -> a -> Parameter a+parameterPlain reson freq =+ let (ComplexFilter.Parameter amp k) = ComplexFilter.parameter reson freq+ kr = Complex.real k+ ki = Complex.imag k+ in Parameter+ (LLVM.consVector kr (-ki) amp)+ (LLVM.consVector ki kr amp)++parameter ::+ (MultiVector.Transcendental a, MultiVector.RationalConstant a) =>+ Exp a -> Exp a -> ParameterExp a+parameter (Exp reson) (Exp freq) =+ ParameterExp (do+ r <- reson+ f <- freq+ ~(ComplexFilter.Parameter amp k) <- ComplexFilter.parameterCode r f+ let kr = Complex.real k+ let ki = Complex.imag k+ kin <- A.neg ki+ liftA2 ParameterMV+ (MultiVector.assembleFromVector $ LLVM.consVector kr kin amp)+ (MultiVector.assembleFromVector $ LLVM.consVector ki kr amp))+++type State a = MultiVector.T D3 a+ next ::- (Vector.Arithmetic a) =>- (Parameter a, Stereo.T (Value a)) ->- Value (State a) ->- CodeGenFunction r (Stereo.T (Value a), (Value (State a)))-next (Parameter kr ki, x) s = do- sr <- insertelement s (Stereo.left x) (valueOf 2)- yr <- Vector.dotProduct kr sr+ (MultiVector.PseudoRing a) =>+ (ParameterMV a, Stereo.T (MultiValue.T a)) ->+ State a -> LLVM.CodeGenFunction r (Stereo.T (MultiValue.T a), State a)+next (ParameterMV kr ki, x) s = do+ let two = LLVM.valueOf 2+ sr <- MultiVector.insert two (Stereo.left x) s+ yr <- MultiVector.dotProduct kr sr - si <- insertelement s (Stereo.right x) (valueOf 2)- yi <- Vector.dotProduct ki si+ si <- MultiVector.insert two (Stereo.right x) s+ yi <- MultiVector.dotProduct ki si - sv <- Vector.assemble [yr,yi]+ sv <- MultiVector.assembleFromVector $ LLVM.consVector yr yi Tuple.undef return (Stereo.cons yr yi, sv) -start ::- (Vector.Arithmetic a) =>- CodeGenFunction r (Value (State a))-start = return A.zero- causal ::- (Causal.C process, Vector.Arithmetic a, Memory.C (Value (State a))) =>- process- (Parameter a, Stereo.T (Value a))- (Stereo.T (Value a))-causal =- Causal.mapAccum next start--{-# DEPRECATED causalP "use causal instead" #-}-causalP ::- (Vector.Arithmetic a, Memory.C (Value (State a))) =>- CausalP.T p- (Parameter a, Stereo.T (Value a))- (Stereo.T (Value a))-causalP =- CausalP.mapAccumSimple next start+ (Marshal.Vector n a, n ~ D3, MultiVector.PseudoRing a) =>+ Causal.T+ (ParameterMV a, Stereo.T (MultiValue.T a))+ (Stereo.T (MultiValue.T a))+causal = Causal.mapAccum next (return A.zero)
src/Synthesizer/LLVM/Filter/FirstOrder.hs view
@@ -1,45 +1,40 @@ {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE MultiParamTypeClasses #-} {-# OPTIONS_GHC -fno-warn-orphans #-} module Synthesizer.LLVM.Filter.FirstOrder (- Result(Result,lowpass_,highpass_), Parameter, parameter,+ Result(Result,lowpass_,highpass_), Parameter, FirstOrder.parameter, causal, lowpassCausal, highpassCausal, causalInit, lowpassCausalInit, highpassCausalInit,- causalInitPacked, lowpassCausalInitPacked, highpassCausalInitPacked, causalPacked, lowpassCausalPacked, highpassCausalPacked,+ causalInitPacked, lowpassCausalInitPacked, highpassCausalInitPacked, causalRecursivePacked, -- for Allpass-- causalP, lowpassCausalP, highpassCausalP,- causalInitP, lowpassCausalInitP, highpassCausalInitP,- causalPackedP, lowpassCausalPackedP, highpassCausalPackedP,- causalInitPackedP, lowpassCausalInitPackedP, highpassCausalInitPackedP,- causalRecursivePackedP, -- for Allpass ) where import qualified Synthesizer.Plain.Filter.Recursive.FirstOrder as FirstOrder+import qualified Synthesizer.Plain.Modifier as Modifier import Synthesizer.Plain.Filter.Recursive.FirstOrder (Parameter(Parameter), Result(Result,lowpass_,highpass_)) -import qualified Synthesizer.Plain.Modifier as Modifier--import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP+import qualified Synthesizer.LLVM.Causal.Private as CausalPriv import qualified Synthesizer.LLVM.Causal.Process as Causal-import qualified Synthesizer.LLVM.Frame.SerialVector as Serial-import qualified Synthesizer.LLVM.Simple.Value as Value+import qualified Synthesizer.LLVM.Frame.SerialVector.Class as SerialCode -import qualified LLVM.DSL.Parameter as Param+import qualified LLVM.DSL.Expression as Expr -import qualified LLVM.Extra.Storable as Storable-import qualified LLVM.Extra.Marshal as Marshal-import qualified LLVM.Extra.Memory as Memory import qualified LLVM.Extra.Tuple as Tuple+import qualified LLVM.Extra.Memory as Memory import qualified LLVM.Extra.Arithmetic as A import qualified LLVM.Core as LLVM import Control.Arrow (arr, (&&&), (<<<))-import Control.Monad (liftM2, foldM)+import Control.Monad (foldM)+import Control.Applicative (liftA2) +import qualified Algebra.Module as Module+ import NumericPrelude.Numeric import NumericPrelude.Base @@ -58,143 +53,70 @@ decompose = Memory.decomposeNewtype Parameter compose = Memory.composeNewtype (\(Parameter k) -> k) -instance (Marshal.C a) => Marshal.C (Parameter a) where- pack (Parameter k) = Marshal.pack k- unpack = Parameter . Marshal.unpack -instance (Storable.C a) => Storable.C (Parameter a) where- load = Storable.loadNewtype Parameter Parameter- store = Storable.storeNewtype Parameter (\(Parameter k) -> k)--instance (Value.Flatten a) => Value.Flatten (Parameter a) where- type Registers (Parameter a) = Parameter (Value.Registers a)- flattenCode = Value.flattenCodeTraversable- unfoldCode = Value.unfoldCodeTraversable--instance (Value.Flatten a) => Value.Flatten (Result a) where- type Registers (Result a) = Result (Value.Registers a)- flattenCode = Value.flattenCodeTraversable- unfoldCode = Value.unfoldCodeTraversable--{--instance LLVM.ValueTuple a => LLVM.ValueTuple (Parameter a) where- buildTuple f = Class.buildTupleTraversable (LLVM.buildTuple f)--instance LLVM.IsTuple a => LLVM.IsTuple (Parameter a) where- tupleDesc = Class.tupleDescFoldable--}--instance (Tuple.Value a) => Tuple.Value (Parameter a) where- type ValueOf (Parameter a) = Parameter (Tuple.ValueOf a)- valueOf = Tuple.valueOfFunctor---parameter ::- (A.Transcendental a, A.RationalConstant a) =>- a -> LLVM.CodeGenFunction r (Parameter a)-parameter = Value.unlift1 FirstOrder.parameter+instance+ (Expr.Aggregate e mv) =>+ Expr.Aggregate (Parameter e) (Parameter mv) where+ type MultiValuesOf (Parameter e) = Parameter (Expr.MultiValuesOf e)+ type ExpressionsOf (Parameter mv) = Parameter (Expr.ExpressionsOf mv)+ bundle (Parameter p) = fmap Parameter $ Expr.bundle p+ dissect (Parameter p) = Parameter $ Expr.dissect p -modifier ::- (a ~ A.Scalar v, A.PseudoModule v, A.IntegerConstant a) =>- Modifier.Simple- (Value.T v)- (Parameter (Value.T a))- (Value.T v) (Result (Value.T v))-modifier = FirstOrder.modifier--lowpassModifier, highpassModifier ::- (a ~ A.Scalar v, A.PseudoModule v, A.IntegerConstant a) =>- Modifier.Simple--- (FirstOrder.State (Value.T v))- (Value.T v)- (Parameter (Value.T a))- (Value.T v) (Value.T v)-lowpassModifier = FirstOrder.lowpassModifier-highpassModifier = FirstOrder.highpassModifier+instance (Expr.Aggregate e mv) => Expr.Aggregate (Result e) (Result mv) where+ type MultiValuesOf (Result e) = Result (Expr.MultiValuesOf e)+ type ExpressionsOf (Result mv) = Result (Expr.ExpressionsOf mv)+ bundle (Result f k) = liftA2 Result (Expr.bundle f) (Expr.bundle k)+ dissect (Result f k) = Result (Expr.dissect f) (Expr.dissect k) causal ::- (Causal.C process,- A.IntegerConstant a, a ~ A.Scalar v, A.PseudoModule v, Memory.C v) =>- process (Parameter a, v) (Result v)-causal = Causal.fromModifier modifier+ (Expr.Aggregate ae a, Module.C ae ve,+ Expr.Aggregate ve v, Memory.C v) =>+ Causal.T (Parameter a, v) (Result v)+causal = Causal.fromModifier FirstOrder.modifier lowpassCausal, highpassCausal ::- (Causal.C process,- A.IntegerConstant a, a ~ A.Scalar v, A.PseudoModule v, Memory.C v) =>- process (Parameter a, v) v-lowpassCausal = CausalP.fromModifier lowpassModifier-highpassCausal = CausalP.fromModifier highpassModifier+ (Expr.Aggregate ae a, Module.C ae ve,+ Expr.Aggregate ve v, Memory.C v) =>+ Causal.T (Parameter a, v) v+lowpassCausal = Causal.fromModifier FirstOrder.lowpassModifier+highpassCausal = Causal.fromModifier FirstOrder.highpassModifier -modifierInit ::- (a ~ A.Scalar v, A.PseudoModule v, A.IntegerConstant a) =>- Modifier.Initialized- (Value.T v) (Value.T v)- (Parameter (Value.T a))- (Value.T v) (Result (Value.T v))-modifierInit = FirstOrder.modifierInit--lowpassModifierInit, highpassModifierInit ::- (a ~ A.Scalar v, A.PseudoModule v, A.IntegerConstant a) =>- Modifier.Initialized- (Value.T v) (Value.T v)- (Parameter (Value.T a))- (Value.T v) (Value.T v)-lowpassModifierInit = FirstOrder.lowpassModifierInit-highpassModifierInit = FirstOrder.highpassModifierInit- causalInit ::- (Causal.C process,- A.IntegerConstant a, a ~ A.Scalar v, A.PseudoModule v, Memory.C v) =>- v -> process (Parameter a, v) (Result v)+ (Expr.Aggregate ae a, Memory.C a, Module.C ae ve,+ Expr.Aggregate ve v, Memory.C v) =>+ ve -> Causal.T (Parameter a, v) (Result v) causalInit =- Causal.fromModifier . Modifier.initialize modifierInit . Value.unfold+ Causal.fromModifier . Modifier.initialize FirstOrder.modifierInit lowpassCausalInit, highpassCausalInit ::- (Causal.C process,- A.IntegerConstant a, a ~ A.Scalar v, A.PseudoModule v, Memory.C v) =>- v -> process (Parameter a, v) v+ (Expr.Aggregate ae a, Memory.C a, Module.C ae ve,+ Expr.Aggregate ve v, Memory.C v) =>+ ve -> Causal.T (Parameter a, v) v lowpassCausalInit =- CausalP.fromModifier .- Modifier.initialize lowpassModifierInit . Value.unfold+ Causal.fromModifier . Modifier.initialize FirstOrder.lowpassModifierInit highpassCausalInit =- CausalP.fromModifier .- Modifier.initialize highpassModifierInit . Value.unfold+ Causal.fromModifier . Modifier.initialize FirstOrder.highpassModifierInit lowpassCausalPacked, highpassCausalPacked, causalRecursivePacked, preampPacked ::- (Causal.C process,- Serial.C v, Serial.Element v ~ a,- Memory.C a, A.IntegerConstant a,- A.PseudoRing v, A.PseudoRing a) =>- process (Parameter a, v) v+ (SerialCode.Write v, SerialCode.Element v ~ a,+ A.PseudoRing v, A.IntegerConstant v,+ A.PseudoRing a, A.IntegerConstant a, Memory.C a) =>+ Causal.T (Parameter a, v) v highpassCausalPacked =- Causal.zipWith A.sub <<< arr snd &&& lowpassCausalPacked+ CausalPriv.zipWith A.sub <<< arr snd &&& lowpassCausalPacked lowpassCausalPacked =- causalRecursivePacked <<< (arr fst &&& preampPacked)+ causalRecursivePacked <<< arr fst &&& preampPacked causalRecursivePacked =- causalRecursiveInitPacked A.zero--lowpassCausalInitPacked, highpassCausalInitPacked, causalRecursiveInitPacked ::- (Causal.C process,- A.PseudoRing v, Serial.C v, Serial.Element v ~ a,- A.PseudoRing a, A.IntegerConstant a, Memory.C a) =>- a -> process (Parameter a, v) v-causalRecursiveInitPacked a =- Causal.mapAccum causalRecursivePackedStep (return a)--highpassCausalInitPacked a =- Causal.zipWith A.sub <<< arr snd &&& lowpassCausalInitPacked a-lowpassCausalInitPacked a =- causalRecursiveInitPacked a <<< (arr fst &&& preampPacked)+ CausalPriv.mapAccum causalRecursivePackedStep (return A.zero) preampPacked =- Causal.map- (\(Parameter k, x) ->- A.mul x =<< Serial.upsample =<< A.sub (A.fromInteger' 1) k)+ CausalPriv.map+ (\(Parameter k, x) -> A.mul x =<< SerialCode.upsample =<< A.sub A.one k) @@ -213,41 +135,24 @@ f2x = f1x + k^2 * f1x->2 -} causalRecursivePackedStep ::- (A.PseudoRing v, Serial.C v, Serial.Element v ~ a, A.PseudoRing a) =>+ (SerialCode.Write v, SerialCode.Element v ~ a,+ A.PseudoRing v, A.IntegerConstant v, A.PseudoRing a) => (Parameter a, v) -> a -> LLVM.CodeGenFunction r (v,a)-causalRecursivePackedStep =- \(Parameter k, xk0) y1 -> do- y1k <- A.mul k y1- xk1 <- Serial.modify A.zero (A.add y1k) xk0- let size = Serial.size xk0- kv <- Serial.upsample k- xk2 <-- fmap fst $- foldM- (\(y,k0) d ->- liftM2 (,)- (A.add y =<<- Serial.shiftUpMultiZero d =<<- A.mul y k0)- (A.mul k0 k0))- (xk1,kv)- (takeWhile (< size) $ iterate (2*) 1)-{- do replicate in the loop- xk2 <-- fmap fst $- foldM- (\(y,k0) d ->- liftM2 (,)- (A.add y =<<- Serial.shiftUpMultiZero d =<<- A.mul y =<<- Serial.upsample k0)- (A.mul k0 k0))- (xk1,k)- (takeWhile (< size) $ iterate (2*) 1)--}- y0 <- Serial.extract (LLVM.valueOf $ fromIntegral $ size - 1) xk2- return (xk2, y0)+causalRecursivePackedStep (Parameter k, xk0) y1 = do+ y1k <- A.mul k y1+ xk1 <- SerialCode.modify A.zero (A.add y1k) xk0+ kv <- SerialCode.upsample k+ xk2 <-+ fmap fst $+ foldM+ (\(y,k0) d ->+ liftA2 (,)+ (A.add y =<< SerialCode.shiftUpMultiZero d =<< A.mul y k0)+ (A.mul k0 k0))+ (xk1,kv)+ (takeWhile (< SerialCode.size xk0) $ iterate (2*) 1)+ y0 <- SerialCode.last xk2+ return (xk2, y0) {- We can also optimize filtering with time-varying filter parameter.@@ -288,105 +193,41 @@ -} - addHighpass ::- (Causal.C process, A.Additive v) =>- process (param, v) v -> process (param, v) (Result v)+ (A.Additive v) =>+ Causal.T (param,v) v -> Causal.T (param,v) (Result v) addHighpass lowpass =-{--Before we added sharing to Simple.Value,-only this implementation allowed sharing-and using CausalP.fromModifier did not.--}- Causal.map (\(l,x) -> do- h <- A.sub x l- return (Result{lowpass_ = l, highpass_ = h}))- <<< (lowpass &&& arr snd)+ CausalPriv.map+ (\(l,x) -> do+ h <- A.sub x l+ return (Result{lowpass_ = l, highpass_ = h}))+ <<<+ lowpass &&& arr snd causalPacked ::- (Causal.C process,- Serial.C v, Serial.Element v ~ a,- Memory.C a, A.IntegerConstant a,- A.PseudoRing v, A.PseudoRing a) =>- process (Parameter a, v) (Result v)+ (SerialCode.Write v, SerialCode.Element v ~ a,+ A.PseudoRing v, A.IntegerConstant v,+ A.PseudoRing a, A.IntegerConstant a, Memory.C a) =>+ Causal.T (Parameter a, v) (Result v) causalPacked = addHighpass lowpassCausalPacked -causalInitPacked ::- (Causal.C process,- Serial.C v, Serial.Element v ~ a,- Memory.C a, A.IntegerConstant a,- A.PseudoRing v, A.PseudoRing a) =>- a -> process (Parameter a, v) (Result v)-causalInitPacked a = addHighpass (lowpassCausalInitPacked a) ---causalP ::- (A.IntegerConstant a, a ~ A.Scalar v, A.PseudoModule v, Memory.C v) =>- CausalP.T p (Parameter a, v) (Result v)-causalP = addHighpass lowpassCausalP--lowpassCausalP, highpassCausalP ::- (A.IntegerConstant a, a ~ A.Scalar v, A.PseudoModule v, Memory.C v) =>- CausalP.T p (Parameter a, v) v-lowpassCausalP = lowpassCausal-highpassCausalP = highpassCausal--causalInitP ::- (A.IntegerConstant a, a ~ A.Scalar v, A.PseudoModule v,- Marshal.C vh, Tuple.ValueOf vh ~ v) =>- Param.T p vh -> CausalP.T p (Parameter a, v) (Result v)-causalInitP = CausalP.fromInitializedModifier modifierInit--lowpassCausalInitP, highpassCausalInitP ::- (A.IntegerConstant a, a ~ A.Scalar v, A.PseudoModule v,- Marshal.C vh, Tuple.ValueOf vh ~ v) =>- Param.T p vh -> CausalP.T p (Parameter a, v) v-lowpassCausalInitP = CausalP.fromInitializedModifier lowpassModifierInit-highpassCausalInitP = CausalP.fromInitializedModifier highpassModifierInit--lowpassCausalPackedP, highpassCausalPackedP, causalRecursivePackedP ::- (Serial.C v, Serial.Element v ~ a,- Memory.C a, A.IntegerConstant a,- A.PseudoRing v, A.PseudoRing a) =>- CausalP.T p (Parameter a, v) v-highpassCausalPackedP = highpassCausalPacked-lowpassCausalPackedP = lowpassCausalPacked-causalRecursivePackedP = causalRecursivePacked--lowpassCausalInitPackedP, highpassCausalInitPackedP,- causalRecursiveInitPackedP ::- (A.PseudoRing v, Serial.C v, Serial.Element v ~ a,- A.PseudoRing a, A.IntegerConstant a,- Marshal.C ah, Tuple.ValueOf ah ~ a) =>- Param.T p ah -> CausalP.T p (Parameter a, v) v-causalRecursiveInitPackedP a =- CausalP.mapAccum (\() -> causalRecursivePackedStep) return (return ()) a--highpassCausalInitPackedP a =- Causal.zipWith A.sub <<< arr snd &&& lowpassCausalInitPackedP a-lowpassCausalInitPackedP a =- causalRecursiveInitPackedP a <<< (arr fst &&& preampPacked)--causalPackedP ::- (Serial.C v, Serial.Element v ~ a,- Memory.C a, A.IntegerConstant a,- A.PseudoRing v, A.PseudoRing a) =>- CausalP.T p (Parameter a, v) (Result v)-causalPackedP = causalPacked--causalInitPackedP ::- (A.PseudoRing v, Serial.C v, Serial.Element v ~ a,- A.PseudoRing a, A.IntegerConstant a,- Marshal.C ah, Tuple.ValueOf ah ~ a) =>- Param.T p ah -> CausalP.T p (Parameter a, v) (Result v)-causalInitPackedP a = addHighpass (lowpassCausalInitPackedP a)+lowpassCausalInitPacked, highpassCausalInitPacked,+ causalRecursiveInitPacked ::+ (A.PseudoRing v, A.IntegerConstant v,+ SerialCode.Write v, SerialCode.Element v ~ a,+ Expr.Aggregate ae a, A.PseudoRing a, A.IntegerConstant a, Memory.C a) =>+ ae -> Causal.T (Parameter a, v) v+causalRecursiveInitPacked a =+ CausalPriv.mapAccum causalRecursivePackedStep (Expr.bundle a) +highpassCausalInitPacked a = arr snd - lowpassCausalInitPacked a+lowpassCausalInitPacked a =+ causalRecursiveInitPacked a <<< arr fst &&& preampPacked -{-# DEPRECATED causalP "use 'causal' instead" #-}-{-# DEPRECATED lowpassCausalP "use 'lowpassCausal' instead" #-}-{-# DEPRECATED highpassCausalP "use 'highpassCausal' instead" #-}-{-# DEPRECATED causalPackedP "use 'causalPacked' instead" #-}-{-# DEPRECATED lowpassCausalPackedP "use 'lowpassCausalPacked' instead" #-}-{-# DEPRECATED highpassCausalPackedP "use 'highpassCausalPacked' instead" #-}-{-# DEPRECATED causalRecursivePackedP "use 'causalRecursivePacked' instead" #-}+causalInitPacked ::+ (A.PseudoRing v, A.IntegerConstant v,+ SerialCode.Write v, SerialCode.Element v ~ a,+ Expr.Aggregate ae a, A.PseudoRing a, A.IntegerConstant a, Memory.C a) =>+ ae -> Causal.T (Parameter a, v) (Result v)+causalInitPacked a = addHighpass (lowpassCausalInitPacked a)
src/Synthesizer/LLVM/Filter/Moog.hs view
@@ -1,33 +1,29 @@ {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE DeriveTraversable #-}-module Synthesizer.LLVM.Filter.Moog- (Parameter, parameter,- causal, causalInit,- causalP, causalInitP,+module Synthesizer.LLVM.Filter.Moog (+ Parameter, parameter,+ causal, causalInit, ) where -import qualified Synthesizer.LLVM.Filter.FirstOrder as Filt1+import qualified Synthesizer.LLVM.Filter.FirstOrder as Filt1 () import qualified Synthesizer.Plain.Filter.Recursive.FirstOrder as FirstOrder import qualified Synthesizer.Plain.Filter.Recursive.Moog as Moog import Synthesizer.Plain.Filter.Recursive (Pole(..)) -import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP import qualified Synthesizer.LLVM.Causal.Process as Causal-import qualified Synthesizer.LLVM.Simple.Value as Value -import qualified LLVM.DSL.Parameter as Param+import qualified LLVM.DSL.Expression as Expr import qualified LLVM.Extra.Vector as Vector-import qualified LLVM.Extra.Marshal as Marshal import qualified LLVM.Extra.Memory as Memory-import qualified LLVM.Extra.Arithmetic as A import qualified LLVM.Extra.Tuple as Tuple import qualified LLVM.Core as LLVM-import LLVM.Core (CodeGenFunction) import qualified Type.Data.Num.Decimal as TypeNum import Type.Data.Num.Decimal (d0, d1)@@ -40,6 +36,8 @@ import Control.Arrow (arr, (>>>), (&&&)) import Control.Applicative (liftA2) +import qualified Algebra.Transcendental as Trans+import qualified Algebra.Module as Module import NumericPrelude.Numeric import NumericPrelude.Base @@ -62,33 +60,30 @@ zero = Tuple.zeroPointed -type ParameterStruct a = LLVM.Struct (a, (a, ()))+type ParameterStruct a =+ LLVM.Struct (Memory.Struct a, (Memory.Struct (FirstOrder.Parameter a), ())) parameterMemory :: (Memory.C a, TypeNum.Natural n) =>- Memory.Record r (ParameterStruct (Memory.Struct a)) (Parameter n a)+ Memory.Record r (ParameterStruct a) (Parameter n a) parameterMemory = liftA2 (\f k -> Parameter (Moog.Parameter f k)) (Memory.element (Moog.feedback . getParam) d0) (Memory.element (Moog.lowpassParam . getParam) d1) instance- (Memory.C a, TypeNum.Natural n) =>+ (Memory.C a, TypeNum.Natural n) => Memory.C (Parameter n a) where- type Struct (Parameter n a) = ParameterStruct (Memory.Struct a)+ type Struct (Parameter n a) = ParameterStruct a load = Memory.loadRecord parameterMemory store = Memory.storeRecord parameterMemory decompose = Memory.decomposeRecord parameterMemory compose = Memory.composeRecord parameterMemory -instance (Value.Flatten a, TypeNum.Natural n) => Value.Flatten (Parameter n a) where- type Registers (Parameter n a) = Parameter n (Value.Registers a)- flattenCode = Value.flattenCodeTraversable- unfoldCode = Value.unfoldCodeTraversable---instance (Vector.Simple v, TypeNum.Natural n) => Vector.Simple (Parameter n v) where+instance+ (Vector.Simple v, TypeNum.Natural n) =>+ Vector.Simple (Parameter n v) where type Element (Parameter n v) = Parameter n (Vector.Element v) type Size (Parameter n v) = Vector.Size v shuffleMatch = Vector.shuffleMatchTraversable@@ -99,81 +94,64 @@ parameter ::- (A.Transcendental a, A.RationalConstant a, TypeNum.Natural n) =>- Proxy n -> a -> a ->- CodeGenFunction r (Parameter n a)-parameter order =- Value.unlift2 $ \reson freq ->- Parameter $ Moog.parameter (TypeNum.integralFromProxy order) (Pole reson freq)+ (TypeNum.Natural n, Trans.C a) =>+ Proxy n -> a -> a -> Parameter n a+parameter order reson freq =+ Parameter $+ Moog.parameter (TypeNum.integralFromProxy order) (Pole reson freq) +instance+ (n ~ m, Expr.Aggregate e mv) =>+ Expr.Aggregate (Parameter n e) (Parameter m mv) where+ type MultiValuesOf (Parameter n e) = Parameter n (Expr.MultiValuesOf e)+ type ExpressionsOf (Parameter m mv) = Parameter m (Expr.ExpressionsOf mv)+ bundle (Parameter (Moog.Parameter f k)) =+ fmap Parameter $ liftA2 Moog.Parameter (Expr.bundle f) (Expr.bundle k)+ dissect (Parameter (Moog.Parameter f k)) =+ Parameter (Moog.Parameter (Expr.dissect f) (Expr.dissect k)) + merge ::- (a ~ A.Scalar v, A.PseudoModule v, A.IntegerConstant a) =>- (Parameter n a, v) -> v ->- CodeGenFunction r (FirstOrder.Parameter a, v)-merge (Parameter (Moog.Parameter f k), x) y0 =- let c :: a -> Value.T a- c = Value.constantValue- in Value.flatten (fmap c k, c x - c f *> c y0)+ (Module.C a v) => (Parameter n a, v) -> v -> (FirstOrder.Parameter a, v)+merge (Parameter (Moog.Parameter f k), x) y0 = (k, x - f *> y0) -amplify ::- (a ~ A.Scalar v, A.PseudoModule v, A.IntegerConstant a) =>- Parameter n a ->- v ->- CodeGenFunction r v-amplify =- Value.unlift2 $ \p y1 ->- case fmap (Moog.feedback . getParam) p of- f -> (1 + f) *> y1+amplify :: (Module.C a v) => Parameter n a -> v -> v+amplify p y1 = (1 + Moog.feedback (getParam p)) *> y1 causal ::- (Causal.C process,- Memory.C v, A.PseudoModule v, A.Scalar v ~ a, A.IntegerConstant a,- TypeNum.Natural n) =>- process (Parameter n a, v) v+ (TypeNum.Natural n, Memory.C v,+ Module.C ae ve, Expr.Aggregate ae a, Expr.Aggregate ve v) =>+ Causal.T (Parameter n a, v) v causal = causalSize- (flip Causal.feedbackControlledZero (arr snd))+ (flip (Causal.feedbackControlled zero) (arr snd)) Proxy -causalP ::- (Memory.C v, A.PseudoModule v, A.Scalar v ~ a, A.IntegerConstant a,- TypeNum.Natural n) =>- CausalP.T p (Parameter n a, v) v-causalP = causal --causalInit, causalInitP ::- (Marshal.C vh, Tuple.ValueOf vh ~ v,- A.PseudoModule v, A.Scalar v ~ a, A.IntegerConstant a,- TypeNum.Natural n) =>- Param.T p vh -> CausalP.T p (Parameter n a, v) v-causalInit = causalInitP-causalInitP initial =- let selectOutput :: Param.T p vh -> (b, Tuple.ValueOf vh) -> Tuple.ValueOf vh- selectOutput _ = snd- in causalSize- (flip- (CausalP.feedbackControlled initial)- (arr $ selectOutput initial))- Proxy+causalInit ::+ (TypeNum.Natural n, Memory.C v,+ Module.C ae ve, Expr.Aggregate ae a, Expr.Aggregate ve v) =>+ ve -> Causal.T (Parameter n a, v) v+causalInit initial =+ causalSize+ (flip+ (Causal.feedbackControlled initial)+ (arr snd))+ Proxy causalSize ::- (Causal.C process,- Memory.C v, A.PseudoModule v, A.Scalar v ~ a, A.IntegerConstant a,- TypeNum.Natural n) =>- (process ((Parameter n a, v), v) v ->- process (Parameter n a, v) v) ->+ (TypeNum.Natural n, Memory.C v,+ Module.C ae ve, Expr.Aggregate ae a, Expr.Aggregate ve v) =>+ (Causal.T ((Parameter n a, v), v) v ->+ Causal.T (Parameter n a, v) v) -> Proxy n ->- process (Parameter n a, v) v+ Causal.T (Parameter n a, v) v causalSize feedback n = let order = TypeNum.integralFromProxy n in Arrow.arr fst &&& feedback (Causal.zipWith merge >>>- Causal.replicateControlled order Filt1.lowpassCausal)+ Causal.replicateControlled order+ (Causal.fromModifier FirstOrder.lowpassModifier)) >>> Causal.zipWith amplify--{-# DEPRECATED causalP "use 'causal' instead" #-}-{-# DEPRECATED causalInitP "use 'causalInit' instead" #-}
src/Synthesizer/LLVM/Filter/NonRecursive.hs view
@@ -1,45 +1,44 @@-{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-}-{-# LANGUAGE FlexibleContexts #-} module Synthesizer.LLVM.Filter.NonRecursive ( convolve, convolvePacked, ) where -import qualified Synthesizer.LLVM.CausalParameterized.ProcessPrivate as CausalP-import qualified Synthesizer.LLVM.CausalParameterized.RingBuffer as RingBuffer-import qualified Synthesizer.LLVM.Frame.SerialVector as Serial+import qualified Synthesizer.LLVM.Causal.Process as Causal+import qualified Synthesizer.LLVM.Causal.Private as CausalPriv+import qualified Synthesizer.LLVM.Generator.Source as Source+import qualified Synthesizer.LLVM.Generator.Signal as Sig+import qualified Synthesizer.LLVM.RingBuffer as RingBuffer+import qualified Synthesizer.LLVM.Frame.SerialVector.Code as Serial -import qualified Synthesizer.LLVM.Storable.Vector as SVU-import qualified Data.StorableVector as SV+import qualified Synthesizer.Causal.Class as CausalClass+import Synthesizer.Causal.Class (($<)) -import qualified LLVM.DSL.Parameter as Param+import qualified LLVM.DSL.Expression as Expr+import LLVM.DSL.Expression (Exp) -import qualified LLVM.Extra.Storable as Storable-import qualified LLVM.Extra.Memory as Memory+import qualified LLVM.Extra.Multi.Value.Storable as Storable+import qualified LLVM.Extra.Multi.Value.Marshal as Marshal+import qualified LLVM.Extra.Multi.Value as MultiValue+import qualified LLVM.Extra.Multi.Vector as MultiVector import qualified LLVM.Extra.Control as C import qualified LLVM.Extra.Arithmetic as A import qualified LLVM.Extra.Tuple as Tuple import qualified LLVM.Core as LLVM-import LLVM.Core (Value, valueOf, CodeGenFunction, IsSized, SizeOf) import qualified Type.Data.Num.Decimal as TypeNum-import Type.Data.Num.Decimal.Number ((:*:)) -import Foreign.ForeignPtr (touchForeignPtr) import Foreign.Ptr (Ptr) import Data.Word (Word) import Control.Arrow ((<<<), (&&&)) import Control.Monad (liftM2) -import qualified Algebra.IntegralDomain as Integral- import NumericPrelude.Numeric import NumericPrelude.Base-+import Prelude () {-@@ -47,86 +46,75 @@ No Karatsuba, No Toom-Cook, No Fourier. -} convolve ::- (Storable.C a, Tuple.ValueOf a ~ al, Memory.C al, A.PseudoRing al) =>- Param.T p (SV.Vector a) -> CausalP.T p al al+ (Storable.C a, Marshal.C a, MultiValue.PseudoRing a, MultiValue.T a ~ am) =>+ Exp (Source.StorableVector a) -> Causal.T am am convolve mask =- let len = fmap SV.length mask- in CausalP.zipWith scalarProduct- (fmap (fromIntegral :: Int -> Word) len)- <<<- RingBuffer.trackConst A.zero len &&& provideMask mask+ let len = Source.storableVectorLength mask+ in (CausalPriv.zipWith (\(MultiValue.Cons l) -> scalarProduct l)+ $< Sig.constant len)+ <<<+ Causal.track Expr.zero len &&& provideMask mask convolvePacked ::- (TypeNum.Positive n, TypeNum.Positive (n :*: asize),- Storable.C a, Tuple.ValueOf a ~ Value al,- LLVM.IsArithmetic al, LLVM.IsPrimitive al, IsSized al, SizeOf al ~ asize) =>- Param.T p (SV.Vector a) ->- CausalP.T p (Serial.Value n al) (Serial.Value n al)-convolvePacked mask =- Serial.withSize $ \vectorSize ->- let len = fmap SV.length mask- in CausalP.zipWith scalarProductPacked- (fmap (fromIntegral :: Int -> Word) len)- <<<- RingBuffer.trackConst A.zero- (fmap (flip Integral.divUp vectorSize) len)- &&&- provideMask mask+ (Marshal.Vector n a, MultiVector.PseudoRing a) =>+ (Storable.C a, MultiValue.PseudoRing a, Serial.Value n a ~ v) =>+ Exp (Source.StorableVector a) -> Causal.T v v+convolvePacked = convolvePackedAux TypeNum.singleton +convolvePackedAux ::+ (Marshal.Vector n a, MultiVector.PseudoRing a) =>+ (Storable.C a, MultiValue.PseudoRing a, Serial.Value n a ~ v) =>+ TypeNum.Singleton n -> Exp (Source.StorableVector a) -> Causal.T v v+convolvePackedAux vectorSize mask =+ let len = Source.storableVectorLength mask+ in (CausalPriv.zipWith (\(MultiValue.Cons l) -> scalarProductPacked l)+ $< Sig.constant len)+ <<<+ Causal.track Expr.zero+ (divUp (TypeNum.integralFromSingleton vectorSize) len)+ &&&+ provideMask mask++divUp :: Exp Word -> Exp Word -> Exp Word+divUp k n = Expr.idiv (n+(k-1)) k+ provideMask ::- (Storable.C a) => Param.T p (SV.Vector a) -> CausalP.T p x (Value (Ptr a))+ (Storable.C a) =>+ Exp (Source.StorableVector a) -> Causal.T x (LLVM.Value (Ptr a)) provideMask mask =- CausalP.Cons- (\p () _x () -> return (p,()))- (return ())- return- (const $ const $ return ())- (\p ->- let (fp,ptr,_l) = SVU.unsafeToPointers $ Param.get mask p- in return (fp, (ptr, ())))- -- keep the foreign ptr alive- touchForeignPtr+ CausalClass.fromSignal $+ fmap (\(MultiValue.Cons (ptr,_l)) -> ptr) $+ Sig.constant mask scalarProduct ::- (Storable.C a, Tuple.ValueOf a ~ al, Memory.C al, A.PseudoRing al) =>- Value Word ->- RingBuffer.T al -> Value (Ptr a) ->- CodeGenFunction r al-scalarProduct n rb mask =+ (Storable.C a, Marshal.C a, MultiValue.T a ~ am, MultiValue.PseudoRing a) =>+ LLVM.Value Word ->+ (RingBuffer.T am, LLVM.Value (Ptr a)) ->+ LLVM.CodeGenFunction r am+scalarProduct n (rb,mask) = fmap snd $ Storable.arrayLoop n mask (A.zero, A.zero) $ \ptr (k, s) -> do a <- RingBuffer.index k rb b <- Storable.load ptr liftM2 (,) (A.inc k) (A.add s =<< A.mul a b) -_scalarProduct ::- (Storable.C a, IsSized a,- Tuple.ValueOf a ~ Value a, LLVM.IsArithmetic a) =>- Value Word ->- RingBuffer.T (Value a) -> Value (Ptr a) ->- CodeGenFunction r (Value a)-_scalarProduct = scalarProduct - scalarProductPacked ::- (Storable.C a,- Tuple.ValueOf a ~ Value al, LLVM.IsArithmetic al,- LLVM.IsPrimitive al, IsSized al, SizeOf al ~ asize,- TypeNum.Positive n, TypeNum.Positive (n :*: asize)) =>- Value Word ->- RingBuffer.T (Serial.Value n al) -> Value (Ptr a) ->- CodeGenFunction r (Serial.Value n al)-scalarProductPacked n0 rb mask0 = do+ (Storable.C a, Marshal.Vector n a, MultiVector.PseudoRing a) =>+ LLVM.Value Word ->+ (RingBuffer.T (Serial.Value n a), LLVM.Value (Ptr a)) ->+ LLVM.CodeGenFunction r (Serial.Value n a)+scalarProductPacked n0 (rb,mask0) = do (ax, rx) <- readSerialStart rb bx <- Storable.load mask0- sx <- A.scale bx ax+ sx <- Serial.scale bx ax n1 <- A.dec n0 mask1 <- Storable.incrementPtr mask0 fmap snd $ Storable.arrayLoop n1 mask1 (rx, sx) $ \ptr (r1, s1) -> do (a,r2) <- readSerialNext rb r1 b <- Storable.load ptr- fmap ((,) r2) (A.add s1 =<< A.scale b a)+ fmap ((,) r2) (A.add s1 =<< Serial.scale b a) type@@ -138,31 +126,29 @@ that is, from high to low indices. -} Serial.Value n a,- Value Word),- Value Word)+ LLVM.Value Word),+ LLVM.Value Word) readSerialStart ::- (LLVM.IsPrimitive a, IsSized a, SizeOf a ~ asize,- TypeNum.Positive n, TypeNum.Positive (n :*: asize)) =>+ (TypeNum.Positive n, Marshal.Vector n a) => RingBuffer.T (Serial.Value n a) ->- CodeGenFunction r (Serial.Value n a, Iterator n a)+ LLVM.CodeGenFunction r (Serial.Value n a, Iterator n a) readSerialStart rb = do a <- RingBuffer.index A.zero rb return (a, ((a, Tuple.undef, A.zero), A.zero)) readSerialNext ::- (LLVM.IsPrimitive a, IsSized a, SizeOf a ~ asize,- TypeNum.Positive n, TypeNum.Positive (n :*: asize)) =>+ (MultiValue.C a, Marshal.Vector n a) => RingBuffer.T (Serial.Value n a) -> Iterator n a ->- CodeGenFunction r (Serial.Value n a, Iterator n a)+ LLVM.CodeGenFunction r (Serial.Value n a, Iterator n a) readSerialNext rb ((a0,r0,j0), k0) = do vectorEnd <- A.cmp LLVM.CmpEQ j0 A.zero ((r1,j1), k1) <- C.ifThen vectorEnd ((r0,j0), k0) $ do k <- A.inc k0 r <- RingBuffer.index k rb- return ((r, valueOf (fromIntegral $ Serial.size r :: Word)), k)+ return ((r, LLVM.valueOf (Serial.size r :: Word)), k) j2 <- A.dec j1 (ai,r2) <- Serial.shiftUp Tuple.undef r1 (_, a1) <- Serial.shiftUp ai a0
src/Synthesizer/LLVM/Filter/SecondOrder.hs view
@@ -1,15 +1,18 @@ {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-}+{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FlexibleContexts #-} {-# OPTIONS_GHC -fno-warn-orphans #-} module Synthesizer.LLVM.Filter.SecondOrder ( Parameter(Parameter), Filt2.c0, Filt2.c1, Filt2.c2, Filt2.d1, Filt2.d2, bandpassParameter,+ bandpassParameterCode, ParameterStruct, composeParameter, decomposeParameter, -- for cascade+ composeParameterMV, decomposeParameterMV,+ causalExp, causal, causalPacked,- causalP, causalPackedP, ) where import qualified Synthesizer.Plain.Filter.Recursive.SecondOrder as Filt2@@ -17,11 +20,15 @@ import qualified Synthesizer.Plain.Modifier as Modifier -import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP-import qualified Synthesizer.LLVM.Causal.Process as Causal-import qualified Synthesizer.LLVM.Frame.SerialVector as Serial-import qualified Synthesizer.LLVM.Simple.Value as Value+import qualified Synthesizer.LLVM.Causal.Process as CausalExp+import qualified Synthesizer.LLVM.Causal.ProcessValue as Causal+import qualified Synthesizer.LLVM.Frame.SerialVector.Class as Serial+import qualified Synthesizer.LLVM.Value as Value +import qualified LLVM.DSL.Expression as Expr++import qualified LLVM.Extra.Multi.Value.Marshal as MarshalMV+import qualified LLVM.Extra.Multi.Value as MultiValue import qualified LLVM.Extra.Storable as Storable import qualified LLVM.Extra.Marshal as Marshal import qualified LLVM.Extra.Memory as Memory@@ -38,8 +45,14 @@ import qualified Control.Applicative.HT as App import Control.Arrow (arr, (<<<), (&&&)) import Control.Monad (liftM2, foldM)-import Control.Applicative (pure, (<$>), (<*>))+import Control.Applicative (pure, liftA2, (<$>), (<*>)) +import qualified Data.Foldable as Fold+import Data.Traversable (traverse)++import qualified Algebra.Transcendental as Trans+import qualified Algebra.Module as Module+ import NumericPrelude.Numeric import NumericPrelude.Base @@ -51,14 +64,6 @@ instance Tuple.Undefined a => Tuple.Undefined (Parameter a) where undef = Tuple.undefPointed -{--instance LLVM.ValueTuple a => LLVM.ValueTuple (Parameter a) where- buildTuple f = Class.buildTupleTraversable (LLVM.buildTuple f)--instance LLVM.IsTuple a => LLVM.IsTuple (Parameter a) where- tupleDesc = Class.tupleDescFoldable--}- instance (Tuple.Value a) => Tuple.Value (Parameter a) where type ValueOf (Parameter a) = Parameter (Tuple.ValueOf a) valueOf = Tuple.valueOfFunctor@@ -88,6 +93,18 @@ <*> LLVM.extractvalue param TypeNum.d3 <*> LLVM.extractvalue param TypeNum.d4 +decomposeParameterMV ::+ (MarshalMV.C a) =>+ LLVM.Value (MarshalMV.Struct (Parameter a)) ->+ CodeGenFunction r (Filt2.Parameter (MultiValue.T a))+decomposeParameterMV param =+ pure Filt2.Parameter+ <*> (Memory.decompose =<< LLVM.extractvalue param TypeNum.d0)+ <*> (Memory.decompose =<< LLVM.extractvalue param TypeNum.d1)+ <*> (Memory.decompose =<< LLVM.extractvalue param TypeNum.d2)+ <*> (Memory.decompose =<< LLVM.extractvalue param TypeNum.d3)+ <*> (Memory.decompose =<< LLVM.extractvalue param TypeNum.d4)+ composeParameter :: (LLVM.IsSized a) => Filt2.Parameter (LLVM.Value a) ->@@ -100,6 +117,20 @@ (\param -> LLVM.insertvalue param d2_ TypeNum.d4) =<< return (LLVM.value LLVM.undef) +composeParameterMV ::+ (MarshalMV.C a) =>+ Filt2.Parameter (MultiValue.T a) ->+ CodeGenFunction r (LLVM.Value (MarshalMV.Struct (Parameter a)))+composeParameterMV (Filt2.Parameter c0_ c1_ c2_ d1_ d2_) =+ let insert field ix param =+ Memory.compose field >>= flip (LLVM.insertvalue param) ix in+ insert c0_ TypeNum.d0 =<<+ insert c1_ TypeNum.d1 =<<+ insert c2_ TypeNum.d2 =<<+ insert d1_ TypeNum.d3 =<<+ insert d2_ TypeNum.d4 =<<+ return (LLVM.value LLVM.undef)+ instance (Memory.C a) => Memory.C (Parameter a) where type Struct (Parameter a) = ParameterStruct (Memory.Struct a) load = Memory.loadRecord parameterMemory@@ -124,8 +155,47 @@ flattenCode = Value.flattenCodeTraversable unfoldCode = Value.unfoldCodeTraversable +instance (MultiValue.C a) => MultiValue.C (Parameter a) where+ type Repr (Parameter a) = Parameter (MultiValue.Repr a)+ cons = parameterMultiValue . fmap MultiValue.cons+ undef = parameterMultiValue $ pure MultiValue.undef+ zero = parameterMultiValue $ pure MultiValue.zero+ phi bb =+ fmap parameterMultiValue .+ traverse (MultiValue.phi bb) .+ parameterUnMultiValue+ addPhi bb a b =+ Fold.sequence_ $+ liftA2 (MultiValue.addPhi bb)+ (parameterUnMultiValue a) (parameterUnMultiValue b) +instance (MarshalMV.C a) => MarshalMV.C (Parameter a) where+ pack p =+ case MarshalMV.pack <$> p of+ Filt2.Parameter c0_ c1_ c2_ d1_ d2_ ->+ LLVM.consStruct c0_ c1_ c2_ d1_ d2_+ unpack = fmap MarshalMV.unpack . LLVM.uncurryStruct Filt2.Parameter +parameterMultiValue ::+ Parameter (MultiValue.T a) -> MultiValue.T (Parameter a)+parameterMultiValue =+ MultiValue.Cons . fmap (\(MultiValue.Cons a) -> a)++parameterUnMultiValue ::+ MultiValue.T (Parameter a) -> Parameter (MultiValue.T a)+parameterUnMultiValue (MultiValue.Cons x) =+ fmap MultiValue.Cons x++instance+ (Expr.Aggregate e mv) =>+ Expr.Aggregate (Parameter e) (Parameter mv) where+ type MultiValuesOf (Parameter e) = Parameter (Expr.MultiValuesOf e)+ type ExpressionsOf (Parameter mv) = Parameter (Expr.ExpressionsOf mv)+ bundle = traverse Expr.bundle+ dissect = fmap Expr.dissect+++ instance (Tuple.Phi a) => Tuple.Phi (Filt2.State a) where phi = Tuple.phiTraversable addPhi = Tuple.addPhiFoldable@@ -159,25 +229,37 @@ flattenCode = Value.flattenCodeTraversable unfoldCode = Value.unfoldCodeTraversable +instance+ (Expr.Aggregate e mv) =>+ Expr.Aggregate (Filt2.State e) (Filt2.State mv) where+ type MultiValuesOf (Filt2.State e) = Filt2.State (Expr.MultiValuesOf e)+ type ExpressionsOf (Filt2.State mv) = Filt2.State (Expr.ExpressionsOf mv)+ bundle = traverse Expr.bundle+ dissect = fmap Expr.dissect + {-# DEPRECATED bandpassParameter "only for testing, use Universal or Moog filter for production code" #-}-bandpassParameter ::+bandpassParameterCode :: (A.Transcendental a, A.RationalConstant a) => a -> a -> CodeGenFunction r (Parameter a)-bandpassParameter reson cutoff = do+bandpassParameterCode reson cutoff = do rreson <- A.fdiv A.one reson k <- A.sub A.one rreson k2 <- A.neg =<< A.mul k k kcos <- A.mul (A.fromInteger' 2) =<< A.mul k =<< A.cos =<< A.mul cutoff =<<- Value.decons Value.twoPi- return $- Filt2.Parameter- rreson A.zero A.zero- kcos k2+ Value.decons Value.tau+ return $ Filt2.Parameter rreson A.zero A.zero kcos k2 +-- ToDo: move to synthesizer-core:Filter.SecondOrder (it is not the universal filter)+bandpassParameter :: (Trans.C a) => a -> a -> Parameter a+bandpassParameter reson cutoff =+ let rreson = recip reson+ k = one - rreson+ in Filt2.Parameter rreson zero zero (2*k*cos(2*pi*cutoff)) (-k*k)+ modifier :: (a ~ A.Scalar v, A.PseudoModule v, A.IntegerConstant a) => Modifier.Simple@@ -188,49 +270,38 @@ Filt2.modifier causal ::- (Causal.C process,- a ~ A.Scalar v, A.PseudoModule v, A.IntegerConstant a, Memory.C v) =>- process (Parameter a, v) v+ (a ~ A.Scalar v, A.PseudoModule v, A.IntegerConstant a, Memory.C v) =>+ Causal.T (Parameter a, v) v causal = Causal.fromModifier modifier -{-# DEPRECATED causalP "use causal instead" #-}-causalP ::- (a ~ A.Scalar v, A.PseudoModule v, A.IntegerConstant a, Memory.C v) =>- CausalP.T p (Parameter a, v) v-causalP =- CausalP.fromModifier modifier+causalExp ::+ (Expr.Aggregate ae a, Memory.C a, Module.C ae ve,+ Expr.Aggregate ve v, Memory.C v) =>+ CausalExp.T (Parameter a, v) v+causalExp =+ CausalExp.fromModifier Filt2.modifier -{-# DEPRECATED causalPackedP "use causalPacked instead" #-}-causalPackedP ::- (Serial.C v, Serial.Element v ~ a,- Memory.C v, Memory.C a, A.IntegerConstant v, A.IntegerConstant a,- A.PseudoRing v, A.PseudoRing a) =>- CausalP.T p (Parameter a, v) v-causalPackedP = causalPacked- {- | Vector size must be at least D2. -} causalPacked, causalRecursivePacked ::- (Causal.C process,- Serial.C v, Serial.Element v ~ a,+ (Serial.Write v, Serial.Element v ~ a, Memory.C v, Memory.C a, A.IntegerConstant v, A.IntegerConstant a, A.PseudoRing v, A.PseudoRing a) =>- process (Parameter a, v) v+ Causal.T (Parameter a, v) v causalPacked = causalRecursivePacked <<< (arr fst &&& causalNonRecursivePacked) _causalRecursivePackedAlt, causalNonRecursivePacked ::- (Causal.C process,- Serial.C v, Serial.Element v ~ a,+ (Serial.Write v, Serial.Element v ~ a, Memory.C a, A.IntegerConstant v, A.IntegerConstant a, A.PseudoRing v, A.PseudoRing a) =>- process (Parameter a, v) v+ Causal.T (Parameter a, v) v causalNonRecursivePacked = Causal.mapAccum (\(p, v0) (x1,x2) -> do@@ -283,7 +354,7 @@ d2v <- Serial.upsample (Filt2.d2 p) d2vn <- A.neg d2v - y1 <- Serial.extract (valueOf $ fromIntegral size - 1) y1v+ y1 <- Serial.last y1v xk1 <- Serial.modify (valueOf 0) (\u0 -> A.add u0 =<< A.mul (Filt2.d1 p) y1) =<<
src/Synthesizer/LLVM/Filter/SecondOrderCascade.hs view
@@ -1,35 +1,33 @@ {-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE UndecidableInstances #-} module Synthesizer.LLVM.Filter.SecondOrderCascade (- causal, causalPacked,- causalP, causalPackedP,+ causal, causalPacked,+ Parameter, ParameterValue(..), ParameterStruct, fixSize, constArray, ) where import qualified Synthesizer.LLVM.Filter.SecondOrder as Filt2-import qualified Synthesizer.Plain.Filter.Recursive.SecondOrder as Filt2Core -import qualified Synthesizer.LLVM.CausalParameterized.Functional as Func-import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP-import qualified Synthesizer.LLVM.Causal.Process as Causal-import qualified Synthesizer.LLVM.Simple.SignalPrivate as Sig-import Synthesizer.LLVM.CausalParameterized.Functional (($&), (&|&))+import qualified Synthesizer.LLVM.Causal.Functional as Func+import qualified Synthesizer.LLVM.Causal.Private as Causal+import qualified Synthesizer.LLVM.Generator.Private as Sig -import qualified Synthesizer.LLVM.Frame.SerialVector as Serial+import qualified Synthesizer.LLVM.Frame.SerialVector.Class as Serial import Synthesizer.Causal.Class (($<)) +import qualified LLVM.Extra.Multi.Value.Marshal as Marshal+import qualified LLVM.Extra.Multi.Value as MultiValue import qualified LLVM.Extra.Arithmetic as A import qualified LLVM.Extra.Tuple as Tuple-import qualified LLVM.Extra.ScalarOrVector as SoV import qualified LLVM.Extra.Memory as Memory import qualified LLVM.Core as LLVM-import LLVM.Core (Value, IsArithmetic, IsSized, CodeGenFunction) import qualified Type.Data.Num.Decimal as TypeNum import Type.Data.Num.Decimal.Number ((:*:))@@ -37,19 +35,16 @@ import Data.Word (Word) -import qualified Control.Arrow as Arrow-import Control.Arrow ((>>>), (<<<), (^<<), (&&&), arr)-import Control.Applicative (liftA2)-+import Control.Arrow ((<<<), (^<<), (&&&), arr) -import NumericPrelude.Numeric import NumericPrelude.Base -type ParameterStruct n a = LLVM.Array n (Filt2.ParameterStruct a)+type Parameter n a = MultiValue.Array n (Filt2.Parameter a)+type ParameterStruct n a = Marshal.Struct (Parameter n a) newtype ParameterValue n a =- ParameterValue {parameterValue :: Value (ParameterStruct n a)}+ ParameterValue {parameterValue :: MultiValue.T (Parameter n a)} {- Automatic deriving is not allowed even with GeneralizedNewtypeDeriving because of IsSized constraint@@ -59,24 +54,20 @@ Functor, App.Applicative, Fold.Foldable, Trav.Traversable) -} -instance (TypeNum.Natural n, IsSized a) =>+instance (TypeNum.Natural n, Marshal.C a) => Tuple.Phi (ParameterValue n a) where- phi bb (ParameterValue r) =- fmap ParameterValue $ Tuple.phi bb r- addPhi bb- (ParameterValue r)- (ParameterValue r') =- Tuple.addPhi bb r r'+ phi bb (ParameterValue r) = fmap ParameterValue $ MultiValue.phi bb r+ addPhi bb (ParameterValue r) (ParameterValue r') = MultiValue.addPhi bb r r' -instance (TypeNum.Natural n, IsSized a) =>+instance (TypeNum.Natural n, Marshal.C a) => Tuple.Undefined (ParameterValue n a) where- undef = ParameterValue Tuple.undef+ undef = ParameterValue MultiValue.undef -instance (TypeNum.Natural n, IsSized a) =>+instance (TypeNum.Natural n, Marshal.C a) => Tuple.Zero (ParameterValue n a) where- zero = ParameterValue Tuple.zero+ zero = ParameterValue MultiValue.zero -instance (TypeNum.Natural n, IsSized a,+instance (TypeNum.Natural n, Marshal.C a, TypeNum.Positive (n :*: LLVM.UnknownSize)) => Memory.C (ParameterValue n a) where type Struct (ParameterValue n a) = ParameterStruct n a@@ -103,54 +94,31 @@ fixSize _n = id constArray ::- (TypeNum.Natural n, IsSized a) =>- Proxy n -> [LLVM.ConstValue a] ->- LLVM.Value (LLVM.Array n a)-constArray _n = LLVM.value . LLVM.constArray---causalP ::- (Memory.C v, A.PseudoModule v, A.Scalar v ~ LLVM.Value a,- IsSized a, IsArithmetic a, SoV.IntegerConstant a, TypeNum.Natural n,- TypeNum.Positive (n :*: LLVM.UnknownSize)) =>- CausalP.T p (ParameterValue n a, v) v-causalP = causal--causalPackedP ::- (Memory.C v, A.PseudoRing v, A.IntegerConstant v, A.PseudoModule v,- Serial.C v, Serial.Element v ~ LLVM.Value a,- A.Scalar v ~ LLVM.Value a,- SoV.IntegerConstant a, LLVM.IsPrimitive a, IsSized a,- TypeNum.Positive (n :*: LLVM.UnknownSize),- TypeNum.Natural n) =>- CausalP.T p (ParameterValue n a, v) v-causalPackedP = causalPacked+ (TypeNum.Natural n, Marshal.C a) =>+ Proxy n -> [a] -> MultiValue.T (MultiValue.Array n a)+constArray _n = MultiValue.cons . MultiValue.Array causal ::- (Causal.C process,- Memory.C v, A.PseudoModule v, A.Scalar v ~ LLVM.Value a,- IsSized a, IsArithmetic a, SoV.IntegerConstant a, TypeNum.Natural n,- TypeNum.Positive (n :*: LLVM.UnknownSize)) =>- process (ParameterValue n a, v) v+ (A.PseudoModule v, Memory.C v, A.Scalar v ~ MultiValue.T a,+ Marshal.C a, MultiValue.IntegerConstant a,+ TypeNum.Natural n, TypeNum.Positive (n :*: LLVM.UnknownSize)) =>+ Causal.T (ParameterValue n a, v) v causal = causalGen Filt2.causal causalPacked ::- (Causal.C process,- A.PseudoRing v, A.IntegerConstant v,- Memory.C v, A.PseudoModule v, A.Scalar v ~ LLVM.Value a,- Serial.C v, Serial.Element v ~ LLVM.Value a,- SoV.IntegerConstant a, LLVM.IsPrimitive a, IsSized a,- TypeNum.Positive (n :*: LLVM.UnknownSize),- TypeNum.Natural n) =>- process (ParameterValue n a, v) v+ (Marshal.C a, MultiValue.PseudoRing a, MultiValue.IntegerConstant a,+ Serial.Write v, Serial.Element v ~ MultiValue.T a,+ Memory.C v, A.PseudoRing v, A.IntegerConstant v,+ TypeNum.Natural n, TypeNum.Positive (n :*: LLVM.UnknownSize)) =>+ Causal.T (ParameterValue n a, v) v causalPacked = causalGen Filt2.causalPacked causalGen ::- (Causal.C process, IsSized a, Tuple.Phi v, Tuple.Undefined v,+ (Marshal.C a, Tuple.Phi v, Tuple.Undefined v, TypeNum.Natural n, TypeNum.Positive (n :*: LLVM.UnknownSize)) =>- process (Filt2Core.Parameter (Value a), v) v ->- process (ParameterValue n a, v) v+ Causal.T (Filt2.Parameter (MultiValue.T a), v) v ->+ Causal.T (ParameterValue n a, v) v causalGen stage = withSize $ \n -> snd@@ -161,17 +129,17 @@ <<< Causal.map (\(ptr, (p,v)) -> do- LLVM.store (parameterValue p) ptr+ Memory.store (parameterValue p) ptr return (ptr, (A.zero, v))) $< Sig.alloca paramStage ::- (Causal.C process, IsSized a,- TypeNum.Natural n, TypeNum.Positive (n :*: LLVM.UnknownSize)) =>- process (Filt2Core.Parameter (Value a), v) v ->- process- (Value (LLVM.Ptr (ParameterStruct n a)), (Value Word, v)) (Value Word, v)+ (TypeNum.Natural n, Marshal.C a) =>+ Causal.T (Filt2.Parameter (MultiValue.T a), v) v ->+ Causal.T+ (LLVM.Value (LLVM.Ptr (ParameterStruct n a)), (LLVM.Value Word, v))+ (LLVM.Value Word, v) paramStage stage = let p = arr fst i = arr (fst.snd)@@ -183,59 +151,12 @@ &&& v) -_paramStage ::- (IsSized a,- TypeNum.Natural n, TypeNum.Positive (n :*: LLVM.UnknownSize)) =>- CausalP.T p (Filt2Core.Parameter (Value a), v) v ->- CausalP.T p- (Value (LLVM.Ptr (ParameterStruct n a)), (Value Word, v)) (Value Word, v)-_paramStage stage =- Func.withGuidedArgs (Func.atom, (Func.atom, Func.atom)) $ \(p,(i,v)) ->- liftA2 (,) (i+1)- (stage $&- (Causal.zipWith getStageParameterGEP $& p &|& i)- &|&- v)--_causalGenP ::- (Causal.C process, IsSized a,- TypeNum.Natural n, TypeNum.Positive (n :*: LLVM.UnknownSize)) =>- process (Filt2Core.Parameter (Value a), v) v ->- process (ParameterValue n a, v) v-_causalGenP stage =- withSize $ \n ->- foldl (\x y -> (arr fst &&& x) >>> y) (arr snd) $- map- (\k ->- stage <<<- Arrow.first (Causal.map (flip getStageParameter k)))- (take (TypeNum.integralFromSingleton n) [0..])---getStageParameter ::- (IsSized a,- TypeNum.Natural n, TypeNum.Positive (n :*: LLVM.UnknownSize)) =>- ParameterValue n a ->- Word ->- CodeGenFunction r (Filt2Core.Parameter (Value a))-getStageParameter ps k =- Filt2.decomposeParameter =<< LLVM.extractvalue (parameterValue ps) k-{-- Memory.decompose =<<- flip LLVM.extractvalue k =<<- Memory.compose ps--}- getStageParameterGEP ::- (IsSized a,- TypeNum.Natural n, TypeNum.Positive (n :*: LLVM.UnknownSize)) =>- Value (LLVM.Ptr (ParameterStruct n a)) ->- Value Word -> CodeGenFunction r (Filt2Core.Parameter (Value a))+ (TypeNum.Natural n, Marshal.C a) =>+ LLVM.Value (LLVM.Ptr (ParameterStruct n a)) ->+ LLVM.Value Word ->+ LLVM.CodeGenFunction r (Filt2.Parameter (MultiValue.T a)) getStageParameterGEP ptr k =- Filt2.decomposeParameter+ Filt2.decomposeParameterMV =<< LLVM.load =<< LLVM.getElementPtr0 ptr (k, ())---{-# DEPRECATED causalP "use 'causal' instead" #-}-{-# DEPRECATED causalPackedP "use 'causalPacked' instead" #-}
src/Synthesizer/LLVM/Filter/SecondOrderPacked.hs view
@@ -1,37 +1,34 @@ {-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE Rank2Types #-} {-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE UndecidableInstances #-} module Synthesizer.LLVM.Filter.SecondOrderPacked (- Parameter, bandpassParameter, State, causal, causalP,+ Parameter, ParameterExp, bandpassParameter, State, causal, ) where import qualified Synthesizer.LLVM.Filter.SecondOrder as Filt2L import qualified Synthesizer.Plain.Filter.Recursive.SecondOrder as Filt2 -import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP-import qualified Synthesizer.LLVM.Causal.Process as Causal-import qualified LLVM.Extra.ScalarOrVector as SoV-import qualified LLVM.Extra.Vector as Vector+import qualified Synthesizer.LLVM.Causal.Private as Causal++import qualified LLVM.DSL.Expression as Expr+import LLVM.DSL.Expression (Exp(Exp))++import qualified LLVM.Extra.Multi.Value.Marshal as Marshal+import qualified LLVM.Extra.Multi.Value as MultiValue+import qualified LLVM.Extra.Multi.Vector as MultiVector+import qualified LLVM.Extra.Tuple as Tuple import qualified LLVM.Extra.Memory as Memory import qualified LLVM.Extra.Arithmetic as A-import qualified LLVM.Extra.Tuple as Tuple import qualified LLVM.Core as LLVM-import LLVM.Core- (Value, valueOf, Struct,- IsFirstClass, IsFloating,- Vector, IsPrimitive, IsSized,- CodeGenFunction) -import qualified Type.Data.Num.Decimal as TypeNum-import Type.Data.Num.Decimal (D4, d0, d1, (:*:))+import Type.Data.Num.Decimal (D4, d0, d1) import Control.Applicative (liftA2) -import qualified Algebra.Transcendental as Trans- import NumericPrelude.Numeric import NumericPrelude.Base @@ -41,10 +38,9 @@ > c0 [c1 d1 c2 d2] -}-data Parameter a =- Parameter (Value a) (Value (Vector D4 a))+data Parameter a = Parameter (MultiValue.T a) (MultiVector.T D4 a) -instance (IsFirstClass a, IsPrimitive a) => Tuple.Phi (Parameter a) where+instance (MultiVector.C a) => Tuple.Phi (Parameter a) where phi bb (Parameter r i) = do r' <- Tuple.phi bb r i' <- Tuple.phi bb i@@ -53,23 +49,21 @@ Tuple.addPhi bb r r' Tuple.addPhi bb i i' -instance (IsFirstClass a, IsPrimitive a) => Tuple.Undefined (Parameter a) where+instance (MultiVector.C a) => Tuple.Undefined (Parameter a) where undef = Parameter Tuple.undef Tuple.undef -type ParameterStruct a = Struct (a, (Vector D4 a, ()))+type ParameterStruct a = Memory.Struct (MultiValue.T a, MultiVector.T D4 a) parameterMemory ::- (IsPrimitive a, IsSized a, TypeNum.Positive (D4 :*: LLVM.SizeOf a)) =>+ (Marshal.C a, Marshal.Vector D4 a) => Memory.Record r (ParameterStruct a) (Parameter a) parameterMemory = liftA2 Parameter (Memory.element (\(Parameter c0 _) -> c0) d0) (Memory.element (\(Parameter _ cd) -> cd) d1) -instance- (IsPrimitive a, IsSized a, TypeNum.Positive (D4 :*: LLVM.SizeOf a)) =>- Memory.C (Parameter a) where+instance (Marshal.C a, Marshal.Vector D4 a) => Memory.C (Parameter a) where type Struct (Parameter a) = ParameterStruct a load = Memory.loadRecord parameterMemory store = Memory.storeRecord parameterMemory@@ -77,44 +71,60 @@ compose = Memory.composeRecord parameterMemory -type State = Vector D4+data ParameterExp a =+ ParameterExp (forall r. LLVM.CodeGenFunction r (Parameter a)) +instance Expr.Aggregate (ParameterExp a) (Parameter a) where+ type MultiValuesOf (ParameterExp a) = Parameter a+ type ExpressionsOf (Parameter a) = ParameterExp a+ dissect x = ParameterExp (return x)+ bundle (ParameterExp code) = code ++type State = MultiVector.T D4++ {-# DEPRECATED bandpassParameter "only for testing, use Universal or Moog filter for production code" #-} bandpassParameter ::- (Trans.C a, IsFloating a, SoV.TranscendentalConstant a, IsPrimitive a) =>- Value a ->- Value a ->- CodeGenFunction r (Parameter a)-bandpassParameter reson cutoff = do- p <- Filt2L.bandpassParameter reson cutoff- v <- Vector.assemble [Filt2.c1 p, Filt2.d1 p, Filt2.c2 p, Filt2.d2 p]+ (MultiVector.C a, MultiValue.Transcendental a,+ MultiValue.RationalConstant a) =>+ Exp a -> Exp a -> ParameterExp a+bandpassParameter (Exp reson) (Exp cutoff) =+ ParameterExp (do+ r <- reson+ c <- cutoff+ bandpassParameterCode r c)++bandpassParameterCode ::+ (MultiVector.C a, MultiValue.Transcendental a,+ MultiValue.RationalConstant a) =>+ MultiValue.T a ->+ MultiValue.T a ->+ LLVM.CodeGenFunction r (Parameter a)+bandpassParameterCode reson cutoff = do+ p <- Filt2L.bandpassParameterCode reson cutoff+ v <-+ MultiVector.assembleFromVector $ fmap ($ p) $+ LLVM.consVector Filt2.c1 Filt2.d1 Filt2.c2 Filt2.d2 return $ Parameter (Filt2.c0 p) v next ::- (Vector.Arithmetic a) =>- (Parameter a, Value a) ->- Value (State a) ->- CodeGenFunction r (Value a, Value (State a))+ (MultiVector.PseudoRing a) =>+ (Parameter a, MultiValue.T a) ->+ State a ->+ LLVM.CodeGenFunction r (MultiValue.T a, State a) next (Parameter c0 k1, x0) y1 = do s0 <- A.mul c0 x0- s1 <- Vector.dotProduct k1 y1+ s1 <- MultiVector.dotProduct k1 y1 y0 <- A.add s0 s1- x1new <- Vector.extract (valueOf 0) y1- y1new <- Vector.extract (valueOf 1) y1- yv <- Vector.assemble [x0, y0, x1new, y1new]+ x1new <- MultiVector.extract (LLVM.valueOf 0) y1+ y1new <- MultiVector.extract (LLVM.valueOf 1) y1+ yv <- MultiVector.assembleFromVector $ LLVM.consVector x0 y0 x1new y1new return (y0, yv) causal ::- (Causal.C process,- Vector.Arithmetic a, Value (State a) ~ value, Memory.C value) =>- process (Parameter a, Value a) (Value a)-causal =- Causal.mapAccum next (return A.zero)--{-# DEPRECATED causalP "use causal instead" #-}-causalP ::- (Vector.Arithmetic a, Value (State a) ~ value, Memory.C value) =>- CausalP.T p (Parameter a, Value a) (Value a)-causalP = causal+ (MultiVector.PseudoRing a) =>+ (Marshal.Vector D4 a) =>+ Causal.T (Parameter a, MultiValue.T a) (MultiValue.T a)+causal = Causal.mapAccum next (return A.zero)
src/Synthesizer/LLVM/Filter/Universal.hs view
@@ -1,22 +1,31 @@ {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE MultiParamTypeClasses #-} {-# OPTIONS_GHC -fno-warn-orphans #-} module Synthesizer.LLVM.Filter.Universal ( Result(Result, lowpass, highpass, bandpass, bandlimit),- Parameter, parameter, causal, causalP,+ Parameter, parameter, causal,+ parameterCode, causalExp,+ multiValueResult, unMultiValueResult,+ multiValueParameter, unMultiValueParameter, ) where import qualified Synthesizer.Plain.Filter.Recursive.Universal as Universal import Synthesizer.Plain.Filter.Recursive.Universal- (Parameter(Parameter), Result)+ (Parameter(Parameter), Result(..)) import Synthesizer.Plain.Filter.Recursive (Pole(..)) import qualified Synthesizer.Plain.Modifier as Modifier -import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP-import qualified Synthesizer.LLVM.Causal.Process as Causal-import qualified Synthesizer.LLVM.Frame.SerialVector as Serial-import qualified Synthesizer.LLVM.Simple.Value as Value+import qualified Synthesizer.LLVM.Causal.Process as CausalExp+import qualified Synthesizer.LLVM.Causal.ProcessValue as Causal+import qualified Synthesizer.LLVM.Frame.SerialVector.Class as Serial+import qualified Synthesizer.LLVM.Value as Value +import qualified LLVM.DSL.Expression as Expr++import qualified LLVM.Extra.Multi.Value.Marshal as MarshalMV+import qualified LLVM.Extra.Multi.Value as MultiValue import qualified LLVM.Extra.Storable as Storable import qualified LLVM.Extra.Marshal as Marshal import qualified LLVM.Extra.Memory as Memory@@ -30,9 +39,15 @@ import Type.Data.Num.Decimal (d0, d1, d2, d3, d4, d5) import qualified Control.Applicative.HT as App-import Control.Applicative ((<$>))+import Control.Applicative (liftA2, (<$>)) +import qualified Data.Foldable as Fold+import Data.Traversable (traverse) +import qualified Algebra.Transcendental as Trans+import qualified Algebra.Module as Module++ instance (Tuple.Phi a) => Tuple.Phi (Parameter a) where phi = Tuple.phiTraversable addPhi = Tuple.addPhiFoldable@@ -74,14 +89,28 @@ load = Storable.loadApplicative store = Storable.storeFoldable -{--instance LLVM.ValueTuple a => LLVM.ValueTuple (Result a) where- buildTuple f = Class.buildTupleTraversable (LLVM.buildTuple f) -instance LLVM.IsTuple a => LLVM.IsTuple (Result a) where- tupleDesc = Class.tupleDescFoldable--} +type ResultStruct a = LLVM.Struct (a, (a, (a, (a, ()))))++resultMemory ::+ (Memory.C a) =>+ Memory.Record r (ResultStruct (Memory.Struct a)) (Result a)+resultMemory =+ App.lift4 Result+ (Memory.element Universal.highpass d0)+ (Memory.element Universal.bandpass d1)+ (Memory.element Universal.lowpass d2)+ (Memory.element Universal.bandlimit d3)+++instance (Memory.C a) => Memory.C (Result a) where+ type Struct (Result a) = ResultStruct (Memory.Struct a)+ load = Memory.loadRecord resultMemory+ store = Memory.storeRecord resultMemory+ decompose = Memory.decomposeRecord resultMemory+ compose = Memory.composeRecord resultMemory+ instance (Tuple.Value a) => Tuple.Value (Result a) where type ValueOf (Result a) = Result (Tuple.ValueOf a) valueOf = Tuple.valueOfFunctor@@ -91,15 +120,40 @@ flattenCode = Value.flattenCodeTraversable unfoldCode = Value.unfoldCodeTraversable +instance (MultiValue.C a) => MultiValue.C (Result a) where+ type Repr (Result a) = Result (MultiValue.Repr a)+ cons = multiValueResult . fmap MultiValue.cons+ undef = multiValueResult $ pure MultiValue.undef+ zero = multiValueResult $ pure MultiValue.zero+ phi bb =+ fmap multiValueResult .+ traverse (MultiValue.phi bb) . unMultiValueResult+ addPhi bb a b =+ Fold.sequence_ $+ liftA2 (MultiValue.addPhi bb)+ (unMultiValueResult a) (unMultiValueResult b) -{--instance LLVM.ValueTuple a => LLVM.ValueTuple (Parameter a) where- buildTuple f = Class.buildTupleTraversable (LLVM.buildTuple f)+multiValueResult ::+ Result (MultiValue.T a) -> MultiValue.T (Result a)+multiValueResult = MultiValue.Cons . fmap (\(MultiValue.Cons a) -> a) -instance LLVM.IsTuple a => LLVM.IsTuple (Parameter a) where- tupleDesc = Class.tupleDescFoldable--}+unMultiValueResult ::+ MultiValue.T (Result a) -> Result (MultiValue.T a)+unMultiValueResult (MultiValue.Cons x) = fmap MultiValue.Cons x +instance (MarshalMV.C a) => MarshalMV.C (Result a) where+ pack p =+ case MarshalMV.pack <$> p of+ Result hp bp lp bl -> LLVM.consStruct hp bp lp bl+ unpack = fmap MarshalMV.unpack . LLVM.uncurryStruct Result++instance (Expr.Aggregate e mv) => Expr.Aggregate (Result e) (Result mv) where+ type MultiValuesOf (Result e) = Result (Expr.MultiValuesOf e)+ type ExpressionsOf (Result mv) = Result (Expr.ExpressionsOf mv)+ bundle = traverse Expr.bundle+ dissect = fmap Expr.dissect++ instance (Tuple.Value a) => Tuple.Value (Parameter a) where type ValueOf (Parameter a) = Parameter (Tuple.ValueOf a) valueOf = Tuple.valueOfFunctor@@ -109,7 +163,43 @@ flattenCode = Value.flattenCodeTraversable unfoldCode = Value.unfoldCodeTraversable +instance (MultiValue.C a) => MultiValue.C (Parameter a) where+ type Repr (Parameter a) = Parameter (MultiValue.Repr a)+ cons = multiValueParameter . fmap MultiValue.cons+ undef = multiValueParameter $ pure MultiValue.undef+ zero = multiValueParameter $ pure MultiValue.zero+ phi bb =+ fmap multiValueParameter .+ traverse (MultiValue.phi bb) . unMultiValueParameter+ addPhi bb a b =+ Fold.sequence_ $+ liftA2 (MultiValue.addPhi bb)+ (unMultiValueParameter a) (unMultiValueParameter b) +multiValueParameter ::+ Parameter (MultiValue.T a) -> MultiValue.T (Parameter a)+multiValueParameter = MultiValue.Cons . fmap (\(MultiValue.Cons a) -> a)++unMultiValueParameter ::+ MultiValue.T (Parameter a) -> Parameter (MultiValue.T a)+unMultiValueParameter (MultiValue.Cons x) = fmap MultiValue.Cons x++instance (MarshalMV.C a) => MarshalMV.C (Parameter a) where+ pack p =+ case MarshalMV.pack <$> p of+ Parameter k1 k2 ampIn ampI1 ampI2 ampLimit ->+ LLVM.consStruct k1 k2 ampIn ampI1 ampI2 ampLimit+ unpack = fmap MarshalMV.unpack . LLVM.uncurryStruct Parameter++instance+ (Expr.Aggregate e mv) =>+ Expr.Aggregate (Parameter e) (Parameter mv) where+ type MultiValuesOf (Parameter e) = Parameter (Expr.MultiValuesOf e)+ type ExpressionsOf (Parameter mv) = Parameter (Expr.ExpressionsOf mv)+ bundle = traverse Expr.bundle+ dissect = fmap Expr.dissect++ instance (Vector.Simple v) => Vector.Simple (Parameter v) where type Element (Parameter v) = Parameter (Vector.Element v) type Size (Parameter v) = Vector.Size v@@ -146,7 +236,7 @@ readStart = Serial.readStartTraversable readNext = Serial.readNextTraversable -instance (Serial.C v) => Serial.C (Result v) where+instance (Serial.Write v) => Serial.Write (Result v) where type WriteIt (Result v) = Result (Serial.WriteIt v) insert = Serial.insertTraversable writeStart = Serial.writeStartTraversable@@ -154,14 +244,17 @@ writeStop = Serial.writeStopTraversable -parameter ::+parameterCode :: (A.Transcendental a, A.RationalConstant a) => a -> a -> CodeGenFunction r (Parameter a)-parameter =+parameterCode = Value.unlift2 $ \reson freq -> Universal.parameter (Pole reson freq) +parameter :: (Trans.C a) => a -> a -> Parameter a+parameter reson freq = Universal.parameter (Pole reson freq) + modifier :: (a ~ A.Scalar v, A.PseudoModule v, A.IntegerConstant a) => Modifier.Simple@@ -172,16 +265,14 @@ Universal.modifier causal ::- (Causal.C process,- a ~ A.Scalar v, A.PseudoModule v, A.IntegerConstant a, Memory.C v) =>- process (Parameter a, v) (Result v)+ (a ~ A.Scalar v, A.PseudoModule v, A.IntegerConstant a, Memory.C v) =>+ Causal.T (Parameter a, v) (Result v) causal = Causal.fromModifier modifier -{-# DEPRECATED causalP "use causal instead" #-}-causalP ::- (a ~ A.Scalar v, A.PseudoModule v, A.IntegerConstant a, Memory.C v) =>- CausalP.T p (Parameter a, v) (Result v)-causalP = causal+causalExp ::+ (Module.C ae ve, Expr.Aggregate ae a, Expr.Aggregate ve v, Memory.C v) =>+ CausalExp.T (Parameter a, v) (Result v)+causalExp = CausalExp.fromModifier Universal.modifier {- The state variable filter could be vectorised
src/Synthesizer/LLVM/ForeignPtr.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-} {- | Adding the finalizer to a ForeignPtr seems to be the only way that warrants execution of the finalizer (not too early and not never).@@ -12,6 +13,7 @@ module Synthesizer.LLVM.ForeignPtr where import qualified LLVM.DSL.Execution as Exec+import qualified LLVM.Extra.Multi.Value.Marshal as MarshalMV import qualified LLVM.Extra.Marshal as Marshal import qualified LLVM.ExecutionEngine as EE import qualified LLVM.Core as LLVM@@ -47,6 +49,14 @@ b -> IO (MemoryPtr a) newParam stop start b = newInit stop (Marshal.with b start)++newParamMV ::+ (MarshalMV.C b) =>+ Exec.Finalizer a ->+ (LLVM.Ptr (MarshalMV.Struct b) -> IO (LLVM.Ptr a)) ->+ b -> IO (MemoryPtr a)+newParamMV stop start b =+ newInit stop (MarshalMV.with b start) new :: (Marshal.C a, Marshal.Struct a ~ struct) =>
src/Synthesizer/LLVM/Frame/Binary.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-} module Synthesizer.LLVM.Frame.Binary ( toCanonical, ) where
src/Synthesizer/LLVM/Frame/SerialVector.hs view
@@ -1,8 +1,5 @@ {-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE EmptyDataDecls #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TypeOperators #-} {- | A special vector type that represents a time-sequence of samples. This way we can distinguish safely between LLVM vectors@@ -14,648 +11,99 @@ -} module Synthesizer.LLVM.Frame.SerialVector ( T(Cons),- Plain, Value,- plain, value, constant,-- Read, Element, ReadIt, extract, readStart, readNext,- C, WriteIt, insert, writeStart, writeNext, writeStop,- Zero, writeZero,- Iterator(Iterator), ReadIterator, WriteIterator, ReadMode, WriteMode,-- Sized, Size, size, sizeOfIterator, withSize,-- insertTraversable, extractTraversable,- readStartTraversable, readNextTraversable,- writeStartTraversable, writeNextTraversable, writeStopTraversable,- writeZeroTraversable,-- extractAll, assemble, modify,+ fromFixedList, upsample, subsample,- cumulate, iterate, iteratePlain, reverse,- shiftUp, shiftUpMultiZero, shiftDownMultiZero,- replicate, replicate_, replicateOf, fromList, fromFixedList,- mapPlain, mapV, zipV,+ shiftUp,+ reverse, iterate, cumulate,+ limit,+ select, cmp, ) where -import qualified Synthesizer.LLVM.Frame.Stereo as Stereo+import qualified Synthesizer.LLVM.Frame.SerialVector.Code as Code+import Synthesizer.LLVM.Frame.SerialVector.Code+ (T, fromMultiVector, toMultiVector) -import qualified LLVM.Extra.Vector as Vector+import qualified LLVM.DSL.Expression.Vector as ExprVec+import qualified LLVM.DSL.Expression as Expr+import LLVM.DSL.Expression (Exp)++import qualified LLVM.Extra.Multi.Vector as MultiVector+import qualified LLVM.Extra.Multi.Value.Vector as MultiValueVec+import qualified LLVM.Extra.Multi.Value as MultiValue import qualified LLVM.Extra.Arithmetic as A-import qualified LLVM.Extra.Tuple as Tuple-import qualified LLVM.Extra.Storable as Storable-import qualified LLVM.Extra.Marshal as Marshal-import qualified LLVM.Extra.Memory as Memory import qualified LLVM.Core as LLVM import qualified Type.Data.Num.Decimal as TypeNum -import qualified Foreign.Storable as St import Data.Word (Word32) -import Control.Monad (liftM2, liftM3, foldM, replicateM, (<=<))-import Control.Applicative (liftA2)-import qualified Control.Monad.Trans.State as MS-import qualified Control.Applicative as App-import qualified Data.Traversable as Trav--import qualified Data.NonEmpty.Class as NonEmptyC-import qualified Data.NonEmpty as NonEmpty-import qualified Data.List.HT as ListHT-import qualified Data.List as List-import Data.Tuple.HT (mapSnd, fst3, snd3, thd3)--import Prelude hiding (Read, replicate, reverse, iterate)---{--This datatype can be used for both Haskell vector and LLVM.Value Vector.-It should not contain tuples of vectors,-since the interpretation is:-"Everything inside Cons will be virtually concatenated."--We tried to use distinct types (T n a) and (Value n a)-for Haskell and LLVM objects, respectively,-but then GHC-6.12.3 to GHC-7.4.1 could not perform the GeneralizedNewtypeDeriving,-because it was not able to add a (IsPositive n ~ True) constraint-to the instances.--The disadvantage of this approach is,-that we cannot have a type that contains both parallel and serial data.--}-newtype T v = Cons v- deriving (- Eq, St.Storable,- Tuple.Zero, Tuple.Undefined,- A.IntegerConstant, A.RationalConstant, Num)--- SoV.IntegerConstant, SoV.RationalConstant, SoV.TranscendentalConstant)--instance (Tuple.Phi v) => Tuple.Phi (T v) where- phi bb (Cons v) = fmap Cons $ Tuple.phi bb v- addPhi bb (Cons x) (Cons y) = Tuple.addPhi bb x y--instance (A.Additive v) => A.Additive (T v) where- add = lift2 A.add- sub = lift2 A.sub- neg = lift1 A.neg- zero = Cons A.zero--instance (A.PseudoRing v) => A.PseudoRing (T v) where- mul = lift2 A.mul--instance (A.Real v) => A.Real (T v) where- min = lift2 A.min- max = lift2 A.max- abs = lift1 A.abs- signum = lift1 A.signum--instance (A.Fraction v) => A.Fraction (T v) where- truncate = lift1 A.truncate- fraction = lift1 A.fraction--instance (A.Field v) => A.Field (T v) where- fdiv = lift2 A.fdiv--instance (A.Algebraic v) => A.Algebraic (T v) where- sqrt = lift1 A.sqrt--instance (A.Transcendental v) => A.Transcendental (T v) where- pi = fmap Cons A.pi- sin = lift1 A.sin- log = lift1 A.log- exp = lift1 A.exp- cos = lift1 A.cos- pow = lift2 A.pow---lift1 :: Functor f => (a -> f b) -> T a -> f (T b)-lift1 f (Cons x) = fmap Cons $ f x--lift2 :: Functor f => (a -> b -> f c) -> T a -> T b -> f (T c)-lift2 f (Cons x) (Cons y) = fmap Cons $ f x y---type instance A.Scalar (T v) = A.Scalar v-instance (A.PseudoModule v) => A.PseudoModule (T v) where- scale a (Cons v) = fmap Cons $ A.scale a v---type Plain n a = T (LLVM.Vector n a)-type Value n a = T (LLVM.Value (LLVM.Vector n a))---plain :: LLVM.Vector n a -> Plain n a-plain = Cons--value :: LLVM.Value (LLVM.Vector n a) -> Value n a-value = Cons+import Prelude hiding (replicate, reverse, iterate) -replicate :: (TypeNum.Positive n) => a -> Plain n a-replicate x = Cons $ App.pure x--replicate_ :: (TypeNum.Positive n) => TypeNum.Singleton n -> a -> Plain n a-replicate_ _ = replicate--replicateOf :: (TypeNum.Positive n, LLVM.IsPrimitive a, LLVM.IsConst a) => a -> Value n a-replicateOf x = Cons $ LLVM.valueOf $ App.pure x--fromList :: (TypeNum.Positive n) => NonEmpty.T [] a -> Plain n a-fromList = Cons . LLVM.cyclicVector- fromFixedList ::- (TypeNum.Positive n) =>- LLVM.FixedList (TypeNum.ToUnary n) a -> Plain n a-fromFixedList = Cons . LLVM.vector+ (TypeNum.Positive n, MultiVector.C a) =>+ LLVM.FixedList (TypeNum.ToUnary n) a -> Exp (T n a)+fromFixedList = fromOrdinary . Expr.cons . LLVM.vector -constant :: (TypeNum.Positive n) => a -> T (Vector.Constant n a)-constant = Cons . Vector.constant -newtype Iterator mode it v = Iterator {unIterator :: it}- deriving (Tuple.Undefined)--instance Tuple.Phi it => Tuple.Phi (Iterator mode it v) where- phi bb (Iterator x) = fmap Iterator $ Tuple.phi bb x- addPhi bb (Iterator x) (Iterator y) = Tuple.addPhi bb x y---type ReadIterator = Iterator ReadMode-type WriteIterator = Iterator WriteMode--data ReadMode-data WriteMode---instance (Memory.C it) => Memory.C (Iterator mode it v) where- type Struct (Iterator mode it v) = Memory.Struct it- load = Memory.loadNewtype Iterator- store = Memory.storeNewtype (\(Iterator v) -> v)- decompose = Memory.decomposeNewtype Iterator- compose = Memory.composeNewtype (\(Iterator v) -> v)---fmapIt ::- (ita -> itb) -> (va -> vb) ->- Iterator mode ita va -> Iterator mode itb vb-fmapIt f _ (Iterator a) = Iterator (f a)---combineIt2 :: Iterator mode xa va -> Iterator mode xb vb -> Iterator mode (xa,xb) (va,vb)-combineIt2 (Iterator va) (Iterator vb) = Iterator (va,vb)--combineIt3 :: Iterator mode xa va -> Iterator mode xb vb -> Iterator mode xc vc -> Iterator mode (xa,xb,xc) (va,vb,vc)-combineIt3 (Iterator va) (Iterator vb) (Iterator vc) = Iterator (va,vb,vc)--combineItFunctor ::- (Functor f) =>- f (Iterator mode x v) -> Iterator mode (f x) (f v)-combineItFunctor =- Iterator . fmap unIterator--sequenceItFunctor ::- (Functor f) =>- Iterator mode (f it) (f v) ->- f (Iterator mode it v)-sequenceItFunctor =- fmap Iterator . unIterator---class- (TypeNum.Positive (Size v), Sized v,- Tuple.Phi (ReadIt v), Tuple.Undefined (ReadIt v),- Tuple.Phi v, Tuple.Undefined v) =>- Read v where-- type Element v :: *- type ReadIt v :: *-- extract :: LLVM.Value Word32 -> v -> LLVM.CodeGenFunction r (Element v)-- extractAll :: v -> LLVM.CodeGenFunction r [Element v]- extractAll x =- mapM- (flip extract x . LLVM.valueOf)- (take (size x) [0..])-- readStart :: v -> LLVM.CodeGenFunction r (ReadIterator (ReadIt v) v)- readNext ::- ReadIterator (ReadIt v) v ->- LLVM.CodeGenFunction r (Element v, ReadIterator (ReadIt v) v)--class (Read v, Tuple.Phi (WriteIt v), Tuple.Undefined (WriteIt v)) => C v where- type WriteIt v :: *-- insert :: LLVM.Value Word32 -> Element v -> v -> LLVM.CodeGenFunction r v-- assemble :: [Element v] -> LLVM.CodeGenFunction r v- assemble =- foldM (\v (k,x) -> insert (LLVM.valueOf k) x v) Tuple.undef .- zip [0..]-- writeStart :: LLVM.CodeGenFunction r (WriteIterator (WriteIt v) v)- writeNext ::- Element v -> WriteIterator (WriteIt v) v ->- LLVM.CodeGenFunction r (WriteIterator (WriteIt v) v)- writeStop :: WriteIterator (WriteIt v) v -> LLVM.CodeGenFunction r v--class (C v, Tuple.Phi (WriteIt v), Tuple.Zero (WriteIt v)) => Zero v where- -- initializes the target with zeros- -- you may only call 'writeStop' on the result of 'writeZero'- writeZero :: LLVM.CodeGenFunction r (WriteIterator (WriteIt v) v)--instance (Vector.Simple v) => Sized (T v) where- type Size (T v) = Vector.Size v--{- |-This instance also allows to wrap tuples of vectors,-but you cannot reasonably use them,-because it would mean to serialize vectors with different element types.--}-instance (Vector.Simple v) => Read (T v) where-- type Element (T v) = Vector.Element v- type ReadIt (T v) = v-- extract k (Cons v) = Vector.extract k v-- readStart (Cons v) = return $ Iterator v- readNext (Iterator v0) = do- x <- Vector.extract (LLVM.valueOf 0) v0- v1 <- Vector.rotateDown v0- return (x, Iterator v1)---instance (Vector.C v) => C (T v) where- type WriteIt (T v) = v-- insert k a (Cons v) = fmap Cons $ Vector.insert k a v-- writeStart = return (Iterator Tuple.undef)- writeNext x (Iterator v0) = do- v1 <- fmap snd $ Vector.shiftDown x v0- return (Iterator v1)- writeStop (Iterator v0) = return (Cons v0)--instance (Vector.C v, Tuple.Zero v) => Zero (T v) where- writeZero = return (Iterator Tuple.zero)---instance- (Read va, Read vb, Size va ~ Size vb) =>- Read (va, vb) where-- type Element (va, vb) = (Element va, Element vb)- type ReadIt (va, vb) = (ReadIt va, ReadIt vb)-- extract k (va,vb) =- liftM2 (,)- (extract k va)- (extract k vb)-- readStart (va,vb) =- liftM2 combineIt2 (readStart va) (readStart vb)- readNext it = do- (a, ita) <- readNext $ fmapIt fst fst it- (b, itb) <- readNext $ fmapIt snd snd it- return ((a,b), combineIt2 ita itb)--instance- (C va, C vb, Size va ~ Size vb) =>- C (va, vb) where-- type WriteIt (va, vb) = (WriteIt va, WriteIt vb)-- insert k (a,b) (va,vb) =- liftM2 (,)- (insert k a va)- (insert k b vb)-- writeStart =- liftM2 combineIt2 writeStart writeStart- writeNext (a,b) it =- liftM2 combineIt2- (writeNext a $ fmapIt fst fst it)- (writeNext b $ fmapIt snd snd it)- writeStop it =- liftM2 (,)- (writeStop (fmapIt fst fst it))- (writeStop (fmapIt snd snd it))--instance- (Zero va, Zero vb, Size va ~ Size vb) =>- Zero (va, vb) where-- writeZero =- liftM2 combineIt2 writeZero writeZero---instance- (Read va, Read vb, Read vc,- Size va ~ Size vb,- Size vb ~ Size vc) =>- Read (va, vb, vc) where-- type Element (va, vb, vc) = (Element va, Element vb, Element vc)- type ReadIt (va, vb, vc) = (ReadIt va, ReadIt vb, ReadIt vc)-- extract k (va,vb,vc) =- liftM3 (,,)- (extract k va)- (extract k vb)- (extract k vc)-- readStart (va,vb,vc) =- liftM3 combineIt3 (readStart va) (readStart vb) (readStart vc)- readNext it = do- (a, ita) <- readNext $ fmapIt fst3 fst3 it- (b, itb) <- readNext $ fmapIt snd3 snd3 it- (c, itc) <- readNext $ fmapIt thd3 thd3 it- return ((a,b,c), combineIt3 ita itb itc)---instance- (C va, C vb, C vc,- Size va ~ Size vb,- Size vb ~ Size vc) =>- C (va, vb, vc) where-- type WriteIt (va, vb, vc) = (WriteIt va, WriteIt vb, WriteIt vc)-- insert k (a,b,c) (va,vb,vc) =- liftM3 (,,)- (insert k a va)- (insert k b vb)- (insert k c vc)-- writeStart =- liftM3 combineIt3 writeStart writeStart writeStart- writeNext (a,b,c) it =- liftM3 combineIt3- (writeNext a $ fmapIt fst3 fst3 it)- (writeNext b $ fmapIt snd3 snd3 it)- (writeNext c $ fmapIt thd3 thd3 it)- writeStop it =- liftM3 (,,)- (writeStop (fmapIt fst3 fst3 it))- (writeStop (fmapIt snd3 snd3 it))- (writeStop (fmapIt thd3 thd3 it))--instance- (Zero va, Zero vb, Zero vc,- Size va ~ Size vb,- Size vb ~ Size vc) =>- Zero (va, vb, vc) where-- writeZero =- liftM3 combineIt3 writeZero writeZero writeZero---instance (Read v) => Read (Stereo.T v) where-- type Element (Stereo.T v) = Stereo.T (Element v)- type ReadIt (Stereo.T v) = Stereo.T (ReadIt v)-- extract = extractTraversable-- readStart = readStartTraversable- readNext = readNextTraversable--instance (C v) => C (Stereo.T v) where-- type WriteIt (Stereo.T v) = Stereo.T (WriteIt v)-- insert = insertTraversable-- writeStart = writeStartTraversable- writeNext = writeNextTraversable- writeStop = writeStopTraversable--instance (Zero v) => Zero (Stereo.T v) where-- writeZero = writeZeroTraversable---modify ::- (C v) =>- LLVM.Value Word32 ->- (Element v -> LLVM.CodeGenFunction r (Element v)) ->- v -> LLVM.CodeGenFunction r v-modify k f v = do- flip (insert k) v =<< f =<< extract k v---subsample ::- (Read v) =>- v -> LLVM.CodeGenFunction r (Element v)-subsample v =- extract (A.zero :: LLVM.Value Word32) v+subsample :: (TypeNum.Positive n, MultiVector.C a) => Exp (T n a) -> Exp a+subsample =+ Expr.liftM (MultiValueVec.extract (A.zero :: LLVM.Value Word32)) . toOrdinary --- this will be translated to an efficient pshufd-upsample ::- (C v) =>- Element v -> LLVM.CodeGenFunction r v-upsample x =- withSize $ \n -> assemble $ List.replicate n x+upsample :: (TypeNum.Positive n, MultiVector.C a) => Exp a -> Exp (T n a)+upsample = fromOrdinary . ExprVec.replicate -cumulate ::- (Vector.Arithmetic a, TypeNum.Positive n) =>- LLVM.Value a -> Value n a ->- LLVM.CodeGenFunction r (LLVM.Value a, Value n a)-cumulate x (Cons v) =- fmap (mapSnd Cons) $ Vector.cumulate x v+shiftUp ::+ (TypeNum.Positive n, MultiVector.C x, Exp x ~ a, Exp (T n x) ~ v) =>+ a -> v -> (a, v)+shiftUp a v =+ (Expr.liftM2 ((fmap fst .) . Code.shiftUp) a v,+ Expr.liftM2 ((fmap snd .) . Code.shiftUp) a v) -mapPlain ::- (TypeNum.Positive n) => (a -> b) -> Plain n a -> Plain n b-mapPlain f (Cons v) = Cons $ fmap f v--iteratePlain ::- (TypeNum.Positive n) => (a -> a) -> a -> Plain n a-iteratePlain f x = fromList $ NonEmptyC.iterate f x- iterate ::- (C v) =>- (Element v -> LLVM.CodeGenFunction r (Element v)) ->- Element v -> LLVM.CodeGenFunction r v-iterate f x =- withSize $ \n ->- assemble =<<- (flip MS.evalStateT x $- replicateM n $- MS.StateT $ \x0 -> do x1 <- f x0; return (x0,x1))+ (TypeNum.Positive n, MultiVector.C a) =>+ (Exp a -> Exp a) -> Exp a -> Exp (T n a)+iterate f = fromOrdinary . ExprVec.iterate f reverse ::- (C v) =>- v -> LLVM.CodeGenFunction r v+ (TypeNum.Positive n, MultiVector.C a) =>+ Exp (T n a) -> Exp (T n a) reverse =- assemble . List.reverse <=< extractAll--shiftUp ::- (C v) =>- Element v -> v -> LLVM.CodeGenFunction r (Element v, v)-shiftUp x v =- ListHT.switchR- (return (x,v))- (\ys0 y -> fmap ((,) y) $ assemble (x:ys0))- =<<- extractAll v---shiftUpMultiZero ::- (C v, A.Additive (Element v)) =>- Int -> v -> LLVM.CodeGenFunction r v-shiftUpMultiZero n v =- assemble . take (size v) . (List.replicate n A.zero ++) =<< extractAll v--shiftDownMultiZero ::- (C v, A.Additive (Element v)) =>- Int -> v -> LLVM.CodeGenFunction r v-shiftDownMultiZero n v =- assemble . take (size v) . (++ List.repeat A.zero) . List.drop n- =<< extractAll v---insertTraversable ::- (C v, Trav.Traversable f, App.Applicative f) =>- LLVM.Value Word32 -> f (Element v) -> f v -> LLVM.CodeGenFunction r (f v)-insertTraversable n a v =- Trav.sequence (liftA2 (insert n) a v)--extractTraversable ::- (Read v, Trav.Traversable f) =>- LLVM.Value Word32 -> f v -> LLVM.CodeGenFunction r (f (Element v))-extractTraversable n v =- Trav.mapM (extract n) v---readStartTraversable ::- (Trav.Traversable f, App.Applicative f, Read v) =>- f v -> LLVM.CodeGenFunction r (ReadIterator (f (ReadIt v)) (f v))-readNextTraversable ::- (Trav.Traversable f, App.Applicative f, Read v) =>- ReadIterator (f (ReadIt v)) (f v) ->- LLVM.CodeGenFunction r (f (Element v), ReadIterator (f (ReadIt v)) (f v))--readStartTraversable v =- fmap combineItFunctor $ Trav.mapM readStart v--readNextTraversable it = do- st <- Trav.mapM readNext $ sequenceItFunctor it- return (fmap fst st, combineItFunctor $ fmap snd st)---writeStartTraversable ::- (Trav.Traversable f, App.Applicative f, C v) =>- LLVM.CodeGenFunction r (WriteIterator (f (WriteIt v)) (f v))-writeNextTraversable ::- (Trav.Traversable f, App.Applicative f, C v) =>- f (Element v) -> WriteIterator (f (WriteIt v)) (f v) ->- LLVM.CodeGenFunction r (WriteIterator (f (WriteIt v)) (f v))-writeStopTraversable ::- (Trav.Traversable f, App.Applicative f, C v) =>- WriteIterator (f (WriteIt v)) (f v) -> LLVM.CodeGenFunction r (f v)-writeZeroTraversable ::- (Trav.Traversable f, App.Applicative f, Zero v) =>- LLVM.CodeGenFunction r (WriteIterator (f (WriteIt v)) (f v))--writeStartTraversable =- fmap combineItFunctor $ Trav.sequence $ App.pure writeStart--writeNextTraversable x it =- fmap combineItFunctor $ Trav.sequence $- liftA2 writeNext x $ sequenceItFunctor it--writeStopTraversable = Trav.mapM writeStop . sequenceItFunctor--writeZeroTraversable =- fmap combineItFunctor $ Trav.sequence $ App.pure writeZero---instance (Tuple.Value v) => Tuple.Value (T v) where- type ValueOf (T v) = T (Tuple.ValueOf v)- valueOf (Cons v) = Cons (Tuple.valueOf v)--instance (Memory.C v) => Memory.C (T v) where- type Struct (T v) = Memory.Struct v- load = Memory.loadNewtype Cons- store = Memory.storeNewtype (\(Cons v) -> v)- decompose = Memory.decomposeNewtype Cons- compose = Memory.composeNewtype (\(Cons v) -> v)--instance (Marshal.C v) => Marshal.C (T v) where- pack (Cons v) = Marshal.pack v- unpack v = Cons $ Marshal.unpack v--instance (Storable.C v) => Storable.C (T v) where- load = Storable.loadNewtype Cons Cons- store = Storable.storeNewtype Cons (\(Cons v) -> v)+ Expr.liftM (fmap fromMultiVector . MultiVector.reverse . toMultiVector) -mapV :: (Functor m) =>- (LLVM.Value (LLVM.Vector n a) -> m (LLVM.Value (LLVM.Vector n b))) ->- Value n a -> m (Value n b)-mapV f (Cons x) = fmap Cons (f x)--zipV :: (Functor m) =>- (c -> d) ->- (LLVM.Value (LLVM.Vector n a) ->- LLVM.Value (LLVM.Vector n b) ->- m c) ->- Value n a ->- Value n b ->- m d-zipV g f (Cons x) (Cons y) =- fmap g (f x y)+cumulate ::+ (TypeNum.Positive n, MultiVector.Additive a) =>+ Exp a -> Exp (T n a) -> (Exp a, Exp (T n a))+cumulate a v =+ (Expr.liftM2 ((fmap fst .) . Code.cumulate) a v,+ Expr.liftM2 ((fmap snd .) . Code.cumulate) a v) +limit ::+ (TypeNum.Positive n, MultiVector.Real a) =>+ (Exp (T n a), Exp (T n a)) -> Exp (T n a) -> Exp (T n a)+limit (l,u) =+ fromOrdinary . ExprVec.limit (toOrdinary l, toOrdinary u) . toOrdinary -withSize :: Sized v => (Int -> m v) -> m v-withSize =- let sz :: (Sized v) => TypeNum.Singleton (Size v) -> (Int -> m v) -> m v- sz n f = f (TypeNum.integralFromSingleton n)- in sz TypeNum.singleton--size :: Sized v => v -> Int-size =- let sz :: (Sized v) => TypeNum.Singleton (Size v) -> v -> Int- sz n _ = TypeNum.integralFromSingleton n- in sz TypeNum.singleton+cmp ::+ (TypeNum.Positive n, MultiVector.Comparison a) =>+ LLVM.CmpPredicate -> Exp (T n a) -> Exp (T n a) -> Exp (T n Bool)+cmp ord a b = fromOrdinary $ ExprVec.cmp ord (toOrdinary a) (toOrdinary b) -sizeOfIterator :: Sized v => Iterator mode it v -> Int-sizeOfIterator =- let sz :: Sized v => TypeNum.Singleton (Size v) -> Iterator mode it v -> Int- sz n _ = TypeNum.integralFromSingleton n- in sz TypeNum.singleton+select ::+ (TypeNum.Positive n, MultiVector.Select a) =>+ Exp (T n Bool) -> Exp (T n a) -> Exp (T n a) -> Exp (T n a)+select c a b =+ fromOrdinary $ ExprVec.select (toOrdinary c) (toOrdinary a) (toOrdinary b) -{- |-The type parameter @value@ shall be a virtual LLVM register-or a wrapper around one or more virtual LLVM registers.--}-class (TypeNum.Positive (Size valueTuple)) => Sized valueTuple where- type Size valueTuple :: *--{- |-Basic LLVM types are all counted as scalar values, even LLVM Vectors.-This means that an LLVM Vector can be used for parallel handling of data.--}-instance Sized (LLVM.Value a) where- type Size (LLVM.Value a) = TypeNum.D1--instance (Sized value) => Sized (Stereo.T value) where- type Size (Stereo.T value) = Size value--instance- (Sized value0, Sized value1,- Size value0 ~ Size value1) =>- Sized (value0, value1) where- type Size (value0, value1) = Size value0+fromOrdinary :: Exp (LLVM.Vector n a) -> Exp (T n a)+fromOrdinary = Expr.lift1 MultiValue.cast -instance- (Sized value0, Sized value1, Sized value2,- Size value0 ~ Size value1,- Size value1 ~ Size value2) =>- Sized (value0, value1, value2) where- type Size (value0, value1, value2) = Size value0+toOrdinary :: Exp (T n a) -> Exp (LLVM.Vector n a)+toOrdinary = Expr.lift1 MultiValue.cast
+ src/Synthesizer/LLVM/Frame/SerialVector/Class.hs view
@@ -0,0 +1,523 @@+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE EmptyDataDecls #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE StandaloneDeriving #-}+{- |+A special vector type that represents a time-sequence of samples.+This way we can distinguish safely between LLVM vectors+used for parallel signals and pipelines and+those used for chunky processing of scalar signals.+For the chunky processing this data type allows us+to derive the factor from the type+that time constants have to be multiplied with.+-}+module Synthesizer.LLVM.Frame.SerialVector.Class (+ Constant(Constant), constant,++ Read, Element, ReadIt, extract, readStart, readNext,+ Write, WriteIt, insert, writeStart, writeNext, writeStop,+ Zero, writeZero,+ Iterator(Iterator), ReadIterator, WriteIterator, ReadMode, WriteMode,++ Sized, Size, size, sizeOfIterator, withSize,++ insertTraversable, extractTraversable,+ readStartTraversable, readNextTraversable,+ writeStartTraversable, writeNextTraversable, writeStopTraversable,+ writeZeroTraversable,++ dissect, assemble, modify,+ upsample, subsample, last,+ iterate, reverse,+ shiftUp, shiftUpMultiZero, shiftDownMultiZero,+ ) where++import qualified Synthesizer.LLVM.Frame.SerialVector.Code as SerialCode+import qualified Synthesizer.LLVM.Frame.Stereo as Stereo++import qualified LLVM.Extra.Multi.Vector as MultiVector+import qualified LLVM.Extra.Multi.Value as MultiValue+import qualified LLVM.Extra.Memory as Memory+import qualified LLVM.Extra.Arithmetic as A+import qualified LLVM.Extra.Tuple as Tuple++import qualified LLVM.Core as LLVM++import qualified Type.Data.Num.Decimal as TypeNum++import Data.Word (Word32)++import qualified Control.Monad.Trans.State as MS+import qualified Control.Applicative as App+import Control.Monad (foldM, replicateM, (<=<))+import Control.Applicative (liftA2, liftA3, (<$>))++import qualified Data.Traversable as Trav+import qualified Data.List.HT as ListHT+import qualified Data.List as List+import Data.Tuple.HT (mapSnd, fst3, snd3, thd3)++import Prelude hiding (Read, replicate, reverse, iterate, last)++++newtype Constant n a = Constant a++constant :: (TypeNum.Positive n) => a -> Constant n a+constant = Constant++instance Functor (Constant n) where+ fmap f (Constant a) = Constant (f a)++instance App.Applicative (Constant n) where+ pure = Constant+ Constant f <*> Constant a = Constant (f a)++instance (Tuple.Phi a) => Tuple.Phi (Constant n a) where+ phi bb (Constant a) = Constant <$> Tuple.phi bb a+ addPhi bb (Constant a) (Constant b) = Tuple.addPhi bb a b++instance (Tuple.Undefined a) => Tuple.Undefined (Constant n a) where+ undef = Tuple.undefPointed++++instance (TypeNum.Positive n) => Sized (Constant n a) where+ type Size (Constant n a) = n++instance+ (TypeNum.Positive n, Tuple.Phi a, Tuple.Undefined a) =>+ Read (Constant n a) where++ type Element (Constant n a) = a+ type ReadIt (Constant n a) = a++ extract _k (Constant a) = return a++ readStart (Constant a) = return $ Iterator a+ readNext it@(Iterator a) = return (a, it)++++newtype Iterator mode it v = Iterator {unIterator :: it}+ deriving (Tuple.Undefined)++instance Tuple.Phi it => Tuple.Phi (Iterator mode it v) where+ phi bb (Iterator x) = fmap Iterator $ Tuple.phi bb x+ addPhi bb (Iterator x) (Iterator y) = Tuple.addPhi bb x y+++type ReadIterator = Iterator ReadMode+type WriteIterator = Iterator WriteMode++data ReadMode+data WriteMode+++instance (Memory.C it) => Memory.C (Iterator mode it v) where+ type Struct (Iterator mode it v) = Memory.Struct it+ load = Memory.loadNewtype Iterator+ store = Memory.storeNewtype (\(Iterator v) -> v)+ decompose = Memory.decomposeNewtype Iterator+ compose = Memory.composeNewtype (\(Iterator v) -> v)+++fmapIt ::+ (ita -> itb) -> (va -> vb) ->+ Iterator mode ita va -> Iterator mode itb vb+fmapIt f _ (Iterator a) = Iterator (f a)+++combineIt2 ::+ Iterator mode xa va -> Iterator mode xb vb ->+ Iterator mode (xa,xb) (va,vb)+combineIt2 (Iterator va) (Iterator vb) = Iterator (va,vb)++combineIt3 ::+ Iterator mode xa va -> Iterator mode xb vb -> Iterator mode xc vc ->+ Iterator mode (xa,xb,xc) (va,vb,vc)+combineIt3 (Iterator va) (Iterator vb) (Iterator vc) = Iterator (va,vb,vc)++combineItFunctor ::+ (Functor f) => f (Iterator mode x v) -> Iterator mode (f x) (f v)+combineItFunctor = Iterator . fmap unIterator++sequenceItFunctor ::+ (Functor f) => Iterator mode (f it) (f v) -> f (Iterator mode it v)+sequenceItFunctor = fmap Iterator . unIterator+++withSize :: Sized v => (Int -> m v) -> m v+withSize =+ let sz :: (Sized v) => TypeNum.Singleton (Size v) -> (Int -> m v) -> m v+ sz n f = f (TypeNum.integralFromSingleton n)+ in sz TypeNum.singleton++size :: (Sized v, Integral i) => v -> i+size =+ let sz :: (Sized v, Integral i) => TypeNum.Singleton (Size v) -> v -> i+ sz n _ = TypeNum.integralFromSingleton n+ in sz TypeNum.singleton++sizeOfIterator :: (Sized v, Integral i) => Iterator mode it v -> i+sizeOfIterator =+ let sz :: (Sized v, Integral i) =>+ TypeNum.Singleton (Size v) -> Iterator mode it v -> i+ sz n _ = TypeNum.integralFromSingleton n+ in sz TypeNum.singleton+++{- |+The type parameter @v@ shall be a @MultiVector@ or @MultiValue Serial@+or a wrapper around one or more such things sharing the same size.+-}+class (TypeNum.Positive (Size v)) => Sized v where+ type Size v++class+ (Sized v,+ Tuple.Phi (ReadIt v), Tuple.Undefined (ReadIt v),+ Tuple.Phi v, Tuple.Undefined v) =>+ Read v where++ type Element v+ type ReadIt v++ extract :: LLVM.Value Word32 -> v -> LLVM.CodeGenFunction r (Element v)++ dissect :: v -> LLVM.CodeGenFunction r [Element v]+ dissect x = mapM (flip extract x . LLVM.valueOf) (take (size x) [0..])++ readStart :: v -> LLVM.CodeGenFunction r (ReadIterator (ReadIt v) v)+ readNext ::+ ReadIterator (ReadIt v) v ->+ LLVM.CodeGenFunction r (Element v, ReadIterator (ReadIt v) v)++class+ (Read v, Tuple.Phi (WriteIt v), Tuple.Undefined (WriteIt v)) =>+ Write v where+ type WriteIt v++ insert :: LLVM.Value Word32 -> Element v -> v -> LLVM.CodeGenFunction r v++ assemble :: [Element v] -> LLVM.CodeGenFunction r v+ assemble =+ foldM (\v (k,x) -> insert (LLVM.valueOf k) x v) Tuple.undef . zip [0..]++ writeStart :: LLVM.CodeGenFunction r (WriteIterator (WriteIt v) v)+ writeNext ::+ Element v -> WriteIterator (WriteIt v) v ->+ LLVM.CodeGenFunction r (WriteIterator (WriteIt v) v)+ writeStop :: WriteIterator (WriteIt v) v -> LLVM.CodeGenFunction r v++class (Write v, Tuple.Phi (WriteIt v), Tuple.Zero (WriteIt v)) => Zero v where+ -- initializes the target with zeros+ -- you may only call 'writeStop' on the result of 'writeZero'+ writeZero :: LLVM.CodeGenFunction r (WriteIterator (WriteIt v) v)++++instance (TypeNum.Positive n) => Sized (MultiVector.T n a) where+ type Size (MultiVector.T n a) = n++instance (TypeNum.Positive n, MultiVector.C a) => Read (MultiVector.T n a) where++ type Element (MultiVector.T n a) = MultiValue.T a+ type ReadIt (MultiVector.T n a) = MultiVector.T n a++ extract = MultiVector.extract++ readStart v = return $ Iterator v+ readNext (Iterator v) =+ mapSnd Iterator <$> MultiVector.shiftDown MultiValue.undef v++instance+ (TypeNum.Positive n, MultiVector.C a) => Write (MultiVector.T n a) where++ type WriteIt (MultiVector.T n a) = MultiVector.T n a++ insert = MultiVector.insert++ writeStart = return (Iterator MultiVector.undef)+ writeNext x (Iterator v) = Iterator . snd <$> MultiVector.shiftDown x v+ writeStop (Iterator v) = return v++instance (TypeNum.Positive n, MultiVector.C a) => Zero (MultiVector.T n a) where+ writeZero = return (Iterator Tuple.zero)++++type Serial n a = SerialCode.Value n a++instance (TypeNum.Positive n) => Sized (Serial n a) where+ type Size (Serial n a) = n++instance (TypeNum.Positive n, MultiVector.C a) => Read (Serial n a) where++ type Element (Serial n a) = MultiValue.T a+ type ReadIt (Serial n a) = Serial n a++ extract = SerialCode.extract++ readStart v = return $ Iterator v+ readNext (Iterator v) =+ mapSnd Iterator <$> SerialCode.shiftDown MultiValue.undef v++instance (TypeNum.Positive n, MultiVector.C a) => Write (Serial n a) where++ type WriteIt (Serial n a) = Serial n a++ insert = SerialCode.insert++ writeStart = return (Iterator Tuple.undef)+ writeNext x (Iterator v) = Iterator . snd <$> SerialCode.shiftDown x v+ writeStop (Iterator v) = return v++instance (TypeNum.Positive n, MultiVector.C a) => Zero (Serial n a) where+ writeZero = return (Iterator Tuple.zero)++++instance (Sized va, Sized vb, Size va ~ Size vb) => Sized (va, vb) where+ type Size (va, vb) = Size va++instance (Read va, Read vb, Size va ~ Size vb) => Read (va, vb) where++ type Element (va, vb) = (Element va, Element vb)+ type ReadIt (va, vb) = (ReadIt va, ReadIt vb)++ extract k (va,vb) = liftA2 (,) (extract k va) (extract k vb)++ readStart (va,vb) = liftA2 combineIt2 (readStart va) (readStart vb)+ readNext it = do+ (a, ita) <- readNext $ fmapIt fst fst it+ (b, itb) <- readNext $ fmapIt snd snd it+ return ((a,b), combineIt2 ita itb)++instance (Write va, Write vb, Size va ~ Size vb) => Write (va, vb) where++ type WriteIt (va, vb) = (WriteIt va, WriteIt vb)++ insert k (a,b) (va,vb) =+ liftA2 (,)+ (insert k a va)+ (insert k b vb)++ writeStart = liftA2 combineIt2 writeStart writeStart+ writeNext (a,b) it =+ liftA2 combineIt2+ (writeNext a $ fmapIt fst fst it)+ (writeNext b $ fmapIt snd snd it)+ writeStop it =+ liftA2 (,)+ (writeStop (fmapIt fst fst it))+ (writeStop (fmapIt snd snd it))++instance (Zero va, Zero vb, Size va ~ Size vb) => Zero (va, vb) where+ writeZero = liftA2 combineIt2 writeZero writeZero+++instance+ (Sized va, Sized vb, Sized vc, Size va ~ Size vb, Size vb ~ Size vc) =>+ Sized (va, vb, vc) where+ type Size (va, vb, vc) = Size va++instance+ (Read va, Read vb, Read vc, Size va ~ Size vb, Size vb ~ Size vc) =>+ Read (va, vb, vc) where++ type Element (va, vb, vc) = (Element va, Element vb, Element vc)+ type ReadIt (va, vb, vc) = (ReadIt va, ReadIt vb, ReadIt vc)++ extract k (va,vb,vc) =+ liftA3 (,,)+ (extract k va)+ (extract k vb)+ (extract k vc)++ readStart (va,vb,vc) =+ liftA3 combineIt3 (readStart va) (readStart vb) (readStart vc)+ readNext it = do+ (a, ita) <- readNext $ fmapIt fst3 fst3 it+ (b, itb) <- readNext $ fmapIt snd3 snd3 it+ (c, itc) <- readNext $ fmapIt thd3 thd3 it+ return ((a,b,c), combineIt3 ita itb itc)+++instance+ (Write va, Write vb, Write vc, Size va ~ Size vb, Size vb ~ Size vc) =>+ Write (va, vb, vc) where++ type WriteIt (va, vb, vc) = (WriteIt va, WriteIt vb, WriteIt vc)++ insert k (a,b,c) (va,vb,vc) =+ liftA3 (,,)+ (insert k a va)+ (insert k b vb)+ (insert k c vc)++ writeStart = liftA3 combineIt3 writeStart writeStart writeStart+ writeNext (a,b,c) it =+ liftA3 combineIt3+ (writeNext a $ fmapIt fst3 fst3 it)+ (writeNext b $ fmapIt snd3 snd3 it)+ (writeNext c $ fmapIt thd3 thd3 it)+ writeStop it =+ liftA3 (,,)+ (writeStop (fmapIt fst3 fst3 it))+ (writeStop (fmapIt snd3 snd3 it))+ (writeStop (fmapIt thd3 thd3 it))++instance+ (Zero va, Zero vb, Zero vc, Size va ~ Size vb, Size vb ~ Size vc) =>+ Zero (va, vb, vc) where++ writeZero = liftA3 combineIt3 writeZero writeZero writeZero+++instance (Sized value) => Sized (Stereo.T value) where+ type Size (Stereo.T value) = Size value++instance (Read v) => Read (Stereo.T v) where++ type Element (Stereo.T v) = Stereo.T (Element v)+ type ReadIt (Stereo.T v) = Stereo.T (ReadIt v)++ extract = extractTraversable++ readStart = readStartTraversable+ readNext = readNextTraversable++instance (Write v) => Write (Stereo.T v) where++ type WriteIt (Stereo.T v) = Stereo.T (WriteIt v)++ insert = insertTraversable++ writeStart = writeStartTraversable+ writeNext = writeNextTraversable+ writeStop = writeStopTraversable++instance (Zero v) => Zero (Stereo.T v) where++ writeZero = writeZeroTraversable+++insertTraversable ::+ (Write v, Trav.Traversable f, App.Applicative f) =>+ LLVM.Value Word32 -> f (Element v) -> f v -> LLVM.CodeGenFunction r (f v)+insertTraversable n a v =+ Trav.sequence (liftA2 (insert n) a v)++extractTraversable ::+ (Read v, Trav.Traversable f) =>+ LLVM.Value Word32 -> f v -> LLVM.CodeGenFunction r (f (Element v))+extractTraversable n v =+ Trav.mapM (extract n) v+++readStartTraversable ::+ (Trav.Traversable f, App.Applicative f, Read v) =>+ f v -> LLVM.CodeGenFunction r (ReadIterator (f (ReadIt v)) (f v))+readNextTraversable ::+ (Trav.Traversable f, App.Applicative f, Read v) =>+ ReadIterator (f (ReadIt v)) (f v) ->+ LLVM.CodeGenFunction r (f (Element v), ReadIterator (f (ReadIt v)) (f v))++readStartTraversable v =+ fmap combineItFunctor $ Trav.mapM readStart v++readNextTraversable it = do+ st <- Trav.mapM readNext $ sequenceItFunctor it+ return (fmap fst st, combineItFunctor $ fmap snd st)+++writeStartTraversable ::+ (Trav.Traversable f, App.Applicative f, Write v) =>+ LLVM.CodeGenFunction r (WriteIterator (f (WriteIt v)) (f v))+writeNextTraversable ::+ (Trav.Traversable f, App.Applicative f, Write v) =>+ f (Element v) -> WriteIterator (f (WriteIt v)) (f v) ->+ LLVM.CodeGenFunction r (WriteIterator (f (WriteIt v)) (f v))+writeStopTraversable ::+ (Trav.Traversable f, App.Applicative f, Write v) =>+ WriteIterator (f (WriteIt v)) (f v) -> LLVM.CodeGenFunction r (f v)+writeZeroTraversable ::+ (Trav.Traversable f, App.Applicative f, Zero v) =>+ LLVM.CodeGenFunction r (WriteIterator (f (WriteIt v)) (f v))++writeStartTraversable =+ fmap combineItFunctor $ Trav.sequence $ App.pure writeStart++writeNextTraversable x it =+ fmap combineItFunctor $ Trav.sequence $+ liftA2 writeNext x $ sequenceItFunctor it++writeStopTraversable = Trav.mapM writeStop . sequenceItFunctor++writeZeroTraversable =+ fmap combineItFunctor $ Trav.sequence $ App.pure writeZero+++modify ::+ (Write v, Element v ~ a) =>+ LLVM.Value Word32 ->+ (a -> LLVM.CodeGenFunction r a) ->+ v -> LLVM.CodeGenFunction r v+modify k f v = flip (insert k) v =<< f =<< extract k v+++last :: (Read v) => v -> LLVM.CodeGenFunction r (Element v)+last v = extract (LLVM.valueOf (size v - 1 :: Word32)) v++subsample :: (Read v) => v -> LLVM.CodeGenFunction r (Element v)+subsample v = extract (A.zero :: LLVM.Value Word32) v++-- this will be translated to an efficient pshufd+upsample :: (Write v) => Element v -> LLVM.CodeGenFunction r v+upsample x = withSize $ \n -> assemble $ List.replicate n x+++iterate ::+ (Write v) =>+ (Element v -> LLVM.CodeGenFunction r (Element v)) ->+ Element v -> LLVM.CodeGenFunction r v+iterate f x =+ withSize $ \n ->+ assemble =<<+ (flip MS.evalStateT x $+ replicateM n $+ MS.StateT $ \x0 -> do x1 <- f x0; return (x0,x1))++reverse ::+ (Write v) =>+ v -> LLVM.CodeGenFunction r v+reverse =+ assemble . List.reverse <=< dissect++shiftUp ::+ (Write v) =>+ Element v -> v -> LLVM.CodeGenFunction r (Element v, v)+shiftUp x v =+ ListHT.switchR+ (return (x,v))+ (\ys0 y -> fmap ((,) y) $ assemble (x:ys0))+ =<<+ dissect v+++shiftUpMultiZero ::+ (Write v, A.Additive (Element v)) =>+ Int -> v -> LLVM.CodeGenFunction r v+shiftUpMultiZero n v =+ assemble . take (size v) . (List.replicate n A.zero ++) =<< dissect v++shiftDownMultiZero ::+ (Write v, A.Additive (Element v)) =>+ Int -> v -> LLVM.CodeGenFunction r v+shiftDownMultiZero n v =+ assemble . take (size v) . (++ List.repeat A.zero) . List.drop n+ =<< dissect v
+ src/Synthesizer/LLVM/Frame/SerialVector/Code.hs view
@@ -0,0 +1,279 @@+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+module Synthesizer.LLVM.Frame.SerialVector.Code (+ T(Cons), Value, size,+ fromOrdinary, toOrdinary,+ fromMultiVector, toMultiVector,+ extract, insert, modify,+ assemble, dissect,+ assemble1, dissect1,+ upsample, subsample, last,+ reverse, shiftUp, shiftUpMultiZero, shiftDown,+ cumulate, iterate,+ scale,+ ) where++import qualified LLVM.Extra.Multi.Vector.Instance as MultiVectorInst+import qualified LLVM.Extra.Multi.Vector as MultiVector+import qualified LLVM.Extra.Multi.Value.Storable as Storable+import qualified LLVM.Extra.Multi.Value.Marshal as Marshal+import qualified LLVM.Extra.Multi.Value.Vector as MultiValueVec+import qualified LLVM.Extra.Multi.Value as MultiValue+import qualified LLVM.Extra.Arithmetic as A++import qualified LLVM.Core as LLVM++import qualified Type.Data.Num.Decimal as TypeNum++import qualified Foreign.Storable as Store+import Foreign.Storable (Storable)+import Foreign.Ptr (castPtr)++import Control.Applicative ((<$>))++import qualified Data.NonEmpty as NonEmpty+import Data.Word (Word32)+import Data.Tuple.HT (mapSnd)++import Prelude as P hiding (last, reverse, iterate)+++newtype T n a = Cons (LLVM.Vector n a)+ deriving (Eq, Num)++type Value n a = MultiValue.T (T n a)++instance (TypeNum.Positive n, MultiVector.C a) => MultiValue.C (T n a) where+ type Repr (T n a) = MultiVector.Repr n a+ cons (Cons v) = fromOrdinary $ MultiValue.cons v+ undef = fromOrdinary MultiValue.undef+ zero = fromOrdinary MultiValue.zero+ phi bb = fmap fromOrdinary . MultiValue.phi bb . toOrdinary+ addPhi bb a b = MultiValue.addPhi bb (toOrdinary a) (toOrdinary b)++instance (Marshal.Vector n a) => Marshal.C (T n a) where+ pack (Cons v) = Marshal.pack v+ unpack = Cons . Marshal.unpack++instance (TypeNum.Positive n, Storable a) => Storable (T n a) where+ sizeOf (Cons v) = Store.sizeOf v+ alignment (Cons v) = Store.alignment v+ poke ptr (Cons v) = Store.poke (castPtr ptr) v+ peek ptr = Cons <$> Store.peek (castPtr ptr)++instance+ (TypeNum.Positive n, Storable.Vector a, MultiVector.C a) =>+ Storable.C (T n a) where+ load ptr = fmap fromOrdinary $ Storable.load =<< LLVM.bitcast ptr+ store v ptr = Storable.store (toOrdinary v) =<< LLVM.bitcast ptr++instance+ (TypeNum.Positive n, MultiVector.IntegerConstant a) =>+ MultiValue.IntegerConstant (T n a) where+ fromInteger' = fromMultiVector . MultiVector.fromInteger'++instance+ (TypeNum.Positive n, MultiVector.RationalConstant a) =>+ MultiValue.RationalConstant (T n a) where+ fromRational' = fromMultiVector . MultiVector.fromRational'++instance+ (TypeNum.Positive n, MultiVector.Additive a) =>+ MultiValue.Additive (T n a) where+ add = lift2 MultiVector.add+ sub = lift2 MultiVector.sub+ neg = lift1 MultiVector.neg++instance+ (TypeNum.Positive n, MultiVector.PseudoRing a) =>+ MultiValue.PseudoRing (T n a) where+ mul = lift2 MultiVector.mul++scale ::+ (TypeNum.Positive n, MultiVector.PseudoRing a) =>+ MultiValue.T a -> Value n a -> LLVM.CodeGenFunction r (Value n a)+scale = lift1 . MultiVector.scale++instance+ (TypeNum.Positive n, MultiVector.Real a) =>+ MultiValue.Real (T n a) where+ min = lift2 MultiVector.min+ max = lift2 MultiVector.max+ abs = lift1 MultiVector.abs+ signum = lift1 MultiVector.signum++instance+ (TypeNum.Positive n, MultiVector.Fraction a) =>+ MultiValue.Fraction (T n a) where+ truncate = lift1 MultiVector.truncate+ fraction = lift1 MultiVector.fraction++instance+ (TypeNum.Positive n, MultiVector.Field a) =>+ MultiValue.Field (T n a) where+ fdiv = lift2 MultiVector.fdiv++instance+ (TypeNum.Positive n, MultiVector.Algebraic a) =>+ MultiValue.Algebraic (T n a) where+ sqrt = lift1 MultiVector.sqrt++instance+ (TypeNum.Positive n, MultiVector.Transcendental a) =>+ MultiValue.Transcendental (T n a) where+ pi = fmap fromMultiVector MultiVector.pi+ sin = lift1 MultiVector.sin+ log = lift1 MultiVector.log+ exp = lift1 MultiVector.exp+ cos = lift1 MultiVector.cos+ pow = lift2 MultiVector.pow++instance+ (TypeNum.Positive n, n ~ m,+ MultiVector.NativeInteger n a ar,+ MultiValue.NativeInteger a ar) =>+ MultiValueVec.NativeInteger (T n a) (LLVM.Vector m ar) where++instance+ (TypeNum.Positive n, n ~ m,+ MultiVector.NativeFloating n a ar,+ MultiValue.NativeFloating a ar) =>+ MultiValueVec.NativeFloating (T n a) (LLVM.Vector m ar) where++lift1 ::+ (Functor f) =>+ (MultiVector.T n a -> f (MultiVector.T m b)) ->+ (Value n a -> f (Value m b))+lift1 f a = fromMultiVector <$> f (toMultiVector a)++lift2 ::+ (Functor f) =>+ (MultiVector.T n a -> MultiVector.T m b -> f (MultiVector.T k c)) ->+ (Value n a -> Value m b -> f (Value k c))+lift2 f a b = fromMultiVector <$> f (toMultiVector a) (toMultiVector b)+++extract ::+ (TypeNum.Positive n,+ MultiVector.C x, MultiValue.T x ~ a, Value n x ~ v) =>+ LLVM.Value Word32 -> v -> LLVM.CodeGenFunction r a+extract i v = MultiVector.extract i (toMultiVector v)++insert ::+ (TypeNum.Positive n,+ MultiVector.C x, MultiValue.T x ~ a, Value n x ~ v) =>+ LLVM.Value Word32 -> a -> v -> LLVM.CodeGenFunction r v+insert i a v =+ fromMultiVector <$> MultiVector.insert i a (toMultiVector v)++modify ::+ (TypeNum.Positive n,+ MultiVector.C x, MultiValue.T x ~ a, Value n x ~ v) =>+ LLVM.Value Word32 ->+ (a -> LLVM.CodeGenFunction r a) ->+ v -> LLVM.CodeGenFunction r v+modify k f v = flip (insert k) v =<< f =<< extract k v+++assemble ::+ (TypeNum.Positive n, MultiVector.C a) =>+ [MultiValue.T a] ->+ LLVM.CodeGenFunction r (Value n a)+assemble = fmap fromMultiVector . MultiVector.assemble++dissect ::+ (TypeNum.Positive n, MultiVector.C a) =>+ Value n a ->+ LLVM.CodeGenFunction r [MultiValue.T a]+dissect = MultiVector.dissect . toMultiVector++assemble1 ::+ (TypeNum.Positive n, MultiVector.C a) =>+ NonEmpty.T [] (MultiValue.T a) ->+ LLVM.CodeGenFunction r (Value n a)+assemble1 = fmap fromMultiVector . MultiVector.assemble1++dissect1 ::+ (TypeNum.Positive n, MultiVector.C a) =>+ Value n a ->+ LLVM.CodeGenFunction r (NonEmpty.T [] (MultiValue.T a))+dissect1 = MultiVector.dissect1 . toMultiVector+++sizeS :: TypeNum.Positive n => Value n a -> TypeNum.Singleton n+sizeS _ = TypeNum.singleton++size :: (TypeNum.Positive n, P.Integral i) => Value n a -> i+size = TypeNum.integralFromSingleton . sizeS+++last ::+ (TypeNum.Positive n, MultiVector.C a) =>+ Value n a -> LLVM.CodeGenFunction r (MultiValue.T a)+last v = extract (LLVM.valueOf (size v - 1 :: Word32)) v++subsample ::+ (TypeNum.Positive n, MultiVector.C a) =>+ Value n a -> LLVM.CodeGenFunction r (MultiValue.T a)+subsample = extract (A.zero :: LLVM.Value Word32)++upsample ::+ (TypeNum.Positive n, MultiVector.C a) =>+ MultiValue.T a -> LLVM.CodeGenFunction r (Value n a)+upsample = fmap fromOrdinary . MultiValueVec.replicate+++reverse ::+ (TypeNum.Positive n, MultiVector.C a) =>+ Value n a -> LLVM.CodeGenFunction r (Value n a)+reverse =+ fmap fromMultiVector . MultiVector.reverse . toMultiVector++shiftUp ::+ (TypeNum.Positive n, MultiVector.C x,+ MultiValue.T x ~ a, Value n x ~ v) =>+ a -> v -> LLVM.CodeGenFunction r (a, v)+shiftUp a v =+ mapSnd fromMultiVector <$> MultiVector.shiftUp a (toMultiVector v)++shiftUpMultiZero ::+ (TypeNum.Positive n, MultiVector.C x, Value n x ~ v) =>+ Int -> v -> LLVM.CodeGenFunction r v+shiftUpMultiZero k v =+ fromMultiVector <$> MultiVector.shiftUpMultiZero k (toMultiVector v)++shiftDown ::+ (TypeNum.Positive n, MultiVector.C x,+ MultiValue.T x ~ a, Value n x ~ v) =>+ a -> v -> LLVM.CodeGenFunction r (a, v)+shiftDown a v =+ mapSnd fromMultiVector <$> MultiVector.shiftDown a (toMultiVector v)+++iterate ::+ (TypeNum.Positive n, MultiVector.C a) =>+ (MultiValue.T a -> LLVM.CodeGenFunction r (MultiValue.T a)) ->+ MultiValue.T a -> LLVM.CodeGenFunction r (Value n a)+iterate f = fmap fromOrdinary . MultiValueVec.iterate f++cumulate ::+ (TypeNum.Positive n, MultiVector.Additive a) =>+ MultiValue.T a -> Value n a ->+ LLVM.CodeGenFunction r (MultiValue.T a, Value n a)+cumulate a =+ fmap (mapSnd fromMultiVector) . MultiVector.cumulate a . toMultiVector+++fromOrdinary :: MultiValue.T (LLVM.Vector n a) -> Value n a+fromOrdinary = MultiValue.cast++toOrdinary :: Value n a -> MultiValue.T (LLVM.Vector n a)+toOrdinary = MultiValue.cast++fromMultiVector :: MultiVector.T n a -> Value n a+fromMultiVector = fromOrdinary . MultiVectorInst.toMultiValue++toMultiVector :: Value n a -> MultiVector.T n a+toMultiVector = MultiVectorInst.fromMultiValue . toOrdinary
+ src/Synthesizer/LLVM/Frame/SerialVector/Plain.hs view
@@ -0,0 +1,38 @@+{-# LANGUAGE TypeFamilies #-}+{- |+A special vector type that represents a time-sequence of samples.+This way we can distinguish safely between LLVM vectors+used for parallel signals and pipelines and+those used for chunky processing of scalar signals.+For the chunky processing this data type allows us+to derive the factor from the type+that time constants have to be multiplied with.+-}+module Synthesizer.LLVM.Frame.SerialVector.Plain (+ T(Cons),+ fromList,+ replicate,+ iterate,+ ) where++import qualified Synthesizer.LLVM.Frame.SerialVector.Code as Code+import Synthesizer.LLVM.Frame.SerialVector.Code (T)++import qualified LLVM.Core as LLVM++import qualified Type.Data.Num.Decimal as TypeNum++import qualified Data.NonEmpty.Class as NonEmptyC+import qualified Data.NonEmpty as NonEmpty++import Prelude as P hiding (zip, unzip, last, reverse, iterate, replicate)+++fromList :: (TypeNum.Positive n) => NonEmpty.T [] a -> T n a+fromList = Code.Cons . LLVM.cyclicVector++replicate :: (TypeNum.Positive n) => a -> T n a+replicate = Code.Cons . pure++iterate :: (TypeNum.Positive n) => (a -> a) -> a -> T n a+iterate f x = fromList $ NonEmptyC.iterate f x
src/Synthesizer/LLVM/Frame/Stereo.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE MultiParamTypeClasses #-} {-# OPTIONS_GHC -fno-warn-orphans #-} {- | Re-export functions from "Sound.Frame.Stereo"@@ -9,7 +10,11 @@ -} module Synthesizer.LLVM.Frame.Stereo ( Stereo.T, Stereo.cons, Stereo.left, Stereo.right,- Stereo.Channel(Left, Right), Stereo.select,+ Stereo.Channel(Stereo.Left, Stereo.Right), Stereo.select,+ Stereo.swap,+ multiValue, unMultiValue, consMultiValue, unExpression,+ multiVector, unMultiVector,+ multiValueSerial, unMultiValueSerial, Stereo.arrowFromMono, Stereo.arrowFromMonoControlled, Stereo.arrowFromChannels,@@ -18,22 +23,31 @@ Stereo.liftApplicative, ) where +import qualified Synthesizer.LLVM.Frame.SerialVector as Serial import qualified Synthesizer.Frame.Stereo as Stereo -import qualified LLVM.Extra.Arithmetic as A+import qualified LLVM.DSL.Expression as Expr+import qualified LLVM.DSL.Value as Value++import qualified LLVM.Extra.Multi.Vector as MultiVector+import qualified LLVM.Extra.Multi.Value.Storable as StorableMV+import qualified LLVM.Extra.Multi.Value.Marshal as MarshalMV+import qualified LLVM.Extra.Multi.Value as MultiValue import qualified LLVM.Extra.Tuple as Tuple import qualified LLVM.Extra.Storable as Storable import qualified LLVM.Extra.Marshal as Marshal import qualified LLVM.Extra.Memory as Memory+import qualified LLVM.Extra.Arithmetic as A import qualified LLVM.Extra.Control as C import qualified LLVM.Extra.Vector as Vector import qualified LLVM.Core as LLVM import Type.Data.Num.Decimal (d0, d1) -import Control.Monad (liftM2)-import Control.Applicative (liftA2)+import Control.Applicative (liftA2, pure, (<$>))+ import qualified Data.Traversable as Trav+import qualified Data.Foldable as Fold import Prelude hiding (Either(Left, Right), sequence) @@ -47,38 +61,104 @@ instance (C.Select a) => C.Select (Stereo.T a) where select = C.selectTraversable -{--instance LLVM.CmpRet a, LLVM.CmpResult a ~ b => LLVM.CmpRet (Stereo.T a) (Stereo.T b) where--}- instance (Tuple.Value h) => Tuple.Value (Stereo.T h) where type ValueOf (Stereo.T h) = Stereo.T (Tuple.ValueOf h)- valueOf s =- Stereo.cons- (Tuple.valueOf $ Stereo.left s)- (Tuple.valueOf $ Stereo.right s)--{--instance Tuple.Value a => Tuple.Value (Stereo.T a) where- buildTuple f =- liftM2 Stereo.cons (buildTuple f) (buildTuple f)--instance IsTuple a => IsTuple (Stereo.T a) where- tupleDesc s =- tupleDesc (Stereo.left s) ++- tupleDesc (Stereo.right s)--}+ valueOf = fmap Tuple.valueOf instance (Tuple.Phi a) => Tuple.Phi (Stereo.T a) where phi bb v =- liftM2 Stereo.cons+ liftA2 Stereo.cons (Tuple.phi bb (Stereo.left v)) (Tuple.phi bb (Stereo.right v)) addPhi bb x y = do Tuple.addPhi bb (Stereo.left x) (Stereo.left y) Tuple.addPhi bb (Stereo.right x) (Stereo.right y) +instance (MultiValue.C a) => MultiValue.C (Stereo.T a) where+ type Repr (Stereo.T a) = Stereo.T (MultiValue.Repr a)+ cons = multiValue . fmap MultiValue.cons+ undef = multiValue $ pure MultiValue.undef+ zero = multiValue $ pure MultiValue.zero+ phi bb = fmap multiValue . Trav.traverse (MultiValue.phi bb) . unMultiValue+ addPhi bb a b =+ Fold.sequence_ $+ liftA2 (MultiValue.addPhi bb) (unMultiValue a) (unMultiValue b) +instance (MultiValue.Compose a) => MultiValue.Compose (Stereo.T a) where+ type Composed (Stereo.T a) = Stereo.T (MultiValue.Composed a)+ compose = multiValue . fmap MultiValue.compose++instance (MultiValue.Decompose p) => MultiValue.Decompose (Stereo.T p) where+ decompose p = liftA2 MultiValue.decompose p . unMultiValue++type instance MultiValue.Decomposed f (Stereo.T pa) =+ Stereo.T (MultiValue.Decomposed f pa)+type instance MultiValue.PatternTuple (Stereo.T pa) =+ Stereo.T (MultiValue.PatternTuple pa)++multiValue :: Stereo.T (MultiValue.T a) -> MultiValue.T (Stereo.T a)+multiValue = MultiValue.Cons . fmap (\(MultiValue.Cons a) -> a)++unMultiValue :: MultiValue.T (Stereo.T a) -> Stereo.T (MultiValue.T a)+unMultiValue (MultiValue.Cons x) = fmap MultiValue.Cons x++consMultiValue :: MultiValue.T a -> MultiValue.T a -> MultiValue.T (Stereo.T a)+consMultiValue l r = multiValue $ Stereo.cons l r+++unExpression :: Expr.Exp (Stereo.T a) -> Stereo.T (Expr.Exp a)+unExpression x =+ Stereo.cons+ (Expr.lift1 (MultiValue.lift1 Stereo.left) x)+ (Expr.lift1 (MultiValue.lift1 Stereo.right) x)+++instance (MultiVector.C a) => MultiVector.C (Stereo.T a) where+ type Repr n (Stereo.T a) = Stereo.T (MultiVector.Repr n a)+ cons = multiVector . fmap MultiVector.cons . Stereo.sequence+ undef = multiVector $ pure MultiVector.undef+ zero = multiVector $ pure MultiVector.zero+ phi bb =+ fmap multiVector . Trav.traverse (MultiVector.phi bb) . unMultiVector+ addPhi bb a b =+ Fold.sequence_ $+ liftA2 (MultiVector.addPhi bb) (unMultiVector a) (unMultiVector b)++ shuffle is u v =+ multiVector <$>+ traverse2 (MultiVector.shuffle is) (unMultiVector u) (unMultiVector v)+ extract k =+ fmap multiValue . Trav.traverse (MultiVector.extract k) . unMultiVector+ insert k a v =+ multiVector <$>+ traverse2 (MultiVector.insert k) (unMultiValue a) (unMultiVector v)++multiVector :: Stereo.T (MultiVector.T n a) -> MultiVector.T n (Stereo.T a)+multiVector = MultiVector.Cons . fmap (\(MultiVector.Cons a) -> a)++unMultiVector :: MultiVector.T n (Stereo.T a) -> Stereo.T (MultiVector.T n a)+unMultiVector (MultiVector.Cons x) = fmap MultiVector.Cons x+++multiValueSerial ::+ Stereo.T (MultiValue.T (Serial.T n a)) ->+ MultiValue.T (Serial.T n (Stereo.T a))+multiValueSerial = MultiValue.Cons . fmap (\(MultiValue.Cons a) -> a)++unMultiValueSerial ::+ MultiValue.T (Serial.T n (Stereo.T a)) ->+ Stereo.T (MultiValue.T (Serial.T n a))+unMultiValueSerial (MultiValue.Cons x) = fmap MultiValue.Cons x+++instance+ (Expr.Aggregate e mv) => Expr.Aggregate (Stereo.T e) (Stereo.T mv) where+ type MultiValuesOf (Stereo.T e) = Stereo.T (Expr.MultiValuesOf e)+ type ExpressionsOf (Stereo.T mv) = Stereo.T (Expr.ExpressionsOf mv)+ bundle = Trav.traverse Expr.bundle+ dissect = fmap Expr.dissect++ instance (Vector.Simple v) => Vector.Simple (Stereo.T v) where type Element (Stereo.T v) = Stereo.T (Vector.Element v) type Size (Stereo.T v) = Vector.Size v@@ -114,13 +194,31 @@ load = Storable.loadApplicative store = Storable.storeFoldable +instance (MarshalMV.C l) => MarshalMV.C (Stereo.T l) where+ pack x = MarshalMV.pack (Stereo.left x, Stereo.right x)+ unpack = uncurry Stereo.cons . MarshalMV.unpack +instance (StorableMV.C l) => StorableMV.C (Stereo.T l) where+ load = StorableMV.loadApplicative+ store = StorableMV.storeFoldable++instance+ (StorableMV.Vector l, MultiVector.C l) =>+ StorableMV.Vector (Stereo.T l) where+ assembleVector p =+ Trav.traverse (StorableMV.assembleVector (Stereo.left<$>p)) .+ Stereo.sequence+ disassembleVector p =+ fmap (\x -> liftA2 Stereo.cons (Stereo.left x) (Stereo.right x)) .+ Trav.traverse (StorableMV.disassembleVector (Stereo.left<$>p))++ {- instance (Memory l s) => Memory (Stereo.T l) (LLVM.Struct (s, (s, ()))) where load ptr =- liftM2 Stereo.cons+ liftA2 Stereo.cons (load =<< getElementPtr0 ptr (d0, ())) (load =<< getElementPtr0 ptr (d1, ())) store y ptr = do@@ -130,11 +228,33 @@ instance (A.Additive a) => A.Additive (Stereo.T a) where zero = Stereo.cons A.zero A.zero- add x y = Trav.sequence $ liftA2 A.add x y- sub x y = Trav.sequence $ liftA2 A.sub x y- neg x = Trav.sequence $ fmap A.neg x+ add x y = traverse2 A.add x y+ sub x y = traverse2 A.sub x y+ neg x = Trav.traverse A.neg x type instance A.Scalar (Stereo.T a) = A.Scalar a instance (A.PseudoModule a) => A.PseudoModule (Stereo.T a) where- scale a = Trav.sequence . fmap (A.scale a)+ scale a = Trav.traverse (A.scale a)++++instance (MultiValue.Additive a) => MultiValue.Additive (Stereo.T a) where+ add x y =+ multiValue <$> traverse2 MultiValue.add (unMultiValue x) (unMultiValue y)+ sub x y =+ multiValue <$> traverse2 MultiValue.sub (unMultiValue x) (unMultiValue y)+ neg x = multiValue <$> Trav.traverse MultiValue.neg (unMultiValue x)+++traverse2 ::+ (Monad m, Applicative t, Traversable t) =>+ (a -> b -> m c) -> t a -> t b -> m (t c)+traverse2 f x y = Trav.sequence $ liftA2 f x y++++instance Value.Flatten a => Value.Flatten (Stereo.T a) where+ type Registers (Stereo.T a) = Stereo.T (Value.Registers a)+ flattenCode = Value.flattenCodeTraversable+ unfoldCode = Value.unfoldCodeTraversable
src/Synthesizer/LLVM/Frame/StereoInterleaved.hs view
@@ -1,332 +1,45 @@-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE FlexibleContexts #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}-{- |-Represent a vector of Stereo values in two vectors-that store the values in an interleaved way.-That is:--> vector0[0] = left[0]-> vector0[1] = right[0]-> vector0[2] = left[1]-> vector0[3] = right[1]-> vector1[0] = left[2]-> vector1[1] = right[2]-> vector1[2] = left[3]-> vector1[3] = right[3]--This representation is not very useful for computation,-but necessary as intermediate representation for interfacing with memory.-SSE/SSE2 have the instructions UNPACK(L|H)P(S|D) that interleave efficiently.--} module Synthesizer.LLVM.Frame.StereoInterleaved ( T,- Value(Value),+ Value, interleave, deinterleave,- fromMono,- assemble, extractAll,- zero, amplify, envelope, ) where -import qualified Synthesizer.LLVM.Frame.Stereo as Stereo-import qualified Synthesizer.LLVM.Frame.SerialVector as Serial-import qualified Synthesizer.LLVM.CausalParameterized.Functional as F--import qualified LLVM.Extra.Arithmetic as A-import qualified LLVM.Extra.Control as C-import qualified LLVM.Extra.Tuple as Tuple-import qualified LLVM.Extra.Storable as Storable-import qualified LLVM.Extra.Memory as Memory-import qualified LLVM.Extra.ScalarOrVector as SoV-import qualified LLVM.Extra.Vector as Vector-import qualified LLVM.Core as LLVM-import LLVM.Core (Vector, IsSized, SizeOf)--import qualified Type.Data.Num.Decimal as TypeNum--import qualified Foreign.Storable as St-import Foreign.Ptr (Ptr, castPtr)--import qualified Data.Foldable as Fold-import Control.Monad (liftM2)-import Control.Applicative (liftA2, pure)--import Data.Tuple.HT (mapPair)--import qualified Algebra.Additive as Additive---data T n a = Cons (Vector n a) (Vector n a)--data Value n a = Value (LLVM.Value (Vector n a)) (LLVM.Value (Vector n a))+import qualified Synthesizer.LLVM.Frame.StereoInterleavedCode as StereoInt+import Synthesizer.LLVM.Frame.StereoInterleavedCode (T, Value) +import qualified Synthesizer.LLVM.Frame.Stereo as Stereo+import qualified Synthesizer.LLVM.Frame.SerialVector.Code as Serial -type instance F.Arguments f (Value n a) = f (Value n a)-instance F.MakeArguments (Value n a) where- makeArgs = id+import qualified LLVM.DSL.Expression as Expr+import LLVM.DSL.Expression (Exp) +import qualified LLVM.Extra.Multi.Vector as MultiVector -withSize :: (TypeNum.Natural n) => (Int -> m (Value n a)) -> m (Value n a)-withSize =- let sz ::- (TypeNum.Natural n) =>- TypeNum.Singleton n -> (Int -> m (Value n a)) -> m (Value n a)- sz n f = f (TypeNum.integralFromSingleton n)- in sz TypeNum.singleton+import qualified Type.Data.Num.Decimal as TypeNum interleave ::- (LLVM.IsPrimitive a, TypeNum.Positive n) =>- Stereo.T (Serial.Value n a) ->- LLVM.CodeGenFunction r (Value n a)-interleave x =- assemble =<< Serial.extractAll x+ (TypeNum.Positive n, MultiVector.C a) =>+ Stereo.T (Exp (Serial.T n a)) -> Exp (T n a)+interleave = Expr.liftM StereoInt.interleave deinterleave ::- (LLVM.IsPrimitive a, TypeNum.Positive n) =>- Value n a ->- LLVM.CodeGenFunction r (Stereo.T (Serial.Value n a))-deinterleave v =- Serial.assemble =<< extractAll v--fromMono ::- (LLVM.IsPrimitive a, TypeNum.Positive n) =>- Serial.Value n a ->- LLVM.CodeGenFunction r (Value n a)-fromMono x =- assemble . map pure =<< Serial.extractAll x--assemble ::- (LLVM.IsPrimitive a, TypeNum.Positive n) =>- [Stereo.T (LLVM.Value a)] -> LLVM.CodeGenFunction r (Value n a)-assemble x =- withSize $ \n ->- uncurry (liftM2 Value) .- mapPair (Vector.assemble, Vector.assemble) .- splitAt n .- concatMap Fold.toList $ x--extractAll ::- (LLVM.IsPrimitive a, TypeNum.Positive n) =>- Value n a -> LLVM.CodeGenFunction r [Stereo.T (LLVM.Value a)]-extractAll (Value v0 v1) =- fmap- (let aux (l:r:xs) = Stereo.cons l r : aux xs- aux [] = []- aux _ = error "odd number of stereo elements"- in aux) $- liftM2 (++)- (Vector.extractAll v0)- (Vector.extractAll v1)---instance- (TypeNum.Positive n, LLVM.IsPrimitive a, St.Storable a) =>- St.Storable (T n a) where- sizeOf ~(Cons v0 v1) = St.sizeOf v0 + St.sizeOf v1- alignment ~(Cons v _) = St.alignment v- peek ptr =- let p = castPtr ptr- in liftM2 Cons- (St.peekElemOff p 0)- (St.peekElemOff p 1)- poke ptr (Cons v0 v1) =- let p = castPtr ptr- in St.pokeElemOff p 0 v0 >>- St.pokeElemOff p 1 v1--instance (TypeNum.Positive n, LLVM.IsPrimitive a) => Tuple.Zero (Value n a) where- zero = Value Tuple.zero Tuple.zero--instance (TypeNum.Positive n, LLVM.IsPrimitive a) => Tuple.Undefined (Value n a) where- undef = Value (LLVM.value LLVM.undef) (LLVM.value LLVM.undef)--{--Can only be implemented by ifThenElse-since the atomic 'select' command wants a bool vector.--instance (TypeNum.Positive n, LLVM.IsPrimitive a, Tuple.Phi a) => C.Select (Value n a) where- select b (Value x0 x1) (Value y0 y1) =- liftM2 Value- (C.select b x0 y0)- (C.select b x1 y1)--instance LLVM.CmpRet a, LLVM.CmpResult a ~ b => LLVM.CmpRet (Stereo.T a) (Stereo.T b) where--}--instance (TypeNum.Positive n, LLVM.IsPrimitive a, LLVM.IsConst a) =>- Tuple.Value (T n a) where- type ValueOf (T n a) = Value n a- valueOf (Cons v0 v1) =- Value- (LLVM.valueOf v0)- (LLVM.valueOf v1)--instance (TypeNum.Positive n, LLVM.IsPrimitive a) => Tuple.Phi (Value n a) where- phi bb = mapV (Tuple.phi bb)- addPhi bb = zipV (\_ _ -> ()) (Tuple.addPhi bb)---instance (TypeNum.Positive n) => Serial.Sized (Value n a) where- type Size (Value n a) = n--{- |-The implementation of 'extract' may need to perform-arithmetics at run-time and is thus a bit inefficient.--}-instance (TypeNum.Positive n, LLVM.IsPrimitive a, LLVM.IsFirstClass a) => Serial.Read (Value n a) where- type Element (Value n a) = Stereo.T (LLVM.Value a)- type ReadIt (Value n a) = Value n a-- extract k (Value v0 v1) =- let size = LLVM.valueOf $ fromIntegral $ Vector.sizeInTuple v0- ext j = do- b <- A.cmp LLVM.CmpLT j size- C.ifThenElse b- (Vector.extract j v0)- (do j1 <- A.sub j size- Vector.extract j1 v1)- in do- k20 <- A.add k k- k21 <- A.inc k20- liftM2 Stereo.cons (ext k20) (ext k21)-- extractAll = extractAll-- readStart = return . Serial.Iterator- readNext (Serial.Iterator v) = do- xt <- extractAll v- case xt of- x:xs -> fmap ((,) x . Serial.Iterator) $ assemble xs- [] -> error "StereoInterleaved.readNext: size zero"---{- |-The implementation of 'insert' may need to perform-arithmetics at run-time and is thus a bit inefficient.--}-instance (TypeNum.Positive n, LLVM.IsPrimitive a) => Serial.C (Value n a) where- type WriteIt (Value n a) = Value n a-- insert k x v =- let size = LLVM.valueOf $ fromIntegral $ Serial.size v- ins j c (Value v0 v1) = do- b <- A.cmp LLVM.CmpLT j size- C.ifThenElse b- (do w0 <- Vector.insert j c v0- return $ Value w0 v1)- (do j1 <- A.sub j size- w1 <- Vector.insert j1 c v1- return $ Value v0 w1)- in do- k20 <- A.add k k- k21 <- A.inc k20- ins k21 (Stereo.right x) =<< ins k20 (Stereo.left x) v-- assemble = assemble-- writeStart = return (Serial.Iterator Tuple.undef)- writeNext x (Serial.Iterator v) = do- xs <- extractAll v- fmap Serial.Iterator $ assemble $ tail xs ++ [x]- writeStop (Serial.Iterator v) = return v---type Struct n a = LLVM.Struct (Vector n a, (Vector n a, ()))--memory ::- (TypeNum.Positive n, LLVM.IsPrimitive a, IsSized a,- TypeNum.Positive (n TypeNum.:*: SizeOf a)) =>- Memory.Record r (Struct n a) (Value n a)-memory =- liftA2 Value- (Memory.element (\(Value v _) -> v) TypeNum.d0)- (Memory.element (\(Value _ v) -> v) TypeNum.d1)--instance- (TypeNum.Positive n,- LLVM.IsPrimitive a, IsSized a,- TypeNum.Positive (n TypeNum.:*: SizeOf a)) =>- Memory.C (Value n a) where- type Struct (Value n a) = Struct n a- load = Memory.loadRecord memory- store = Memory.storeRecord memory- decompose = Memory.decomposeRecord memory- compose = Memory.composeRecord memory--instance- (TypeNum.Positive n, Tuple.VectorValue n a,- Tuple.VectorValueOf n a ~ LLVM.Value (Vector n a),- LLVM.IsPrimitive a, LLVM.IsConst a, Storable.Vector a) =>- Storable.C (T n a) where- load ptrV = do- ptr <- castHalfPtr ptrV- liftM2 Value- (Storable.load ptr)- (Storable.load =<< Storable.incrementPtr ptr)- store (Value v0 v1) ptrV = do- ptr <- castHalfPtr ptrV- Storable.storeNext v0 ptr >>= Storable.store v1--castHalfPtr ::- LLVM.Value (Ptr (T n a)) ->- LLVM.CodeGenFunction r (LLVM.Value (Ptr (Vector n a)))-castHalfPtr = LLVM.bitcast---{- |-This instance allows to run @arrange@ on interleaved stereo vectors.--}-instance- (TypeNum.Positive n, LLVM.IsPrimitive a, LLVM.IsArithmetic a) =>- A.Additive (Value n a) where- zero = Value A.zero A.zero- add = zipV Value A.add- sub = zipV Value A.sub- neg = mapV A.neg---zero :: (TypeNum.Positive n, Additive.C a) => (T n a)-zero = Cons (pure Additive.zero) (pure Additive.zero)---scale ::- (TypeNum.Positive n, LLVM.IsPrimitive a, LLVM.IsArithmetic a) =>- LLVM.Value a -> Value n a -> LLVM.CodeGenFunction r (Value n a)-scale a v = do- av <- SoV.replicate a- mapV (A.mul av) v+ (TypeNum.Positive n, MultiVector.C a) =>+ Exp (T n a) -> Stereo.T (Exp (Serial.T n a))+deinterleave x =+ Stereo.cons+ (Expr.liftM (fmap Stereo.left . StereoInt.deinterleave) x)+ (Expr.liftM (fmap Stereo.right . StereoInt.deinterleave) x) amplify ::- (TypeNum.Positive n, LLVM.IsPrimitive a, LLVM.IsArithmetic a, LLVM.IsConst a) =>- a -> Value n a -> LLVM.CodeGenFunction r (Value n a)-amplify a = scale (LLVM.valueOf a)+ (TypeNum.Positive n, MultiVector.PseudoRing a) =>+ Exp a -> Exp (T n a) -> Exp (T n a)+amplify = Expr.liftM2 StereoInt.scale envelope ::- (TypeNum.Positive n, LLVM.IsPrimitive a, LLVM.IsArithmetic a, LLVM.IsConst a) =>- Serial.Value n a -> Value n a -> LLVM.CodeGenFunction r (Value n a)-envelope e a =- zipV Value (flip A.mul) a =<< fromMono e---mapV :: (Monad m) =>- (LLVM.Value (Vector n a) -> m (LLVM.Value (Vector n a))) ->- Value n a -> m (Value n a)-mapV f (Value x0 x1) =- liftM2 Value (f x0) (f x1)--zipV :: (Monad m) =>- (c -> c -> d) ->- (LLVM.Value (Vector n a) ->- LLVM.Value (Vector n b) ->- m c) ->- Value n a ->- Value n b ->- m d-zipV g f (Value x0 x1) (Value y0 y1) =- liftM2 g (f x0 y0) (f x1 y1)+ (TypeNum.Positive n, MultiVector.PseudoRing a) =>+ Exp (Serial.T n a) -> Exp (T n a) -> Exp (T n a)+envelope = Expr.liftM2 StereoInt.envelope
+ src/Synthesizer/LLVM/Frame/StereoInterleavedCode.hs view
@@ -0,0 +1,241 @@+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE FlexibleContexts #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+{- |+Represent a vector of Stereo values in two vectors+that store the values in an interleaved way.+That is:++> vector0[0] = left[0]+> vector0[1] = right[0]+> vector0[2] = left[1]+> vector0[3] = right[1]+> vector1[0] = left[2]+> vector1[1] = right[2]+> vector1[2] = left[3]+> vector1[3] = right[3]++This representation is not very useful for computation,+but necessary as intermediate representation for interfacing with memory.+SSE/SSE2 have the instructions UNPACK(L|H)P(S|D) that interleave efficiently.+-}+module Synthesizer.LLVM.Frame.StereoInterleavedCode (+ T,+ Value,+ interleave,+ deinterleave,+ fromMono,+ assemble, dissect,+ zero,+ scale,+ amplify,+ envelope,+ ) where++import qualified Synthesizer.LLVM.Frame.Stereo as Stereo+import qualified Synthesizer.LLVM.Frame.SerialVector.Code as Serial++import qualified LLVM.Extra.Multi.Vector as MultiVector+import qualified LLVM.Extra.Multi.Value.Storable as Storable+import qualified LLVM.Extra.Multi.Value.Marshal as Marshal+import qualified LLVM.Extra.Multi.Value as MultiValue+import qualified LLVM.Extra.Arithmetic as A+import qualified LLVM.Core as LLVM+import LLVM.Core (Vector)++import qualified Type.Data.Num.Decimal as TypeNum++import qualified Foreign.Storable as St+import Foreign.Ptr (Ptr, castPtr)++import qualified Control.Applicative.HT as AppHT+import Control.Applicative (liftA2, pure)++import qualified Data.Foldable as Fold+import Data.Tuple.HT (mapPair)++import qualified Algebra.Additive as Additive+++data T n a = Cons (Vector n a) (Vector n a)++type Value n a = MultiValue.T (T n a)+++withSize :: (TypeNum.Natural n) => (Int -> m (Value n a)) -> m (Value n a)+withSize =+ let sz ::+ (TypeNum.Natural n) =>+ TypeNum.Singleton n -> (Int -> m (Value n a)) -> m (Value n a)+ sz n f = f (TypeNum.integralFromSingleton n)+ in sz TypeNum.singleton+++interleave ::+ (TypeNum.Positive n, MultiVector.C a) =>+ Stereo.T (Serial.Value n a) ->+ LLVM.CodeGenFunction r (Value n a)+interleave x =+ assemble . map Stereo.unMultiValue+ =<< Serial.dissect (Stereo.multiValueSerial x)++deinterleave ::+ (TypeNum.Positive n, MultiVector.C a) =>+ Value n a ->+ LLVM.CodeGenFunction r (Stereo.T (Serial.Value n a))+deinterleave v =+ Stereo.unMultiValueSerial <$>+ (Serial.assemble . map Stereo.multiValue =<< dissect v)++fromMono ::+ (TypeNum.Positive n, MultiVector.C a) =>+ Serial.Value n a ->+ LLVM.CodeGenFunction r (Value n a)+fromMono x =+ assemble . map pure =<< Serial.dissect x++assemble ::+ (TypeNum.Positive n, MultiVector.C a) =>+ [Stereo.T (MultiValue.T a)] -> LLVM.CodeGenFunction r (Value n a)+assemble x =+ withSize $ \n ->+ uncurry (liftA2 merge) .+ mapPair (MultiVector.assemble, MultiVector.assemble) .+ splitAt n .+ concatMap Fold.toList $ x++dissect ::+ (TypeNum.Positive n, MultiVector.C a) =>+ Value n a -> LLVM.CodeGenFunction r [Stereo.T (MultiValue.T a)]+dissect v =+ let (v0,v1) = split v in+ fmap+ (let aux (l:r:xs) = Stereo.cons l r : aux xs+ aux [] = []+ aux _ = error "odd number of stereo elements"+ in aux) $+ liftA2 (++)+ (MultiVector.dissect v0)+ (MultiVector.dissect v1)+++merge :: MultiVector.T n a -> MultiVector.T n a -> MultiValue.T (T n a)+merge (MultiVector.Cons a) (MultiVector.Cons b) = MultiValue.Cons (a,b)++split :: MultiValue.T (T n a) -> (MultiVector.T n a, MultiVector.T n a)+split (MultiValue.Cons (a,b)) = (MultiVector.Cons a, MultiVector.Cons b)++merge_ ::+ MultiValue.T (Vector n a) -> MultiValue.T (Vector n a) ->+ MultiValue.T (T n a)+merge_ (MultiValue.Cons a) (MultiValue.Cons b) = MultiValue.Cons (a,b)++split_ ::+ MultiValue.T (T n a) ->+ (MultiValue.T (Vector n a), MultiValue.T (Vector n a))+split_ (MultiValue.Cons (a,b)) = (MultiValue.Cons a, MultiValue.Cons b)++instance (TypeNum.Positive n, MultiVector.C a) => MultiValue.C (T n a) where+ type Repr (T n a) = (MultiVector.Repr n a, MultiVector.Repr n a)+ cons (Cons v0 v1) = merge (MultiVector.cons v0) (MultiVector.cons v1)+ undef = merge MultiVector.undef MultiVector.undef+ zero = merge MultiVector.zero MultiVector.zero+ phi bb =+ fmap (uncurry merge) .+ AppHT.mapPair (MultiVector.phi bb, MultiVector.phi bb) . split+ addPhi bb a b =+ case (split a, split b) of+ ((a0,a1), (b0,b1)) -> do+ MultiVector.addPhi bb a0 b0+ MultiVector.addPhi bb a1 b1++instance (Marshal.Vector n a) => Marshal.C (T n a) where+ pack (Cons v0 v1) = Marshal.pack (v0,v1)+ unpack = uncurry Cons . Marshal.unpack++instance+ (TypeNum.Positive n, MultiVector.C a, St.Storable a) =>+ St.Storable (T n a) where+ sizeOf ~(Cons v0 v1) = St.sizeOf v0 + St.sizeOf v1+ alignment ~(Cons v _) = St.alignment v+ peek ptr =+ let p = castPtr ptr+ in liftA2 Cons+ (St.peekElemOff p 0)+ (St.peekElemOff p 1)+ poke ptr (Cons v0 v1) =+ let p = castPtr ptr+ in St.pokeElemOff p 0 v0 >>+ St.pokeElemOff p 1 v1++instance (TypeNum.Positive n, Storable.Vector a) => Storable.C (T n a) where+ load ptrV = do+ ptr <- castHalfPtr ptrV+ liftA2 merge_+ (Storable.load ptr)+ (Storable.load =<< Storable.incrementPtr ptr)+ store v ptrV = do+ let (v0,v1) = split_ v+ ptr <- castHalfPtr ptrV+ Storable.storeNext v0 ptr >>= Storable.store v1++castHalfPtr ::+ LLVM.Value (Ptr (T n a)) ->+ LLVM.CodeGenFunction r (LLVM.Value (Ptr (Vector n a)))+castHalfPtr = LLVM.bitcast+++{- |+This instance allows to run @arrange@ on interleaved stereo vectors.+-}+instance+ (TypeNum.Positive n, MultiVector.Additive a) =>+ MultiValue.Additive (T n a) where+ add = zipV merge A.add+ sub = zipV merge A.sub+ neg = mapV A.neg+++zero :: (TypeNum.Positive n, Additive.C a) => T n a+zero = Cons (pure Additive.zero) (pure Additive.zero)+++scale ::+ (TypeNum.Positive n, MultiVector.PseudoRing a) =>+ MultiValue.T a -> Value n a -> LLVM.CodeGenFunction r (Value n a)+scale a v = do+ av <- MultiVector.replicate a+ mapV (A.mul av) v++amplify ::+ (TypeNum.Positive n, MultiVector.PseudoRing a) =>+ a -> Value n a -> LLVM.CodeGenFunction r (Value n a)+amplify a = scale (MultiValue.cons a)++envelope ::+ (TypeNum.Positive n, MultiVector.PseudoRing a) =>+ Serial.Value n a -> Value n a -> LLVM.CodeGenFunction r (Value n a)+envelope e a =+ zipV merge (flip A.mul) a =<< fromMono e+++mapV :: (Applicative m) =>+ (MultiVector.T n a -> m (MultiVector.T n a)) ->+ Value n a -> m (Value n a)+mapV f x =+ case split x of+ (x0,x1) -> uncurry merge <$> liftA2 (,) (f x0) (f x1)++zipV :: (Applicative m) =>+ (c -> c -> d) ->+ (MultiVector.T n a ->+ MultiVector.T n b ->+ m c) ->+ Value n a ->+ Value n b ->+ m d+zipV g f x y =+ case (split x, split y) of+ ((x0,x1), (y0,y1)) -> liftA2 g (f x0 y0) (f x1 y1)
+ src/Synthesizer/LLVM/Generator/Core.hs view
@@ -0,0 +1,86 @@+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+module Synthesizer.LLVM.Generator.Core where++import qualified Synthesizer.LLVM.Causal.Private as Causal+import qualified Synthesizer.LLVM.Generator.Private as Sig+import qualified Synthesizer.LLVM.Random as Rnd++import Synthesizer.Causal.Class (($*))++import qualified LLVM.DSL.Expression as Expr+import LLVM.DSL.Expression (Exp)++import qualified LLVM.Extra.Multi.Value.Marshal as Marshal+import qualified LLVM.Extra.Multi.Value as MultiValue+import qualified LLVM.Extra.Arithmetic as A++import Control.Applicative ((<$>))++import Data.Word (Word32)++import NumericPrelude.Numeric+import NumericPrelude.Base hiding (map, iterate, takeWhile, tail)++++type MV a = Sig.T (MultiValue.T a)++iterate :: (Marshal.C a) => (Exp a -> Exp a) -> Exp a -> MV a+iterate f a = Sig.iterate (Expr.unliftM1 f) (Expr.unExp a)++-- ToDo: replace by constantSharing and scanl+iterateParam ::+ (Marshal.C a, Marshal.C b) =>+ (Exp b -> Exp a -> Exp a) -> Exp b -> Exp a -> MV a+iterateParam f b a =+ MultiValue.snd <$>+ iterate (Expr.uncurry $ \bi ai -> Expr.zip bi $ f bi ai) (Expr.zip b a)+++ramp ::+ (Marshal.C a, MultiValue.Additive a) =>+ Exp a -> Exp a -> MV a+ramp = iterateParam Expr.add++parabola ::+ (Marshal.C a, MultiValue.Additive a) =>+ Exp a -> Exp a -> Exp a -> MV a+parabola d2 d1 start = integrate start $* ramp d2 d1++integrate ::+ (Marshal.C a, MultiValue.Additive a, MultiValue.T a ~ al) =>+ Exp a -> Causal.T al al+integrate start =+ Causal.mapAccum (\a s -> (,) s <$> A.add s a) (Expr.unExp start)+++osci ::+ (MultiValue.Fraction t, Marshal.C t) =>+ Exp t -> Exp t -> MV t+osci phase freq = iterate (Expr.liftM2 A.incPhase freq) phase++exponential ::+ (Marshal.C a, MultiValue.PseudoRing a) =>+ Exp a -> Exp a -> MV a+exponential = iterateParam Expr.mul++exponentialBounded ::+ (Marshal.C a, MultiValue.PseudoRing a,+ MultiValue.Real a, MultiValue.IntegerConstant a) =>+ Exp a -> Exp a -> Exp a -> MV a+exponentialBounded bound decay =+ iterateParam+ (\bk y -> case Expr.unzip bk of (b,k) -> Expr.max b $ k*y)+ (Expr.zip bound decay)+++noise, noiseAlt :: Exp Word32 -> MV Word32+noise seed =+ iterate (Expr.liftReprM Rnd.nextCG)+ (Expr.irem seed (Expr.cons Rnd.modulus-1) + 1)++noiseAlt seed =+ iterate (Expr.liftReprM Rnd.nextCG32)+ (Expr.irem seed (Expr.cons Rnd.modulus-1) + 1)
− src/Synthesizer/LLVM/Generator/Exponential2.hs
@@ -1,332 +0,0 @@-{-# LANGUAGE NoImplicitPrelude #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{- |-Exponential curve with controllable delay.--}-module Synthesizer.LLVM.Generator.Exponential2 (- Parameter,- parameter,- parameterPlain,- causalP,-- ParameterPacked,- parameterPacked,- parameterPackedPlain,- causalPackedP,- ) where--import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP-import qualified Synthesizer.LLVM.Simple.Value as Value-import qualified Synthesizer.LLVM.Frame.SerialVector as Serial-import qualified Synthesizer.LLVM.CausalParameterized.Functional as F--import qualified LLVM.DSL.Parameter as Param--import qualified LLVM.Extra.ScalarOrVector as SoV-import qualified LLVM.Extra.Vector as Vector-import qualified LLVM.Extra.Storable as Storable-import qualified LLVM.Extra.Marshal as Marshal-import qualified LLVM.Extra.Memory as Memory-import qualified LLVM.Extra.Tuple as Tuple-import qualified LLVM.Extra.Arithmetic as A--import qualified LLVM.Core as LLVM-import LLVM.Core- (CodeGenFunction, Value, IsArithmetic, IsPrimitive, IsFloating, SizeOf)--import qualified Type.Data.Num.Decimal as TypeNum-import Type.Data.Num.Decimal.Number ((:*:))--import Foreign.Storable (Storable)-import qualified Foreign.Storable--- import qualified Foreign.Storable.Record as Store-import qualified Foreign.Storable.Traversable as Store--import qualified Control.Applicative as App-import qualified Data.Foldable as Fold-import qualified Data.Traversable as Trav-import Control.Applicative (liftA2, (<*>))-import Control.Arrow (arr, (^<<), (&&&))-import Control.Monad (liftM2)--import qualified Algebra.Transcendental as Trans--import NumericPrelude.Numeric-import NumericPrelude.Base---newtype Parameter a = Parameter a- deriving (Show, Storable)---instance Functor Parameter where- {-# INLINE fmap #-}- fmap f (Parameter k) = Parameter (f k)--instance App.Applicative Parameter where- {-# INLINE pure #-}- pure x = Parameter x- {-# INLINE (<*>) #-}- Parameter f <*> Parameter k =- Parameter (f k)--instance Fold.Foldable Parameter where- {-# INLINE foldMap #-}- foldMap = Trav.foldMapDefault--instance Trav.Traversable Parameter where- {-# INLINE sequenceA #-}- sequenceA (Parameter k) =- fmap Parameter k---instance (Tuple.Phi a) => Tuple.Phi (Parameter a) where- phi = Tuple.phiTraversable- addPhi = Tuple.addPhiFoldable--instance Tuple.Undefined a => Tuple.Undefined (Parameter a) where- undef = Tuple.undefPointed--instance Tuple.Zero a => Tuple.Zero (Parameter a) where- zero = Tuple.zeroPointed--instance (Memory.C a) => Memory.C (Parameter a) where- type Struct (Parameter a) = Memory.Struct a- load = Memory.loadNewtype Parameter- store = Memory.storeNewtype (\(Parameter k) -> k)- decompose = Memory.decomposeNewtype Parameter- compose = Memory.composeNewtype (\(Parameter k) -> k)--instance (Storable.C a) => Storable.C (Parameter a) where- load = Storable.loadNewtype Parameter Parameter- store = Storable.storeNewtype Parameter (\(Parameter k) -> k)--{--instance LLVM.ValueTuple a => LLVM.ValueTuple (Parameter a) where- buildTuple f = Class.buildTupleTraversable (LLVM.buildTuple f)--instance LLVM.IsTuple a => LLVM.IsTuple (Parameter a) where- tupleDesc = Class.tupleDescFoldable--}--instance (Tuple.Value a) => Tuple.Value (Parameter a) where- type ValueOf (Parameter a) = Parameter (Tuple.ValueOf a)- valueOf = Tuple.valueOfFunctor---instance (Value.Flatten a) => Value.Flatten (Parameter a) where- type Registers (Parameter a) = Parameter (Value.Registers a)- flattenCode = Value.flattenCodeTraversable- unfoldCode = Value.unfoldCodeTraversable---instance (Vector.Simple v) => Vector.Simple (Parameter v) where- type Element (Parameter v) = Parameter (Vector.Element v)- type Size (Parameter v) = Vector.Size v- shuffleMatch = Vector.shuffleMatchTraversable- extract = Vector.extractTraversable--instance (Vector.C v) => Vector.C (Parameter v) where- insert = Vector.insertTraversable---parameter ::- (Trans.C a, SoV.TranscendentalConstant a, IsFloating a) =>- Value a ->- CodeGenFunction r (Parameter (Value a))-parameter = Value.unlift1 parameterPlain--parameterPlain ::- (Trans.C a) =>- a -> Parameter a-parameterPlain halfLife =- Parameter $ 0.5 ** recip halfLife---causalP ::- (Marshal.C a, Tuple.ValueOf a ~ al, A.PseudoRing al) =>- Param.T p a ->- CausalP.T p (Parameter al) al-causalP initial =- CausalP.loop initial- (arr snd &&& CausalP.zipWithSimple (\(Parameter a) -> A.mul a))---data ParameterPacked a =- ParameterPacked {ppFeedback, ppCurrent :: a}---instance Functor ParameterPacked where- {-# INLINE fmap #-}- fmap f p = ParameterPacked- (f $ ppFeedback p) (f $ ppCurrent p)--instance App.Applicative ParameterPacked where- {-# INLINE pure #-}- pure x = ParameterPacked x x- {-# INLINE (<*>) #-}- f <*> p = ParameterPacked- (ppFeedback f $ ppFeedback p)- (ppCurrent f $ ppCurrent p)--instance Fold.Foldable ParameterPacked where- {-# INLINE foldMap #-}- foldMap = Trav.foldMapDefault--instance Trav.Traversable ParameterPacked where- {-# INLINE sequenceA #-}- sequenceA p =- liftA2 ParameterPacked- (ppFeedback p) (ppCurrent p)---instance (Tuple.Phi a) => Tuple.Phi (ParameterPacked a) where- phi = Tuple.phiTraversable- addPhi = Tuple.addPhiFoldable--instance Tuple.Undefined a => Tuple.Undefined (ParameterPacked a) where- undef = Tuple.undefPointed--instance Tuple.Zero a => Tuple.Zero (ParameterPacked a) where- zero = Tuple.zeroPointed---{--storeParameter ::- Storable a => Store.Dictionary (ParameterPacked a)-storeParameter =- Store.run $- liftA2 ParameterPacked- (Store.element ppFeedback)- (Store.element ppCurrent)--instance Storable a => Storable (ParameterPacked a) where- sizeOf = Store.sizeOf storeParameter- alignment = Store.alignment storeParameter- peek = Store.peek storeParameter- poke = Store.poke storeParameter--}--instance Storable a => Storable (ParameterPacked a) where- sizeOf = Store.sizeOf- alignment = Store.alignment- peek = Store.peekApplicative- poke = Store.poke---type ParameterPackedStruct a = LLVM.Struct (a, (a, ()))--memory ::- (Memory.C a) =>- Memory.Record r (ParameterPackedStruct (Memory.Struct a)) (ParameterPacked a)-memory =- liftA2 ParameterPacked- (Memory.element ppFeedback TypeNum.d0)- (Memory.element ppCurrent TypeNum.d1)--instance (Memory.C a) => Memory.C (ParameterPacked a) where- type Struct (ParameterPacked a) = ParameterPackedStruct (Memory.Struct a)- load = Memory.loadRecord memory- store = Memory.storeRecord memory- decompose = Memory.decomposeRecord memory- compose = Memory.composeRecord memory--instance (Storable.C a) => Storable.C (ParameterPacked a) where- load = Storable.loadApplicative- store = Storable.storeFoldable---{--instance LLVM.ValueTuple a => LLVM.ValueTuple (ParameterPacked a) where- buildTuple f = Class.buildTupleTraversable (LLVM.buildTuple f)--instance LLVM.IsTuple a => LLVM.IsTuple (ParameterPacked a) where- tupleDesc = Class.tupleDescFoldable--}--instance (Tuple.Value a) => Tuple.Value (ParameterPacked a) where- type ValueOf (ParameterPacked a) = ParameterPacked (Tuple.ValueOf a)- valueOf = Tuple.valueOfFunctor---instance (Value.Flatten a) => Value.Flatten (ParameterPacked a) where- type Registers (ParameterPacked a) = ParameterPacked (Value.Registers a)- flattenCode = Value.flattenCodeTraversable- unfoldCode = Value.unfoldCodeTraversable--type instance F.Arguments f (ParameterPacked a) = f (ParameterPacked a)-instance F.MakeArguments (ParameterPacked a) where- makeArgs = id----withSize ::- (TypeNum.Natural n) =>- (Serial.C v, Serial.Size v ~ n, TypeNum.Positive n) =>- (TypeNum.Singleton n -> m (param v)) ->- m (param v)-withSize f = f TypeNum.singleton--parameterPacked ::- (Serial.C v, Serial.Element v ~ a,- A.PseudoRing v, A.RationalConstant v,- A.Transcendental a, A.RationalConstant a) =>- a -> CodeGenFunction r (ParameterPacked v)-parameterPacked halfLife = withSize $ \n -> do- feedback <-- Serial.upsample =<<- A.pow (A.fromRational' 0.5) =<<- A.fdiv (A.fromInteger' $ TypeNum.integralFromSingleton n) halfLife- k <-- A.pow (A.fromRational' 0.5) =<<- A.fdiv (A.fromInteger' 1) halfLife- current <-- Serial.iterate (A.mul k) (A.fromInteger' 1)- return $ ParameterPacked feedback current-{-- Value.unlift1 parameterPackedPlain--}--withSizePlain ::- (TypeNum.Natural n) =>- (TypeNum.Singleton n -> param (Serial.Plain n a)) ->- param (Serial.Plain n a)-withSizePlain f = f TypeNum.singleton--parameterPackedPlain ::- (Trans.C a,- TypeNum.Positive n) =>- a -> ParameterPacked (Serial.Plain n a)-parameterPackedPlain halfLife =- withSizePlain $ \n ->- ParameterPacked- (Serial.replicate_ n (0.5 ** (fromInteger (TypeNum.integerFromSingleton n) / halfLife)))- (Serial.iteratePlain (0.5 ** recip halfLife *) one)---withSizeValue ::- (TypeNum.Natural n) =>- (TypeNum.Singleton n -> f (Serial.Value n a)) ->- f (Serial.Value n a)-withSizeValue f = f TypeNum.singleton--causalPackedP ::- (IsArithmetic a, SoV.IntegerConstant a,- Marshal.C a, Tuple.ValueOf a ~ Value a,- Marshal.Vector n a, Tuple.VectorValueOf n a ~ Value (LLVM.Vector n a),- IsPrimitive a,- TypeNum.Positive (n :*: SizeOf a),- TypeNum.Positive n) =>- Param.T p a ->- CausalP.T p (ParameterPacked (Serial.Value n a)) (Serial.Value n a)-causalPackedP initial =- withSizeValue $ \n ->- CausalP.loop- (Serial.replicate_ n ^<< initial)- (CausalP.mapSimple $- \(p, s0) -> liftM2 (,)- (A.mul (ppCurrent p) s0)- (A.mul (ppFeedback p) s0))
+ src/Synthesizer/LLVM/Generator/Extra.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE Rank2Types #-}+module Synthesizer.LLVM.Generator.Extra where++import qualified Synthesizer.LLVM.Causal.Process as Causal+import qualified Synthesizer.LLVM.Generator.Signal as Sig+import Synthesizer.Causal.Class (($*))++import qualified LLVM.DSL.Expression as Expr+import LLVM.DSL.Expression (Exp)++import qualified LLVM.Extra.Multi.Value.Marshal as Marshal+import qualified LLVM.Extra.Multi.Value as MultiValue++import Data.Word (Word)++import NumericPrelude.Numeric++++ramp,+ parabolaFadeIn, parabolaFadeOut,+ parabolaFadeInMap, parabolaFadeOutMap ::+ (Marshal.C a, MultiValue.Field a, MultiValue.IntegerConstant a,+ MultiValue.NativeFloating a ar) =>+ Exp Word -> Sig.MV a++ramp dur =+ Causal.take dur $* Sig.rampInf (Expr.fromIntegral dur)++parabolaFadeIn dur =+ Causal.take dur $* Sig.parabolaFadeInInf (Expr.fromIntegral dur)++parabolaFadeOut dur =+ Causal.take dur $* Sig.parabolaFadeOutInf (Expr.fromIntegral dur)++parabolaFadeInMap dur = Causal.map (\t -> t*(2-t)) $* ramp dur+parabolaFadeOutMap dur = Causal.map (\t -> 1-t*t) $* ramp dur
+ src/Synthesizer/LLVM/Generator/Private.hs view
@@ -0,0 +1,201 @@+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE Rank2Types #-}+module Synthesizer.LLVM.Generator.Private where++import Synthesizer.LLVM.Private (getPairPtrs, noLocalPtr)++import qualified LLVM.Extra.Memory as Memory+import qualified LLVM.Extra.MaybeContinuation as MaybeCont+import qualified LLVM.Extra.Arithmetic as A+import qualified LLVM.Extra.Tuple as Tuple++import qualified LLVM.Core as LLVM+import LLVM.Core (CodeGenFunction)++import Type.Base.Proxy (Proxy(Proxy))++import Control.Applicative (Applicative, liftA2, pure, (<*>), (<$>))++import Data.Semigroup (Semigroup, (<>))+import Data.Tuple.Strict (mapFst, zipPair)++import qualified Number.Ratio as Ratio+import qualified Algebra.Field as Field+import qualified Algebra.Ring as Ring+import qualified Algebra.Additive as Additive++import qualified Prelude as P+import Prelude hiding (iterate, takeWhile, map, zipWith)+++data T a =+ forall global local state.+ (Memory.C global, LLVM.IsSized local, Memory.C state) =>+ Cons (forall r c.+ (Tuple.Phi c) =>+ global ->+ -- pointer to loop local storage+ LLVM.Value (LLVM.Ptr local) ->+ state -> MaybeCont.T r c (a, state))+ -- compute next value+ (forall r. CodeGenFunction r (global, state))+ -- initial state+ (forall r. global -> CodeGenFunction r ())+ -- cleanup+++noGlobal ::+ (LLVM.IsSized local, Memory.C state) =>+ (forall r c.+ (Tuple.Phi c) =>+ LLVM.Value (LLVM.Ptr local) -> state -> MaybeCont.T r c (a, state)) ->+ (forall r. CodeGenFunction r state) ->+ T a+noGlobal next start = Cons (const next) (fmap ((,) ()) start) return++alloca :: (LLVM.IsSized a) => T (LLVM.Value (LLVM.Ptr a))+alloca =+ noGlobal+ (\ptr () -> return (ptr, ()))+ (return ())+++iterate ::+ (Memory.C a) =>+ (forall r. a -> CodeGenFunction r a) ->+ (forall r. CodeGenFunction r a) -> T a+iterate f a =+ noGlobal+ (noLocalPtr $ \s -> fmap ((,) s) $ MaybeCont.lift $ f s)+ a++iterateParam ::+ (Memory.C b, Memory.C a) =>+ (forall r. b -> a -> CodeGenFunction r a) ->+ (forall r. CodeGenFunction r b) ->+ (forall r. CodeGenFunction r a) -> T a+iterateParam f b a =+ fmap snd $ iterate (\(bi,ai) -> (,) bi <$> f bi ai) (liftA2 (,) b a)++takeWhile ::+ (forall r. a -> CodeGenFunction r (LLVM.Value Bool)) -> T a -> T a+takeWhile p (Cons next start stop) = Cons+ (\global local s0 -> do+ (a,s1) <- next global local s0+ MaybeCont.guard =<< MaybeCont.lift (p a)+ return (a,s1))+ start+ stop+++empty :: T a+empty = noGlobal (noLocalPtr $ \ _state -> MaybeCont.nothing) (return ())++{- |+Appending many signals is inefficient,+since in cascadingly appended signals the parts are counted in an unary way.+Concatenating infinitely many signals is impossible.+If you want to concatenate a lot of signals,+please render them to lazy storable vectors first.+-}+{-+We might save a little space by using a union+for the states of the first and the second signal generator.+If the concatenated generators allocate memory,+we could also save some memory by calling @startB@+only after the first generator finished.+However, for correct deallocation+we would need to track which of the @start@ blocks+have been executed so far.+This in turn might be difficult in connection with the garbage collector.+-}+append :: (Tuple.Phi a, Tuple.Undefined a) => T a -> T a -> T a+append (Cons nextA startA stopA) (Cons nextB startB stopB) = Cons+ (\(globalA, globalB) local (sa0,sb0,phaseB) -> do+ (localA,localB) <- getPairPtrs local+ MaybeCont.alternative+ (do+ MaybeCont.guard =<< MaybeCont.lift (LLVM.inv phaseB)+ (a,sa1) <- nextA globalA localA sa0+ return (a, (sa1, sb0, LLVM.valueOf False)))+ (do+ (b,sb1) <- nextB globalB localB sb0+ return (b, (sa0, sb1, LLVM.valueOf True))))+ (do+ (globalA,stateA) <- startA+ (globalB,stateB) <- startB+ return ((globalA,globalB), (stateA, stateB, LLVM.valueOf False)))+ (\(globalA,globalB) -> stopB globalB >> stopA globalA)++instance (Tuple.Phi a, Tuple.Undefined a) => Semigroup (T a) where+ (<>) = append++instance (Tuple.Phi a, Tuple.Undefined a) => Monoid (T a) where+ mempty = empty+ mappend = (<>)++++instance Functor T where+ fmap f (Cons next start stop) = Cons+ (\global local s -> mapFst f <$> next global local s)+ start stop++instance Applicative T where+ pure a = noGlobal (noLocalPtr $ \() -> return (a, ())) (return ())+ Cons nextF startF stopF <*> Cons nextA startA stopA = Cons+ (\(globalF, globalA) local (sf0,sa0) -> do+ (localF,localA) <- getPairPtrs local+ (f,sf1) <- nextF globalF localF sf0+ (a,sa1) <- nextA globalA localA sa0+ return (f a, (sf1,sa1)))+ (liftA2 zipPair startF startA)+ (\(globalF, globalA) -> stopA globalA >> stopF globalF)+++map :: (forall r. a -> CodeGenFunction r b) -> T a -> T b+map f (Cons next start stop) =+ Cons+ (\global local sa0 -> do+ (a,sa1) <- next global local sa0+ b <- MaybeCont.lift $ f a+ return (b, sa1))+ start stop++zipWith :: (forall r. a -> b -> CodeGenFunction r c) -> T a -> T b -> T c+zipWith f as bs = map (uncurry f) $ liftA2 (,) as bs++instance (A.Additive a) => Additive.C (T a) where+ zero = pure A.zero+ negate = map A.neg+ (+) = zipWith A.add+ (-) = zipWith A.sub++instance (A.PseudoRing a, A.IntegerConstant a) => Ring.C (T a) where+ one = pure A.one+ fromInteger n = pure (A.fromInteger' n)+ (*) = zipWith A.mul++instance (A.Field a, A.RationalConstant a) => Field.C (T a) where+ fromRational' x = pure (A.fromRational' $ Ratio.toRational98 x)+ (/) = zipWith A.fdiv+++instance (A.PseudoRing a, A.Real a, A.IntegerConstant a) => P.Num (T a) where+ fromInteger n = pure (A.fromInteger' n)+ negate = map A.neg+ (+) = zipWith A.add+ (-) = zipWith A.sub+ (*) = zipWith A.mul+ abs = map A.abs+ signum = map A.signum++instance (A.Field a, A.Real a, A.RationalConstant a) => P.Fractional (T a) where+ fromRational x = pure (A.fromRational' x)+ (/) = zipWith A.fdiv++++arraySize :: value (array n a) -> Proxy n+arraySize _ = Proxy
+ src/Synthesizer/LLVM/Generator/Render.hs view
@@ -0,0 +1,525 @@+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE ForeignFunctionInterface #-}+module Synthesizer.LLVM.Generator.Render where++import qualified Synthesizer.LLVM.Causal.Parameterized as Parameterized+import qualified Synthesizer.LLVM.Generator.Source as Source+import qualified Synthesizer.LLVM.Storable.ChunkIterator as ChunkIt+import qualified Synthesizer.LLVM.Storable.LazySizeIterator as SizeIt+import qualified Synthesizer.LLVM.EventIterator as EventIt+import Synthesizer.LLVM.Generator.Private (T(Cons))++import qualified Synthesizer.LLVM.Frame.Stereo as Stereo+import qualified Synthesizer.LLVM.Storable.Vector as SVU+import qualified Synthesizer.LLVM.ForeignPtr as ForeignPtr+import qualified Synthesizer.LLVM.ConstantPiece as Const++import qualified Synthesizer.PiecewiseConstant.Signal as PC+import qualified Synthesizer.Causal.Class as CausalClass++import qualified LLVM.DSL.Execution as Exec+import qualified LLVM.DSL.Expression as Expr+import LLVM.DSL.Expression (Exp(Exp))++import qualified LLVM.Extra.Multi.Value.Storable as Storable+import qualified LLVM.Extra.Multi.Value.Marshal as Marshal+import qualified LLVM.Extra.Multi.Value as MultiValue+import qualified LLVM.Extra.Memory as Memory+import qualified LLVM.Extra.MaybeContinuation as MaybeCont+import qualified LLVM.Extra.Maybe as Maybe+import qualified LLVM.Extra.Control as C+import qualified LLVM.Extra.Arithmetic as A+import qualified LLVM.Extra.Tuple as Tuple++import qualified LLVM.Core as LLVM++import qualified Type.Data.Num.Decimal as TypeNum++import qualified Data.StorableVector.Lazy as SVL+import qualified Data.StorableVector.Base as SVB+import qualified Data.StorableVector as SV++import qualified Data.EventList.Relative.BodyTime as EventList+import qualified Numeric.NonNegative.Wrapper as NonNeg+import qualified Numeric.NonNegative.Chunky as NonNegChunky++import Control.Monad (join)+import Control.Applicative (liftA3)++import Foreign.ForeignPtr (touchForeignPtr)+import Foreign.Ptr (Ptr)++import Data.Foldable (traverse_)+import Data.Tuple.Strict (mapPair, mapTriple)+import Data.Word (Word, Word8, Word32)++import qualified System.Unsafe as Unsafe+++foreign import ccall safe "dynamic" derefFillPtr ::+ Exec.Importer (LLVM.Ptr param -> Word -> Ptr struct -> IO Word)+++compile ::+ (Storable.C a, MultiValue.T a ~ value,+ Marshal.C param, Marshal.Struct param ~ paramStruct) =>+ (Exp param -> T value) ->+ IO (LLVM.Ptr paramStruct -> Word -> Ptr a -> IO Word)+compile sig =+ Exec.compile "signal" $+ Exec.createFunction derefFillPtr "fill" $ \paramPtr size bPtr ->+ case sig (Exp (Memory.load paramPtr)) of+ Cons next start stop -> do+ (global,s) <- start+ local <- LLVM.alloca+ (pos,_) <- Storable.arrayLoopMaybeCont size bPtr s $ \ ptri s0 -> do+ (y,s1) <- next global local s0+ MaybeCont.lift $ Storable.store y ptri+ return s1+ stop global+ return pos++runAux ::+ (Marshal.C p, Storable.C a, MultiValue.T a ~ value) =>+ (Exp p -> T value) -> IO (IO () -> Int -> p -> IO (SV.Vector a))+runAux sig = do+ fill <- compile sig+ return $ \final len param ->+ Marshal.with param $ \paramPtr ->+ SVB.createAndTrim len $ \ptr -> do+ n <- fill paramPtr (fromIntegral len) ptr+ final+ return $ fromIntegral n++run_ ::+ (Marshal.C p, Storable.C a, MultiValue.T a ~ value) =>+ (Exp p -> T value) -> IO (Int -> p -> IO (SV.Vector a))+run_ = fmap ($ return ()) . runAux+++foreign import ccall safe "dynamic" derefStartPtr ::+ Exec.Importer (LLVM.Ptr param -> IO (LLVM.Ptr globalState))++foreign import ccall safe "dynamic" derefStopPtr ::+ Exec.Importer (LLVM.Ptr globalState -> IO ())++foreign import ccall safe "dynamic" derefChunkPtr ::+ Exec.Importer (LLVM.Ptr globalState -> Word -> Ptr a -> IO Word)+++type MemoryPtr a = LLVM.Ptr (Memory.Struct a)++type WithGlobalState param = LLVM.Struct (param, ())++type Pair a b = LLVM.Struct (a,(b,()))+type Triple a b c = LLVM.Struct (a,(b,(c,())))++tripleStruct ::+ (LLVM.IsSized a, LLVM.IsSized b, LLVM.IsSized c) =>+ LLVM.Value a -> LLVM.Value b -> LLVM.Value c ->+ LLVM.CodeGenFunction r (LLVM.Value (Triple a b c))+tripleStruct a b c = do+ s0 <- LLVM.insertvalue Tuple.undef a TypeNum.d0+ s1 <- LLVM.insertvalue s0 b TypeNum.d1+ LLVM.insertvalue s1 c TypeNum.d2++{- |+This is a pretty ugly hack, but its seems to be the least ugly one.+We need to solve the following problem:+We have a function of type @Exp param -> T value@.+This means that all methods in @T value@ depend on @Exp param@.+We need to choose one piece of LLVM code in @Exp param@+that generates appropriate code for all methods in @T value@.+If we access a function parameter via @Memory.load paramPtr@+this means that all methods must end up in the same LLVM function+in order to access this parameter.+Thus I have to put all functionality in one LLVM function+and then the three functions in 'compileChunky'+jump into the handler function with a 'Word8' code+specifying the actual sub-routine.+We need to squeeze all possible inputs and outputs+through one function interface.++However, since the handler is marked as internal+the optimizer inlines it in the three functions from 'compileChunky'+and eliminates dead code.+This way, we end up with the code that we would have written otherwise.++The alternative would be to construct @T value@ multiple times.+Due to existential quantification we cannot prove+that the pointer types of different methods match,+so we need to cast pointers.+However, with the current approach we also have to do that.+-}+compileHandler ::+ (Marshal.C param, Marshal.Struct param ~ paramStruct,+ Storable.C a, MultiValue.T a ~ value) =>+ (Exp param -> T value) ->+ LLVM.CodeGenModule+ (LLVM.Function+ (Word8 -> LLVM.Ptr paramStruct -> Word -> Ptr a ->+ IO (Pair (LLVM.Ptr (WithGlobalState paramStruct)) Word)))+compileHandler sig =+ LLVM.createNamedFunction LLVM.InternalLinkage "handlesignal" $+ \phase paramPtr loopLen bufferPtr ->+ case sig $ Exp (Memory.load paramPtr) of+ Cons next start stop -> do+ paramGlobalStatePtr <- LLVM.bitcast paramPtr++ let create = do+ newParamGlobalStatePtr <- LLVM.malloc+ (global,state) <- start+ flip LLVM.store newParamGlobalStatePtr =<<+ join+ (liftA3 tripleStruct+ (LLVM.load paramPtr)+ (Memory.compose global)+ (Memory.compose state))+ newOpaqueParamGlobalStatePtr <-+ LLVM.bitcast+ (newParamGlobalStatePtr `asTypeOf` paramGlobalStatePtr)+ LLVM.insertvalue Tuple.undef+ newOpaqueParamGlobalStatePtr TypeNum.d0++ let delete = do+ globalPtr <-+ LLVM.getElementPtr0 paramGlobalStatePtr (TypeNum.d1, ())+ stop =<< Memory.load globalPtr+ LLVM.free paramGlobalStatePtr+ return Tuple.undef++ let fill = do+ globalPtr <-+ LLVM.getElementPtr0 paramGlobalStatePtr (TypeNum.d1, ())+ statePtr <-+ LLVM.getElementPtr0 paramGlobalStatePtr (TypeNum.d2, ())+ global <- Memory.load globalPtr+ sInit <- Memory.load statePtr+ local <- LLVM.alloca+ (pos,sExit) <-+ Storable.arrayLoopMaybeCont loopLen bufferPtr sInit $+ \ ptr s0 -> do+ (y,s1) <- next global local s0+ MaybeCont.lift $ Storable.store y ptr+ return s1+ Memory.store (Maybe.fromJust sExit) statePtr+ LLVM.insertvalue Tuple.undef pos TypeNum.d1++ doCreate <- A.cmp LLVM.CmpEQ (LLVM.valueOf 0) phase+ doDelete <- A.cmp LLVM.CmpEQ (LLVM.valueOf 1) phase+ C.ret =<<+ (C.ifThenElse doCreate create $+ C.ifThenElse doDelete delete fill)++compileChunky ::+ (LLVM.IsSized paramStruct, LLVM.Value (LLVM.Ptr paramStruct) ~ pPtr,+ Memory.C state, Memory.Struct state ~ stateStruct,+ Memory.C global, Memory.Struct global ~ globalStruct,+ Triple paramStruct globalStruct stateStruct ~ triple,+ LLVM.IsSized local,+ Storable.C a, MultiValue.T a ~ value) =>+ (forall r z. (Tuple.Phi z) =>+ pPtr -> global -> LLVM.Value (LLVM.Ptr local) ->+ () -> state -> MaybeCont.T r z (value, state)) ->+ (forall r. pPtr -> LLVM.CodeGenFunction r (global, state)) ->+ (forall r. pPtr -> global -> LLVM.CodeGenFunction r ()) ->+ IO (LLVM.Ptr paramStruct -> IO (LLVM.Ptr triple),+ Exec.Finalizer triple,+ LLVM.Ptr triple -> Word -> Ptr a -> IO Word)+compileChunky next start stop =+ Exec.compile "signal-chunky" $+ liftA3 (,,)+ (Exec.createFunction derefStartPtr "startsignal" $+ \paramPtr -> do+ paramGlobalStatePtr <- LLVM.malloc+ (global,state) <- start paramPtr+ flip LLVM.store paramGlobalStatePtr =<<+ join+ (liftA3 tripleStruct+ (LLVM.load paramPtr)+ (Memory.compose global)+ (Memory.compose state))+ return paramGlobalStatePtr)+ (Exec.createFinalizer derefStopPtr "stopsignal" $+ \paramGlobalStatePtr -> do+ paramPtr <-+ LLVM.getElementPtr0 paramGlobalStatePtr (TypeNum.d0, ())+ stop paramPtr =<<+ Memory.load =<<+ LLVM.getElementPtr0 paramGlobalStatePtr (TypeNum.d1, ())+ LLVM.free paramGlobalStatePtr)+ (Exec.createFunction derefChunkPtr "fillsignal" $+ \paramGlobalStatePtr loopLen ptr -> do+ paramPtr <-+ LLVM.getElementPtr0 paramGlobalStatePtr (TypeNum.d0, ())+ global <-+ Memory.load =<<+ LLVM.getElementPtr0 paramGlobalStatePtr (TypeNum.d1, ())+ statePtr <-+ LLVM.getElementPtr0 paramGlobalStatePtr (TypeNum.d2, ())+ sInit <- Memory.load statePtr+ local <- LLVM.alloca+ (pos,sExit) <-+ Storable.arrayLoopMaybeCont loopLen ptr sInit $+ \ ptri s0 -> do+ (y,s1) <- next paramPtr global local () s0+ MaybeCont.lift $ Storable.store y ptri+ return s1+ Memory.store (Maybe.fromJust sExit) statePtr+ return pos)+++runChunkyAux ::+ (Storable.C a, MultiValue.T a ~ value, Marshal.C p) =>+ (Exp p -> T value) -> IO (IO () -> SVL.ChunkSize -> p -> IO (SVL.Vector a))+runChunkyAux sig = do+ paramd <-+ Parameterized.fromProcessPtr "Signal.run" (CausalClass.fromSignal . sig)+ case paramd of+ Parameterized.Cons next start stop -> do+ (startFunc,stopFunc,fill) <- compileChunky next start stop+ return $ \final (SVL.ChunkSize size) p -> do+ statePtr <- ForeignPtr.newParamMV stopFunc startFunc p++ let go =+ Unsafe.interleaveIO $ do+ v <-+ ForeignPtr.with statePtr $ \sptr ->+ SVB.createAndTrim size $+ fmap (fromIntegral :: Word -> Int) .+ fill sptr (fromIntegral size)+ (if SV.length v > 0+ then fmap (v:)+ else id) $+ (if SV.length v < size+ then final >> return []+ else go)+ fmap SVL.fromChunks go++runChunky ::+ (Storable.C a, MultiValue.T a ~ value, Marshal.C p) =>+ (Exp p -> T value) -> IO (SVL.ChunkSize -> p -> IO (SVL.Vector a))+runChunky = fmap ($ return ()) . runChunkyAux+++runChunkyOnVector ::+ (Storable.C a, MultiValue.T a ~ al) =>+ (Storable.C b, MultiValue.T b ~ bl) =>+ (T al -> T bl) ->+ IO (SVL.ChunkSize -> SV.Vector a -> IO (SVL.Vector b))+runChunkyOnVector sig = do+ f <- runChunkyAux (sig . Source.storableVector)+ return $ \chunkSize av -> do+ let (fp,ptr,l) = SVU.unsafeToPointers av+ f (touchForeignPtr fp) chunkSize (Source.consStorableVector ptr l)+++class Run f where+ type DSL f+ type Shape f+ build ::+ (Marshal.C p) =>+ (Exp p -> DSL f) -> IO (IO (p, IO ()) -> Shape f -> f)++instance (Storable.C a) => Run (SVL.Vector a) where+ type DSL (SVL.Vector a) = T (MultiValue.T a)+ type Shape (SVL.Vector a) = SVL.ChunkSize+ build =+ fmap (\f create shape -> Unsafe.performIO $ buildIOGen f create shape) .+ runChunkyAux++instance (Storable.C a) => Run (SV.Vector a) where+ type DSL (SV.Vector a) = T (MultiValue.T a)+ type Shape (SV.Vector a) = Int+ build =+ fmap (\f create shape -> Unsafe.performIO $ buildIOGen f create shape) .+ runAux++instance (RunIO a) => Run (IO a) where+ type DSL (IO a) = T (DSL_IO a)+ type Shape (IO a) = ShapeIO a+ build = buildIO++instance (RunArg a, Run f) => Run (a -> f) where+ type DSL (a -> f) = DSLArg a -> DSL f+ type Shape (a -> f) = Shape f+ build sig =+ case buildArg of+ BuildArg pass createA -> do+ f <- build (Expr.uncurry $ \p -> sig p . pass)+ return $ \createP shape av ->+ f (do (p,finalP) <- createP+ (pa,finalA) <- createA av+ return ((p,pa), finalA >> finalP))+ shape+++class RunIO a where+ type DSL_IO a+ type ShapeIO a+ buildIO ::+ (Marshal.C p) =>+ (Exp p -> T (DSL_IO a)) -> IO (IO (p, IO ()) -> ShapeIO a -> IO a)++instance (Storable.C a) => RunIO (SVL.Vector a) where+ type DSL_IO (SVL.Vector a) = MultiValue.T a+ type ShapeIO (SVL.Vector a) = SVL.ChunkSize+ buildIO = fmap buildIOGen . runChunkyAux++instance (Storable.C a) => RunIO (SV.Vector a) where+ type DSL_IO (SV.Vector a) = MultiValue.T a+ type ShapeIO (SV.Vector a) = Int+ buildIO = fmap buildIOGen . runAux++buildIOGen ::+ (Monad m) => (final -> shape -> p -> m a) -> m (p, final) -> shape -> m a+buildIOGen f create shape = do (p,final) <- create; f final shape p+++data BuildArg a =+ forall al. Marshal.C al =>+ BuildArg (Exp al -> DSLArg a) (a -> IO (al, IO ()))++class RunArg a where+ type DSLArg a+ buildArg :: BuildArg a++instance RunArg () where+ type DSLArg () = ()+ buildArg = BuildArg (\ _unit -> ()) (\() -> return ((), return ()))++instance (RunArg a, RunArg b) => RunArg (a,b) where+ type DSLArg (a,b) = (DSLArg a, DSLArg b)+ buildArg =+ case (buildArg,buildArg) of+ (BuildArg passA createA, BuildArg passB createB) ->+ BuildArg+ (mapPair (passA,passB) . Expr.unzip)+ (\(a,b) -> do+ (pa,finalA) <- createA a+ (pb,finalB) <- createB b+ return ((pa,pb), finalB>>finalA))++instance (RunArg a, RunArg b, RunArg c) => RunArg (a,b,c) where+ type DSLArg (a,b,c) = (DSLArg a, DSLArg b, DSLArg c)+ buildArg =+ case (buildArg,buildArg,buildArg) of+ (BuildArg passA createA, BuildArg passB createB,+ BuildArg passC createC) ->+ BuildArg+ (mapTriple (passA,passB,passC) . Expr.unzip3)+ (\(a,b,c) -> do+ (pa,finalA) <- createA a+ (pb,finalB) <- createB b+ (pc,finalC) <- createC c+ return ((pa,pb,pc), finalC>>finalB>>finalA))++primitiveArg :: (Marshal.C a, DSLArg a ~ Exp a) => BuildArg a+primitiveArg = BuildArg id (\a -> return (a, return ()))++instance RunArg Float where+ type DSLArg Float = Exp Float+ buildArg = primitiveArg++instance RunArg Int where+ type DSLArg Int = Exp Int+ buildArg = primitiveArg++instance RunArg Word where+ type DSLArg Word = Exp Word+ buildArg = primitiveArg++instance RunArg Word32 where+ type DSLArg Word32 = Exp Word32+ buildArg = primitiveArg++instance (RunArg a) => RunArg (Stereo.T a) where+ type DSLArg (Stereo.T a) = Stereo.T (DSLArg a)+ buildArg =+ case buildArg of+ BuildArg pass create ->+ BuildArg+ (fmap pass . Stereo.unExpression)+ (\s -> do+ pf <- traverse create s+ return (fst<$>pf, traverse_ snd pf))++instance+ (TypeNum.Natural n, Marshal.C a, LLVM.IsSized (Marshal.Struct a),+ TypeNum.Natural (n TypeNum.:*: LLVM.SizeOf (Marshal.Struct a))) =>+ RunArg (MultiValue.Array n a) where+ type DSLArg (MultiValue.Array n a) = Exp (MultiValue.Array n a)+ buildArg = primitiveArg++instance (Storable.C a) => RunArg (SV.Vector a) where+ type DSLArg (SV.Vector a) = T (MultiValue.T a)+ buildArg =+ BuildArg+ Source.storableVector+ (\av -> do+ let (fp,ptr,l) = SVU.unsafeToPointers av+ return (Source.consStorableVector ptr l, touchForeignPtr fp))++newtype Buffer a = Buffer (SV.Vector a)++buffer :: SV.Vector a -> Buffer a+buffer = Buffer++instance (Storable.C a) => RunArg (Buffer a) where+ type DSLArg (Buffer a) = Exp (Source.StorableVector a)+ buildArg =+ BuildArg id+ (\(Buffer av) -> do+ let (fp,ptr,l) = SVU.unsafeToPointers av+ return (Source.consStorableVector ptr l, touchForeignPtr fp))++newDisposeArg ::+ (Marshal.C handle) =>+ (a -> IO handle) -> (handle -> IO ()) ->+ (Exp handle -> DSLArg a) -> BuildArg a+newDisposeArg new dispose fetch =+ BuildArg fetch+ (\x -> do+ it <- new x+ return (it, dispose it))++instance (Storable.C a) => RunArg (SVL.Vector a) where+ type DSLArg (SVL.Vector a) = T (MultiValue.T a)+ buildArg =+ newDisposeArg ChunkIt.new ChunkIt.dispose Source.storableVectorLazy++class TimeInteger int where+ subdivideLong :: EventList.T (NonNeg.T int) a -> EventList.T NonNeg.Int a++instance TimeInteger Int where+ subdivideLong = id++instance TimeInteger Integer where+ subdivideLong = PC.subdivideLongStrict++instance+ (time ~ NonNeg.T int, TimeInteger int, Marshal.C a) =>+ RunArg (EventList.T time a) where+ type DSLArg (EventList.T time a) = T (Const.T (MultiValue.T a))+ buildArg =+ newDisposeArg+ (EventIt.new . subdivideLong) EventIt.dispose Source.eventList++instance (a ~ SVL.ChunkSize) => RunArg (NonNegChunky.T a) where+ type DSLArg (NonNegChunky.T a) = T (Const.T ())+ buildArg =+ newDisposeArg SizeIt.new SizeIt.dispose Source.lazySize++{-+do f <- run (\n -> takeWhile (<*n) (iterate (1+) 0) <> takeWhile (<*n) (iterate (2+) 0)); f SVL.defaultChunkSize (12::Float) :: IO (SVL.Vector Float)+do f <- Sig.run (\n -> Sig.takeWhile (Expr.<*n) (Sig.iterate (1+) 0) <> Sig.takeWhile (Expr.<*n) (Sig.iterate (2+) 0)); f SVL.defaultChunkSize (12::Float) :: IO (SVL.Vector Float)+-}+run :: (Run f) => DSL f -> IO (Shape f -> f)+run sig = do+ act <- build (const sig)+ return $ act (return ((), return ()))
+ src/Synthesizer/LLVM/Generator/Signal.hs view
@@ -0,0 +1,345 @@+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE Rank2Types #-}+module Synthesizer.LLVM.Generator.Signal (+ Sig.T,+ MV,++ constant,+ fromArray,+ Core.iterate,+ takeWhile,+ take,+ tail,+ drop,+ Sig.append,+ cycle,++ amplify,++ osci,+ exponential2,+ exponentialBounded2,+ noise,++ adjacentNodes02,+ adjacentNodes13,+ interpolateConstant,++ rampSlope,+ rampInf,+ ramp,+ parabolaFadeInInf,+ parabolaFadeOutInf,+ parabolaFadeIn,+ parabolaFadeOut,+ parabolaFadeInMap,+ parabolaFadeOutMap,+ ) where++import qualified Synthesizer.LLVM.Causal.Private as Causal+import qualified Synthesizer.LLVM.Generator.Core as Core+import qualified Synthesizer.LLVM.Generator.Private as Sig+import qualified Synthesizer.LLVM.Interpolation as Interpolation+import qualified Synthesizer.LLVM.Frame as Frame+import qualified Synthesizer.LLVM.Random as Rnd+import Synthesizer.LLVM.Generator.Private (arraySize)+import Synthesizer.LLVM.Private (noLocalPtr)++import qualified Synthesizer.Causal.Class as CausalC+import Synthesizer.Causal.Class (apply, ($*), ($<))++import qualified LLVM.DSL.Expression as Expr+import LLVM.DSL.Expression (Exp)++import qualified LLVM.Extra.Multi.Value.Marshal as Marshal+import qualified LLVM.Extra.Multi.Value as MultiValue+import qualified LLVM.Extra.Iterator as Iter+import qualified LLVM.Extra.MaybeContinuation as MaybeCont+import qualified LLVM.Extra.Memory as Memory+import qualified LLVM.Extra.Arithmetic as A+import qualified LLVM.Extra.Tuple as Tuple++import qualified LLVM.Core as LLVM+import LLVM.Core (CodeGenFunction)++import qualified Type.Data.Num.Decimal.Number as TypeNum+import Type.Data.Num.Decimal.Number ((:*:))++import Control.Monad.HT ((<=<))+import Control.Applicative (liftA2)++import Data.Word (Word32, Word)+import Data.Int (Int32)++import NumericPrelude.Numeric+import NumericPrelude.Base hiding+ (map, iterate, takeWhile, take, tail, drop, cycle)++++type MV a = Sig.T (MultiValue.T a)++constant :: (Expr.Aggregate ae al, Memory.C al) => ae -> Sig.T al+constant a = Sig.iterate return (Expr.bundle a)+++fromArray ::+ (TypeNum.Natural n, Marshal.C a) =>+ ((n :*: LLVM.SizeOf (Marshal.Struct a)) ~ arrSize,+ TypeNum.Natural arrSize) =>+ Exp (MultiValue.Array n a) -> MV a+fromArray arrExp = Sig.Cons+ (\arrPtr -> noLocalPtr $ \i -> do+ inRange <- MaybeCont.lift $+ LLVM.cmp LLVM.CmpLT i $ LLVM.valueOf $+ TypeNum.integralFromProxy $ arraySize arrExp+ MaybeCont.guard inRange+ MaybeCont.lift $ do+ ptr <- LLVM.getElementPtr0 arrPtr (i, ())+ liftA2 (,) (Memory.load ptr) (A.inc i))+ (do+ arrPtr <- LLVM.malloc+ flip Memory.store arrPtr =<< Expr.unExp arrExp+ return (arrPtr, A.zero :: LLVM.Value Word))+ LLVM.free+++takeWhile :: (Expr.Aggregate ae a) => (ae -> Exp Bool) -> Sig.T a -> Sig.T a+takeWhile p =+ Sig.takeWhile (fmap (\(MultiValue.Cons cont) -> cont) . Expr.unliftM1 p)++take :: Exp Word -> Sig.T a -> Sig.T a+take len =+ liftA2 (flip const) $ takeWhile (0 Expr.<*) (Core.iterate (subtract 1) len)++{- |+@tail empty@ generates the empty signal.+-}+tail :: Sig.T a -> Sig.T a+tail (Sig.Cons next start stop) = Sig.Cons+ next+ (do+ local <- LLVM.alloca+ (global,s0) <- start+ MaybeCont.resolve (next global local s0)+ (return (global,s0))+ (\(_a,s1) -> return (global,s1)))+ stop++drop :: Exp Word -> Sig.T a -> Sig.T a+drop n (Sig.Cons next start stop) = Sig.Cons+ next+ (do+ local <- LLVM.alloca+ (global,state0) <- start+ ~(MultiValue.Cons nv) <- Expr.unExp n+ state1 <-+ Iter.mapWhileState_+ (\_ s0 ->+ MaybeCont.resolve (next global local s0)+ (return (LLVM.valueOf False, s0))+ (\(_a,s1) -> return (LLVM.valueOf True, s1)))+ (Iter.countDown nv) state0+ return (global,state1))+ stop+++{- |+> cycle empty == empty+-}+cycle :: (Tuple.Phi a, Tuple.Undefined a) => Sig.T a -> Sig.T a+cycle (Sig.Cons next start stop) =+ Sig.Cons+ (\globalPtr local s0 ->+ MaybeCont.alternative+ (do+ c0 <- MaybeCont.lift $ Memory.load globalPtr+ next c0 local s0)+ (do+ (c1,s1) <- MaybeCont.lift $ do+ stop =<< Memory.load globalPtr+ cs1 <- start+ Memory.store (fst cs1) globalPtr+ return cs1+ next c1 local s1))+ (do+ globalPtr <- LLVM.malloc+ (global,state) <- start+ Memory.store global globalPtr+ return (globalPtr, state))+ (\globalPtr -> do+ stop =<< Memory.load globalPtr+ LLVM.free globalPtr)+++amplify ::+ (Expr.Aggregate ea a, Memory.C a, A.PseudoRing a) =>+ ea -> Sig.T a -> Sig.T a+amplify x = apply (Causal.zipWith Frame.amplifyMono $< constant x)+++rampInf, rampSlope,+ parabolaFadeInInf, parabolaFadeOutInf ::+ (Marshal.C a, MultiValue.Field a, MultiValue.IntegerConstant a) =>+ Exp a -> MV a+rampSlope slope = Core.ramp slope Expr.zero+rampInf dur = rampSlope (Expr.recip dur)++{-+t*(2-t) = 1 - (t-1)^2++(t+d)*(2-t-d) - t*(2-t)+ = d*(2-t) - d*t - d^2+ = 2*d*(1-t) - d^2+ = d*(2*(1-t) - d)++2*d*(1-t-d) + d^2 - (2*d*(1-t) + d^2)+ = -2*d^2+-}+parabolaFadeInInf dur =+ Core.parabola+ ((\d -> -2*d*d) $ Expr.recip dur)+ ((\d -> d*(2-d)) $ Expr.recip dur)+ Expr.zero++{-+1-t^2+-}+parabolaFadeOutInf dur =+ Core.parabola+ ((\d -> -2*d*d) $ Expr.recip dur)+ ((\d -> -d*d) $ Expr.recip dur)+ Expr.one++ramp,+ parabolaFadeIn, parabolaFadeOut,+ parabolaFadeInMap, parabolaFadeOutMap ::+ (Marshal.C a, MultiValue.Field a, MultiValue.IntegerConstant a,+ MultiValue.NativeFloating a ar) =>+ Exp Word -> MV a++ramp dur =+ take dur $ rampInf (Expr.fromIntegral dur)++parabolaFadeIn dur =+ take dur $ parabolaFadeInInf (Expr.fromIntegral dur)++parabolaFadeOut dur =+ take dur $ parabolaFadeOutInf (Expr.fromIntegral dur)++parabolaFadeInMap dur =+ Causal.map (Expr.unliftM1 (\t -> t*(2-t))) $* ramp dur++parabolaFadeOutMap dur =+ Causal.map (Expr.unliftM1 (\t -> 1-t*t)) $* ramp dur+++osci ::+ (MultiValue.Fraction t, Marshal.C t) =>+ (forall r. MultiValue.T t -> CodeGenFunction r y) ->+ Exp t -> Exp t -> Sig.T y+osci wave phase freq = Causal.map wave $* Core.osci phase freq+++exponential2 ::+ (Marshal.C a) =>+ (MultiValue.Real a) =>+ (MultiValue.RationalConstant a) =>+ (MultiValue.Transcendental a) =>+ Exp a -> Exp a -> MV a+exponential2 halfLife = Core.exponential (1 / 2 ** recip halfLife)++exponentialBounded2 ::+ (Marshal.C a) =>+ (MultiValue.Real a) =>+ (MultiValue.RationalConstant a) =>+ (MultiValue.Transcendental a) =>+ Exp a -> Exp a -> Exp a -> MV a+exponentialBounded2 bound halfLife =+ Core.exponentialBounded bound (1 / 2 ** recip halfLife)+++{- |+@noise seed rate@++The @rate@ parameter is for adjusting the amplitude+such that it is uniform across different sample rates+and after frequency filters.+The @rate@ is the ratio of the current sample rate to the default sample rate,+where the variance of the samples would be one.+If you want that at sample rate 22050 the variance is 1,+then in order to get a consistent volume at sample rate 44100+you have to set @rate = 2@.++I use the variance as quantity and not the amplitude,+because the amplitude makes only sense for uniformly distributed samples.+However, frequency filters transform the probabilistic density of the samples+towards the normal distribution according to the central limit theorem.+-}+noise ::+ (Marshal.C a, MultiValue.Transcendental a, MultiValue.RationalConstant a,+ MultiValue.NativeFloating a ar) =>+ Exp Word32 -> Exp a -> MV a+noise seed rate =+ let m2 = Expr.fromInteger' $ div Rnd.modulus 2+ r = sqrt (3 * rate) / m2+ in Causal.map (Expr.unliftM1 (\y -> r * (int31tofp y - (m2+1)))) $*+ Core.noise seed++{-+sitofp is a single instruction on x86+and thus we use it, since the arguments are below 2^31.+-}+int31tofp ::+ (MultiValue.NativeFloating a ar) =>+ Exp Word32 -> Exp a+int31tofp =+ Expr.liftM+ (MultiValue.fromIntegral <=<+ (MultiValue.liftM LLVM.bitcast ::+ MultiValue.T Word32 -> CodeGenFunction r (MultiValue.T Int32)))+++adjacentNodes02 ::+ (Memory.C a) =>+ Sig.T a -> Sig.T (Interpolation.Nodes02 a)+adjacentNodes02 =+ tail+ .+ apply+ (Causal.mapAccum+ (\new old -> return (Interpolation.Nodes02 old new, new))+ (return Tuple.undef))++adjacentNodes13 ::+ (Marshal.C a, MultiValue.T a ~ al) =>+ Exp a -> Sig.T al -> Sig.T (Interpolation.Nodes13 al)+adjacentNodes13 yp0 =+ tail .+ tail .+ apply+ (Causal.mapAccum+ (\new (x0, x1, x2) ->+ return (Interpolation.Nodes13 x0 x1 x2 new, (x1, x2, new)))+ (do+ y0 <- Expr.unExp yp0+ return (MultiValue.undef, MultiValue.undef, y0)))+++{- |+Stretch signal in time by a certain factor.++This can be used for doing expensive computations+of filter parameters at a lower rate.+Alternatively, we could provide an adaptive @map@+that recomputes output values only if the input value changes,+or if the input value differs from the last processed one by a certain amount.+-}+interpolateConstant ::+ (Memory.C a, Marshal.C b, MultiValue.IntegerConstant b,+ MultiValue.Additive b, MultiValue.Comparison b) =>+ Exp b -> Sig.T a -> Sig.T a+interpolateConstant k sig =+ CausalC.toSignal (Causal.quantizeLift (CausalC.fromSignal sig) $< constant k)
+ src/Synthesizer/LLVM/Generator/SignalPacked.hs view
@@ -0,0 +1,351 @@+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE FlexibleContexts #-}+{- |+Signal generators that generate the signal in chunks+that can be processed natively by the processor.+Some of the functions for plain signals can be re-used without modification.+E.g. rendering a signal and reading from and to signals work+because the vector type as element type warrents correct alignment.+We can convert between atomic and chunked signals.++The article+<http://perilsofparallel.blogspot.com/2008/09/larrabee-vs-nvidia-mimd-vs-simd.html>+explains the difference between Vector and SIMD computing.+According to that the SSE extensions in Intel processors+must be called Vector computing.+But since we use the term Vector already in the mathematical sense,+I like to use the term "packed" that is used in Intel mnemonics like mulps.+-}+module Synthesizer.LLVM.Generator.SignalPacked (+ pack, packRotate,+ packSmall,+ unpack, unpackRotate,+ constant,+ exponential2,+ exponentialBounded2,+ osciCore,+ osci,+ parabolaFadeInInf, parabolaFadeOutInf,+ rampInf, rampSlope,+ noise,+ noiseCore, noiseCoreAlt,+ ) where++import qualified Synthesizer.LLVM.Causal.Process as Causal+import qualified Synthesizer.LLVM.Generator.Private as Priv+import qualified Synthesizer.LLVM.Generator.Core as Core+import qualified Synthesizer.LLVM.Generator.Signal as Sig+import qualified Synthesizer.LLVM.Frame.SerialVector.Class as SerialClass+import qualified Synthesizer.LLVM.Frame.SerialVector.Code as SerialCode+import qualified Synthesizer.LLVM.Frame.SerialVector as Serial+import qualified Synthesizer.LLVM.Random as Rnd++import Synthesizer.Causal.Class (($*))++import qualified LLVM.DSL.Expression as Expr+import LLVM.DSL.Expression (Exp)++import qualified LLVM.Extra.Multi.Vector as MultiVector+import qualified LLVM.Extra.Multi.Value.Marshal as Marshal+import qualified LLVM.Extra.Multi.Value.Vector as MultiValueVec+import qualified LLVM.Extra.Multi.Value as MultiValue+import qualified LLVM.Extra.Memory as Memory+import qualified LLVM.Extra.MaybeContinuation as Maybe+import qualified LLVM.Extra.Control as U+import qualified LLVM.Extra.Arithmetic as A+import qualified LLVM.Extra.Tuple as Tuple++import qualified Type.Data.Num.Decimal as TypeNum+import Type.Data.Num.Decimal ((:*:))++import qualified LLVM.Core as LLVM++import qualified Control.Monad.Trans.Class as MT+import qualified Control.Monad.Trans.State as MS+import Control.Monad.HT ((<=<))+import Control.Monad (replicateM)+import Control.Applicative ((<$>))++import qualified Algebra.Ring as Ring++import Data.Tuple.HT (mapSnd)+import Data.Word (Word32, Word)+import Data.Int (Int32)++import NumericPrelude.Numeric+import NumericPrelude.Base++++{- |+Convert a signal of scalar values into one using processor vectors.+If the signal length is not divisible by the chunk size,+then the last chunk is dropped.+-}+pack, packRotate ::+ (SerialClass.Write v, a ~ SerialClass.Element v) =>+ Sig.T a -> Sig.T v+pack = packRotate++packRotate (Priv.Cons next start stop) = Priv.Cons+ (\global local s -> do+ wInit <- Maybe.lift $ SerialClass.writeStart+ (w2,_,s2) <-+ Maybe.fromBool $+ U.whileLoop+ (LLVM.valueOf True,+ (wInit,+ LLVM.valueOf $ (SerialClass.sizeOfIterator wInit :: Word),+ s))+ (\(cont,(_w0,i0,_s0)) ->+ A.and cont =<<+ A.cmp LLVM.CmpGT i0 A.zero)+ (\(_,(w0,i0,s0)) -> Maybe.toBool $ do+ (a,s1) <- next global local s0+ Maybe.lift $ do+ w1 <- SerialClass.writeNext a w0+ i1 <- A.dec i0+ return (w1,i1,s1))+ v <- Maybe.lift $ SerialClass.writeStop w2+ return (v, s2))+ start+ stop++{-+We could reformulate it in terms of WriteIterator+that accesses elements using LLVM.extract.+We might move the loop counter into the Iterator,+but we have to assert that the counter is not duplicated.++packIndex ::+ (SerialClass.Write v, a ~ SerialClass.Element v) =>+ Sig.T a -> Sig.T v+packIndex = alter (\(Core next start stop) -> Core+ (\param s -> do+ (v2,_,s2) <-+ Maybe.fromBool $+ U.whileLoop+ (LLVM.valueOf True, (Tuple.undef, A.zero, s))+ (\(cont,(v0,i0,_s0)) ->+ A.and cont =<<+ A.cmp LLVM.CmpLT i0 (LLVM.valueOf $ SerialClass.size v0))+ (\(_,(v0,i0,s0)) -> Maybe.toBool $ do+ (a,s1) <- next param s0+ Maybe.lift $ do+ v1 <- Vector.insert i0 a v0+ i1 <- A.inc i0+ return (v1,i1,s1))+ return (v2, s2))+ start+ stop)+-}+++{- |+Like 'pack' but duplicates the code for creating elements.+That is, for vectors of size n, the code of the input signal+will be emitted n times.+This is efficient only for simple input generators.+-}+packSmall ::+ (SerialClass.Write v, a ~ SerialClass.Element v) =>+ Sig.T a -> Sig.T v+packSmall (Priv.Cons next start stop) = Priv.Cons+ (\global local ->+ MS.runStateT $+ SerialClass.withSize $ \n ->+ MT.lift . Maybe.lift . SerialClass.assemble+ =<<+ replicateM n (MS.StateT $ next global local))+ start+ stop+++unpack, unpackRotate ::+ (SerialClass.Read v, a ~ SerialClass.Element v,+ SerialClass.ReadIt v ~ itv, Memory.C itv) =>+ Sig.T v -> Sig.T a+unpack = unpackRotate++unpackRotate (Priv.Cons next start stop) = Priv.Cons+ (\global local (i0,r0,s0) -> do+ endOfVector <-+ Maybe.lift $ A.cmp LLVM.CmpEQ i0 (LLVM.valueOf (0::Word))+ (i2,r2,s2) <-+ Maybe.fromBool $+ U.ifThen endOfVector (LLVM.valueOf True, (i0,r0,s0)) $ do+ (cont1, (v1,s1)) <- Maybe.toBool $ next global local s0+ r1 <- SerialClass.readStart v1+ return (cont1, (LLVM.valueOf $ SerialClass.size v1, r1, s1))+ Maybe.lift $ do+ (a,r3) <- SerialClass.readNext r2+ i3 <- A.dec i2+ return (a, (i3,r3,s2)))+ (mapSnd (\s -> (A.zero, Tuple.undef, s)) <$> start)+ stop+++{-+We could reformulate it in terms of ReadIterator+that accesses elements using LLVM.extract.+We might move the loop counter into the Iterator,+but we have to assert that the counter is not duplicated.++unpackIndex ::+ (SerialClass.Write v, a ~ SerialClass.Element v, Memory.C v) =>+ Sig.T v -> Sig.T a+unpackIndex = alter (\(Core next start stop) -> Core+ (\param (i0,v0,s0) -> do+ endOfVector <-+ Maybe.lift $ A.cmp LLVM.CmpGE i0 (LLVM.valueOf $ SerialClass.size v0)+ (i2,v2,s2) <-+ Maybe.fromBool $+ U.ifThen endOfVector (LLVM.valueOf True, (i0,v0,s0)) $ do+ (cont1, (v1,s1)) <- Maybe.toBool $ next param s0+ return (cont1, (A.zero, v1, s1))+ Maybe.lift $ do+ a <- Vector.extract i2 v2+ i3 <- A.inc i2+ return (a, (i3,v2,s2)))+ (\p -> do+ s <- start p+ let v = Tuple.undef+ return (LLVM.valueOf $ SerialClass.size v, v, s))+ stop)+-}++++type Serial n a = SerialCode.Value n a++withSize ::+ (TypeNum.Positive n) =>+ (TypeNum.Singleton n -> Sig.T (Serial n a)) ->+ Sig.T (Serial n a)+withSize f = f TypeNum.singleton++withSizeRing ::+ (Ring.C b, TypeNum.Positive n) =>+ (b -> Sig.T (Serial n a)) ->+ Sig.T (Serial n a)+withSizeRing f =+ withSize $ f . fromInteger . TypeNum.integerFromSingleton+++constant ::+ (Marshal.Vector n a) =>+ Exp a -> Sig.T (Serial n a)+constant = Sig.constant . Serial.upsample+++exponential2 ::+ (Marshal.Vector n a, MultiVector.Transcendental a,+ MultiValue.RationalConstant a) =>+ Exp a -> Exp a -> Sig.T (Serial n a)+exponential2 halfLife start = withSizeRing $ \n ->+ Core.exponential+ (Serial.upsample (0.5 ** (n / halfLife)))+ (Serial.iterate (0.5 ** recip halfLife *) start)++exponentialBounded2 ::+ (Marshal.Vector n a, MultiVector.Transcendental a,+ MultiValue.RationalConstant a,+ MultiVector.IntegerConstant a, MultiVector.Real a) =>+ Exp a -> Exp a -> Exp a -> Sig.T (Serial n a)+exponentialBounded2 bound halfLife start = withSizeRing $ \n ->+ Core.exponentialBounded+ (Serial.upsample bound)+ (Serial.upsample (0.5 ** (n / halfLife)))+ (Serial.iterate (0.5 ** recip halfLife *) start)++osciCore ::+ (Marshal.Vector n t, MultiVector.PseudoRing t, MultiVector.Fraction t,+ MultiValue.IntegerConstant t) =>+ Exp t -> Exp t -> Sig.T (Serial n t)+osciCore phase freq = withSizeRing $ \n ->+ Core.osci+ (Serial.iterate (Expr.fraction . (freq +)) phase)+ (Serial.upsample (Expr.fraction (n * freq)))++osci ::+ (Marshal.Vector n t, MultiVector.PseudoRing t, MultiVector.Fraction t,+ MultiValue.IntegerConstant t) =>+ (forall r. Serial n t -> LLVM.CodeGenFunction r y) ->+ Exp t -> Exp t -> Sig.T y+osci wave phase freq = Priv.map wave $ osciCore phase freq+++rampInf, rampSlope, parabolaFadeInInf, parabolaFadeOutInf ::+ (Marshal.Vector n a, MultiVector.Field a, MultiVector.IntegerConstant a,+ MultiValue.RationalConstant a) =>+ Exp a -> Sig.T (Serial n a)+rampSlope slope = withSizeRing $ \n ->+ Core.ramp+ (Serial.upsample (n * slope))+ (Serial.iterate (slope +) 0)+rampInf dur = rampSlope (Expr.recip dur)++parabolaFadeInInf dur = withSizeRing $ \n ->+ let d = n/dur+ in Core.parabola+ (Serial.upsample (-2*d*d))+ (Serial.iterate (subtract $ 2 / dur ^ 2) (d*(2-d)))+ ((\t -> t*(2-t)) $ Serial.iterate (recip dur +) 0)++parabolaFadeOutInf dur = withSizeRing $ \n ->+ let d = n/dur+ in Core.parabola+ (Serial.upsample (-2*d*d))+ (Serial.iterate (subtract $ 2 / dur ^ 2) (-d*d))+ ((\t -> 1-t*t) $ Serial.iterate (recip dur +) 0)+++{- |+For the mysterious rate parameter see 'Sig.noise'.+-}+noise ::+ (MultiVector.NativeFloating n a ar) =>+ (MultiVector.PseudoRing a, MultiVector.IntegerConstant a) =>+ (MultiValue.Algebraic a, MultiValue.RationalConstant a) =>+ (TypeNum.Positive n, TypeNum.Positive (n :*: TypeNum.D32)) =>+ Exp Word32 -> Exp a -> Sig.T (Serial n a)+noise seed rate =+ let m2 = div Rnd.modulus 2+ r = Serial.upsample $ Expr.sqrt (3*rate) / Expr.fromInteger' m2+ in Causal.map+ (\y -> r * (Expr.liftM int31tofp y - Expr.fromInteger' (m2+1))) $*+ noiseCoreAlt seed++{-+sitofp is a single instruction on x86+and thus we use it, since the arguments are below 2^31.++It would be better to use LLVM's range annotation, instead.+-}+int31tofp ::+ (MultiVector.NativeFloating n a ar,+ TypeNum.Positive n, TypeNum.Positive (n :*: TypeNum.D32)) =>+ Serial n Word32 -> LLVM.CodeGenFunction r (Serial n a)+int31tofp =+ fmap SerialCode.fromOrdinary . MultiValueVec.fromIntegral .+ SerialCode.toOrdinary . forceInt32+ <=< MultiValue.liftM LLVM.bitcast++type Id a = a -> a++forceInt32 :: Id (Serial n Int32)+forceInt32 = id++noiseCore, noiseCoreAlt ::+ (TypeNum.Positive n, TypeNum.Positive (n :*: TypeNum.D32)) =>+ Exp Word32 -> Sig.T (Serial n Word32)+noiseCore = Sig.iterate (Expr.liftReprM Rnd.nextVector) . vectorSeed+noiseCoreAlt = Sig.iterate (Expr.liftReprM Rnd.nextVector64) . vectorSeed++vectorSeed :: (TypeNum.Positive n) => Exp Word32 -> Exp (Serial.T n Word32)+vectorSeed seed =+ Serial.iterate (Expr.liftReprM Rnd.nextCG) $+ Expr.irem seed (fromInteger Rnd.modulus - 1) + 1
+ src/Synthesizer/LLVM/Generator/Source.hs view
@@ -0,0 +1,148 @@+{-# LANGUAGE TypeFamilies #-}+module Synthesizer.LLVM.Generator.Source where++import qualified Synthesizer.LLVM.Storable.ChunkIterator as ChunkIt+import qualified Synthesizer.LLVM.Storable.LazySizeIterator as SizeIt+import qualified Synthesizer.LLVM.Generator.Private as Sig+import qualified Synthesizer.LLVM.ConstantPiece as Const+import qualified Synthesizer.LLVM.EventIterator as EventIt+import Synthesizer.LLVM.Private (noLocalPtr)++import qualified LLVM.DSL.Expression as Expr+import LLVM.DSL.Expression (Exp)++import qualified LLVM.Extra.Multi.Value.Storable as Storable+import qualified LLVM.Extra.Multi.Value.Marshal as Marshal+import qualified LLVM.Extra.Multi.Value as MultiValue+import qualified LLVM.Extra.MaybeContinuation as MaybeCont+import qualified LLVM.Extra.Memory as Memory+import qualified LLVM.Extra.Arithmetic as A+import qualified LLVM.Extra.Control as C++import qualified LLVM.Core as LLVM++import Foreign.Storable (Storable)+import Foreign.StablePtr (StablePtr)+import Foreign.Ptr (Ptr, nullPtr)++import Control.Applicative (liftA2, (<$>))++import Data.Tuple.HT (mapSnd)+import Data.Word (Word)+++type T a = Sig.T (MultiValue.T a)+++data StorableVector a = StorableVector (Ptr a) Word++storableVectorLength :: Exp (StorableVector a) -> Exp Word+storableVectorLength = Expr.lift1 (MultiValue.lift1 (\(_ptr,l) -> l))++consStorableVector :: Ptr a -> Int -> StorableVector a+consStorableVector p = StorableVector p . fromIntegral++instance (Storable a) => MultiValue.C (StorableVector a) where+ type Repr (StorableVector a) = (LLVM.Value (Ptr a), LLVM.Value Word)+ cons (StorableVector p l) = MultiValue.Cons (LLVM.valueOf p, LLVM.valueOf l)+ undef = MultiValue.undefTuple+ zero = MultiValue.zeroTuple+ phi = MultiValue.phiTuple+ addPhi = MultiValue.addPhiTuple++instance (Storable a) => Marshal.C (StorableVector a) where+ pack (StorableVector p l) = LLVM.consStruct p l+ unpack = LLVM.uncurryStruct StorableVector++storableVector :: (Storable.C a) => Exp (StorableVector a) -> T a+storableVector vec =+ Sig.noGlobal+ (noLocalPtr $ \(p0,l0) -> do+ cont <- MaybeCont.lift $ A.cmp LLVM.CmpGT l0 A.zero+ MaybeCont.withBool cont $ do+ y1 <- Storable.load p0+ p1 <- Storable.incrementPtr p0+ l1 <- A.dec l0+ return (y1,(p1,l1)))+ (fmap (\(MultiValue.Cons (p,l)) -> (p,l)) (Expr.unExp vec))+++{-+This function calls back into the Haskell function 'ChunkIt.next'+that returns a pointer to the data of the next chunk+and advances to the next chunk in the sequence.+-}+storableVectorLazy ::+ (Storable.C a) => Exp (StablePtr (ChunkIt.T a)) -> T a+storableVectorLazy = flattenChunks . storableVectorChunks++type Chunk a = (LLVM.Value (Ptr a), LLVM.Value Word)++storableVectorChunks ::+ (Storable.C a) => Exp (StablePtr (ChunkIt.T a)) -> Sig.T (Chunk a)+storableVectorChunks sig =+ Sig.Cons+ (\stable lenPtr () -> MaybeCont.fromBool $ do+ nextChunkFn <-+ LLVM.staticNamedFunction+ "SignalExp.fromStorableVectorLazy.nextChunk"+ ChunkIt.nextCallBack+ (buffer,len) <-+ liftA2 (,)+ (LLVM.call nextChunkFn stable lenPtr)+ (LLVM.load lenPtr)+ valid <- A.cmp LLVM.CmpNE buffer (LLVM.valueOf nullPtr)+ return (valid, ((buffer,len), ())))+ (fmap (\(MultiValue.Cons it) -> (it, ())) $ Expr.unExp sig)+ (\ _it -> return ())++flattenChunks :: (Storable.C a) => Sig.T (Chunk a) -> T a+flattenChunks (Sig.Cons next start stop) =+ Sig.Cons+ (\global local ((buffer0,length0), state0) -> do+ ((buffer1,length1), state1) <- MaybeCont.fromBool $ do+ needNext <- A.cmp LLVM.CmpEQ length0 A.zero+ C.ifThen needNext+ (LLVM.valueOf True, ((buffer0,length0), state0))+ (MaybeCont.toBool $ next global local state0)+ MaybeCont.lift $ do+ x <- Storable.load buffer1+ buffer2 <- Storable.incrementPtr buffer1+ length2 <- A.dec length1+ return (x, ((buffer2,length2), state1)))+ (mapSnd ((,) (LLVM.valueOf nullPtr, A.zero)) <$> start)+ stop+++eventList ::+ (Marshal.C a) =>+ Exp (StablePtr (EventIt.T a)) -> Sig.T (Const.T (MultiValue.T a))+eventList sig =+ Sig.Cons+ -- FixMe: duplicate of ConstantPiece.piecewiseConstant+ (\stable yPtr () -> do+ len <- MaybeCont.lift $ do+ nextFn <-+ LLVM.staticNamedFunction+ "ConstantPiece.piecewiseConstant.nextChunk"+ EventIt.nextCallBack+ LLVM.call nextFn stable yPtr+ MaybeCont.guard =<< MaybeCont.lift (A.cmp LLVM.CmpNE len A.zero)+ y <- MaybeCont.lift $ Memory.load yPtr+ return (Const.Cons len y, ()))+ (fmap (\(MultiValue.Cons it) -> (it, ())) $ Expr.unExp sig)+ (\ _it -> return ())++lazySize :: Exp (StablePtr SizeIt.T) -> Sig.T (Const.T ())+lazySize size = Sig.Cons+ (\stable -> noLocalPtr $ \() -> do+ len <- MaybeCont.lift $ do+ nextFn <-+ LLVM.staticNamedFunction+ "ConstantPiece.lazySize.next"+ SizeIt.nextCallBack+ LLVM.call nextFn stable+ MaybeCont.guard =<< MaybeCont.lift (A.cmp LLVM.CmpNE len A.zero)+ return (Const.Cons len (), ()))+ (fmap (\(MultiValue.Cons it) -> (it, ())) $ Expr.unExp size)+ (\ _it -> return ())
src/Synthesizer/LLVM/Interpolation.hs view
@@ -1,12 +1,19 @@ {-# LANGUAGE Rank2Types #-} {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-} module Synthesizer.LLVM.Interpolation ( C(margin), loadNodes, indexNodes,+ loadNodesExp,+ indexNodesExp, Margin(..),+ zipMargin,+ unzipMargin, toMargin,+ marginNumberExp,+ marginOffsetExp, T, @@ -19,11 +26,14 @@ cubicVector, ) where -import qualified Synthesizer.LLVM.Simple.Value as Value+import qualified Synthesizer.LLVM.Value as Value -import qualified Synthesizer.LLVM.Frame.SerialVector as Serial+import qualified Synthesizer.LLVM.Frame.SerialVector.Class as Serial import qualified Synthesizer.Interpolation.Core as Interpolation +import qualified LLVM.DSL.Expression as Expr++import qualified LLVM.Extra.Multi.Value as MultiValue import qualified LLVM.Extra.Scalar as Scalar import qualified LLVM.Extra.Arithmetic as A import qualified LLVM.Extra.Tuple as Tuple@@ -33,6 +43,7 @@ import LLVM.Core (CodeGenFunction, Value) +import Foreign.Storable (Storable) import Foreign.Ptr (Ptr) import Data.Word (Word) @@ -44,13 +55,47 @@ import Data.Foldable (Foldable, foldMap) -class (Applicative nodes, Traversable nodes) => C nodes where- margin :: Margin (nodes a)- data Margin nodes = Margin { marginNumber, marginOffset :: Int } deriving (Show, Eq) +singletonMargin :: MultiValue.T Int -> MultiValue.T (Margin nodes)+singletonMargin n = zipMargin n n +unzipMargin ::+ MultiValue.T (Margin nodes) -> (MultiValue.T Int, MultiValue.T Int)+unzipMargin (MultiValue.Cons (from, to)) =+ (MultiValue.Cons from, MultiValue.Cons to)++zipMargin :: MultiValue.T Int -> MultiValue.T Int -> MultiValue.T (Margin nodes)+zipMargin (MultiValue.Cons from) (MultiValue.Cons to) =+ MultiValue.Cons (from, to)++marginNumberExp :: (Expr.Value val) => val (Margin nodes) -> val Int+marginNumberExp = Expr.lift1 (fst . unzipMargin)++marginOffsetExp :: (Expr.Value val) => val (Margin nodes) -> val Int+marginOffsetExp = Expr.lift1 (snd . unzipMargin)++instance MultiValue.C (Margin nodes) where+ type Repr (Margin nodes) = (LLVM.Value Int, LLVM.Value Int)+ cons (Margin start len) =+ zipMargin (MultiValue.cons start) (MultiValue.cons len)+ undef = singletonMargin MultiValue.undef+ zero = singletonMargin MultiValue.zero+ phi bb a =+ case unzipMargin a of+ (a0,a1) ->+ liftA2 zipMargin (MultiValue.phi bb a0) (MultiValue.phi bb a1)+ addPhi bb a b =+ case (unzipMargin a, unzipMargin b) of+ ((a0,a1), (b0,b1)) -> do+ MultiValue.addPhi bb a0 b0+ MultiValue.addPhi bb a1 b1+++class (Applicative nodes, Traversable nodes) => C nodes where+ margin :: Margin (nodes a)+ type T r nodes a v = a -> nodes v -> CodeGenFunction r v @@ -96,7 +141,7 @@ readStart = Serial.readStartTraversable readNext = Serial.readNextTraversable -instance (Serial.C v) => Serial.C (Nodes02 v) where+instance (Serial.Write v) => Serial.Write (Nodes02 v) where type WriteIt (Nodes02 v) = Nodes02 (Serial.WriteIt v) insert = Serial.insertTraversable@@ -183,7 +228,7 @@ readStart = Serial.readStartTraversable readNext = Serial.readNextTraversable -instance (Serial.C v) => Serial.C (Nodes13 v) where+instance (Serial.Write v) => Serial.Write (Nodes13 v) where type WriteIt (Nodes13 v) = Nodes13 (Serial.WriteIt v) insert = Serial.insertTraversable@@ -234,8 +279,16 @@ Value.unlift5 Interpolation.cubic a b c d r +loadNodesExp ::+ (C nodes, Storable am) =>+ (Value (Ptr am) -> CodeGenFunction r a) ->+ MultiValue.T Int ->+ Value (Ptr am) -> CodeGenFunction r (nodes a)+loadNodesExp loadNode (MultiValue.Cons step) =+ MS.evalStateT $ sequenceA $ pure $ loadNext loadNode step+ loadNodes ::- (C nodes, Storable.C am) =>+ (C nodes, Storable am) => (Value (Ptr am) -> CodeGenFunction r a) -> Value Int -> Value (Ptr am) -> CodeGenFunction r (nodes a)@@ -243,7 +296,7 @@ MS.evalStateT $ sequenceA $ pure $ loadNext loadNode step loadNext ::- (Storable.C am) =>+ (Storable am) => (Value (Ptr am) -> CodeGenFunction r a) -> Value Int -> MS.StateT (Value (Ptr am)) (CodeGenFunction r) a@@ -251,6 +304,14 @@ MS.StateT $ \ptr -> liftA2 (,) (loadNode ptr) (Storable.advancePtr step ptr) ++indexNodesExp ::+ (C nodes) =>+ (MultiValue.T Word -> CodeGenFunction r v) ->+ MultiValue.T Word ->+ MultiValue.T Word -> CodeGenFunction r (nodes v)+indexNodesExp indexNode (MultiValue.Cons step) (MultiValue.Cons offset) =+ indexNodes (indexNode . MultiValue.Cons) step offset indexNodes :: (C nodes) =>
src/Synthesizer/LLVM/MIDI.hs view
@@ -1,8 +1,7 @@-{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE RebindableSyntax #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE Rank2Types #-} {- | Convert MIDI events of a MIDI controller to a control signal. -}@@ -14,169 +13,62 @@ import qualified Synthesizer.MIDI.Generic as Gen import qualified Synthesizer.LLVM.MIDI.BendModulation as BM-import qualified Synthesizer.LLVM.Frame.SerialVector as Serial+import qualified Synthesizer.LLVM.Frame.SerialVector as SerialExp+import qualified Synthesizer.LLVM.Frame.SerialVector.Code as Serial -import Synthesizer.LLVM.CausalParameterized.Process (($>))-import qualified Synthesizer.LLVM.CausalParameterized.Functional as Func-import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP-import qualified Synthesizer.LLVM.Parameterized.SignalPacked as SigPS-import qualified Synthesizer.LLVM.Parameterized.Signal as SigP+import qualified Synthesizer.LLVM.Causal.Functional as Func+import qualified Synthesizer.LLVM.Causal.Process as Causal+import qualified Synthesizer.LLVM.Generator.SignalPacked as SigPS+import qualified Synthesizer.LLVM.Generator.Signal as Sig import qualified Synthesizer.LLVM.Wave as Wave+import Synthesizer.LLVM.Causal.Process (($>)) -import qualified LLVM.DSL.Parameter as Param+import LLVM.DSL.Expression (Exp) -import qualified LLVM.Extra.ScalarOrVector as SoV-import qualified LLVM.Extra.Vector as Vector-import qualified LLVM.Extra.Marshal as Marshal+import qualified LLVM.Extra.Multi.Value.Marshal as Marshal+import qualified LLVM.Extra.Multi.Value as MultiValue+import qualified LLVM.Extra.Multi.Vector as MultiVector import qualified LLVM.Extra.Arithmetic as A-import qualified LLVM.Extra.Tuple as Tuple import qualified LLVM.Core as LLVM-import LLVM.Core (SizeOf) -import qualified Type.Data.Num.Decimal as TypeNum-import Type.Data.Num.Decimal.Number ((:*:))--import qualified Algebra.RealField as RealField-import qualified Algebra.Additive as Additive- import Control.Arrow (second, (<<<), (<<^))-import Control.Monad ({- liftM, -} liftM2) import NumericPrelude.Numeric import Prelude (($)) -{--{-# INLINE piecewiseConstantInit #-}-piecewiseConstantInit ::- (Storable y, Tuple.Value y, Tuple.ValueOf y ~ yl,- Memory.C yl ym, LLVM.IsSized ym ys) =>- y -> EventListTT.T LazyTime y -> SigP.T p yl-piecewiseConstantInit initial evs =- SigP.piecewiseConstant $#- (PC.subdivideInt $- EventListMT.consBody initial evs)---{-# INLINE controllerLinear #-}-controllerLinear ::- (Field.C y, Storable y, Tuple.Value y, Tuple.ValueOf y ~ yl,- Memory.C yl ym, LLVM.IsSized ym ys) =>- Channel -> Controller ->- (y,y) -> y ->- Filter (SigP.T p yl)-controllerLinear chan ctrl bnd initial =- liftM (piecewiseConstantInit initial .- EventListTT.mapBody (MV.controllerLinear bnd)) $- getControllerEvents chan ctrl---{-# INLINE controllerExponential #-}-controllerExponential ::- (Trans.C y, Storable y, Tuple.Value y, Tuple.ValueOf y ~ yl,- Memory.C yl ym, LLVM.IsSized ym ys) =>- Channel -> Controller ->- (y,y) -> y ->- Filter (SigP.T p yl)-controllerExponential chan ctrl bnd initial =- liftM (piecewiseConstantInit initial .- EventListTT.mapBody (MV.controllerExponential bnd)) $- getControllerEvents chan ctrl---{- |-@pitchBend channel range center@:-emits frequencies on an exponential scale from-@center/range@ to @center*range@.--}-{-# INLINE pitchBend #-}-pitchBend ::- (Trans.C y, Storable y, Tuple.Value y, Tuple.ValueOf y ~ yl,- Memory.C yl ym, LLVM.IsSized ym ys) =>- Channel ->- y -> y ->- Filter (SigP.T p yl)-pitchBend chan range center =- liftM (piecewiseConstantInit center .- EventListTT.mapBody (MV.pitchBend range center)) $- getSlice (maybePitchBend chan)--- getPitchBendEvents chan--{-# INLINE channelPressure #-}-channelPressure ::- (Trans.C y, Storable y, Tuple.Value y, Tuple.ValueOf y ~ yl,- Memory.C yl ym, LLVM.IsSized ym ys) =>- Channel ->- y -> y ->- Filter (SigP.T p yl)-channelPressure chan maxVal initVal =- liftM (piecewiseConstantInit initVal .- EventListTT.mapBody (MV.controllerLinear (0,maxVal))) $- getSlice (maybeChannelPressure chan)---{-# INLINE bendWheelPressure #-}-bendWheelPressure ::- (Ring.C a, LLVM.IsConst a,- RealField.C y, Trans.C y,- LLVM.IsConst y, SoV.Fraction y, a ~ SoV.Scalar y, SoV.Replicate y,- Storable y, Tuple.Value y (LLVM.Value y), LLVM.IsSized y ys) =>- Channel ->- Int -> y -> y -> y ->- Filter (SigP.T p (LLVM.Value y))-bendWheelPressure chan- pitchRange speed wheelDepth pressDepth =- do bend <- pitchBend chan- (2^?(fromIntegral pitchRange/12) `asTypeOf` speed) 1- fm <- controllerLinear chan VoiceMsg.modulation (0,wheelDepth) 0- press <- channelPressure chan pressDepth 0- return $- SigP.envelope bend $- SigP.mapSimple (A.add A.one) $- SigP.envelope- (SigP.mix fm press)- (SigP.osciSimple Wave.approxSine2 zero $# speed)--}-- frequencyFromBendModulation ::- (Marshal.C y, Additive.C y, Tuple.ValueOf y ~ yl,- A.PseudoRing yl, A.Fraction yl, A.IntegerConstant yl) =>- Param.T p y ->- CausalP.T p (BM.T yl) yl+ (Marshal.C y, MultiValue.T y ~ ym,+ MultiValue.PseudoRing y, MultiValue.IntegerConstant y,+ MultiValue.Fraction y) =>+ Exp y -> Causal.T (BM.T ym) ym frequencyFromBendModulation speed =- frequencyFromPair SigP.osciSimple speed+ frequencyFromPair Sig.osci speed <<^ (\(BM.Cons b m) -> (b,m)) frequencyFromBendModulationPacked ::- (Marshal.C a, Tuple.ValueOf a ~ LLVM.Value a,- Marshal.Vector n a, Tuple.VectorValueOf n a ~ LLVM.Value (LLVM.Vector n a),- LLVM.IsPrimitive a, LLVM.IsConst a, LLVM.IsFloating a,- RealField.C a, Vector.Real a, SoV.IntegerConstant a,- TypeNum.Positive n,- TypeNum.Positive (n :*: SizeOf a)) =>- Param.T p a ->- CausalP.T p (BM.T (LLVM.Value a)) (Serial.Value n a)+ (Marshal.Vector n a) =>+ (MultiVector.PseudoRing a, MultiVector.IntegerConstant a) =>+ (MultiVector.Fraction a) =>+ Exp a -> Causal.T (BM.T (MultiValue.T a)) (Serial.Value n a) frequencyFromBendModulationPacked speed =- frequencyFromPair SigPS.osciSimple speed+ frequencyFromPair SigPS.osci speed <<<- CausalP.mapSimple- (\(BM.Cons b m) ->- liftM2 (,) (Serial.upsample b) (Serial.upsample m))+ Causal.map (\(BM.Cons b m) -> (SerialExp.upsample b, SerialExp.upsample m)) frequencyFromPair, _frequencyFromPair ::- (Additive.C y, A.PseudoRing yl, A.IntegerConstant yl, A.Fraction yl) =>- ((forall r. yl -> LLVM.CodeGenFunction r yl) ->- Param.T p y -> Param.T p y -> SigP.T p yl) ->- Param.T p y ->- CausalP.T p (yl,yl) yl+ (MultiValue.Additive y,+ A.PseudoRing ym, A.IntegerConstant ym, A.Fraction ym) =>+ ((forall r. ym -> LLVM.CodeGenFunction r ym) ->+ Exp y -> Exp y -> Sig.T ym) ->+ Exp y -> Causal.T (ym,ym) ym frequencyFromPair osci speed = Func.withGuidedArgs (Func.atom, Func.atom) $ \(b, m) -> b * (1 + m * Func.fromSignal (osci Wave.approxSine2 zero speed)) _frequencyFromPair osci speed =- CausalP.envelope+ Causal.envelope <<<- second (1 + (CausalP.envelope $> osci Wave.approxSine2 zero speed))+ second (1 + (Causal.envelope $> osci Wave.approxSine2 zero speed))
src/Synthesizer/LLVM/MIDI/BendModulation.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE MultiParamTypeClasses #-} {-# OPTIONS_GHC -fno-warn-orphans #-} {- | Various LLVM related instances of the BM.T type.@@ -9,11 +10,18 @@ BM.T(..), BM.deflt, BM.shift,+ multiValue,+ unMultiValue, ) where import qualified Synthesizer.MIDI.Value.BendModulation as BM-import qualified Synthesizer.LLVM.CausalParameterized.Functional as F+import qualified Synthesizer.LLVM.Causal.Functional as F +import qualified LLVM.DSL.Expression as Expr++import qualified LLVM.Extra.Multi.Value.Storable as StorableMV+import qualified LLVM.Extra.Multi.Value.Marshal as MarshalMV+import qualified LLVM.Extra.Multi.Value as MultiValue import qualified LLVM.Extra.Vector as Vector import qualified LLVM.Extra.Tuple as Tuple import qualified LLVM.Extra.Storable as Storable@@ -22,20 +30,16 @@ import qualified LLVM.Extra.Control as C import qualified LLVM.Core as LLVM -import Control.Applicative (liftA2) import qualified Type.Data.Num.Decimal as TypeNum +import qualified Data.Traversable as Trav+import qualified Data.Foldable as Fold -instance (Tuple.Zero a) => Tuple.Zero (BM.T a) where- zero = Tuple.zeroPointed+import Control.Applicative (liftA2) -{--instance (LLVM.ValueTuple a) => LLVM.ValueTuple (BM.T a) where- buildTuple f = Class.buildTupleTraversable (LLVM.buildTuple f) -instance LLVM.IsTuple a => LLVM.IsTuple (BM.T a) where- tupleDesc = Class.tupleDescFoldable--}+instance (Tuple.Zero a) => Tuple.Zero (BM.T a) where+ zero = Tuple.zeroPointed instance (Tuple.Undefined a) => Tuple.Undefined (BM.T a) where undef = Tuple.undefPointed@@ -43,14 +47,40 @@ instance (C.Select a) => C.Select (BM.T a) where select = C.selectTraversable -{--instance LLVM.CmpRet a, LLVM.CmpResult a ~ b =>- LLVM.CmpRet (BM.T a) (BM.T b) where--}- instance Tuple.Value h => Tuple.Value (BM.T h) where type ValueOf (BM.T h) = BM.T (Tuple.ValueOf h) valueOf = Tuple.valueOfFunctor+++instance (Expr.Aggregate e mv) => Expr.Aggregate (BM.T e) (BM.T mv) where+ type MultiValuesOf (BM.T e) = BM.T (Expr.MultiValuesOf e)+ type ExpressionsOf (BM.T mv) = BM.T (Expr.ExpressionsOf mv)+ bundle = Trav.traverse Expr.bundle+ dissect = fmap Expr.dissect++instance (MultiValue.C a) => MultiValue.C (BM.T a) where+ type Repr (BM.T a) = BM.T (MultiValue.Repr a)+ cons = multiValue . fmap MultiValue.cons+ undef = multiValue $ pure MultiValue.undef+ zero = multiValue $ pure MultiValue.zero+ phi bb = fmap multiValue . Trav.traverse (MultiValue.phi bb) . unMultiValue+ addPhi bb a b =+ Fold.sequence_ $+ liftA2 (MultiValue.addPhi bb) (unMultiValue a) (unMultiValue b)++instance (MarshalMV.C l) => MarshalMV.C (BM.T l) where+ pack (BM.Cons bend depth) = MarshalMV.pack (bend, depth)+ unpack = uncurry BM.Cons . MarshalMV.unpack++instance (StorableMV.C l) => StorableMV.C (BM.T l) where+ load = StorableMV.loadApplicative+ store = StorableMV.storeFoldable++multiValue :: BM.T (MultiValue.T a) -> MultiValue.T (BM.T a)+multiValue = MultiValue.Cons . fmap (\(MultiValue.Cons a) -> a)++unMultiValue :: MultiValue.T (BM.T a) -> BM.T (MultiValue.T a)+unMultiValue (MultiValue.Cons x) = fmap MultiValue.Cons x type Struct a = LLVM.Struct (a, (a, ()))
− src/Synthesizer/LLVM/Parameter.hs
@@ -1,12 +0,0 @@-module Synthesizer.LLVM.Parameter (- Param.T,- Param.get,- (Param.$#),-- Param.Tuple(..),- Param.withTuple,- Param.withTuple1,- Param.withTuple2,- ) where--import qualified LLVM.DSL.Parameter as Param
− src/Synthesizer/LLVM/Parameterized/Signal.hs
@@ -1,1000 +0,0 @@-{-# LANGUAGE NoImplicitPrelude #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE Rank2Types #-}-{-# LANGUAGE ForeignFunctionInterface #-}-module Synthesizer.LLVM.Parameterized.Signal (- T,- adjacentNodes02,- adjacentNodes13,- amplify,- amplifyStereo,- Sig.empty,- append,- cycle,- drop,- exponential2,- exponentialCore,- exponentialBounded2,- exponentialBoundedCore,- interpolateConstant,- iterate,- lazySize,- map,- mapSimple,- mapAccum,- Sig.mix,- Sig.mixExt,- noise,- noiseCore,- osci,- osciCore,- osciSaw,- osciSimple,- parabolaCore,- parabolaFadeIn,- parabolaFadeInInf,- parabolaFadeInMap,- parabolaFadeOut,- parabolaFadeOutInf,- parabolaFadeOutMap,- piecewiseConstant,- ramp,- rampCore,- rampInf,- rampSlope,- reparameterize,- tail,- constant,- Sig.envelope,- Sig.envelopeStereo,- simple,- zip,- zipWith,- zipWithSimple,-- fromStorableVector,- fromStorableVectorLazy,-- render,- renderChunky,- run,- runChunky,- runChunkyPattern,- runChunkyPlugged,-- -- for testing- noiseCoreAlt,- ) where--import Synthesizer.LLVM.Parameterized.SignalPrivate-import qualified Synthesizer.LLVM.Simple.SignalPrivate as SigPriv-import qualified Synthesizer.LLVM.Simple.Signal as Sig-import qualified Synthesizer.LLVM.CausalParameterized.ProcessPrivate as CausalP-import qualified Synthesizer.LLVM.Causal.Process as Causal-import qualified Synthesizer.LLVM.Plug.Output as POut-import qualified Synthesizer.LLVM.Interpolation as Interpolation-import qualified Synthesizer.LLVM.ConstantPiece as Const-import Synthesizer.Causal.Class (($*), ($<))--import qualified Synthesizer.LLVM.Frame.Stereo as Stereo-import qualified Synthesizer.LLVM.Frame as Frame-import qualified Synthesizer.LLVM.Random as Rnd-import qualified Synthesizer.LLVM.Wave as Wave-import qualified Synthesizer.LLVM.ForeignPtr as ForeignPtr--import qualified Synthesizer.LLVM.Storable.ChunkIterator as ChunkIt-import qualified Synthesizer.LLVM.Storable.Vector as SVU-import qualified Data.StorableVector.Lazy.Pattern as SVP-import qualified Data.StorableVector.Lazy as SVL-import qualified Data.StorableVector as SV-import qualified Data.StorableVector.Base as SVB--import qualified Data.EventList.Relative.BodyTime as EventList-import qualified Numeric.NonNegative.Chunky as Chunky-import qualified Numeric.NonNegative.Wrapper as NonNeg--import qualified LLVM.DSL.Execution as Exec-import qualified LLVM.DSL.Parameter as Param--import qualified LLVM.Extra.Arithmetic as A-import qualified LLVM.Extra.ScalarOrVector as SoV-import qualified LLVM.Extra.MaybeContinuation as MaybeCont-import qualified LLVM.Extra.Maybe as Maybe-import qualified LLVM.Extra.Storable as Storable-import qualified LLVM.Extra.Marshal as Marshal-import qualified LLVM.Extra.Memory as Memory-import qualified LLVM.Extra.Tuple as Tuple-import LLVM.Extra.Control (whileLoop)--import qualified LLVM.ExecutionEngine as EE-import qualified LLVM.Core as LLVM-import LLVM.Core- (CodeGenFunction, ret, Value, value, valueOf,- IsSized, IsConst, IsArithmetic, IsFloating,- CodeGenModule, Function)--import qualified Type.Data.Num.Decimal as TypeNum--import Control.Monad.HT ((<=<))-import Control.Monad (when)-import Control.Arrow ((^<<))-import Control.Applicative (Applicative, liftA2, liftA3, pure, (<$>))-import Control.Functor.HT (void)--import qualified Algebra.Transcendental as Trans-import qualified Algebra.RealField as RealField-import qualified Algebra.Algebraic as Algebraic-import qualified Algebra.Field as Field-import qualified Algebra.Additive as Additive--import Data.Functor.Compose (Compose(Compose))-import Data.Tuple.HT (mapSnd)-import Data.Word (Word8, Word32, Word)-import Data.Int (Int32)--import Foreign.ForeignPtr (touchForeignPtr)-import Foreign.Ptr (Ptr, nullPtr)-import Control.Exception (bracket)-import qualified System.Unsafe as Unsafe--import qualified LLVM.DSL.Debug.Marshal as DebugSt-import qualified LLVM.DSL.Debug.Counter as Counter--import NumericPrelude.Numeric-import NumericPrelude.Base hiding (and, tail, iterate, map, zip, zipWith, cycle, drop)---reparameterize :: Param.T q p -> T p a -> T q a-reparameterize p (Cons start alloca stop next create delete) =- Cons start alloca stop next (create . Param.get p) delete----- * timeline edit--{- |-@tail empty@ generates the empty signal.--}-tail :: T p a -> T p a-tail (Cons next alloca start stop createIOContext deleteIOContext) = Cons- next- alloca- (\parameter -> do- local <- alloca- (c,s0) <- start parameter- MaybeCont.resolve (next c local s0)- (return (c,s0))- (\(_a,s1) -> return (c,s1)))- stop- createIOContext- deleteIOContext--drop :: Param.T p Int -> T p a -> T p a-drop n (Cons next alloca start stop createIOContext deleteIOContext) =- Param.withValue (Param.wordInt n) $ \getN valueN -> Cons- next- alloca- (\(parameter, i0) -> do- local <- alloca- (c,s0) <- start parameter- (_, _, s3) <-- whileLoop (valueOf True, valueN i0, s0)- (\(cont,i1,_s1) ->- A.and cont =<<- A.cmp LLVM.CmpGT i1 A.zero)- (\(_cont,i1,s1) -> do- (cont, s2) <-- MaybeCont.resolve (next c local s1)- (return (valueOf False, s1))- (\(_a,s) -> return (valueOf True, s))- i2 <- A.dec i1- return (cont, i2, s2))- return (c, s3))- stop- (\p -> do- (ioContext, param) <- createIOContext p- return (ioContext, (param, getN p)))- deleteIOContext---cycle ::- (Tuple.Phi a, Tuple.Undefined a) =>- T p a -> T p a-cycle (Cons next alloca start stop createIOContext deleteIOContext) =- Cons- (\parameter local (c0,s0) ->- MaybeCont.alternative- (fmap (mapSnd ((,) c0)) $ next c0 local s0)- (do (c1,s1) <- MaybeCont.lift $ start parameter- (b0,s2) <- next c1 local s1- return (b0,(c1,s2))))- alloca- (\parameter -> do- contextState <- start parameter- return (parameter, contextState))- (\_parameter contextState -> uncurry stop contextState)- createIOContext- deleteIOContext----- * signal modifiers--{- |-Stretch signal in time by a certain factor.--This can be used for doing expensive computations-of filter parameters at a lower rate.-Alternatively, we could provide an adaptive @map@-that recomputes output values only if the input value changes,-or if the input value differs from the last processed one by a certain amount.--}-interpolateConstant ::- (Memory.C a,- IsFloating b, SoV.IntegerConstant b, LLVM.CmpRet b, LLVM.CmpResult b ~ Bool,- Marshal.C b, Tuple.ValueOf b ~ Value b) =>- Param.T p b -> T p a -> T p a-interpolateConstant k sig =- CausalP.toSignal- (Causal.quantizeLift (CausalP.fromSignal sig) $< constant k)---amplify ::- (A.PseudoRing al, Marshal.C a, Tuple.ValueOf a ~ al) =>- Param.T p a -> T p al -> T p al-amplify =- map Frame.amplifyMono--amplifyStereo ::- (A.PseudoRing al, Marshal.C a, Tuple.ValueOf a ~ al) =>- Param.T p a -> T p (Stereo.T al) -> T p (Stereo.T al)-amplifyStereo =- map Frame.amplifyStereo---mapAccum ::- (Marshal.C pnh, Tuple.ValueOf pnh ~ pnl,- Marshal.C psh, Tuple.ValueOf psh ~ psl, Memory.C s) =>- (forall r. pnl -> a -> s -> CodeGenFunction r (b,s)) ->- (forall r. psl -> CodeGenFunction r s) ->- Param.T p pnh ->- Param.T p psh ->- T p a -> T p b-mapAccum next start n s xs =- CausalP.mapAccum next start n s $* xs--adjacentNodes02 ::- (Memory.C a, Tuple.Undefined a) =>- T p a -> T p (Interpolation.Nodes02 a)-adjacentNodes02 =- tail- .- Sig.mapAccum- (\new old -> return (Interpolation.Nodes02 old new, new))- (return Tuple.undef)--adjacentNodes13 ::- (Marshal.C ah, Tuple.ValueOf ah ~ a, Tuple.Undefined a) =>- Param.T p ah -> T p a -> T p (Interpolation.Nodes13 a)-adjacentNodes13 yp0 =- tail .- tail .- mapAccum- (\() new (x0, x1, x2) ->- return (Interpolation.Nodes13 x0 x1 x2 new, (x1, x2, new)))- (\y0 -> return (Tuple.undef, Tuple.undef, Param.valueTuple yp0 y0))- (pure ()) yp0------ * signal generators---exponentialCore ::- (Marshal.C a, Tuple.ValueOf a ~ al, A.PseudoRing al) =>- Param.T p a -> Param.T p a -> T p al-exponentialCore =- iterate A.mul--exponential2 ::- (Trans.C a, Marshal.C a, Tuple.ValueOf a ~ Value a,- IsArithmetic a, IsConst a) =>- Param.T p a -> Param.T p a -> T p (Value a)-exponential2 halfLife =- exponentialCore (0.5 ** recip halfLife)---exponentialBoundedCore ::- (Marshal.C a, Tuple.ValueOf a ~ al, A.PseudoRing al, A.Real al) =>- Param.T p a -> Param.T p a -> Param.T p a ->- T p al-exponentialBoundedCore bound decay =- iterate- (\(b,k) y -> A.max b =<< A.mul k y)- (liftA2 (,) bound decay)--{- |-Exponential curve that remains at the bound value-if it would fall below otherwise.-This way you can avoid extremal values, e.g. denormalized ones.-The initial value and the bound value must be positive.--}-exponentialBounded2 ::- (Trans.C a, Marshal.C a, Tuple.ValueOf a ~ Value a, SoV.Real a, IsConst a) =>- Param.T p a -> Param.T p a -> Param.T p a ->- T p (Value a)-exponentialBounded2 bound halfLife =- exponentialBoundedCore bound (0.5 ** recip halfLife)---osciCore ::- (Marshal.C t, Tuple.ValueOf t ~ tl, A.Fraction tl) =>- Param.T p t -> Param.T p t -> T p tl-osciCore phase freq =- iterate A.incPhase freq phase--osci ::- (Marshal.C t, Tuple.ValueOf t ~ tl, A.Fraction tl, A.IntegerConstant tl,- Marshal.C c, Tuple.ValueOf c ~ cl) =>- (forall r. cl -> tl -> CodeGenFunction r y) ->- Param.T p c ->- Param.T p t -> Param.T p t -> T p y-osci wave waveParam phase freq =- map wave waveParam $ osciCore phase freq--osciSimple ::- (Marshal.C t, Tuple.ValueOf t ~ tl, A.Fraction tl, A.IntegerConstant tl) =>- (forall r. tl -> CodeGenFunction r y) ->- Param.T p t -> Param.T p t -> T p y-osciSimple wave phase freq =- Sig.map wave $ osciCore phase freq--osciSaw ::- (Marshal.C a, Tuple.ValueOf a ~ al,- A.PseudoRing al, A.Fraction al, A.IntegerConstant al) =>- Param.T p a -> Param.T p a -> T p al-osciSaw =- osciSimple Wave.saw----rampCore ::- (Marshal.C a, Tuple.ValueOf a ~ al, A.Additive al, A.IntegerConstant al) =>- Param.T p a -> Param.T p a -> T p al-rampCore = iterate A.add--parabolaCore ::- (Marshal.C a, Tuple.ValueOf a ~ al, A.Additive al, A.IntegerConstant al) =>- Param.T p a -> Param.T p a -> Param.T p a -> T p al-parabolaCore d2 d1 start =- CausalP.apply (CausalP.integrate start) $- rampCore d2 d1----rampInf, rampSlope,- parabolaFadeInInf, parabolaFadeOutInf ::- (Field.C a,- Marshal.C a, Tuple.ValueOf a ~ al, A.Additive al, A.IntegerConstant al) =>- Param.T p a -> T p al-rampSlope slope = rampCore slope Additive.zero-rampInf dur = rampSlope (recip dur)--{--t*(2-t) = 1 - (t-1)^2--(t+d)*(2-t-d) - t*(2-t)- = d*(2-t) - d*t - d^2- = 2*d*(1-t) - d^2- = d*(2*(1-t) - d)--2*d*(1-t-d) + d^2 - (2*d*(1-t) + d^2)- = -2*d^2--}-parabolaFadeInInf dur =- parabolaCore- (fmap (\d -> -2*d*d) $ recip dur)- (fmap (\d -> d*(2-d)) $ recip dur)- Additive.zero--{--1-t^2--}-parabolaFadeOutInf dur =- parabolaCore- (fmap (\d -> -2*d*d) $ recip dur)- (fmap (\d -> -d*d) $ recip dur)- one--ramp,- parabolaFadeIn, parabolaFadeOut,- parabolaFadeInMap, parabolaFadeOutMap ::- (RealField.C a, Marshal.C a, Tuple.ValueOf a ~ al,- A.PseudoRing al, A.IntegerConstant al) =>- Param.T p a -> T p al--ramp dur =- CausalP.apply (CausalP.take (fmap round dur)) $- rampInf dur--parabolaFadeIn dur =- CausalP.apply (CausalP.take (fmap round dur)) $- parabolaFadeInInf dur--parabolaFadeOut dur =- CausalP.apply (CausalP.take (fmap round dur)) $- parabolaFadeOutInf dur--parabolaFadeInMap dur =- -- t*(2-t)- CausalP.apply (CausalP.mapSimple (\t -> A.mul t =<< A.sub (A.fromInteger' 2) t)) $- ramp dur--parabolaFadeOutMap dur =- -- 1-t^2- CausalP.apply (CausalP.mapSimple (\t -> A.sub (A.fromInteger' 1) =<< A.mul t t)) $- ramp dur---{- |-@noise seed rate@--The @rate@ parameter is for adjusting the amplitude-such that it is uniform across different sample rates-and after frequency filters.-The @rate@ is the ratio of the current sample rate to the default sample rate,-where the variance of the samples would be one.-If you want that at sample rate 22050 the variance is 1,-then in order to get a consistent volume at sample rate 44100-you have to set @rate = 2@.--I use the variance as quantity and not the amplitude,-because the amplitude makes only sense for uniformly distributed samples.-However, frequency filters transform the probabilistic density of the samples-towards the normal distribution according to the central limit theorem.--}-noise ::- (Algebraic.C a, IsFloating a, IsConst a, Marshal.C a,- Tuple.ValueOf a ~ Value a, LLVM.IsPrimitive a) =>- Param.T p Word32 ->- Param.T p a ->- T p (Value a)-noise seed rate =- let m2 = fromInteger $ div Rnd.modulus 2- in map (\r y ->- A.mul r- =<< flip A.sub (valueOf $ m2+1)- =<< int31tofp y)- (sqrt (3 * rate) / return m2) $- noiseCore seed--{--sitofp is a single instruction on x86-and thus we use it, since the arguments are below 2^31.--}-int31tofp ::- (IsFloating a, LLVM.ShapeOf a ~ LLVM.ScalarShape) =>- Value Word32 -> CodeGenFunction r (Value a)-int31tofp =- LLVM.inttofp <=<- (LLVM.bitcast ::- Value Word32 -> CodeGenFunction r (Value Int32))--noiseCore, noiseCoreAlt ::- Param.T p Word32 ->- T p (Value Word32)-noiseCore seed =- iterate (const Rnd.nextCG)- (return ()) ((+1) . flip mod (Rnd.modulus-1) ^<< seed)--noiseCoreAlt seed =- iterate (const Rnd.nextCG32)- (return ()) ((+1) . flip mod (Rnd.modulus-1) ^<< seed)----- * conversion from and to storable vectors--fromStorableVector ::- (Storable.C a, Tuple.ValueOf a ~ value) =>- Param.T p (SV.Vector a) ->- T p value-fromStorableVector selectVec =- Cons- (\() () (p0,l0) -> do- cont <- MaybeCont.lift $ A.cmp LLVM.CmpGT l0 A.zero- MaybeCont.withBool cont $ do- y1 <- Storable.load p0- p1 <- Storable.incrementPtr p0- l1 <- A.dec l0- return (y1,(p1,l1)))- (return ())- (return . (,) ())- (\() _ -> return ())- (\p ->- let (fp,ptr,l) = SVU.unsafeToPointers $ Param.get selectVec p- in return (fp, (ptr, fromIntegral l :: Word)))- -- keep the foreign ptr alive- touchForeignPtr--{--This function calls back into the Haskell function 'ChunkIt.next'-that returns a pointer to the data of the next chunk-and advances to the next chunk in the sequence.--}-fromStorableVectorLazy ::- (Storable.C a, Tuple.ValueOf a ~ value) =>- Param.T p (SVL.Vector a) -> T p value-fromStorableVectorLazy = SigPriv.flattenChunks . storableVectorChunks--storableVectorChunks ::- (Storable.C a, Tuple.ValueOf a ~ value) =>- Param.T p (SVL.Vector a) ->- T p (Value (Ptr a), Value Word)-storableVectorChunks sig =- Cons- (SigPriv.storableVectorNextChunk- "Parameterized.Signal.fromStorableVectorLazy.nextChunk")- LLVM.alloca- (\s -> return (s, ()))- (\ _s _ -> return ())- (\p -> do- s <- ChunkIt.new (Param.get sig p)- return (s, s))- ChunkIt.dispose----piecewiseConstant ::- (Marshal.C a, Tuple.ValueOf a ~ value) =>- Param.T p (EventList.T NonNeg.Int a) ->- T p value-piecewiseConstant =- Const.flatten . Const.piecewiseConstant----{- |-Turns a lazy chunky size into a signal generator with unit element type.-The signal length is the only information that the generator provides.-Using 'zipWith' you can use this signal as a lazy 'take'.--}-lazySize ::- Param.T p SVP.LazySize ->- T p ()-lazySize =- Const.flatten . Const.lazySize----createFunction ::- (Functor genMod, EE.ExecutionFunction fun) =>- Exec.Importer fun -> genMod (Function fun) ->- Compose genMod EE.EngineAccess fun-createFunction importer modul =- Compose $ EE.getExecutionFunction importer <$> modul--createFinalizer ::- (Applicative genMod, EE.ExecutionFunction fun) =>- Exec.Importer fun -> genMod (Function fun) ->- Compose genMod EE.EngineAccess (EE.ExecutionEngine, fun)-createFinalizer importer modul =- liftA2 (,)- (Compose $ pure EE.getEngine)- (createFunction importer modul)---foreign import ccall safe "dynamic" derefFillPtr ::- Exec.Importer (LLVM.Ptr param -> Word -> Ptr a -> IO Word)---moduleFill ::- (Storable.C a, Tuple.ValueOf a ~ value,- Memory.C parameters, Memory.Struct parameters ~ paramStruct,- Tuple.Phi state, Tuple.Undefined state) =>- (forall r z.- (Tuple.Phi z) =>- context -> local -> state -> MaybeCont.T r z (value, state)) ->- (forall r. CodeGenFunction r local) ->- (forall r.- parameters -> CodeGenFunction r (context, state)) ->- (forall r.- context -> state -> CodeGenFunction r ()) ->- CodeGenModule- (Function (LLVM.Ptr paramStruct -> Word -> Ptr a -> IO Word))-moduleFill next alloca start stop =- Exec.createLLVMFunction "fillsignalblock" $- \paramPtr size bPtr -> do- param <- Memory.load paramPtr- (c,s) <- start param- local <- alloca- (pos,se) <- Storable.arrayLoopMaybeCont size bPtr s $ \ ptri s0 -> do- (y,s1) <- next c local s0- MaybeCont.lift $ Storable.store y ptri- return s1- Maybe.for se $ stop c- ret pos---declareMallocBytes :: LLVM.TFunction (Ptr Word8 -> IO (Ptr a))-declareMallocBytes = LLVM.newNamedFunction LLVM.ExternalLinkage "malloc"--debugMain ::- forall parameters a paramStruct.- (Marshal.C parameters,- Storable.C a,- LLVM.IsType paramStruct, IsSized paramStruct) =>- CodeGenModule- (Function (LLVM.Ptr paramStruct -> Word -> Ptr a -> IO Word)) ->- parameters ->- IO (Function (Word -> Ptr (Ptr Word8) -> IO Word))-debugMain sigModule params = do- paramArray <-- DebugSt.withConstArray params (\arr -> do- ptr <- LLVM.alloca- LLVM.store (value arr) =<< LLVM.bitcast ptr- return ptr)-- m <- LLVM.newModule-- mainFunc <- LLVM.defineModule m (do- LLVM.setTarget LLVM.hostTriple- mallocBytes <- declareMallocBytes- fill <- sigModule- Exec.createLLVMFunction "main" $ \ _argc _argv -> do- paramPtr <- paramArray- let chunkSize = 100000- basePtr = LLVM.valueOf nullPtr- buffer <-- LLVM.call mallocBytes =<<- LLVM.bitcast =<<- Storable.advancePtr- (LLVM.valueOf chunkSize) (basePtr :: LLVM.Value (Ptr a))- _done <-- LLVM.call fill paramPtr- (LLVM.valueOf $ fromIntegral chunkSize)- (asTypeOf buffer basePtr)- ret (A.zero :: LLVM.Value Word))-- Exec.dumper "main" >>= \writeBitcodeToFile -> writeBitcodeToFile "" m-- return mainFunc---run ::- (Storable.C a, Tuple.ValueOf a ~ value) =>- T p value ->- IO (Int -> p -> SV.Vector a)-run (Cons next alloca start stop createIOContext deleteIOContext) =- do -- this compiles once and is much faster than simpleFunction- let modul = moduleFill next alloca start stop- fill <- Exec.compile "signal" $ createFunction derefFillPtr modul-- return $ \len p ->- Unsafe.performIO $- bracket (createIOContext p) (deleteIOContext . fst) $- \ (_,params) -> do- when False $ void $ debugMain modul params-- SVB.createAndTrim len $ \ ptr ->- Marshal.with params $ \paramPtr ->- fmap fromIntegral $ fill paramPtr (fromIntegral len) ptr--{- |-This is not really a function, see 'renderChunky'.--}-render ::- (Storable.C a, Tuple.ValueOf a ~ value) =>- T p value -> Int -> p -> SV.Vector a-render gen = Unsafe.performIO $ run gen---foreign import ccall safe "dynamic" derefStartPtr ::- Exec.Importer (LLVM.Ptr b -> IO (LLVM.Ptr a))--foreign import ccall safe "dynamic" derefStopPtr ::- Exec.Importer (LLVM.Ptr a -> IO ())--foreign import ccall safe "dynamic" derefChunkPtr ::- Exec.Importer (LLVM.Ptr contextStateStruct -> Word -> Ptr a -> IO Word)--foreign import ccall safe "dynamic" derefChunkPluggedPtr ::- Exec.Importer- (LLVM.Ptr contextStateStruct -> Word -> LLVM.Ptr struct -> IO Word)---moduleStart ::- (Memory.C parameters, Memory.Struct parameters ~ paramStruct,- Memory.C context, Memory.C state,- Memory.Struct (context, Maybe.T state) ~ contextStateStruct) =>- (forall r. parameters -> CodeGenFunction r (context, state)) ->- CodeGenModule (Function- (LLVM.Ptr paramStruct -> IO (LLVM.Ptr contextStateStruct)))-moduleStart start =- Exec.createLLVMFunction "startsignal" $- \paramPtr -> do- pptr <- LLVM.malloc- flip Memory.store pptr . mapSnd Maybe.just- =<< start =<< Memory.load paramPtr- ret pptr--moduleStop ::- (Memory.C context, Memory.C state,- Memory.Struct (context, Maybe.T state) ~ contextStateStruct) =>- (forall r. context -> state -> CodeGenFunction r ()) ->- CodeGenModule (Function (LLVM.Ptr contextStateStruct -> IO ()))-moduleStop stop =- Exec.createLLVMFunction "stopsignal" $- \contextStatePtr -> do- (c,ms) <- Memory.load contextStatePtr- Maybe.for ms $ stop c- LLVM.free contextStatePtr- ret ()--moduleNext ::- (Storable.C a, Tuple.ValueOf a ~ value,- Memory.C context, Memory.C state,- Memory.Struct (context, Maybe.T state) ~ contextStateStruct,- Tuple.Phi state, Tuple.Undefined state) =>- (forall r z.- (Tuple.Phi z) =>- context -> local -> state -> MaybeCont.T r z (value, state)) ->- (forall r. CodeGenFunction r local) ->- CodeGenModule- (Function (LLVM.Ptr contextStateStruct -> Word -> Ptr a -> IO Word))-moduleNext next alloca =- Exec.createLLVMFunction "fillsignal" $- \contextStatePtr loopLen ptr -> do- (context, msInit) <- Memory.load contextStatePtr- local <- alloca- (pos,msExit) <-- Maybe.run msInit (return (A.zero, Maybe.nothing)) $ \sInit ->- Storable.arrayLoopMaybeCont loopLen ptr sInit $ \ptri s0 -> do- (y,s1) <- next context local s0- MaybeCont.lift $ Storable.store y ptri- return s1- sptr <- LLVM.getElementPtr0 contextStatePtr (TypeNum.d1, ())- Memory.store msExit sptr- ret pos--moduleNextPlugged ::- (Memory.C context, Memory.C state,- Memory.Struct (context, Maybe.T state) ~ contextStateStruct,- Tuple.Undefined stateOut, Tuple.Phi stateOut,- Memory.C paramValueOut, Memory.Struct paramValueOut ~ paramStructOut) =>- (forall r z.- (Tuple.Phi z) =>- context -> local -> state -> MaybeCont.T r z (value, state)) ->- (forall r. CodeGenFunction r local) ->- (forall r.- paramValueOut ->- value -> stateOut -> LLVM.CodeGenFunction r stateOut) ->- (forall r.- paramValueOut ->- LLVM.CodeGenFunction r stateOut) ->- CodeGenModule- (Function- (LLVM.Ptr contextStateStruct -> Word ->- LLVM.Ptr paramStructOut -> IO Word))-moduleNextPlugged next alloca nextOut startOut =- Exec.createLLVMFunction "fillsignal" $- \contextStatePtr loopLen outPtr -> do- (context, msInit) <- Memory.load contextStatePtr- outParam <- Memory.load outPtr- outInit <- startOut outParam- local <- alloca- (pos,msExit) <-- Maybe.run msInit (return (A.zero, Maybe.nothing)) $ \sInit ->- MaybeCont.fixedLengthLoop loopLen (sInit, outInit) $- \ (s0,out0) -> do- (y,s1) <- next context local s0- out1 <- MaybeCont.lift $ nextOut outParam y out0- return (s1, out1)- sptr <- LLVM.getElementPtr0 contextStatePtr (TypeNum.d1, ())- Memory.store (fmap fst msExit) sptr- ret pos--debugChunkyMain ::- forall parameters a paramStruct contextStateStruct.- (Marshal.C parameters,- Storable.C a,- LLVM.IsType contextStateStruct,- LLVM.IsType paramStruct, IsSized paramStruct) =>- CodeGenModule- (Function (LLVM.Ptr paramStruct -> IO (LLVM.Ptr contextStateStruct)),- Function (LLVM.Ptr contextStateStruct -> IO ()),- Function (LLVM.Ptr contextStateStruct ->- Word -> Ptr a -> IO Word)) ->- parameters ->- IO (Function (Word -> Ptr (Ptr Word8) -> IO Word))-debugChunkyMain sigModule params = do-{--This does not work, since we cannot add (Mul n D32 s) constraint-to the function argument in reifyIntegral.- nextArray <-- DebugSt.withConstArray nextParam (\arr -> do- ptr <- LLVM.alloca- LLVM.store (value arr) ptr- LLVM.bitcast ptr)--}- paramArray <-- DebugSt.withConstArray params (\arr -> do- ptr <- LLVM.alloca- LLVM.store (value arr) =<< LLVM.bitcast ptr- return ptr)-- m <- LLVM.newModule-- mainFunc <- LLVM.defineModule m (do- LLVM.setTarget LLVM.hostTriple- mallocBytes <- declareMallocBytes- (start, stop, fill) <- sigModule- Exec.createLLVMFunction "main" $ \ _argc _argv -> do- contextState <- LLVM.call start =<< paramArray- let chunkSize = 100000- basePtr = LLVM.valueOf nullPtr- buffer <-- LLVM.call mallocBytes =<<- LLVM.bitcast =<<- Storable.advancePtr- (LLVM.valueOf chunkSize) (basePtr :: LLVM.Value (Ptr a))- _done <-- LLVM.call fill contextState- (LLVM.valueOf $ fromIntegral chunkSize)- (asTypeOf buffer basePtr)- _ <- LLVM.call stop contextState- ret (A.zero :: LLVM.Value Word))-- Exec.dumper "main-chunky" >>= \writeBitcodeToFile -> writeBitcodeToFile "" m-- return mainFunc----{- |-Renders a signal generator to a chunky storable vector with given pattern.-If the pattern is shorter than the generated signal-this means that the signal is shortened.--}-runChunkyPattern, _runChunkyPattern ::- (Storable.C a, Tuple.ValueOf a ~ value) =>- T p value ->- IO (SVP.LazySize -> p -> SVL.Vector a)-_runChunkyPattern =- fmap (\f size -> SVL.fromChunks . f size) .- flip runChunkyPatternPlugged POut.deflt--runChunkyPattern- (Cons next alloca start stop createIOContext deleteIOContext) = do-- let startF = moduleStart start- let stopF = moduleStop stop- let nextF = moduleNext next alloca-- (startFunc, stopFunc, fill) <-- Exec.compile "signal-pattern" $- liftA3 (,,)- (createFunction derefStartPtr startF)- (createFinalizer derefStopPtr stopF)- (createFunction derefChunkPtr nextF)-- return $- \ lazysize p -> SVL.fromChunks $ Unsafe.performIO $ do- (ioContext, param) <- createIOContext p--{-- putStr "nextParam: "- DebugSt.format nextParam >>= putStrLn--}- when False $- Counter.next DebugSt.dumpCounter >>=- DebugSt.dump "param" param-- when False $ void $- debugChunkyMain (liftA3 (,,) startF stopF nextF) param-- statePtr <- ForeignPtr.newParam stopFunc startFunc param- ioContextPtr <- ForeignPtr.newAux (deleteIOContext ioContext)-- let go cs =- Unsafe.interleaveIO $- case cs of- [] -> return []- SVL.ChunkSize size : rest -> do- v <-- ForeignPtr.with statePtr $ \sptr ->- SVB.createAndTrim size $- fmap fromIntegral .- fill sptr (fromIntegral size)- touchForeignPtr ioContextPtr- (if SV.length v > 0- then fmap (v:)- else id) $- (if SV.length v < size- then return []- else go rest)- go (Chunky.toChunks lazysize)--runChunkyPatternPlugged ::- T p value ->- POut.T value chunk ->- IO (SVP.LazySize -> p -> [chunk])-runChunkyPatternPlugged- (Cons next alloca start stop createIOContext deleteIOContext)- (POut.Cons nextOut startOut createOut deleteOut) = do-- (startFunc, stopFunc, fill) <-- Exec.compile "signal-plugged" $- liftA3 (,,)- (createFunction derefStartPtr $ moduleStart start)- (createFinalizer derefStopPtr $ moduleStop stop)- (createFunction derefChunkPluggedPtr $- moduleNextPlugged next alloca nextOut startOut)-- return $- \ lazysize p -> Unsafe.performIO $ do- (ioContext, param) <- createIOContext p-- statePtr <- ForeignPtr.newParam stopFunc startFunc param- ioContextPtr <- ForeignPtr.newAux (deleteIOContext ioContext)-- let go cs =- Unsafe.interleaveIO $- case cs of- [] -> return []- SVL.ChunkSize maximumSize : rest -> do- (contextOut,paramOut) <- createOut maximumSize- actualSize <-- fmap fromIntegral $- Marshal.with paramOut $ \outptr ->- ForeignPtr.with statePtr $ \sptr ->- fill sptr (fromIntegral maximumSize) outptr- when (fromIntegral actualSize > maximumSize) $- error $ "Parametrized.Signal: " ++- "output size " ++ show actualSize ++- " > input size " ++ show maximumSize- v <- deleteOut actualSize contextOut- touchForeignPtr ioContextPtr- (if actualSize > 0- then fmap (v:)- else id) $- (if actualSize < maximumSize- then return []- else go rest)- go (Chunky.toChunks lazysize)--runChunky, _runChunky ::- (Storable.C a, Tuple.ValueOf a ~ value) =>- T p value ->- IO (SVL.ChunkSize -> p -> SVL.Vector a)-runChunky sig =- flip fmap (runChunkyPattern sig) $ \f size p ->- f (Chunky.fromChunks (repeat size)) p--_runChunky =- fmap (\f size -> SVL.fromChunks . f size) .- flip runChunkyPlugged POut.deflt--runChunkyPlugged ::- T p value ->- POut.T value chunk ->- IO (SVL.ChunkSize -> p -> [chunk])-runChunkyPlugged sig plug =- flip fmap (runChunkyPatternPlugged sig plug) $ \f size p ->- f (Chunky.fromChunks (repeat size)) p--{- |-This looks like a function,-but it is not a function since it depends on LLVM being initialized-with LLVM.initializeNativeTarget before.-It is also problematic since you cannot control when and how often-the underlying LLVM code is compiled.-The compilation cannot be observed, thus it is referential transparent.-But this influences performance considerably-and I assume that you use this package exclusively for performance reasons.--}-renderChunky ::- (Storable.C a, Tuple.ValueOf a ~ value) =>- SVL.ChunkSize -> T p value ->- p -> SVL.Vector a-renderChunky size gen =- Unsafe.performIO (runChunky gen) size
− src/Synthesizer/LLVM/Parameterized/SignalPacked.hs
@@ -1,287 +0,0 @@-{-# LANGUAGE NoImplicitPrelude #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE Rank2Types #-}-{-# LANGUAGE FlexibleContexts #-}-{- |-Signal generators that generate the signal in chunks-that can be processed natively by the processor.-Some of the functions for plain signals can be re-used without modification.-E.g. rendering a signal and reading from and to signals work-because the vector type as element type warrents correct alignment.-We can convert between atomic and chunked signals.--The article-<http://perilsofparallel.blogspot.com/2008/09/larrabee-vs-nvidia-mimd-vs-simd.html>-explains the difference between Vector and SIMD computing.-According to that the SSE extensions in Intel processors-must be called Vector computing.-But since we use the term Vector already in the mathematical sense,-I like to use the term "packed" that is used in Intel mnemonics like mulps.--}-module Synthesizer.LLVM.Parameterized.SignalPacked (- SigS.pack, SigS.packRotate,- SigS.packSmall,- SigS.unpack, SigS.unpackRotate,- constant,- exponential2,- exponentialBounded2,- osciCore,- osci,- osciSimple,- parabolaFadeInInf, parabolaFadeOutInf,- rampInf, rampSlope,- noise,- noiseCore, noiseCoreAlt,- ) where--import Synthesizer.LLVM.Parameterized.Signal (T)-import qualified Synthesizer.LLVM.Simple.SignalPacked as SigS-import qualified Synthesizer.LLVM.Parameterized.Signal as Sig-import qualified Synthesizer.LLVM.Frame.SerialVector as Serial-import qualified Synthesizer.LLVM.Random as Rnd--import qualified LLVM.DSL.Parameter as Param--import qualified LLVM.Extra.Marshal as Marshal-import qualified LLVM.Extra.Memory as Memory-import qualified LLVM.Extra.ScalarOrVector as SoV-import qualified LLVM.Extra.Vector as Vector-import qualified LLVM.Extra.Arithmetic as A-import qualified LLVM.Extra.Tuple as Tuple--import qualified Type.Data.Num.Decimal as TypeNum-import Type.Data.Num.Decimal ((:*:))--import qualified LLVM.Core as LLVM-import LLVM.Core- (CodeGenFunction, Value,- IsConst, IsArithmetic, IsFloating, IsPrimitive, Vector, SizeOf)--import Control.Monad.HT ((<=<))--- we can also use <$> for parameters-import Control.Arrow ((^<<))-import Control.Applicative (liftA2)--import qualified Algebra.Transcendental as Trans-import qualified Algebra.Algebraic as Algebraic-import qualified Algebra.RealField as RealField-import qualified Algebra.Ring as Ring--import Data.Word (Word32)-import Data.Int (Int32)--import NumericPrelude.Numeric as NP-import NumericPrelude.Base hiding (and, iterate, map, zip, zipWith)----withSize ::- (TypeNum.Positive n) =>- (TypeNum.Singleton n -> T p (Serial.Value n a)) ->- T p (Serial.Value n a)-withSize f = f TypeNum.singleton--withSizeRing ::- (Ring.C b, TypeNum.Positive n) =>- (TypeNum.Singleton n -> b -> T p (Serial.Value n a)) ->- T p (Serial.Value n a)-withSizeRing f =- withSize $ \n -> f n $ fromInteger $ TypeNum.integerFromSingleton n---constant ::- (Marshal.Vector n a, Tuple.ValueOf a ~ Value a, IsConst a,- Tuple.VectorValueOf n a ~ Value (Vector n a),- IsPrimitive a, SizeOf a ~ asize,- TypeNum.Positive (n :*: asize),- TypeNum.Positive n) =>- Param.T p a -> T p (Serial.Value n a)-constant x =- withSize $ \n -> Sig.constant (Serial.replicate_ n ^<< x)---exponential2 ::- (Trans.C a, Marshal.Vector n a, Tuple.ValueOf a ~ Value a,- Tuple.VectorValueOf n a ~ Value (Vector n a),- IsArithmetic a, IsConst a,- IsPrimitive a, SizeOf a ~ asize,- TypeNum.Positive (n :*: asize),- TypeNum.Positive n) =>- Param.T p a -> Param.T p a -> T p (Serial.Value n a)-exponential2 halfLife start = withSizeRing $ \sn n ->- Sig.exponentialCore- (Serial.replicate_ sn ^<< 0.5 ** (n / halfLife))- (liftA2- (\h -> Serial.iteratePlain (0.5 ** recip h *))- halfLife start)--exponentialBounded2 ::- (Trans.C a, Marshal.Vector n a, Tuple.ValueOf a ~ Value a,- Tuple.VectorValueOf n a ~ Value (Vector n a),- Vector.Real a, IsConst a,- IsPrimitive a, SizeOf a ~ as,- TypeNum.Positive (n :*: as),- TypeNum.Positive n) =>- Param.T p a -> Param.T p a -> Param.T p a ->- T p (Serial.Value n a)-exponentialBounded2 bound halfLife start = withSizeRing $ \sn n ->- Sig.exponentialBoundedCore- (fmap (Serial.replicate_ sn) bound)- (Serial.replicate_ sn ^<< 0.5 ** (n / halfLife))- (liftA2- (\h -> Serial.iteratePlain (0.5 ** recip h *))- halfLife start)---osciCore ::- (Marshal.Vector n t, Tuple.ValueOf t ~ Value t,- Tuple.VectorValueOf n t ~ Value (Vector n t),- IsPrimitive t, SizeOf t ~ tsize,- TypeNum.Positive (n :*: tsize),- Vector.Real t, IsFloating t, RealField.C t, IsConst t,- TypeNum.Positive n) =>- Param.T p t -> Param.T p t -> T p (Serial.Value n t)-osciCore phase freq = withSizeRing $ \sn n ->- Sig.osciCore- (liftA2- (\f -> Serial.iteratePlain (fraction . (f +)))- freq phase)- (fmap- (\f -> Serial.replicate_ sn (fraction (n * f)))- freq)--osci ::- (Marshal.Vector n t, Tuple.ValueOf t ~ Value t,- Marshal.C c, Tuple.ValueOf c ~ cl,- Tuple.VectorValueOf n t ~ Value (Vector n t),- IsPrimitive t, SizeOf t ~ tsize,- TypeNum.Positive (n :*: tsize),- Memory.C cl,- Vector.Real t, IsFloating t, RealField.C t, IsConst t,- TypeNum.Positive n) =>- (forall r. cl -> Serial.Value n t -> CodeGenFunction r y) ->- Param.T p c ->- Param.T p t -> Param.T p t -> T p y-osci wave waveParam phase freq =- Sig.map wave waveParam $- osciCore phase freq--osciSimple ::- (Marshal.Vector n t, Tuple.ValueOf t ~ Value t,- Tuple.VectorValueOf n t ~ Value (Vector n t),- IsPrimitive t, SizeOf t ~ tsize,- TypeNum.Positive (n :*: tsize),- Vector.Real t, IsFloating t, RealField.C t, IsConst t,- TypeNum.Positive n) =>- (forall r. Serial.Value n t -> CodeGenFunction r y) ->- Param.T p t -> Param.T p t -> T p y-osciSimple wave =- osci (const wave) (return ())---rampInf, rampSlope,- parabolaFadeInInf, parabolaFadeOutInf ::- (RealField.C a, Marshal.Vector n a, Tuple.ValueOf a ~ Value a,- Tuple.VectorValueOf n a ~ Value (Vector n a),- IsPrimitive a, SizeOf a ~ as,- TypeNum.Positive (n :*: as),- IsArithmetic a, SoV.IntegerConstant a,- TypeNum.Positive n) =>- Param.T p a -> T p (Serial.Value n a)-rampSlope slope = withSizeRing $ \sn n ->- Sig.rampCore- (fmap (\s -> Serial.replicate_ sn (n * s)) slope)- (fmap (\s -> Serial.iteratePlain (s +) 0) slope)-rampInf dur = rampSlope (recip dur)--parabolaFadeInInf dur = withSizeRing $ \sn n ->- Sig.parabolaCore- (fmap- (\dr ->- let d = n / dr- in Serial.replicate_ sn (-2*d*d)) dur)- (fmap- (\dr ->- let d = n / dr- in Serial.iteratePlain (subtract $ 2 / dr ^ 2) (d*(2-d)))- dur)- (fmap- (\dr ->- Serial.mapPlain (\t -> t*(2-t)) $ Serial.iteratePlain (recip dr +) 0)- dur)--parabolaFadeOutInf dur = withSizeRing $ \sn n ->- Sig.parabolaCore- (fmap- (\dr ->- let d = n / dr- in Serial.replicate_ sn (-2*d*d)) dur)- (fmap- (\dr ->- let d = n / dr- in Serial.iteratePlain (subtract $ 2 / dr ^ 2) (-d*d))- dur)- (fmap- (\dr ->- Serial.mapPlain (\t -> 1-t*t) $ Serial.iteratePlain (recip dr +) 0)- dur)---{- |-For the mysterious rate parameter see 'Sig.noise'.--}-noise ::- (Algebraic.C a, IsFloating a, SoV.IntegerConstant a,- TypeNum.Positive n,- TypeNum.Positive (n :*: TypeNum.D32),- IsPrimitive a, SizeOf a ~ as,- TypeNum.Positive (n :*: as),- Marshal.Vector n a, Tuple.VectorValueOf n a ~ Value (Vector n a),- Tuple.ValueOf a ~ Value a) =>- Param.T p Word32 ->- Param.T p a ->- T p (Serial.Value n a)-noise seed rate =- withSize $ \n ->- let m2 = div Rnd.modulus 2- in Sig.map- (\r y ->- A.mul r- =<< flip A.sub (A.fromInteger' $ m2+1)- =<< int31tofp y)- (Serial.replicate_ n ^<< sqrt (3 * rate) / return (fromInteger m2)) $- noiseCore seed--{--sitofp is a single instruction on x86-and thus we use it, since the arguments are below 2^31.--}-int31tofp ::- (IsFloating a, IsPrimitive a,- TypeNum.Positive n, TypeNum.Positive (n :*: TypeNum.D32)) =>- Serial.Value n Word32 -> CodeGenFunction r (Serial.Value n a)-int31tofp =- Serial.mapV $- LLVM.inttofp <=<- (LLVM.bitcast ::- (TypeNum.Positive n, TypeNum.Positive (n :*: TypeNum.D32)) =>- Value (Vector n Word32) ->- CodeGenFunction r (Value (Vector n Int32)))--noiseCore, noiseCoreAlt ::- (TypeNum.Positive n,- TypeNum.Positive (n :*: TypeNum.D32)) =>- Param.T p Word32 ->- T p (Serial.Value n Word32)-noiseCore seed =- fmap Serial.value $- Sig.iterate (const Rnd.nextVector)- (return ())- (Rnd.vectorSeed . (+1) . flip mod (Rnd.modulus-1) ^<< seed)--noiseCoreAlt seed =- fmap Serial.value $- Sig.iterate (const Rnd.nextVector64)- (return ())- (Rnd.vectorSeed . (+1) . flip mod (Rnd.modulus-1) ^<< seed)
− src/Synthesizer/LLVM/Parameterized/SignalPrivate.hs
@@ -1,346 +0,0 @@-{-# LANGUAGE NoImplicitPrelude #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE ExistentialQuantification #-}-{-# LANGUAGE Rank2Types #-}-module Synthesizer.LLVM.Parameterized.SignalPrivate where--import qualified Synthesizer.LLVM.Simple.SignalPrivate as Sig-import qualified LLVM.Extra.Tuple as Tuple-import qualified LLVM.Extra.MaybeContinuation as MaybeCont-import qualified LLVM.Extra.Either as Either-import qualified LLVM.Extra.Maybe as Maybe-import qualified LLVM.Extra.Marshal as Marshal-import qualified LLVM.Extra.Memory as Memory-import qualified LLVM.Extra.Arithmetic as A--import qualified LLVM.DSL.Parameter as Param-import qualified LLVM.Core as LLVM-import LLVM.Core (CodeGenFunction)--import Control.Arrow ((&&&))-import Control.Monad (liftM, liftM2)-import Control.Applicative (Applicative, pure, (<*>))--import Data.Tuple.Strict (zipPair)-import Data.Monoid (Monoid, mempty, mappend)-import Data.Semigroup (Semigroup, (<>))--import qualified Number.Ratio as Ratio-import qualified Algebra.Field as Field-import qualified Algebra.Ring as Ring-import qualified Algebra.Additive as Additive--import NumericPrelude.Base hiding (and, iterate, map, zip, zipWith)--import qualified Prelude as P---{--In this attempt we use a Haskell value as parameter supply.-This is okay, since the Haskell value will be converted to internal parameters-and then to LLVM values only once.-We can even have a storable vector as parameter.-However, this way we cannot easily implement-the Vanilla signal using Parameterized.Value as element type.--This separation is nice for maximum efficiency,-but it cannot be utilized by Generic.Signal methods.-Consider an expression like @iterate ((0.5 ** recip halfLife) *) 1@.-How shall we know, that the sub-expression @(0.5 ** recip halfLife)@-needs to be computated only once?-I do not try to do such optimization, instead I let LLVM do it.-However, this means that parameter initialization-will be performed (unnecessarily) at the beginning of every chunk.-For Generic.Signal method instances-we will always set the @(p -> paramTuple)@ to 'id'.--Could we drop parameterized signals at all-and rely entirely on Causal processes?-Unfortunately 'interpolateConstant' does not fit into the Causal process scheme.-(... although it would be causal for stretching factor being at least one.-It would have to maintain the waiting signal as state,-i.e. the state would grow linearly with time.)-Consider a signal algorithm, where the LFO frequency is a parameter.--}-data T p a =- forall context state local ioContext parameters.- (Marshal.C parameters, Memory.C context, Memory.C state) =>- Cons- (forall r c.- (Tuple.Phi c) =>- context -> local -> state -> MaybeCont.T r c (a, state))- -- compute next value- (forall r.- CodeGenFunction r local)- -- allocate temporary variables before a loop- (forall r.- Tuple.ValueOf parameters ->- CodeGenFunction r (context, state))- -- allocate initial state- (forall r.- context -> state ->- CodeGenFunction r ())- {- cleanup- You must make sure to call this- whenever you allocated context and state with the 'start' function.- You must call it with the latest state returned from the 'next' function.- -}- (p -> IO (ioContext, parameters))- {- initialization from IO monad- This will be run within Unsafe.performIO,- so no observable In/Out actions please!- -}- (ioContext -> IO ())- -- finalization from IO monad, also run within Unsafe.performIO---instance Sig.C (T p) where- simpleAlloca next alloca0 start =- Cons- (\() local -> next local)- alloca0- (const $ fmap ((,) ()) start)- (const $ const $ return ())- (const $ return ((), ()))- (const $ return ())-- alter f (Cons next0 alloca0 start0 stop0 create delete) =- case f (Sig.Core (uncurry next0) return id) of- Sig.Core next1 start1 stop1 ->- Cons- (curry next1)- alloca0- (withStart start0 start1)- (\c -> stop0 c . stop1)- create delete---withStart ::- Monad m =>- (startParam -> m (context, state0)) ->- (state0 -> m state1) ->- startParam -> m (context, state1)-withStart start act p = do- (c,s) <- start p- liftM ((,) c) $ act s--combineStart ::- Monad m =>- (paramA -> m (contextA, stateA)) ->- (paramB -> m (contextB, stateB)) ->- (paramA, paramB) -> m ((contextA, contextB), (stateA, stateB))-combineStart startA startB (paramA, paramB) =- liftM2 zipPair (startA paramA) (startB paramB)--combineStop ::- Monad m =>- (contextA -> stateA -> m ()) ->- (contextB -> stateB -> m ()) ->- (contextA, contextB) -> (stateA, stateB) -> m ()-combineStop stopA stopB (ca, cb) (sa, sb) =- stopA ca sa >> stopB cb sb--combineCreate ::- Monad m =>- (p -> m (ioContextA, contextA)) ->- (p -> m (ioContextB, contextB)) ->- p -> m ((ioContextA, ioContextB), (contextA, contextB))-combineCreate createIOContextA createIOContextB p =- liftM2 zipPair (createIOContextA p) (createIOContextB p)--combineDelete ::- (Monad m) =>- (ca -> m ()) -> (cb -> m ()) -> (ca, cb) -> m ()-combineDelete deleteIOContextA deleteIOContextB (ca,cb) =- deleteIOContextA ca >> deleteIOContextB cb----simple ::- (Marshal.C parameters, Tuple.ValueOf parameters ~ paramTuple,- Memory.C context, Memory.C state) =>- (forall r c.- (Tuple.Phi c) =>- context -> state -> MaybeCont.T r c (al, state)) ->- (forall r.- paramTuple ->- CodeGenFunction r (context, state)) ->- Param.T p parameters -> T p al-simple f start param =- Param.withValue param $ \getParam valueParam ->- Cons- (\context () state -> f context state)- (return ())- (start . valueParam)- (const $ const $ return ())- (return . (,) () . getParam)- (const $ return ())---constant :: (Marshal.C a, Tuple.ValueOf a ~ al) => Param.T p a -> T p al-constant =- simple- (\pl () -> return (pl, ()))- (return . flip (,) ())---map ::- (Marshal.C ph, Tuple.ValueOf ph ~ pl) =>- (forall r. pl -> a -> CodeGenFunction r b) ->- Param.T p ph ->- T p a -> T p b-map f param =- Sig.map (uncurry f) . zip (constant param)---- for backwards compatibility-mapSimple ::- (forall r. a -> CodeGenFunction r b) ->- T p a -> T p b-mapSimple = Sig.map---zipWith ::- (Marshal.C ph, Tuple.ValueOf ph ~ pl) =>- (forall r. pl -> a -> b -> CodeGenFunction r c) ->- Param.T p ph ->- T p a -> T p b -> T p c-zipWith f param as bs =- map (uncurry . f) param $ zip as bs--zip :: T p a -> T p b -> T p (a,b)-zip (Cons nextA allocaA startA stopA createIOContextA deleteIOContextA)- (Cons nextB allocaB startB stopB createIOContextB deleteIOContextB) =- Cons- (\(parameterA, parameterB) (localA, localB) (sa0,sb0) -> do- (a,sa1) <-- MaybeCont.onFail (stopB parameterB sb0) $- nextA parameterA localA sa0- (b,sb1) <-- MaybeCont.onFail (stopA parameterA sa1) $- nextB parameterB localB sb0- return ((a,b), (sa1,sb1)))- (liftM2 (,) allocaA allocaB)- (combineStart startA startB)- (combineStop stopA stopB)- (combineCreate createIOContextA createIOContextB)- (combineDelete deleteIOContextA deleteIOContextB)--{--maintained for backwards compatibility-It is a specialisation of Sig.zipWith.-However, we cannot define zipWithSimple = Sig.zipWith,-since Sig.zipWith depends on Applicative.liftA2,-which depends on zipWithSimple.--}-zipWithSimple ::- (forall r. a -> b -> CodeGenFunction r c) ->- T p a -> T p b -> T p c-zipWithSimple f as bs =- mapSimple (uncurry f) $ zip as bs---instance Functor (T p) where- fmap f = mapSimple (return . f)--{- |-ZipList semantics--}-instance Applicative (T p) where- pure x =- simple- (\() () -> return (x, ()))- (\() -> return ((),()))- (return ())- (<*>) = zipWithSimple (\f a -> return (f a))---instance (A.Additive a) => Additive.C (T p a) where- zero = pure A.zero- negate = mapSimple A.neg- (+) = zipWithSimple A.add- (-) = zipWithSimple A.sub--instance (A.PseudoRing a, A.IntegerConstant a) => Ring.C (T p a) where- one = pure A.one- fromInteger n = pure (A.fromInteger' n)- (*) = zipWithSimple A.mul--instance (A.Field a, A.RationalConstant a) => Field.C (T p a) where- fromRational' x = pure (A.fromRational' $ Ratio.toRational98 x)- (/) = zipWithSimple A.fdiv---instance (A.PseudoRing a, A.Real a, A.IntegerConstant a) => P.Num (T p a) where- fromInteger n = pure (A.fromInteger' n)- negate = mapSimple A.neg- (+) = zipWithSimple A.add- (-) = zipWithSimple A.sub- (*) = zipWithSimple A.mul- abs = mapSimple A.abs- signum = mapSimple A.signum--instance (A.Field a, A.Real a, A.RationalConstant a) => P.Fractional (T p a) where- fromRational x = pure (A.fromRational' x)- (/) = zipWithSimple A.fdiv---{- |-For restrictions see 'Sig.append'.--}-append :: (Tuple.Phi a, Tuple.Undefined a) => T p a -> T p a -> T p a-append- (Cons nextA allocaA startA stopA createIOContextA deleteIOContextA)- (Cons nextB allocaB startB stopB createIOContextB deleteIOContextB) =- Cons- (\parameterB (localA, localB) ecs0 -> MaybeCont.fromMaybe $ do- ecs1 <-- Either.run ecs0- (\(ca, sa0) ->- MaybeCont.resolve- (nextA ca localA sa0)- (fmap Either.right $ startB parameterB)- (\(a1,sa1) -> return (Either.left (a1, (ca, sa1)))))- (return . Either.right)-- Either.run ecs1- (\(a1,cs1) ->- return (Maybe.just (a1, Either.left cs1)))- (\(cb,sb0) ->- MaybeCont.toMaybe $- fmap (\(b,sb1) -> (b, Either.right (cb,sb1))) $- nextB cb localB sb0))- (liftM2 (,) allocaA allocaB)- (\(parameterA, parameterB) -> do- cs <- startA parameterA- return (parameterB, Either.left cs))- (\ _parameterB s -> Either.run s (uncurry stopA) (uncurry stopB))- (combineCreate createIOContextA createIOContextB)- (combineDelete deleteIOContextA deleteIOContextB)--instance (Tuple.Phi a, Tuple.Undefined a) => Semigroup (T p a) where- (<>) = append--instance (Tuple.Phi a, Tuple.Undefined a) => Monoid (T p a) where- mempty = Sig.empty- mappend = append---iterate ::- (Marshal.C c, Tuple.ValueOf c ~ cl,- Marshal.C a, Tuple.ValueOf a ~ al) =>- (forall r. cl -> al -> CodeGenFunction r al) ->- Param.T p c -> Param.T p a -> T p al-iterate f param initial = simple- (\pl al0 -> MaybeCont.lift $ fmap (\al1 -> (al0,al1)) (f pl al0))- return- (param &&& initial)--malloc :: (LLVM.IsSized a) => T p (LLVM.Value (LLVM.Ptr a))-malloc =- Cons- (\ptr () () -> return (ptr, ()))- (return ())- (const $ fmap (flip (,) ()) $ LLVM.malloc)- (\ptr () -> LLVM.free ptr)- (const $ return ((), ()))- (const $ return ())
src/Synthesizer/LLVM/Plug/Input.hs view
@@ -1,9 +1,7 @@-{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-} {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE Rank2Types #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE UndecidableInstances #-} module Synthesizer.LLVM.Plug.Input ( T(..), Default(..),@@ -21,16 +19,19 @@ import qualified Synthesizer.LLVM.ConstantPiece as Const -import qualified LLVM.Extra.Storable as Storable-import qualified LLVM.Extra.Marshal as Marshal+import qualified LLVM.Extra.Multi.Value.Storable as Storable+import qualified LLVM.Extra.Multi.Value.Marshal as Marshal+import qualified LLVM.Extra.Multi.Value as MultiValue import qualified LLVM.Extra.Memory as Memory import qualified LLVM.Extra.Arithmetic as A import qualified LLVM.Extra.Tuple as Tuple import qualified LLVM.Extra.Control as C +import qualified LLVM.ExecutionEngine as EE import qualified LLVM.Core as LLVM import qualified Type.Data.Num.Decimal as TypeNum+import Type.Data.Num.Decimal ((:*:)) import Type.Base.Proxy (Proxy) import qualified Synthesizer.MIDI.PiecewiseConstant.ControllerSet as PCS@@ -49,14 +50,17 @@ import qualified Foreign.ForeignPtr as FPtr import Foreign.Storable (pokeElemOff) -import Control.Applicative (liftA2)+import qualified Control.Functor.HT as FuncHT+import Control.Applicative (liftA2, (<$>)) import qualified Data.Map as Map--import Data.Tuple.Strict (mapFst, mapPair, swap, zipPair)+import qualified Data.List as List+import Data.Tuple.Strict (mapFst, zipPair) import Data.Word (Word) +import Prelude hiding (map) + {- This datatype does not provide an early exit option, e.g. by Maybe.T, since we warrant that the driver function will always@@ -69,104 +73,90 @@ (Marshal.C parameters, Memory.C state) => Cons (forall r.- Tuple.ValueOf parameters ->+ MultiValue.T parameters -> state -> LLVM.CodeGenFunction r (b, state))- -- compute next value+ -- compute next value (forall r.- Tuple.ValueOf parameters ->+ MultiValue.T parameters -> LLVM.CodeGenFunction r state)- -- initial state+ -- initial state (a -> IO (ioContext, parameters))- {- initialization from IO monad- This is called once input chunk.- This will be run within Unsafe.performIO,- so no observable In/Out actions please!- -}+ {- initialization from IO monad+ This is called once input chunk.+ This will be run within Unsafe.performIO,+ so no observable In/Out actions please!+ -} (ioContext -> IO ())- {-- finalization from IO monad, also run within Unsafe.performIO- -}+ {-+ finalization from IO monad, also run within Unsafe.performIO+ -} instance Functor (T a) where fmap f (Cons next start create delete) = Cons (\p s -> fmap (mapFst f) $ next p s) start create delete +map :: (forall r. a -> LLVM.CodeGenFunction r b) -> T inp a -> T inp b+map f (Cons next start create delete) =+ Cons (\p s -> FuncHT.mapFst f =<< next p s) start create delete -class Default a where- type Element a :: *- deflt :: T a (Element a) -instance (Default a, Default b) => Default (Zip.T a b) where- type Element (Zip.T a b) = (Element a, Element b)- deflt = split deflt deflt -instance Default SigG.LazySize where- type Element SigG.LazySize = ()- deflt = lazySize--instance (Storable.C a) => Default (SV.Vector a) where- type Element (SV.Vector a) = Tuple.ValueOf a- deflt = storableVector---{--This is intentionally restricted to NonNegW.Int aka StrictTimeShort,-since chunks must fit into memory.-If you have good reasons to allow other types,-see the versioning history for an according hack.--}-instance- (Storable.C a, Memory.C (Tuple.ValueOf a)) =>- Default (EventListBT.T NonNegW.Int a) where- type Element (EventListBT.T NonNegW.Int a) = Tuple.ValueOf a- deflt = piecewiseConstant-+class Default a where+ type Element a+ deflt :: T a (Element a) rmap :: (a -> b) -> T b c -> T a c rmap f (Cons next start create delete) = Cons next start (create . f) delete +fanout :: T a b -> T a c -> T a (b,c)+fanout f g = rmap (\a -> Zip.Cons a a) $ split f g ++instance (Default a, Default b) => Default (Zip.T a b) where+ type Element (Zip.T a b) = (Element a, Element b)+ deflt = split deflt deflt+ split :: T a c -> T b d -> T (Zip.T a b) (c,d) split (Cons nextA startA createA deleteA) (Cons nextB startB createB deleteB) = Cons- (\(parameterA, parameterB) (sa,sb) ->- liftA2 zipPair- (nextA parameterA sa)- (nextB parameterB sb))- (\(parameterA, parameterB) ->- liftA2 (,)- (startA parameterA)- (startB parameterB))+ (MultiValue.uncurry $ \parameterA parameterB (sa,sb) ->+ liftA2 zipPair (nextA parameterA sa) (nextB parameterB sb))+ (MultiValue.uncurry $ \parameterA parameterB ->+ liftA2 (,) (startA parameterA) (startB parameterB)) (\(Zip.Cons a b) ->- liftA2 zipPair- (createA a)- (createB b))- (\(ca,cb) ->- deleteA ca >>- deleteB cb)+ liftA2 zipPair (createA a) (createB b))+ (\(ca,cb) -> deleteA ca >> deleteB cb) -fanout :: T a b -> T a c -> T a (b,c)-fanout f g = rmap (\a -> Zip.Cons a a) $ split f g +instance Default SigG.LazySize where+ type Element SigG.LazySize = ()+ deflt = lazySize+ lazySize :: T SigG.LazySize () lazySize = ignore ignore :: T a () ignore = Cons- (\ _ _ -> return ((), ()))+ (\ _ unit -> return ((), unit)) return (\ _a -> return ((), ())) (const $ return ()) -storableVector ::- (Storable.C a, Tuple.ValueOf a ~ value) => T (SV.Vector a) value+instance (Storable.C a) => Default (SV.Vector a) where+ type Element (SV.Vector a) = MultiValue.T a+ deflt = storableVector++storableVector :: (Storable.C a) => T (SV.Vector a) (MultiValue.T a) storableVector = Cons- (\ _ p -> liftA2 (,) (Storable.load p) (Storable.incrementPtr p))+ (\ _ (MultiValue.Cons p) ->+ liftA2 (,)+ (Storable.load p)+ (MultiValue.Cons <$> Storable.incrementPtr p)) return (\vec -> let (fp,ptr,_l) = SVU.unsafeToPointers vec@@ -174,24 +164,40 @@ -- keep the foreign ptr alive FPtr.touchForeignPtr + {-+This is intentionally restricted to NonNegW.Int aka StrictTimeShort,+since chunks must fit into memory.+If you have good reasons to allow other types,+see the versioning history for an according hack.+-}+instance+ (Marshal.C a, time ~ NonNegW.Int) =>+ Default (EventListBT.T time a) where+ type Element (EventListBT.T time a) = MultiValue.T a+ deflt = piecewiseConstant++{- I would like to re-use code from ConstantPiece here. Unfortunately, it is based on the LLVM-Maybe-Monad, but here we do not accept early exit. -} piecewiseConstant ::- (Storable.C a, Tuple.ValueOf a ~ value, Memory.C value) =>- T (EventListBT.T NonNegW.Int a) value+ (Marshal.C a) => T (EventListBT.T NonNegW.Int a) (MultiValue.T a) piecewiseConstant = expandConstantPieces $- rmap (uncurry Zip.Cons .- mapPair- (SV.pack .- map ((fromIntegral :: Int -> Word) . NonNegW.toNumber),- SV.pack) .- swap . unzip . EventListBT.toPairList) $- fmap (uncurry Const.Cons) $- split storableVector storableVector+ rmap+ (SV.pack .+ List.map+ (\(a,t) -> EE.Stored $ LLVM.Struct+ (fromIntegral $ NonNegW.toNumber t :: Word, (Marshal.pack a, ()))) .+ EventListBT.toPairList) $+ map+ (\(MultiValue.Cons s) -> do+ t <- LLVM.extractvalue s TypeNum.d0+ a <- LLVM.extractvalue s TypeNum.d1+ Const.Cons t . MultiValue.Cons <$> Memory.decompose a) $+ storableVector expandConstantPieces :: (Memory.C value) => T events (Const.T value) -> T events value@@ -204,9 +210,7 @@ next param s)) length2 <- A.dec length1 return (y1, (Const.Cons length2 y1, s1)))- (\param ->- fmap ((,) (Const.Cons Tuple.zero Tuple.undef)) $- start param)+ (\param -> (,) (Const.Cons Tuple.zero Tuple.undef) <$> start param) create delete @@ -215,33 +219,41 @@ in order to forbid writing to the array. -} controllerSet ::- (TypeNum.Natural n, Storable.C a,- LLVM.Storable a, Tuple.ValueOf a ~ LLVM.Value a, LLVM.IsSized a) =>- Proxy n -> T (PCS.T Int a) (LLVM.Value (LLVM.Array n a))+ (Marshal.C a, Marshal.Struct a ~ aStruct, LLVM.IsSized aStruct,+ TypeNum.Natural n,+ (n:*:LLVM.SizeOf aStruct) ~ arrSize, TypeNum.Natural arrSize) =>+ Proxy n -> T (PCS.T Int a) (MultiValue.T (MultiValue.Array n a)) controllerSet pn = controllerSetFromSV pn $- split storableVector $ split storableVector storableVector+ map+ (\(MultiValue.Cons s) -> do+ len <- LLVM.extractvalue s TypeNum.d0+ i <- LLVM.extractvalue s TypeNum.d1+ a <- Memory.decompose =<< LLVM.extractvalue s TypeNum.d2+ return (len,(i,a))) $+ storableVector controllerSetFromSV ::- (TypeNum.Natural n,- LLVM.Storable a, Tuple.ValueOf a ~ LLVM.Value a, LLVM.IsSized a) =>+ (Marshal.C a, Marshal.Struct a ~ aStruct, LLVM.IsSized aStruct,+ TypeNum.Natural n,+ (n:*:LLVM.SizeOf aStruct) ~ arrSize, TypeNum.Natural arrSize) => Proxy n ->- T (Zip.T (SV.Vector Word) (Zip.T (SV.Vector Word) (SV.Vector a)))- (LLVM.Value Word, (LLVM.Value Word, LLVM.Value a)) ->- T (PCS.T Int a) (LLVM.Value (LLVM.Array n a))+ T (SV.Vector (EE.Stored (Marshal.Struct (Word,Word,a))))+ (LLVM.Value Word, (LLVM.Value Word, MultiValue.T a)) ->+ T (PCS.T Int a) (MultiValue.T (MultiValue.Array n a)) controllerSetFromSV pn (Cons next start create delete) = Cons- (\((arrPtr, _), param) state0 -> do+ (MultiValue.uncurry $ \(MultiValue.Cons (arrPtr, _)) param state0 -> do (length2, s2) <- C.whileLoopShared state0 (\(len0, s0) -> (A.cmp LLVM.CmpEQ len0 Tuple.zero, do ((len1, (i,a)), s1) <- next param s0- LLVM.store a =<< LLVM.getElementPtr arrPtr (i, ())+ Memory.store a =<< LLVM.getElementPtr arrPtr (i, ()) return (len1, s1))) length3 <- A.dec length2- arr <- LLVM.load =<< LLVM.bitcast arrPtr+ arr <- Memory.load =<< LLVM.bitcast arrPtr return (arr, (length3, s2)))- (\((_, initialTime), param) -> do+ (MultiValue.uncurry $ \(MultiValue.Cons (_, initialTime)) param -> do state <- start param return (initialTime, state)) @@ -250,14 +262,14 @@ (\initialTime bt -> do (context, param) <- create- (uncurry Zip.Cons .- mapPair- (SV.pack,- uncurry Zip.Cons . mapPair (SV.pack, SV.pack). unzip) .- unzip .- map (\((i,a),len) ->- (fromIntegral len :: Word,- (fromIntegral i :: Word, a))) .+ (SV.pack .+ List.map+ (\((i,a),len) ->+ EE.Stored $+ Marshal.pack+ (fromIntegral len :: Word,+ fromIntegral i :: Word,+ a)) . EventListBT.toPairList $ bt) @@ -267,11 +279,12 @@ flip mapM_ (Map.toList $ PCS.initial pcs) $ \(i,a) -> if i >= n then error "Plug.Input.controllerSet: array too small"- else pokeElemOff arr i a+ else pokeElemOff arr i $ EE.Stored $ Marshal.pack a return ((arr, context),- ((LLVM.fromPtr arr, fromIntegral initialTime :: Word), param)))+ ((EE.castFromStoredPtr arr, fromIntegral initialTime :: Word),+ param))) {- It would be more elegant, if we could pass Arrays around just like Vectors.
src/Synthesizer/LLVM/Plug/Output.hs view
@@ -1,9 +1,6 @@-{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE Rank2Types #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE UndecidableInstances #-} module Synthesizer.LLVM.Plug.Output ( T(..), Default(..),@@ -13,14 +10,14 @@ import qualified Synthesizer.Zip as Zip -import qualified LLVM.Extra.Storable as Storable-import qualified LLVM.Extra.Marshal as Marshal+import qualified LLVM.Extra.Multi.Value.Storable as Storable+import qualified LLVM.Extra.Multi.Value.Marshal as Marshal+import qualified LLVM.Extra.Multi.Value as MultiValue import qualified LLVM.Extra.Memory as Memory-import qualified LLVM.Extra.Tuple as Tuple import qualified LLVM.Core as LLVM -import Control.Monad (liftM2)+import Control.Applicative (liftA2) import qualified Synthesizer.LLVM.Storable.Vector as SVU import qualified Data.StorableVector as SV@@ -30,76 +27,59 @@ import Data.Tuple.Strict (zipPair) -import NumericPrelude.Numeric-import NumericPrelude.Base hiding (and, iterate, map, zip, zipWith, take, takeWhile) - data T a b = forall state ioContext parameters. (Marshal.C parameters, Memory.C state) => Cons (forall r.- Tuple.ValueOf parameters ->- a -> state -> LLVM.CodeGenFunction r state)- -- compute next value- (forall r.- Tuple.ValueOf parameters ->- LLVM.CodeGenFunction r state)- -- initial state+ MultiValue.T parameters -> a -> state -> LLVM.CodeGenFunction r state)+ -- compute next value+ (forall r. MultiValue.T parameters -> LLVM.CodeGenFunction r state)+ -- initial state (Int -> IO (ioContext, parameters))- {- initialization from IO monad- This is called once per output chunk- with the number of input samples.- This number is also the maximum possible number of output samples.- This will be run within Unsafe.performIO,- so no observable In/Out actions please!- -}+ {- initialization from IO monad+ This is called once per output chunk+ with the number of input samples.+ This number is also the maximum possible number of output samples.+ This will be run within Unsafe.performIO,+ so no observable In/Out actions please!+ -} (Int -> ioContext -> IO b)- {-- finalization from IO monad, also run within Unsafe.performIO- The integer argument is the actually produced size of data.- We must clip the allocated output vectors accordingly.- -}+ {-+ finalization from IO monad, also run within Unsafe.performIO+ The integer argument is the actually produced size of data.+ We must clip the allocated output vectors accordingly.+ -} class Default b where- type Element b :: *+ type Element b deflt :: T (Element b) b + instance (Default c, Default d) => Default (Zip.T c d) where type Element (Zip.T c d) = (Element c, Element d) deflt = split deflt deflt -instance (Storable.C a) => Default (SV.Vector a) where- type Element (SV.Vector a) = Tuple.ValueOf a- deflt = storableVector-- split :: T a c -> T b d -> T (a,b) (Zip.T c d) split (Cons nextA startA createA deleteA) (Cons nextB startB createB deleteB) = Cons- (\(parameterA, parameterB) (a,b) (sa,sb) ->- liftM2 (,)- (nextA parameterA a sa)- (nextB parameterB b sb))- (\(parameterA, parameterB) ->- liftM2 (,)- (startA parameterA)- (startB parameterB))- (\len ->- liftM2 zipPair- (createA len)- (createB len))- (\len (ca,cb) ->- liftM2 Zip.Cons- (deleteA len ca)- (deleteB len cb))+ (MultiValue.uncurry $ \parameterA parameterB (a,b) (sa,sb) ->+ liftA2 (,) (nextA parameterA a sa) (nextB parameterB b sb))+ (MultiValue.uncurry $ \parameterA parameterB ->+ liftA2 (,) (startA parameterA) (startB parameterB))+ (\len -> liftA2 zipPair (createA len) (createB len))+ (\len (ca,cb) -> liftA2 Zip.Cons (deleteA len ca) (deleteB len cb)) -storableVector ::- (Storable.C a, Tuple.ValueOf a ~ value) => T value (SV.Vector a)+instance (Storable.C a) => Default (SV.Vector a) where+ type Element (SV.Vector a) = MultiValue.T a+ deflt = storableVector++storableVector :: (Storable.C a) => T (MultiValue.T a) (SV.Vector a) storableVector = Cons- (const Storable.storeNext)+ (\ _param -> MultiValue.liftM . Storable.storeNext) return (\len -> do vec <- SVB.create len (const $ return ())
+ src/Synthesizer/LLVM/Private.hs view
@@ -0,0 +1,26 @@+module Synthesizer.LLVM.Private where++import qualified LLVM.Extra.MaybeContinuation as MaybeCont+import qualified LLVM.Extra.Multi.Value as MultiValue++import qualified LLVM.Core as LLVM++import qualified Type.Data.Num.Decimal as TypeNum++import Control.Applicative (liftA2)+++unbool :: MultiValue.T Bool -> LLVM.Value Bool+unbool (MultiValue.Cons b) = b++noLocalPtr :: f -> (LLVM.Value (LLVM.Ptr (LLVM.Struct ())) -> f)+noLocalPtr = const++getPairPtrs ::+ LLVM.Value (LLVM.Ptr (LLVM.Struct (a, (b, ())))) ->+ MaybeCont.T r c (LLVM.Value (LLVM.Ptr a), LLVM.Value (LLVM.Ptr b))+getPairPtrs ptr =+ MaybeCont.lift $+ liftA2 (,)+ (LLVM.getElementPtr0 ptr (TypeNum.d0, ()))+ (LLVM.getElementPtr0 ptr (TypeNum.d1, ()))
+ src/Synthesizer/LLVM/Server/CausalPacked/Common.hs view
@@ -0,0 +1,37 @@+module Synthesizer.LLVM.Server.CausalPacked.Common where++import Synthesizer.LLVM.Server.Common (SampleRate(SampleRate), Real)++import qualified Synthesizer.LLVM.MIDI.BendModulation as BM++import qualified Data.EventList.Relative.TimeTime as EventListTT++import qualified Numeric.NonNegative.Class as NonNeg++import Prelude hiding (Real)+++-- ToDo: might be moved to event-list package+chopEvents ::+ (NonNeg.C time, Num time) =>+ time ->+ EventListTT.T time body ->+ [EventListTT.T time body]+chopEvents chunkSize =+ let go evs =+ -- splitBeforeTime?+ let (chunk,rest) = EventListTT.splitAtTime chunkSize evs+ in if EventListTT.duration chunk == 0+ then []+ else chunk : go rest+ in go+++transposeModulation ::+ (Functor stream) =>+ SampleRate Real ->+ Real ->+ stream (BM.T Real) ->+ stream (BM.T Real)+transposeModulation (SampleRate sampleRate) freq =+ fmap (BM.shift (freq/sampleRate))
src/Synthesizer/LLVM/Server/CausalPacked/Instrument.hs view
@@ -32,12 +32,12 @@ frequencyControl, zipEnvelope, ) where -import qualified Synthesizer.LLVM.Server.Parameter as ParamS import Synthesizer.LLVM.Server.Packed.Instrument (stereoNoise)+import Synthesizer.LLVM.Server.CausalPacked.Common (transposeModulation) import Synthesizer.LLVM.Server.CommonPacked-import Synthesizer.LLVM.Server.Common hiding (Instrument)-import Synthesizer.LLVM.Server.Parameter- (Number(Number), VectorTime(VectorTime), Signal(Signal))+import Synthesizer.LLVM.Server.Common hiding+ (Instrument, Frequency, Time, Control, transposeModulation)+import Synthesizer.LLVM.Server.Common (Arg(Frequency, Time)) import qualified Synthesizer.LLVM.Server.SampledSound as Sample import qualified Synthesizer.LLVM.Storable.Process as PSt@@ -45,31 +45,31 @@ import qualified Synthesizer.CausalIO.Gate as Gate import qualified Synthesizer.CausalIO.Process as PIO -import Synthesizer.LLVM.CausalParameterized.Process (($<))-import Synthesizer.LLVM.CausalParameterized.Functional (($&), (&|&)) import qualified Synthesizer.LLVM.Filter.Universal as UniFilter import qualified Synthesizer.LLVM.Filter.Allpass as Allpass import qualified Synthesizer.LLVM.Filter.Moog as Moog-import qualified Synthesizer.LLVM.Generator.Exponential2 as Exp+import qualified Synthesizer.LLVM.Causal.Exponential2 as Exp import qualified Synthesizer.LLVM.Frame.Stereo as Stereo import qualified Synthesizer.LLVM.Frame as Frame import qualified Synthesizer.LLVM.Frame.SerialVector as Serial-import qualified Synthesizer.LLVM.CausalParameterized.Helix as Helix-import qualified Synthesizer.LLVM.CausalParameterized.Functional as F-import qualified Synthesizer.LLVM.CausalParameterized.ControlledPacked as CtrlPS-import qualified Synthesizer.LLVM.CausalParameterized.ProcessPacked as CausalPS-import qualified Synthesizer.LLVM.CausalParameterized.ProcessValue as CausalPV-import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP-import qualified Synthesizer.LLVM.Parameterized.SignalPacked as SigPS-import qualified Synthesizer.LLVM.Parameterized.Signal as SigP+import qualified Synthesizer.LLVM.Causal.Helix as Helix+import qualified Synthesizer.LLVM.Causal.Functional as F+import qualified Synthesizer.LLVM.Causal.ControlledPacked as CtrlPS+import qualified Synthesizer.LLVM.Causal.Render as CausalRender+import qualified Synthesizer.LLVM.Causal.ProcessPacked as CausalPS+import qualified Synthesizer.LLVM.Causal.Process as Causal+import qualified Synthesizer.LLVM.Generator.SignalPacked as SigPS+import qualified Synthesizer.LLVM.Generator.Render as Render+import qualified Synthesizer.LLVM.Generator.Signal as Sig import qualified Synthesizer.LLVM.Interpolation as Interpolation import qualified Synthesizer.LLVM.Wave as WaveL-import qualified Synthesizer.LLVM.Simple.Value as Value-import Synthesizer.LLVM.Simple.Value ((%>), (%<=))+import Synthesizer.LLVM.Causal.Functional (($&), (&|&))+import Synthesizer.LLVM.Causal.Process (($<), ($>), ($<#)) import qualified Synthesizer.LLVM.MIDI.BendModulation as BM import qualified Synthesizer.LLVM.MIDI as MIDIL import qualified Synthesizer.PiecewiseConstant.Signal as PC+import qualified Synthesizer.Causal.Class as CausalClass import qualified Synthesizer.Generic.Cut as CutG import qualified Synthesizer.Zip as Zip import qualified Data.EventList.Relative.BodyTime as EventListBT@@ -78,24 +78,31 @@ import qualified Data.StorableVector.Lazy as SVL import qualified Data.StorableVector as SV -import qualified LLVM.DSL.Parameter as Param+import qualified LLVM.DSL.Expression as Expr+import LLVM.DSL.Expression (Exp, (<=*), (>*))++import qualified LLVM.Extra.Multi.Value as MultiValue+import qualified LLVM.Extra.Tuple as Tuple import qualified LLVM.Core as LLVM import qualified Type.Data.Num.Decimal as TypeNum +import qualified Control.Applicative.HT as App import qualified Control.Monad.HT as M import Control.Arrow (Arrow, arr, first, second, (&&&), (<<^), (^<<)) import Control.Category (id, (.))-import Control.Monad (liftM2, liftM3, liftM4, (<=<))-import Control.Applicative (pure, liftA2, liftA3)+import Control.Applicative (liftA2, liftA3, (<$>))+import Control.Functor.HT (unzip) import qualified Data.Traversable as Trav+import Data.Semigroup ((<>)) import Data.Monoid (mappend)+import Data.Tuple.HT (mapPair) import qualified Number.DimensionTerm as DN import NumericPrelude.Numeric-import NumericPrelude.Base hiding (id, (.))+import NumericPrelude.Base hiding (id, unzip, (.)) type Instrument a sig = SampleRate a -> MIO.Instrument a sig@@ -113,16 +120,24 @@ type PIOId a = PIO.T a a ++frequencyFromBendModulationPacked ::+ Exp Real ->+ F.T inp (MultiValue.T (BM.T Real)) ->+ F.T inp VectorValue+frequencyFromBendModulationPacked speed fm =+ MIDIL.frequencyFromBendModulationPacked speed $& (BM.unMultiValue <$> fm)+ stereoFrequenciesFromDetuneBendModulation ::- Param p Real ->- (FuncP p inp (LLVM.Value Real),- FuncP p inp (BM.T (LLVM.Value Real))) ->- FuncP p inp (Stereo.T VectorValue)+ Exp Real ->+ (F.T inp (MultiValue.T Real),+ F.T inp (MultiValue.T (BM.T Real))) ->+ F.T inp (Stereo.T VectorValue) stereoFrequenciesFromDetuneBendModulation speed (detune, freq) =- CausalP.envelopeStereo $&- (MIDIL.frequencyFromBendModulationPacked speed $& freq)+ Causal.envelopeStereo $&+ frequencyFromBendModulationPacked speed freq &|&- (CausalP.mapSimple (Trav.mapM Serial.upsample) $&+ (Causal.map (fmap Serial.upsample) $& liftA2 Stereo.cons (one + detune) (one - detune)) @@ -146,12 +161,9 @@ frequencyControl sr = fmap (flip DN.divToScalar $ frequencyFromSampleRate sr) -takeThreshold ::- Param.T p Real ->- CausalP.T p VectorValue VectorValue-takeThreshold =- CausalPV.takeWhile- (\threshold y -> threshold %<= Value.lift1 Serial.subsample y)+takeThreshold :: Exp Real -> Causal.T VectorValue VectorValue+takeThreshold threshold =+ Causal.takeWhile (\y -> threshold <=* Serial.subsample y) type EnvelopeControl =@@ -188,16 +200,16 @@ ping :: IO (Instrument Real Chunk) ping = fmap (\proc sampleRate vel freq ->- proc (sampleRate, (vel,freq))+ proc sampleRate vel freq . Gate.toStorableVector) $- CausalP.processIO $- let vel = number fst- freq = frequency snd- in CausalP.fromSignal $- SigP.envelope- (SigPS.exponential2 (timeConst 0.2) (fmap amplitudeFromVelocity vel)) $- SigPS.osciSimple WaveL.saw zero freq+ CausalRender.run $+ wrapped $ \(Number vel) (Frequency freq) ->+ constant time 0.2 $ \halfLife _sr ->+ Causal.fromSignal $+ SigPS.exponential2 halfLife (amplitudeFromVelocity vel)+ *+ SigPS.osci WaveL.saw zero freq pingReleaseEnvelope ::@@ -205,38 +217,40 @@ SampleRate Real -> Real -> PIO.T MIO.GateChunk Chunk) pingReleaseEnvelope =- liftM2+ liftA2 (\sustain release dec rel sr vel -> PSt.continuePacked- (sustain (sr,(dec,vel))+ (sustain sr dec vel . Gate.toChunkySize) (\y ->- release (sr,(rel,y))+ release sr rel y . Gate.allToChunkySize))- (CausalP.processIO $- ParamS.withTuple2 $ \(VectorTime decay, Number vel) ->- CausalP.fromSignal $- SigPS.exponential2 decay (fmap amplitudeFromVelocity vel))- (CausalP.processIO $- ParamS.withTuple2 $ \(ParamS.Time release, Number level) ->- CausalP.take (fmap round (vectorTime (const 1)))+ (CausalRender.run $+ wrapped $ \(Time decay) (Number vel) (SampleRate _sr) ->+ Causal.fromSignal $+ SigPS.exponential2+ -- FixMe: is division vectorSize correct?+ (decay / fromIntegral vectorSize) (amplitudeFromVelocity vel))+ (CausalRender.run $+ wrapped $ \(Time releaseHL) (Number level) ->+ constant time 1 $ \releaseTime _sr ->+ Causal.take+ (Expr.roundToIntFast $ releaseTime / fromIntegral vectorSize) .- CausalP.fromSignal (SigPS.exponential2 release level))+ Causal.fromSignal (SigPS.exponential2 releaseHL level)) pingRelease :: IO (Real -> Real -> Instrument Real Chunk) pingRelease =- liftM2+ liftA2 (\osci envelope dec rel sr vel freq ->- osci (sr, freq)+ osci sr freq . envelope dec rel sr vel)- (CausalP.processIO $- let freq = frequency id- in CausalP.envelope- .- CausalP.feedFst (SigPS.osciSimple WaveL.saw zero freq))+ (CausalRender.run $+ wrapped $ \(Frequency freq) (SampleRate _sr) ->+ Causal.envelope $> SigPS.osci WaveL.saw zero freq) pingReleaseEnvelope @@ -245,27 +259,27 @@ IO (SampleRate Real -> Real -> PIO.T EnvelopeControl Chunk) pingControlledEnvelope threshold =- liftM2+ liftA2 (\sustain release sr vel -> PSt.continuePacked- (sustain (sr,vel)+ (sustain sr vel . Gate.shorten . Zip.arrowSecond (arr (halfLifeControl sr . Zip.first))) (\y ->- release (sr,y)+ release sr y <<^ halfLifeControl sr . Zip.second . Zip.second))- (CausalP.processIO $- let vel = number id- in Exp.causalPackedP- (fmap amplitudeFromVelocity vel))- (CausalP.processIO $- let level = number id- expo = Exp.causalPackedP level+ (CausalRender.run $+ wrapped $ \(Number vel) (SampleRate _sr) ->+ Exp.causalPacked (amplitudeFromVelocity vel)+ <<^ Exp.unMultiValueParameterPacked)+ (CausalRender.run $+ wrapped $ \(Number level) (SampleRate _sr) ->+ let expo = Exp.causalPacked level <<^ Exp.unMultiValueParameterPacked in case threshold of- Just y -> takeThreshold (pure y) . expo+ Just y -> takeThreshold (Expr.cons y) . expo Nothing -> expo) @@ -282,7 +296,7 @@ pingStereoReleaseFM = liftA2 (\osc env sr vel freq ->- osc (sr, ())+ osc sr . Zip.arrowSecond (Zip.arrowSplit@@ -294,28 +308,33 @@ arr $ halfLifeControl sr))) . zipEnvelope (env sr vel))- (CausalP.processIO- (CausalP.envelopeStereo+ (CausalRender.run $+ constant frequency 10 $ \speed _sr ->+ (arr Stereo.multiValue .+ Causal.envelopeStereo+ . second (F.withArgs $ \((shape0,shapeDecay),((phase,phaseDecay),fm)) ->- let shape = CausalP.mapSimple Serial.upsample $& shape0+ let shape = Causal.map Serial.upsample $& shape0 shapeCtrl = 1/pi + (shape-1/pi) *- (Exp.causalPackedP (1::Param.T p Real) $& shapeDecay)- freqs =- stereoFrequenciesFromDetuneBendModulation- (frequencyConst 10) fm+ (Exp.causalPacked 1+ <<^ Exp.unMultiValueParameterPacked+ $& shapeDecay)+ freqs = stereoFrequenciesFromDetuneBendModulation speed fm expo =- (CausalP.mapSimple Serial.upsample $& phase) *- (Exp.causalPackedP (1::Param.T p Real) $& phaseDecay)+ (Causal.map Serial.upsample $& phase) *+ (Exp.causalPacked 1 <<^ Exp.unMultiValueParameterPacked+ $& phaseDecay) osci ::- CausalP.T p+ Causal.T (VectorValue, (VectorValue, VectorValue)) VectorValue osci = CausalPS.shapeModOsci WaveL.rationalApproxSine1 in liftA2 Stereo.cons (osci $& shapeCtrl &|& (expo &|& fmap Stereo.left freqs))- (osci $& shapeCtrl &|& (negate expo &|& fmap Stereo.right freqs)))))+ (osci $& shapeCtrl &|&+ (negate expo &|& fmap Stereo.right freqs))))) (pingControlledEnvelope (Just 0.01)) @@ -331,7 +350,7 @@ filterSawStereoFM = liftA2 (\osc env sr vel freq ->- osc (sr, ())+ osc sr . Zip.arrowSecond (Zip.arrowSplit@@ -342,33 +361,37 @@ arr $ transposeModulation sr freq)) . zipEnvelope (env sr vel))- (CausalP.processIO- (CausalP.envelopeStereo+ (CausalRender.run $+ constant frequency 10 $ \speed ->+ constant frequency 100 $ \lowerFreq _sr ->+ (arr Stereo.multiValue .+ Causal.envelopeStereo+ . second (F.withArgs $ \((cutoff,cutoffDecay),fm) ->- let freqs =- stereoFrequenciesFromDetuneBendModulation- (frequencyConst 10) fm+ let freqs = stereoFrequenciesFromDetuneBendModulation speed fm {- bound control in order to avoid too low resonant frequency, which makes the filter instable -} expo =- takeThreshold (frequencyConst 100) $&- (CausalP.mapSimple Serial.upsample $& cutoff) *- (Exp.causalPackedP (1::Param.T p Real) $& cutoffDecay)- in CausalP.stereoFromMonoControlled+ takeThreshold lowerFreq $&+ (Causal.map Serial.upsample $& cutoff) *+ (Exp.causalPacked 1 <<^ Exp.unMultiValueParameterPacked+ $& cutoffDecay)+ in Causal.stereoFromMonoControlled (UniFilter.lowpass ^<< CtrlPS.process) $&- (CausalP.quantizeLift (100 / fromIntegral vectorSize :: Param.T p Real)- (CausalP.mapSimple- (UniFilter.parameter (LLVM.valueOf 10)- <=<+ ((Causal.quantizeLift+ (Causal.map+ (UniFilter.parameter 10+ . Serial.subsample))+ $<# (100 / fromIntegral vectorSize :: Real)) $& expo) &|&- (CausalP.stereoFromMono- (CausalPS.osciSimple WaveL.saw $< zero) $&+ (Causal.stereoFromMono+ (CausalPS.osci WaveL.saw $< zero) $& freqs)))) (pingControlledEnvelope (Just 0.01)) @@ -383,38 +406,94 @@ tineStereoFM = liftA2 (\osc env sr vel freq ->- osc (sr, vel)+ osc sr vel . (Zip.arrowSecond $ Zip.arrowSecond $ Zip.arrowSecond $ arr $ transposeModulation sr freq) . zipEnvelope (env sr vel))- (CausalP.processIO- (CausalP.envelopeStereo+ (CausalRender.run $+ wrapped $ \(Number vel) ->+ constant frequency 5 $ \speed ->+ constant time 1 $ \halfLife _sr ->+ (arr Stereo.multiValue .+ Causal.envelopeStereo+ . second (F.withArgs $ \((index0,depth0), fm) ->- let vel = number id- freqs =- stereoFrequenciesFromDetuneBendModulation- (frequencyConst 5) fm- index = CausalP.mapSimple Serial.upsample $& index0- depth = CausalP.mapSimple Serial.upsample $& depth0- expo =- F.fromSignal $- SigPS.exponential2 (timeConst 1) (1 + vel)- osci freq =- CausalPS.osciSimple WaveL.approxSine2 $&- expo * depth *- (CausalPS.osciSimple WaveL.approxSine2- $& zero &|& index*freq)- &|&- freq- in Stereo.liftApplicative osci freqs)))+ let freqs = stereoFrequenciesFromDetuneBendModulation speed fm+ index = Causal.map Serial.upsample $& index0+ depth = Causal.map Serial.upsample $& depth0+ expo = F.fromSignal $ SigPS.exponential2 halfLife (1 + vel)+ osci indexDepth freq =+ case unzip indexDepth of+ (index1,depth1) ->+ CausalPS.osci WaveL.approxSine2 $&+ expo * depth1 *+ (CausalPS.osci WaveL.approxSine2+ $& zero &|& index1*freq)+ &|&+ freq+ in stereoFromMonoControlled osci (index&|&depth) freqs))) (pingControlledEnvelope (Just 0.01)) +{- |+'Stereo.liftApplicative' specialised to 'T'. +Should be moved to Functional utility module.+(Functional module itself would cause cyclic dependency.)+-}+stereoFromMonoControlled,+ _stereoFromMonoControlledArgs,+ _stereoFromMonoControlledGrounded,+ _stereoFromMonoControlledGuided,+ _stereoFromMonoControlledPrepared,+ _stereoFromMonoControlledPrepared2 ::+ (Tuple.Phi a, Tuple.Phi b, Tuple.Phi c) =>+ (Tuple.Undefined a, Tuple.Undefined b, Tuple.Undefined c) =>+ (forall inp0. F.T inp0 c -> F.T inp0 a -> F.T inp0 b) ->+ F.T inp c -> F.T inp (Stereo.T a) -> F.T inp (Stereo.T b)+stereoFromMonoControlled proc ctrl stereo =+ Causal.stereoFromMonoControlled+ (F.compile $ uncurry proc $ unzip $ F.lift id)+ $&+ ctrl &|& stereo++_stereoFromMonoControlledArgs proc ctrl stereo =+ Causal.stereoFromMonoControlled+ (F.withArgs (uncurry proc) <<^ mapPair (F.AnyArg, F.AnyArg))+ $&+ ctrl &|& stereo++_stereoFromMonoControlledGrounded proc ctrl stereo =+ Causal.stereoFromMonoControlled+ (F.withGroundArgs $ \(F.Ground c, F.Ground s) -> proc c s)+ $&+ ctrl &|& stereo++_stereoFromMonoControlledGuided proc ctrl stereo =+ Causal.stereoFromMonoControlled+ (F.withGuidedArgs (F.atom, F.atom) (uncurry proc))+ $&+ ctrl &|& stereo++_stereoFromMonoControlledPrepared proc ctrl stereo =+ Causal.stereoFromMonoControlled+ (F.withPreparedArgs (F.pairArgs F.atomArg F.atomArg) (uncurry proc))+ $&+ ctrl &|& stereo++_stereoFromMonoControlledPrepared2 proc ctrl stereo =+ Causal.stereoFromMonoControlled+ (F.withPreparedArgs2 F.atomArg F.atomArg proc)+ $&+ ctrl &|& stereo+++type RealValue = MultiValue.T Real+ bellNoiseStereoFM :: IO (SampleRate Real -> Real -> Real -> PIO.T@@ -426,7 +505,7 @@ bellNoiseStereoFM = liftA3 (\osc env envInf sr vel freq ->- osc (sr, ())+ osc sr . (Zip.arrowSecond $ Zip.arrowSecond $ Zip.arrowSecond $@@ -450,36 +529,40 @@ (envInf sr (vel*4) . Zip.arrowSecond (shortenTimes 7)))))- (CausalP.processIO+ (CausalRender.run $+ constant noiseReference 20000 $ \noiseRef ->+ constant frequency 5 $ \speed _sr -> (F.withArgs $ \((env1,(env4,env7)),((noiseAmp0,noiseReson),fm)) ->- let noiseAmp = CausalP.mapSimple Serial.upsample $& noiseAmp0+ let noiseAmp = Causal.map Serial.upsample $& noiseAmp0+ noiseParam ::+ Causal.T+ (RealValue, RealValue)+ (Moog.Parameter TypeNum.D8 RealValue) noiseParam =- CausalP.quantizeLift- (100 / fromIntegral vectorSize :: Param.T p Real)- (CausalP.zipWithSimple (Moog.parameter TypeNum.d8))- noise =- F.fromSignal (SigPS.noise 12 (noiseReference 20000))- freqs =- stereoFrequenciesFromDetuneBendModulation- (frequencyConst 5) fm+ Causal.quantizeLift+ (Causal.zipWith (Moog.parameter TypeNum.d8))+ $<# (100 / fromIntegral vectorSize :: Real)+ noise = F.fromSignal (SigPS.noise 12 noiseRef)+ freqs = stereoFrequenciesFromDetuneBendModulation speed fm osci amp env n = CausalPS.amplifyStereo amp $&- CausalP.envelopeStereo $&+ Causal.envelopeStereo $& env &|&- (CausalP.stereoFromMono- (CausalPS.osciSimple WaveL.approxSine4 $< zero)+ (Causal.stereoFromMono+ (CausalPS.osci WaveL.approxSine4 $< zero) $& CausalPS.amplifyStereo n $& freqs)- in (CausalP.envelopeStereo $&+ in Stereo.multiValue <$>+ (Causal.envelopeStereo $& (noiseAmp * env1) &|& Stereo.liftApplicative (\freq -> CtrlPS.process $& (noiseParam $& noiseReson &|&- (CausalP.mapSimple Serial.subsample $& freq))+ (Causal.map Serial.subsample $& freq)) &|& noise) freqs)@@ -495,55 +578,54 @@ IO (SampleRate Real -> Real -> PIO.T EnvelopeControl Chunk) stringControlledEnvelope =- liftM3+ liftA3 (\attack sustain release sr vel -> let amp = amplitudeFromVelocity vel in PSt.continuePacked- (mappend- (attack (sr,amp))- {- we could also feed the sustain process- with a signal with sample type () -}- (sustain (sr,amp))+ ((attack sr amp <>+ {- we could also feed the sustain process+ with a signal with sample type () -}+ sustain sr amp) . Gate.shorten . Zip.arrowSecond (arr (halfLifeControl sr . Zip.first))) (\y ->- release (sr,y)+ release sr y <<^ halfLifeControl sr . Zip.second . Zip.second))- (CausalP.processIO $- let amp = number id- in CausalP.fromSignal (SigPS.constant amp)+ (CausalRender.run $+ wrapped $ \(Number amp) (SampleRate _sr) ->+ Causal.fromSignal (SigPS.constant amp) -- takeThreshold (1e-4 :: Param.T p Real)+ takeThreshold 1e-4 .- Exp.causalPackedP amp)- (CausalP.processIO $- let amp = number id- in CausalP.fromSignal (SigPS.constant amp))- (CausalP.processIO $- let level = number id- in takeThreshold (0.01 :: Param.T p Real)+ Exp.causalPacked amp <<^ Exp.unMultiValueParameterPacked)+ (CausalRender.run $+ wrapped $ \(Number amp) (SampleRate _sr) ->+ Causal.fromSignal (SigPS.constant amp))+ (CausalRender.run $+ wrapped $ \(Number level) (SampleRate _sr) ->+ takeThreshold 0.01 .- Exp.causalPackedP level)+ Exp.causalPacked level <<^ Exp.unMultiValueParameterPacked) windCore ::- F.T (SampleRate Real, p) a (LLVM.Value Real) ->- F.T (SampleRate Real, p) a (BM.T (LLVM.Value Real)) ->- F.T (SampleRate Real, p) a (Stereo.T VectorValue)+ F.T a (MultiValue.T Real) ->+ F.T a (MultiValue.T (BM.T Real)) ->+ SampleRate (Exp Real) ->+ F.T a (Stereo.T VectorValue) windCore reson fm =+ constant frequency 0.2 $ \speed sr -> let modu =- CausalP.mapSimple Serial.subsample $&+ Causal.map Serial.subsample $& (fmap (`asTypeOf` (undefined :: VectorValue)) $- (MIDIL.frequencyFromBendModulationPacked- (frequencyConst 0.2) $& fm))- in CausalP.stereoFromMonoControlled CtrlPS.process $&- (CausalP.zipWithSimple (Moog.parameter TypeNum.d8) $&- reson &|& modu)+ frequencyFromBendModulationPacked speed fm)+ in Causal.stereoFromMonoControlled CtrlPS.process $&+ (Causal.zipWith (Moog.parameter TypeNum.d8) $& reson &|& modu) &|&- F.fromSignal stereoNoise+ F.fromSignal (stereoNoise sr) wind :: IO (SampleRate Real -> Real -> Real ->@@ -553,17 +635,16 @@ wind = liftA2 (\osc env sr vel freq ->- osc (sr, ())+ osc sr . (Zip.arrowSecond $ Zip.arrowSecond $ arr $ transposeModulation sr freq) . zipEnvelope (env sr vel))- (CausalP.processIO- (F.withArgs $ \(env,(reson,fm)) ->- CausalP.envelopeStereo $&- env &|&- windCore reson fm))+ (CausalRender.run $ \sr ->+ F.withArgs $ \(env,(reson,fm)) ->+ Stereo.multiValue <$>+ Causal.envelopeStereo $& env &|& windCore reson fm sr) stringControlledEnvelope @@ -577,35 +658,37 @@ windPhaser = liftA2 (\osc env sr vel freq ->- osc (sr, ())+ osc sr . (Zip.arrowSecond $ Zip.arrowSecond $ Zip.arrowSplit- (arr $ fmap (Allpass.flangerParameterPlain TypeNum.d8) .+ (arr $ fmap (Allpass.flangerParameter TypeNum.d8) . frequencyControl sr) (Zip.arrowSecond $ arr $ transposeModulation sr freq)) . zipEnvelope (env sr vel))- (CausalP.processIO+ (CausalRender.run $ \sr -> (F.withArgs $ \(env,(phaserMix0,(phaserFreq,(reson,fm)))) ->- let phaserMix = CausalP.mapSimple Serial.upsample $& phaserMix0- noise = windCore reson fm+ let phaserMix = Causal.map Serial.upsample $& phaserMix0+ noise = windCore reson fm sr - in CausalP.envelopeStereo $&+ in Stereo.multiValue <$>+ Causal.envelopeStereo $& env &|&- ((CausalP.envelopeStereo $& (1 - phaserMix) &|& noise)+ ((Causal.envelopeStereo $& (1 - phaserMix) &|& noise) +- (CausalP.envelopeStereo $&+ (Causal.envelopeStereo $& phaserMix &|& (Stereo.arrowFromMonoControlled CtrlPS.process $&- phaserFreq &|& noise)))))+ (Allpass.cascadeParameterUnMultiValue <$> phaserFreq)+ &|& noise))))) stringControlledEnvelope phaserOsci ::- (Param.T p Real -> Param.T p Real -> CausalP.T p a VectorValue) ->- CausalP.T p a (Stereo.T VectorValue)+ (Exp Real -> Exp Real -> Causal.T a VectorValue) ->+ Causal.T a (Stereo.T VectorValue) phaserOsci osci = CausalPS.amplifyStereo 0.25 .@@ -632,27 +715,28 @@ softStringShapeCore wave = liftA2 (\osc env sr vel freq ->- osc (sr, ())+ osc sr . (Zip.arrowSecond $ Zip.arrowSecond $ Zip.arrowSecond $ arr $ transposeModulation sr freq) . zipEnvelope (env sr vel))- (CausalP.processIO- (CausalP.envelopeStereo+ (CausalRender.run $+ constant frequency 5 $ \speed _sr ->+ (arr Stereo.multiValue .+ Causal.envelopeStereo+ . second (F.withArgs $ \(shape0,(det0,fm)) ->- let det = CausalP.mapSimple Serial.upsample $& det0- shape = CausalP.mapSimple Serial.upsample $& shape0- modu =- MIDIL.frequencyFromBendModulationPacked- (frequencyConst 5) $& fm+ let det = Causal.map Serial.upsample $& det0+ shape = Causal.map Serial.upsample $& shape0+ modu = frequencyFromBendModulationPacked speed fm osci ::- Param.T (mod,fm) Real ->- Param.T (mod,fm) Real ->- CausalP.T (mod,fm)+ Exp Real ->+ Exp Real ->+ Causal.T (VectorValue, {- wave shape parameter -} (VectorValue, VectorValue)@@ -662,9 +746,9 @@ CausalPS.shapeModOsci wave . second- (CausalP.feedFst (SigPS.constant p)+ (CausalClass.feedFst (SigPS.constant p) .- CausalP.envelope+ Causal.envelope . first (one + CausalPS.amplify d)) @@ -709,51 +793,51 @@ fmStringStereoFM = liftA2 (\osc env sr vel freq ->- osc (sr, ())+ osc sr . (Zip.arrowSecond $ Zip.arrowSecond $ Zip.arrowSecond $ arr $ transposeModulation sr freq) . zipEnvelope (env sr vel))- (CausalP.processIO+ (CausalRender.run $+ constant frequency 5 $ \speed _sr -> (F.withArgs $ \(env,((depth0,shape0),(det0,fm))) ->- let det = CausalP.mapSimple Serial.upsample $& det0- shape = CausalP.mapSimple Serial.upsample $& shape0+ let det = Causal.map Serial.upsample $& det0+ shape = Causal.map Serial.upsample $& shape0 depth =- CausalP.envelope $&+ Causal.envelope $& env &|&- (CausalP.mapSimple Serial.upsample $& depth0)- modu =- MIDIL.frequencyFromBendModulationPacked- (frequencyConst 5) $& fm+ (Causal.map Serial.upsample $& depth0)+ modu = frequencyFromBendModulationPacked speed fm osci ::- Param.T (mod,fm) Real ->- Param.T (mod,fm) Real ->- CausalP.T (mod,fm)+ Exp Real ->+ Exp Real ->+ Causal.T ((VectorValue, VectorValue) {- phase modulation depth, modulator distortion -}, (VectorValue, VectorValue) {- detune, frequency modulation -}) VectorValue osci p d =- CausalPS.osciSimple WaveL.approxSine2+ CausalPS.osci WaveL.approxSine2 .- ((CausalP.envelope+ ((Causal.envelope . second (CausalPS.shapeModOsci WaveL.rationalApproxSine1- . second (CausalP.feedFst (SigPS.constant p)))+ . second (CausalClass.feedFst (SigPS.constant p))) <<^ (\((dp, ds), f) -> (dp, (ds, f)))) &&& arr snd) . second- (CausalP.envelope .+ (Causal.envelope . first (one + CausalPS.amplify d)) - in CausalP.envelopeStereo $&+ in Stereo.multiValue <$>+ Causal.envelopeStereo $& env &|& (phaserOsci osci $& (depth &|& shape) &|& (det &|& modu)))) stringControlledEnvelope@@ -775,13 +859,20 @@ Zip.arrowSecond ((id :: PIOId StereoChunk) .- freqMod (sr, ())+ freqMod sr . (Zip.arrowSecond $ arr $ transposeModulation sr (freq * Sample.period pos))))- (CausalP.processIO (CausalP.stereoFromMono resamplingProc))- (CausalP.processIO- (F.withArgs $ stereoFrequenciesFromDetuneBendModulation (frequencyConst 3)))+ (CausalRender.run $ \sr (amp, smp) ->+ Stereo.multiValue+ ^<<+ Causal.stereoFromMono (resamplingProc sr (amp, smp))+ <<^+ Stereo.unMultiValue)+ (CausalRender.run $+ constant frequency 3 $ \speed _sr ->+ fmap Stereo.multiValue $+ F.withArgs $ stereoFrequenciesFromDetuneBendModulation speed) {- |@@ -800,12 +891,13 @@ Zip.arrowSecond ((id :: PIOId Chunk) .- freqMod (sr, ())+ freqMod sr . (arr $ transposeModulation sr (freq * Sample.period pos))))- (CausalP.processIO resamplingProc)- (CausalP.processIO- (MIDIL.frequencyFromBendModulationPacked (frequencyConst 3)))+ (CausalRender.run resamplingProc)+ (CausalRender.run $+ constant frequency 3 $ \speed _sr ->+ F.withArgs $ frequencyFromBendModulationPacked speed) {- We split the frequency modulation signal@@ -815,14 +907,14 @@ -} assembleParts :: (CutG.Transform a, CutG.Transform b) =>- ((SampleRate Real, (Real, SVL.Vector Real)) -> PIO.T a b) ->+ (SampleRate Real -> (Real, SVL.Vector Real) -> PIO.T a b) -> Sample.T -> SampleRate Real -> Real -> PIO.T (Zip.T (Gate.Chunk gate) a) b assembleParts osc smp sr vel = let pos = Sample.positions smp amp = 2 * amplitudeFromVelocity vel (attack, sustain, release) = Sample.parts smp- osci smpBody = osc (sr, (amp, smpBody))+ osci smpBody = osc sr (amp, smpBody) in mappend (osci (attack `SigSt.append`@@ -832,22 +924,20 @@ (osci release <<^ Zip.second) resamplingProc ::- CausalP.T- (SampleRate Real, (Real, SigSt.T Real))- VectorValue VectorValue-resamplingProc =- let amp = number fst- smp = signal snd- in CausalPS.amplify amp+ SampleRate (Exp Real) ->+ (Exp Real, Sig.T (MultiValue.T Real)) ->+ Causal.T VectorValue VectorValue+resamplingProc _sr (amp, smp) =+ CausalPS.amplify amp . CausalPS.pack- (CausalP.frequencyModulationLinear+ (Causal.frequencyModulationLinear {-- (SigP.fromStorableVector $+ (Sig.fromStorableVector $ fmap (SV.concat . SVL.chunks . SVL.take 1000000) smp) -}- (SigP.fromStorableVectorLazy smp)- {- (SigP.osciSimple WaveL.saw 0 (1 / 324 {- samplePeriod smp -})) -})+ smp+ {- (Sig.osci WaveL.saw 0 (1 / 324 {- samplePeriod smp -})) -}) helixSound :: IO (Sample.T ->@@ -857,7 +947,7 @@ (Zip.T (Control Real) DetuneBendModControl)) StereoChunk) helixSound =- liftM4+ App.lift4 (\helix zigZag integrate freqMod smp sr vel freq -> let pos = Sample.positions smp amp = 2 * amplitudeFromVelocity vel@@ -875,16 +965,17 @@ (fromIntegral $ Sample.start pos, fromIntegral $ Sample.loopStart pos, fromIntegral $ Sample.loopLength pos)- in helix (sr, ((amp, Sample.period pos), Sample.body smp))+ in helix sr amp (Sample.period pos)+ (Render.buffer $ SV.concat $ SVL.chunks $ Sample.body smp) . Zip.arrowFirstShorten (mappend- (zigZag (sr, poss) . Gate.shorten)- (integrate (sr, (releaseStart, releaseStop))+ (zigZag sr poss . Gate.shorten)+ (integrate sr (releaseStart, releaseStop) <<^ Zip.second)) . Zip.arrowSecond- (freqMod (sr, ())+ (freqMod sr . (Zip.arrowSecond $ arr $ transposeModulation sr freq)) .@@ -893,52 +984,56 @@ makeHelix makeZigZag makeIntegrate- (CausalP.processIO- (F.withArgs $ stereoFrequenciesFromDetuneBendModulation (frequencyConst 3)))+ (CausalRender.run $+ constant frequency 3 $ \speed _sr ->+ fmap Stereo.multiValue $+ F.withArgs $ stereoFrequenciesFromDetuneBendModulation speed) makeHelix ::- IO ((SampleRate Real, ((Real, Real), SigSt.T Real)) ->+ IO (SampleRate Real -> Real -> Real -> Render.Buffer Real -> PIO.T (Zip.T Chunk StereoChunk) StereoChunk) makeHelix =- CausalP.processIO $- ParamS.withTuple2 $- \((Number amp, Number per), Signal smp) ->+ CausalRender.run $+ wrapped $+ \(Number amp) (Number per) (SampleRate _sr) smp ->+ arr Stereo.multiValue+ . CausalPS.amplifyStereo amp .- CausalP.stereoFromMono+ Causal.stereoFromMono (Helix.staticPacked Interpolation.linear Interpolation.linear- (fmap round per) per- (fmap (SV.concat . SVL.chunks) smp)+ (Expr.roundToIntFast per) per+ smp . second (CausalPS.osciCore $< 0)) .- arr (\(shape, freq) -> fmap ((,) shape) freq)+ arr (\(shape, freq) -> (,) shape <$> Stereo.unMultiValue freq) makeZigZag ::- IO ((SampleRate Real, (Real, Real, Real)) ->+ IO (SampleRate Real -> (Real, Real, Real) -> PIO.T (Control Real) Chunk) makeZigZag =- CausalP.processIO $- ParamS.withTuple2 $- \(Number start, Number loopStart, Number loopLength) ->+ CausalRender.run $+ wrapped $+ \(Number start, Number loopStart, Number loopLength) (SampleRate _sr) -> CausalPS.raise start . -- CausalPS.pack (Helix.zigZagLong (loopStart-start) loopLength) Helix.zigZagLongPacked (loopStart-start) loopLength .- CausalP.mapSimple Serial.upsample+ Causal.map Serial.upsample makeIntegrate ::- IO ((SampleRate Real, (Real, Real)) ->+ IO (SampleRate Real -> (Real, Real) -> PIO.T (Control Real) Chunk) makeIntegrate =- CausalP.processIO $- ParamS.withTuple2 $- \(Number start, Number stop) ->- CausalPV.takeWhile (\s v -> s %> Value.lift1 Serial.subsample v) stop+ CausalRender.run $+ wrapped $+ \(Number start, Number stop) (SampleRate _sr) ->+ Causal.takeWhile (\v -> stop >* Serial.subsample v) . CausalPS.integrate start .- CausalP.mapSimple Serial.upsample+ Causal.map Serial.upsample
src/Synthesizer/LLVM/Server/CausalPacked/InstrumentPlug.hs view
@@ -4,7 +4,7 @@ The Instruments in this module have the same causal arrow interface as the ones in "Synthesizer.LLVM.Server.CausalPacked.Instrument", but here we use the higher level interface-of the "Synthesizer.LLVM.CausalParameterized.FunctionalPlug" module.+of the "Synthesizer.LLVM.Causal.FunctionalPlug" module. -} module Synthesizer.LLVM.Server.CausalPacked.InstrumentPlug ( tineStereoFM,@@ -17,55 +17,54 @@ pingControlledEnvelope, stringControlledEnvelope, reorderEnvelopeControl)-import Synthesizer.LLVM.Server.CommonPacked (- Param, VectorValue)+import Synthesizer.LLVM.Server.CausalPacked.Common (transposeModulation)+import Synthesizer.LLVM.Server.CommonPacked (VectorValue) import Synthesizer.LLVM.Server.Common (- SampleRate, Real,- frequencyConst, timeConst,- number, transposeModulation)+ SampleRate, expSampleRate, Real,+ Arg(Number), wrapped,+ constant, frequency, time) import qualified Synthesizer.CausalIO.Process as PIO -import Synthesizer.LLVM.CausalParameterized.FunctionalPlug (($&), (&|&)) import qualified Synthesizer.LLVM.Frame.Stereo as Stereo import qualified Synthesizer.LLVM.Frame.SerialVector as Serial-import qualified Synthesizer.LLVM.CausalParameterized.Helix as Helix-import qualified Synthesizer.LLVM.CausalParameterized.FunctionalPlug as FP-import qualified Synthesizer.LLVM.CausalParameterized.ProcessPacked as CausalPS-import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP-import qualified Synthesizer.LLVM.Parameterized.SignalPacked as SigPS-import qualified Synthesizer.LLVM.Parameterized.Signal as SigP+import qualified Synthesizer.LLVM.Causal.Helix as Helix+import qualified Synthesizer.LLVM.Causal.FunctionalPlug as FP+import qualified Synthesizer.LLVM.Causal.ProcessPacked as CausalPS+import qualified Synthesizer.LLVM.Causal.Process as Causal+import qualified Synthesizer.LLVM.Generator.SignalPacked as SigPS+import qualified Synthesizer.LLVM.Generator.Signal as Sig import qualified Synthesizer.LLVM.Interpolation as Interpolation import qualified Synthesizer.LLVM.Wave as WaveL+import Synthesizer.LLVM.Causal.FunctionalPlug (($&), (&|&)) import qualified Synthesizer.LLVM.MIDI.BendModulation as BM import qualified Synthesizer.LLVM.MIDI as MIDIL import qualified Synthesizer.Zip as Zip -import qualified LLVM.DSL.Parameter as Param-import qualified LLVM.Core as LLVM+import qualified LLVM.DSL.Expression as Expr+import LLVM.DSL.Expression (Exp) -import qualified Data.Traversable as Trav-import Control.Category (id, (.))-import Control.Applicative (liftA2)+import qualified LLVM.Extra.Multi.Value as MultiValue +import Control.Category ((.))+import Control.Applicative (liftA2, (<$>))+ import NumericPrelude.Numeric import NumericPrelude.Base hiding (id, (.)) -type FuncP pp pl = FP.T pp (SampleRate Real, pl)-- stereoFrequenciesFromDetuneBendModulation ::- Param pl Real ->- (FuncP pp pl inp (LLVM.Value Real),- FuncP pp pl inp (BM.T (LLVM.Value Real))) ->- FuncP pp pl inp (Stereo.T VectorValue)+ Exp Real ->+ (FP.T p inp (MultiValue.T Real),+ FP.T p inp (MultiValue.T (BM.T Real))) ->+ FP.T p inp (Stereo.T VectorValue) stereoFrequenciesFromDetuneBendModulation speed (detune, freq) =- CausalP.envelopeStereo $&- (MIDIL.frequencyFromBendModulationPacked speed $& freq)+ Causal.envelopeStereo $&+ (MIDIL.frequencyFromBendModulationPacked speed $&+ (BM.unMultiValue <$> freq)) &|&- (CausalP.mapSimple (Trav.mapM Serial.upsample) $&+ (Causal.map (fmap Serial.upsample) $& liftA2 Stereo.cons (one + detune) (one - detune)) tineStereoFM ::@@ -84,27 +83,30 @@ Zip.arrowFirstShorten (env sr vel) . reorderEnvelopeControl)- (FP.withArgs $ \(env, ((index0,depth0), (detune,fm))) ->- let vel = number id- freqs =+ (FP.withArgs $ \(env, ((index0,depth0), (detune,fm))) pl ->+ (\f -> case Expr.unzip pl of (sr,vel) -> f (expSampleRate sr) vel) $+ wrapped $ \(Number vel) ->+ constant time 1 $ \halfLife ->+ constant frequency 5 $ \speed _sr ->+ let freqs = stereoFrequenciesFromDetuneBendModulation- (frequencyConst 5)+ speed (FP.plug detune,- FP.plug $ liftA2 (uncurry transposeModulation) FP.askParameter fm)- index = CausalP.mapSimple Serial.upsample $& FP.plug index0- depth = CausalP.mapSimple Serial.upsample $& FP.plug depth0- expo =- FP.fromSignal $- SigPS.exponential2 (timeConst 1) (1 + vel)+ FP.plug $+ liftA2 (uncurry transposeModulation) FP.askParameter fm)+ index = Causal.map Serial.upsample $& FP.plug index0+ depth = Causal.map Serial.upsample $& FP.plug depth0+ expo = FP.fromSignal $ SigPS.exponential2 halfLife (1 + vel) osci freq =- CausalPS.osciSimple WaveL.approxSine2 $&+ CausalPS.osci WaveL.approxSine2 $& expo * depth *- (CausalPS.osciSimple WaveL.approxSine2+ (CausalPS.osci WaveL.approxSine2 $& zero &|& index*freq) &|& freq- in CausalP.envelopeStereo $&- FP.plug env &|& Stereo.liftApplicative osci freqs)+ in fmap Stereo.multiValue $+ Causal.envelopeStereo $&+ FP.plug env &|& Stereo.liftApplicative osci freqs) (pingControlledEnvelope (Just 0.01)) @@ -117,30 +119,34 @@ helixNoise = liftA2 (\osc env sr vel freq ->- osc (sr, freq) (sr, vel)+ osc (sr, freq) sr . Zip.arrowFirstShorten (env sr vel) . reorderEnvelopeControl)- (FP.withArgs $ \(env, (speed0, (detune,fm))) ->+ (FP.withArgs $ \(env, (speed0, (detune,fm))) sr ->+ (\f -> f (expSampleRate sr)) $+ constant frequency 5 $ \modSpeed _sr -> let freqs = stereoFrequenciesFromDetuneBendModulation- (frequencyConst 5)+ modSpeed (FP.plug detune,- FP.plug $ liftA2 (uncurry transposeModulation) FP.askParameter fm)- speed = CausalP.mapSimple Serial.upsample $& FP.plug speed0- in CausalP.envelopeStereo $&- FP.plug env &|& Stereo.liftApplicative (helixOsci speed) freqs)+ FP.plug $+ liftA2 (uncurry transposeModulation) FP.askParameter fm)+ speed = Causal.map Serial.upsample $& FP.plug speed0+ in fmap Stereo.multiValue $+ Causal.envelopeStereo $&+ FP.plug env &|& Stereo.liftApplicative (helixOsci speed) freqs) stringControlledEnvelope helixOsci ::- FP.T pp pl inp VectorValue ->- FP.T pp pl inp VectorValue ->- FP.T pp pl inp VectorValue+ FP.T pp inp VectorValue ->+ FP.T pp inp VectorValue ->+ FP.T pp inp VectorValue helixOsci speed freq = CausalPS.pack (Helix.dynamicLimited Interpolation.cubic Interpolation.cubic- 64 (64 :: Param.T p Real) (SigP.noise 66 0.2))+ 64 (64 :: Exp Real) (Sig.noise 66 0.2)) $& speed &|& (CausalPS.osciCore $& 0 &|& freq)
src/Synthesizer/LLVM/Server/CausalPacked/Speech.hs view
@@ -22,25 +22,29 @@ (StereoChunk, Control, Frequency, frequencyControl, WithEnvelopeControl, zipEnvelope, stringControlledEnvelope, pingControlledEnvelope)-import Synthesizer.LLVM.Server.CommonPacked (VectorValue)+import Synthesizer.LLVM.Server.CommonPacked (Vector) import Synthesizer.LLVM.Server.Common- (SampleRate(SampleRate), Real, parameter, noiseReference, frequency)+ (SampleRate(SampleRate), Real, wrapped,+ Arg(Frequency), constant, noiseReference) import qualified Synthesizer.LLVM.Server.SampledSound as Sample import qualified Synthesizer.MIDI.CausalIO.Process as MIO import qualified Synthesizer.CausalIO.Gate as Gate import qualified Synthesizer.CausalIO.Process as PIO -import Synthesizer.LLVM.CausalParameterized.Process (($<), ($>), ($*))-import Synthesizer.LLVM.CausalParameterized.FunctionalPlug (($&), (&|&)) import qualified Synthesizer.LLVM.Frame.Stereo as Stereo import qualified Synthesizer.LLVM.Frame.SerialVector as Serial+import qualified Synthesizer.LLVM.Filter.Universal as UniFilterL import qualified Synthesizer.LLVM.Filter.NonRecursive as FiltNR-import qualified Synthesizer.LLVM.CausalParameterized.FunctionalPlug as FP-import qualified Synthesizer.LLVM.CausalParameterized.ControlledPacked as CtrlPS-import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP-import qualified Synthesizer.LLVM.Parameterized.SignalPacked as SigPS-import qualified Synthesizer.LLVM.Parameterized.Signal as SigP+import qualified Synthesizer.LLVM.Causal.FunctionalPlug as FP+import qualified Synthesizer.LLVM.Causal.ControlledPacked as CtrlPS+import qualified Synthesizer.LLVM.Causal.Render as CausalRender+import qualified Synthesizer.LLVM.Causal.Process as Causal+import qualified Synthesizer.LLVM.Generator.SignalPacked as SigPS+import qualified Synthesizer.LLVM.Generator.Render as Render+import qualified Synthesizer.LLVM.Generator.Signal as Sig+import Synthesizer.LLVM.Causal.FunctionalPlug (($&), (&|&))+import Synthesizer.LLVM.Causal.Process (($*), ($<), ($>)) import qualified Synthesizer.Zip as Zip import qualified Sound.MIDI.Message.Channel.Voice as VoiceMsg@@ -57,12 +61,12 @@ import qualified Data.StorableVector as SV import qualified Data.Map as Map ; import Data.Map (Map) -import qualified LLVM.Core as LLVM+import qualified LLVM.Extra.Multi.Value as MultiValue import qualified System.Path as Path import System.Path ((</>), (<.>)) -import Control.Arrow (arr, second, (^<<), (***))+import Control.Arrow (arr, second, (^<<), (<<^), (***)) import Control.Category ((.)) import Control.Applicative (pure, liftA, liftA3, (<$>), (<*>)) @@ -111,19 +115,23 @@ case formants p of Nothing -> arr $ const SV.empty Just fs ->- filt (sr, fs)+ filt sr fs . Gate.shorten)- (CausalP.processIO- (CausalP.stereoFromMono+ (CausalRender.run $+ wrapped $ \(Frequency low, Frequency high) (SampleRate _sr) ->+ Stereo.multiValue+ ^<<+ Causal.stereoFromMono (let lowpass q f = UniFilter.bandpass ^<< CtrlPS.process $<- SigP.constant- (UniFilter.parameter . Pole q ^<< frequency f)- in lowpass 100 fst + lowpass 20 snd)))+ Sig.constant (UniFilter.parameter $ Pole q f)+ in lowpass 100 low + lowpass 20 high)+ <<^+ Stereo.unMultiValue) formants :: VoiceMsg.Pitch -> Maybe (Real, Real) formants p =@@ -146,15 +154,16 @@ IO (Map VoiceMsg.Pitch (SV.Vector Real) -> VowelSynth) vowelMask = liftA- (\filt dict sr p ->+ (\filt dict _sr p -> case Map.lookup p dict of Nothing -> arr $ const SV.empty- Just mask ->- filt (sr, mask)- .- Gate.shorten)- (CausalP.processIO- (CausalP.stereoFromMono (FiltNR.convolvePacked (parameter id))))+ Just mask -> filt (Render.buffer mask) . Gate.shorten)+ (CausalRender.run $ \mask ->+ Stereo.multiValue+ ^<<+ Causal.stereoFromMono (FiltNR.convolvePacked mask)+ <<^+ Stereo.unMultiValue) type@@ -183,53 +192,57 @@ case Map.lookup p dict of Nothing -> arr $ const SV.empty Just (typ, mask) ->+ let maskBuf = Render.buffer mask in case typ of Filtered env carrier -> (case carrier of- Voiced -> filt (sr, mask)- Unvoiced -> filtNoise (sr, mask) . arr Zip.first+ Voiced -> filt maskBuf+ Unvoiced -> filtNoise sr maskBuf . arr Zip.first Rasp ->- filtRasp (sr, (mask,+ filtRasp maskBuf $ case sr of SampleRate r -> SVL.cycle $ SVL.take (round $ r/20) $ CtrlG.exponential SigG.defaultLazySize- (r/40) 1)))+ (r/40) 1) . zipEnvelope (case env of Continuous -> contEnv sr vel Percussive -> percEnv sr vel) Sampled ->- smp (sr, SVL.fromChunks $ repeat mask)+ smp (SVL.fromChunks $ repeat mask) . arr Zip.first . zipEnvelope (contEnv sr vel))- <*> CausalP.processIO- (CausalP.envelopeStereo+ <*> (CausalRender.run $ \mask ->+ Stereo.multiValue <$>+ Causal.envelopeStereo . second- (CausalP.stereoFromMono (FiltNR.convolvePacked (parameter id))))- <*> CausalP.processIO- (CausalP.envelopeStereo+ (Causal.stereoFromMono (FiltNR.convolvePacked mask)+ <<^ Stereo.unMultiValue))+ <*> (CausalRender.run $ \mask env ->+ Stereo.multiValue <$>+ Causal.envelopeStereo .- ((CausalP.envelope- $< SigPS.pack (SigP.fromStorableVectorLazy (parameter snd)))+ ((Causal.envelope $< SigPS.pack env) ***- CausalP.stereoFromMono (FiltNR.convolvePacked (parameter fst))))- <*> CausalP.processIO- (CausalP.envelopeStereo $>+ (Causal.stereoFromMono (FiltNR.convolvePacked mask)+ <<^ Stereo.unMultiValue)))+ <*> (CausalRender.run $+ constant noiseReference 1e7 $ \noiseRef _sr mask ->+ Stereo.multiValue <$>+ Causal.envelopeStereo $> traverse (\seed ->- FiltNR.convolvePacked (parameter id) $*- (SigPS.noise seed $ noiseReference 1e7))+ FiltNR.convolvePacked mask $* SigPS.noise seed noiseRef) (Stereo.cons 42 23))- <*> CausalP.processIO- (let smp = parameter id- in pure ^<<- (CausalP.envelope $>- (SigPS.pack $ SigP.fromStorableVectorLazy smp)))+ <*> (CausalRender.run $ \smp ->+ (\x -> Stereo.consMultiValue x x)+ ^<<+ (Causal.envelope $> SigPS.pack smp)) <*> stringControlledEnvelope <*> pingControlledEnvelope (Just 0.01) @@ -422,8 +435,9 @@ plugUniFilterParameter :: Input a (Control Real) -> Input a (Control Frequency) ->- FP.T (SampleRate Real) pl a (UniFilter.Parameter (LLVM.Value Real))+ FP.T (SampleRate Real) a (UniFilter.Parameter (MultiValue.T Real)) plugUniFilterParameter reson freq =+ fmap UniFilterL.unMultiValueParameter $ FP.plug $ liftA3 (\resonChunk freqChunk sr ->@@ -441,16 +455,17 @@ (Input inp (Control Real), (Input inp (Control Real), Input inp (Control Frequency))) -> Input inp StereoChunk ->- FP.T (SampleRate Real) pl inp (Stereo.T VectorValue)+ FP.T (SampleRate Real) inp (MultiValue.T (Stereo.T Vector)) singleFormant (amp, (reson, freq)) x =- CausalP.envelopeStereo $&- (CausalP.mapSimple Serial.upsample $& FP.plug amp)+ Stereo.multiValue <$>+ Causal.envelopeStereo $&+ (Causal.map Serial.upsample $& FP.plug amp) &|&- (CausalP.stereoFromMonoControlled+ (Causal.stereoFromMonoControlled (UniFilter.bandpass ^<< CtrlPS.process) $& plugUniFilterParameter reson freq &|&- FP.plug x)+ (Stereo.unMultiValue <$> FP.plug x)) filterFormant :: IO (SampleRate Real ->@@ -459,8 +474,8 @@ StereoChunk) filterFormant = liftA- (\filt sr -> filt sr (sr, ()))- (FP.withArgs $ \(fmt, x) -> singleFormant fmt x)+ (\filt sr -> filt sr ())+ (FP.withArgs $ \(fmt, x) _unit -> singleFormant fmt x) filterFormants :: IO (SampleRate Real ->@@ -473,6 +488,6 @@ StereoChunk) filterFormants = liftA- (\filt sr -> filt sr (sr, ()))- (FP.withArgs $ \((fmt0, (fmt1, (fmt2, (fmt3, fmt4)))), x) ->+ (\filt sr -> filt sr ())+ (FP.withArgs $ \((fmt0, (fmt1, (fmt2, (fmt3, fmt4)))), x) _unit -> foldl1 (+) $ map (flip singleFormant x) [fmt0, fmt1, fmt2, fmt3, fmt4])
src/Synthesizer/LLVM/Server/CausalPacked/SpeechExplore.hs view
@@ -1,7 +1,7 @@ {-# LANGUAGE NoImplicitPrelude #-} module Main where -import Synthesizer.LLVM.Server.Common (Real)+import Synthesizer.LLVM.Server.Common (Real, pioApply) import qualified Synthesizer.LLVM.Server.SampledSound as Sample import qualified Sound.Sox.Write as SoxWrite@@ -11,13 +11,18 @@ import qualified Graphics.Gnuplot.Plot.TwoDimensional as Plot2D import qualified Graphics.Gnuplot.Graph.TwoDimensional as Graph2D -import qualified Synthesizer.LLVM.CausalParameterized.Controlled as CtrlP-import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP-import qualified Synthesizer.LLVM.Parameterized.Signal as SigP-import qualified Synthesizer.LLVM.Filter.FirstOrder as Filt1+import qualified Synthesizer.LLVM.Causal.Controlled as Ctrl+import qualified Synthesizer.LLVM.Causal.Render as CausalRender+import qualified Synthesizer.LLVM.Causal.Process as Causal+import qualified Synthesizer.LLVM.Generator.Render as Render+import qualified Synthesizer.LLVM.Generator.Signal as Sig+import qualified Synthesizer.LLVM.Filter.Universal as UniFilterL import qualified Synthesizer.LLVM.Filter.NonRecursive as FiltNR-import Synthesizer.LLVM.Causal.Process (($*), ($<), ($<#))+import qualified Synthesizer.LLVM.Filter.FirstOrder as Filt1+import Synthesizer.LLVM.Causal.Process (($*), ($<)) +import qualified LLVM.DSL.Expression as Expr+ import qualified Synthesizer.Plain.Filter.Recursive.Universal as UniFilter import qualified Synthesizer.Plain.Filter.Recursive.FirstOrder as FirstOrder import Synthesizer.Plain.Filter.Recursive (Pole(Pole))@@ -35,8 +40,8 @@ import qualified Data.StorableVector.Lazy as SVL import qualified Data.StorableVector as SV -import Control.Arrow (arr, (<<<), (^<<))-import Control.Category ((.), id)+import Control.Arrow ((<<<), (^<<))+import Control.Category ((.)) import Control.Applicative ((<$>)) import Control.Functor.HT (void)@@ -48,7 +53,9 @@ import Data.Maybe (catMaybes) import Data.Tuple.HT (mapSnd) import Data.Ord.HT (comparing)-import Data.Monoid (mempty, mappend)+import Data.Semigroup ((<>))+import Data.Monoid (mempty)+import Data.Word (Word) import qualified System.Path.PartClass as PathClass import qualified System.Path as Path@@ -144,20 +151,20 @@ (UniFilter.lowpass, Pole 2 3000, 0.6) : [] -synthesis :: IO (SVL.ChunkSize -> () -> SVL.Vector Real)+synthesis :: IO (SVL.ChunkSize -> SVL.Vector Real) synthesis =- SigP.runChunky $+ Render.run $ (sum (map (\(typ, Pole q f, amp) ->- CausalP.amplify (return amp)+ Causal.amplify (Expr.cons amp) <<< typ ^<<- CtrlP.process+ Ctrl.process $<- (SigP.constant $ return $- UniFilter.parameter $ Pole q $ f / sampleRate))+ (fmap UniFilterL.unMultiValueParameter $ Sig.constant $+ Expr.cons $ UniFilter.parameter $ Pole q $ f / sampleRate)) formants_sch)- $* SigP.noise 174373 0.02)+ $* Sig.noise 174373 0.02) compareSpec ::IO () compareSpec = do@@ -165,39 +172,45 @@ synthesized <- synthesis void $ Plot.plot WXT.cons $ spectrumPlot sampled- `mappend`+ <> spectrumPlot (SVL.take (SVL.length sampled) $- synthesized (SVL.chunkSize 4096) ())+ synthesized (SVL.chunkSize 4096)) render ::IO () render = do synthesized <- synthesis saveSound (Path.relFile "sch-synth.wav") $ SVL.take sampleRateInt $- synthesized (SVL.chunkSize 4096) ()+ synthesized (SVL.chunkSize 4096) -- * purification of sampled periods -- ** using a comb filter -type Comb = (Real, Int) -> SVL.Vector Real -> SVL.Vector Real+type Comb = Real -> Word -> SVL.Vector Real -> SVL.Vector Real makeComb :: IO Comb makeComb =- CausalP.runStorableChunky $ CausalP.comb (arr fst) (arr snd)+ (\proc gain time -> pioApply (proc gain time))+ <$>+ CausalRender.run Causal.comb makeHighComb :: IO Comb makeHighComb =- CausalP.runStorableChunky $- CausalP.comb (arr fst) (arr snd)+ fmap (\proc gain time -> pioApply (proc gain time))+ $+ CausalRender.run $ \gain time ->+ Causal.comb gain time .- (Filt1.highpassCausal $<# FirstOrder.parameter (1000/sampleRate))+ (Filt1.highpassCausal $<+ Sig.constant (FirstOrder.parameter (1000 / Expr.cons sampleRate))) -scorePeriod :: Comb -> Real -> Int -> SVL.Vector Real -> (Real, SVL.Vector Real)+scorePeriod ::+ Comb -> Real -> Word -> SVL.Vector Real -> (Real, SVL.Vector Real) scorePeriod comb gain period sig =- let end = SVL.takeEnd (3*period) $ comb (gain, period) sig+ let end = SVL.takeEnd (3 * fromIntegral period) $ comb gain period sig in (Analysis.volumeEuclideanSqr end, end) vowelNames :: [String]@@ -258,7 +271,7 @@ findPeriod :: Comb -> SVL.Vector Real -> SVL.Vector Real findPeriod comb sampled = normalize $- uncurry bestRotation $+ uncurry (bestRotation . fromIntegral) $ mapSnd snd $ List.maximumBy (comparing (fst . snd)) $ flip map [350 .. 400] $ \period ->@@ -275,7 +288,9 @@ makeFilter :: IO (SV.Vector Real -> SVL.Vector Real -> SVL.Vector Real) makeFilter =- CausalP.runStorableChunky $ FiltNR.convolve id+ (\proc mask -> pioApply (proc (Render.buffer mask)))+ <$>+ CausalRender.run FiltNR.convolve normalizeMax :: SVL.Vector Real -> SVL.Vector Real normalizeMax = FiltNRG.normalize Analysis.volumeMaximum
src/Synthesizer/LLVM/Server/Common.hs view
@@ -1,135 +1,332 @@ {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE EmptyDataDecls #-} module Synthesizer.LLVM.Server.Common (- Real, Param,- SampleRate(SampleRate),+ Real,+ SampleRate(SampleRate), expSampleRate, Instrument,- frequency, time, noiseReference, number, control, signal, parameter,- frequencyConst, timeConst,+ ($+),+ constant, ($++),+ frequency, time, noiseReference, number,+ Quantity(..), Arg(..), Frequency, Time, Number,+ Input(..), InputArg(..), Parameter, Control, Signal,+ ArgTuple(..),+ Wrapped(..),+ amplitudeFromVelocity, ($/), - chopEvents, piecewiseConstant, transposeModulation,- amplitudeFromVelocity, + pioApply,+ pioApplyCont,+ pioApplyToLazyTime,+ controllerAttack, controllerDetune, controllerTimbre0, controllerTimbre1, controllerFilterCutoff, controllerFilterResonance, controllerVolume, ) where -import qualified Sound.MIDI.Controller as Ctrl-import qualified Sound.MIDI.Message.Channel.Voice as VoiceMsg+import qualified Synthesizer.LLVM.Generator.Render as Render+import qualified Synthesizer.LLVM.Generator.Signal as Sig+import Synthesizer.LLVM.Causal.Process (($*)) +import qualified Synthesizer.LLVM.MIDI.BendModulation as BM+import qualified Synthesizer.LLVM.ConstantPiece as Const import qualified Synthesizer.MIDI.Storable as MidiSt+import qualified Synthesizer.MIDI.EventList as Ev import qualified Synthesizer.PiecewiseConstant.Signal as PC-import qualified Synthesizer.LLVM.MIDI.BendModulation as BM+import qualified Synthesizer.CausalIO.Process as PIO+import qualified Synthesizer.Generic.Signal as SigG -import qualified Synthesizer.LLVM.Parameterized.Signal as SigP-import qualified LLVM.DSL.Parameter as Param+import qualified Sound.MIDI.Controller as Ctrl+import qualified Sound.MIDI.Message.Channel.Voice as VoiceMsg -import qualified LLVM.Extra.Marshal as Marshal-import qualified LLVM.Extra.Tuple as Tuple+import qualified LLVM.DSL.Expression as Expr+import LLVM.DSL.Expression (Exp) -import qualified Synthesizer.Storable.Signal as SigSt+import qualified LLVM.Extra.Multi.Value.Marshal as Marshal+import qualified LLVM.Extra.Multi.Value as MultiValue+import qualified LLVM.Extra.Memory as Memory -import qualified Data.EventList.Relative.TimeTime as EventListTT+import qualified Data.StorableVector.Lazy as SVL+import qualified Data.StorableVector as SV+import Foreign.Storable (Storable) -import qualified Numeric.NonNegative.Class as NonNeg+import qualified Numeric.NonNegative.Chunky as NonNegChunky+import qualified Numeric.NonNegative.Wrapper as NonNegW -import Control.Arrow (arr, (^<<))+import Control.Applicative (Applicative, liftA2, pure, (<*>), (<$>)) -import Prelude hiding (Real)+import qualified Data.Traversable as Trav+import qualified Data.Foldable as Fold +import qualified System.Unsafe as Unsafe +import qualified Algebra.Transcendental as Trans+import qualified Algebra.Field as Field+import qualified Algebra.Ring as Ring +import NumericPrelude.Numeric+import NumericPrelude.Base+import Prelude ()++++type Real = Float++type Instrument a sig = SampleRate a -> MidiSt.Instrument a sig++ newtype SampleRate a = SampleRate a deriving (Show) instance Functor SampleRate where fmap f (SampleRate sr) = SampleRate (f sr) +instance Fold.Foldable SampleRate where+ foldMap f (SampleRate sr) = f sr -type Real = Float+instance Trav.Traversable SampleRate where+ traverse f (SampleRate sr) = SampleRate <$> f sr -type Param p = Param.T (SampleRate Real, p)+instance Applicative SampleRate where+ pure = SampleRate+ SampleRate f <*> SampleRate sr = SampleRate $ f sr -type Instrument a sig = SampleRate a -> MidiSt.Instrument a sig +instance (Render.RunArg a) => Render.RunArg (SampleRate a) where+ type DSLArg (SampleRate a) = SampleRate (Render.DSLArg a)+ buildArg =+ case Render.buildArg of+ Render.BuildArg pass create ->+ Render.BuildArg+ (SampleRate . pass)+ (\(SampleRate sr) -> create sr) -frequency :: (p -> Real) -> Param p Real-frequency param =- arr (\(SampleRate sampleRate, p) -> param p / sampleRate)+instance (MultiValue.C a) => MultiValue.C (SampleRate a) where+ type Repr (SampleRate a) = MultiValue.Repr a+ cons = multiValueSampleRate . fmap MultiValue.cons+ undef = multiValueSampleRate $ pure MultiValue.undef+ zero = multiValueSampleRate $ pure MultiValue.zero+ phi bb =+ fmap multiValueSampleRate .+ Trav.traverse (MultiValue.phi bb) . unMultiValueSampleRate+ addPhi bb a b =+ Fold.sequence_ $+ liftA2 (MultiValue.addPhi bb)+ (unMultiValueSampleRate a) (unMultiValueSampleRate b) -time :: (p -> Real) -> Param p Real-time param =- arr (\(SampleRate sampleRate, p) -> param p * sampleRate)+instance (Marshal.C a) => Marshal.C (SampleRate a) where+ pack (SampleRate a) = Marshal.pack a+ unpack = SampleRate . Marshal.unpack -noiseReference :: Real -> Param p Real-noiseReference freq =- arr (\(SampleRate sampleRate, _p) -> sampleRate/freq)+multiValueSampleRate ::+ SampleRate (MultiValue.T a) -> MultiValue.T (SampleRate a)+multiValueSampleRate (SampleRate (MultiValue.Cons a)) = MultiValue.Cons a -number :: (p -> Real) -> Param p Real-number param = arr (param . snd)+unMultiValueSampleRate ::+ MultiValue.T (SampleRate a) -> SampleRate (MultiValue.T a)+unMultiValueSampleRate (MultiValue.Cons a) = SampleRate (MultiValue.Cons a) -control :: (p -> PC.T Real) -> Param p (PC.T Real)-control param = arr (param . snd) -signal :: (p -> SigSt.T a) -> Param p (SigSt.T a)-signal param = arr (param . snd)+expSampleRate :: Exp (SampleRate a) -> SampleRate (Exp a)+expSampleRate = SampleRate . Expr.lift1 MultiValue.cast -parameter :: (p -> a) -> Param p a-parameter param = arr (param . snd) -frequencyConst :: Real -> Param p Real-frequencyConst param =- arr (\(SampleRate sampleRate, _p) -> param / sampleRate)+($/) :: (Functor f) => f (a -> b) -> a -> f b+f $/ x = fmap ($ x) f -timeConst :: Real -> Param p Real-timeConst param =- arr (\(SampleRate sampleRate, _p) -> param * sampleRate) +infixr 0 $+, $++ +($+) ::+ (SampleRate a -> b -> c) ->+ (c -> SampleRate a -> d) ->+ SampleRate a -> b -> d+(p$+f) sampleRate param = f (p sampleRate param) sampleRate -($/) :: (Functor f) => f (a -> b) -> a -> f b-f $/ x = fmap ($x) f+($++) ::+ (SampleRate a -> b -> c, b) ->+ (c -> SampleRate a -> d) ->+ SampleRate a -> d+((p,param)$++f) sampleRate = f (p sampleRate param) sampleRate +constant ::+ (SampleRate a -> b -> c) -> b ->+ (c -> SampleRate a -> d) ->+ SampleRate a -> d+constant p param f sampleRate = f (p sampleRate param) sampleRate --- might be moved to event-list package-chopEvents ::- (NonNeg.C time, Num time) =>- time ->- EventListTT.T time body ->- [EventListTT.T time body]-chopEvents chunkSize =- let go evs =- let (chunk,rest) = EventListTT.splitAtTime chunkSize evs- in if EventListTT.duration chunk == 0- then []- else chunk : go rest- in go +frequency :: (Field.C a) => SampleRate a -> a -> a+frequency (SampleRate sr) param = param / sr -piecewiseConstant ::- (Marshal.C a, Tuple.ValueOf a ~ al) =>- Param.T p (PC.T a) -> SigP.T p al-piecewiseConstant pc =- SigP.piecewiseConstant- (PC.subdivideLongStrict ^<< pc)+time :: (Ring.C a) => SampleRate a -> a -> a+time (SampleRate sr) param = param * sr -transposeModulation ::- (Functor stream) =>- SampleRate Real ->- Real ->- stream (BM.T Real) ->- stream (BM.T Real)-transposeModulation (SampleRate sampleRate) freq =- fmap (BM.shift (freq/sampleRate))+noiseReference :: (Field.C a) => SampleRate a -> a -> a+noiseReference (SampleRate sr) freq = sr/freq +number :: SampleRate a -> a -> a+number = flip const ++data Number+data Frequency+data Time+data NoiseReference++class Quantity quantity a where+ data Arg quantity a+ eval :: SampleRate a -> a -> Arg quantity a++instance Quantity Number a where+ data Arg Number a = Number a+ eval sampleRate a = Number $ number sampleRate a++instance (Field.C a) => Quantity Frequency a where+ data Arg Frequency a = Frequency a+ eval sampleRate a = Frequency $ frequency sampleRate a++instance (Ring.C a) => Quantity Time a where+ data Arg Time a = Time a+ eval sampleRate a = Time $ time sampleRate a++instance (Field.C a) => Quantity NoiseReference a where+ data Arg NoiseReference a = NoiseReference a+ eval sampleRate a = NoiseReference $ noiseReference sampleRate a+++class Input signal a where+ data InputArg signal a+ type InputSource signal a+ evalInput :: SampleRate a -> InputSource signal a -> InputArg signal a++data Parameter b++instance Input (Parameter b) a where+ data InputArg (Parameter b) a = Parameter b+ type InputSource (Parameter b) a = b+ evalInput _sr = Parameter++data Control b++instance Input (Control b) a where+ data InputArg (Control b) a = Control (Sig.T b)+ type InputSource (Control b) a = Sig.T b+ evalInput _sr = Control++data Signal b++instance Input (Signal b) a where+ data InputArg (Signal b) a = Signal (Sig.T b)+ type InputSource (Signal b) a = Sig.T b+ evalInput _sr = Signal+++class ArgTuple a tuple where+ type ArgPlain tuple+ evalTuple :: SampleRate a -> ArgPlain tuple -> tuple++instance (Quantity quantity b, a ~ b) => ArgTuple a (Arg quantity b) where+ type ArgPlain (Arg quantity b) = b+ evalTuple = eval++instance (Input signal b, a ~ b) => ArgTuple a (InputArg signal b) where+ type ArgPlain (InputArg signal b) = InputSource signal b+ evalTuple = evalInput++instance (ArgTuple a b, ArgTuple a c) => ArgTuple a (b,c) where+ type ArgPlain (b,c) = (ArgPlain b, ArgPlain c)+ evalTuple sampleRate (b,c) = (evalTuple sampleRate b, evalTuple sampleRate c)++instance (ArgTuple a b, ArgTuple a c, ArgTuple a d) => ArgTuple a (b,c,d) where+ type ArgPlain (b,c,d) = (ArgPlain b, ArgPlain c, ArgPlain d)+ evalTuple sampleRate (b,c,d) =+ (evalTuple sampleRate b, evalTuple sampleRate c, evalTuple sampleRate d)++++class Wrapped a f where+ type Unwrapped f+ wrapped :: f -> SampleRate a -> Unwrapped f++instance (a ~ b) => Wrapped a (SampleRate b -> f) where+ type Unwrapped (SampleRate b -> f) = f+ wrapped f = f++instance+ (a ~ b, Quantity quantity b, Wrapped a f) =>+ Wrapped a (Arg quantity b -> f) where+ type Unwrapped (Arg quantity b -> f) = b -> Unwrapped f+ wrapped f sampleRate arg =+ wrapped (f (eval sampleRate arg)) sampleRate++instance+ (a ~ b, Input signal b, Wrapped a f) =>+ Wrapped a (InputArg signal b -> f) where+ type Unwrapped (InputArg signal b -> f) =+ InputSource signal b -> Unwrapped f+ wrapped f sampleRate arg =+ wrapped (f (evalInput sampleRate arg)) sampleRate++instance+ (ArgTuple a b, ArgTuple a c, Wrapped a f) =>+ Wrapped a ((b,c) -> f) where+ type Unwrapped ((b,c) -> f) = (ArgPlain b, ArgPlain c) -> Unwrapped f+ wrapped f sampleRate arg =+ wrapped (f (evalTuple sampleRate arg)) sampleRate++instance+ (ArgTuple a b, ArgTuple a c, ArgTuple a d, Wrapped a f) =>+ Wrapped a ((b,c,d) -> f) where+ type Unwrapped ((b,c,d) -> f) =+ (ArgPlain b, ArgPlain c, ArgPlain d) -> Unwrapped f+ wrapped f sampleRate arg =+ wrapped (f (evalTuple sampleRate arg)) sampleRate++ {-# INLINE amplitudeFromVelocity #-}-amplitudeFromVelocity :: Real -> Real-amplitudeFromVelocity vel = 4**vel+amplitudeFromVelocity :: (Trans.C a) => a -> a+amplitudeFromVelocity vel = fromInteger 4 ^? vel+++piecewiseConstant :: (Memory.C a) => Sig.T (Const.T a) -> Sig.T a+piecewiseConstant = Const.flatten++transposeModulation :: (Field.C a, Expr.Aggregate a am) =>+ SampleRate a -> a -> Sig.T (Const.T (BM.T am)) -> Sig.T (Const.T (BM.T am))+transposeModulation (SampleRate sampleRate) freq xs =+ Const.causalMap (BM.shift (freq/sampleRate)) $* xs++++pioApply ::+ (Storable a, Storable b) =>+ PIO.T (SV.Vector a) (SV.Vector b) -> SVL.Vector a -> SVL.Vector b+pioApply = pioApplyCont (const SVL.empty)++pioApplyCont ::+ (Storable a, Storable b) =>+ (SVL.Vector a -> SVL.Vector b) ->+ PIO.T (SV.Vector a) (SV.Vector b) -> SVL.Vector a -> SVL.Vector b+pioApplyCont cont proc sig = Unsafe.performIO $ do+ act <- PIO.runStorableChunkyCont proc+ return $ act cont sig++pioApplyToLazyTime ::+ (Storable b) =>+ PIO.T SigG.LazySize (SV.Vector b) -> Ev.LazyTime -> SVL.Vector b+pioApplyToLazyTime proc sig = Unsafe.performIO $ do+ act <- PIO.runCont proc+ return $ SVL.fromChunks $ act (const []) $+ map (SigG.LazySize . NonNegW.toNumber) $+ concatMap PC.chopLongTime $ NonNegChunky.toChunks sig+ controllerAttack, controllerDetune, controllerTimbre0, controllerTimbre1,
src/Synthesizer/LLVM/Server/CommonPacked.hs view
@@ -1,26 +1,19 @@-module Synthesizer.LLVM.Server.CommonPacked (- module Synthesizer.LLVM.Server.CommonPacked,- Param,- ) where+module Synthesizer.LLVM.Server.CommonPacked where import Synthesizer.LLVM.Server.Common -import qualified Synthesizer.LLVM.Frame.SerialVector as Serial--import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP-import qualified Synthesizer.LLVM.CausalParameterized.Functional as F-import qualified Synthesizer.LLVM.Parameterized.Signal as SigP+import qualified Synthesizer.LLVM.Frame.SerialVector.Code as Serial import qualified Data.NonEmpty as NonEmpty -import qualified Algebra.Additive as Additive- import qualified Type.Data.Num.Decimal as TypeNum -import Control.Arrow (arr)+import qualified Algebra.Field as Field+import qualified Algebra.Additive as Additive -import NumericPrelude.Numeric ((+), (-), (*))-import Prelude hiding (Real, (+), (-), (*))+import NumericPrelude.Numeric+import NumericPrelude.Base+import Prelude () sumNested :: (Additive.C a) => [a] -> a@@ -36,27 +29,19 @@ in n + 0.01*r -type SigP p = SigP.T (SampleRate Real, p)-type CausalP p = CausalP.T (SampleRate Real, p)-type FuncP p = F.T (SampleRate Real, p)---type Vector = Serial.Plain VectorSize Real+type Vector = Serial.T VectorSize Real type VectorValue = Serial.Value VectorSize Real type VectorSize = TypeNum.D4 +-- ToDo: generalize to Integral class vectorSize :: Int vectorSize = TypeNum.integralFromSingleton (TypeNum.singleton :: TypeNum.Singleton VectorSize) -vectorRate :: Fractional a => SampleRate a -> a-vectorRate (SampleRate sampleRate) =- sampleRate / fromIntegral vectorSize-+vectorRate :: (Field.C a) => SampleRate a -> a+vectorRate (SampleRate sr) = sr / fromIntegral vectorSize -vectorTime :: (p -> Real) -> Param p Real-vectorTime param =- arr (\(SampleRate sampleRate, p) ->- param p * sampleRate / fromIntegral vectorSize)+vectorTime :: (Field.C a) => SampleRate a -> a -> a+vectorTime (SampleRate sr) param = param * sr / fromIntegral vectorSize
src/Synthesizer/LLVM/Server/Packed/Instrument.hs view
@@ -13,1489 +13,1494 @@ instruments:- use a greymap picture as source of waveforms- mix of detuned noisy-waverforms, try different and uniform waveforms- mix of sawtooth, where every sawtooth is modulated with red noise- mix of sine with harmonics where every harmonic is modulated differently- Flute: sine + filtered noise- Drum with various parameters- derive percussive instruments from fmString and arcString (for bass synths)- an FM sound with a slowly changing timbre- by using a very slightly detuned frequency for the modulator- making a tone out of noise using time stretch with helix algorithm- a chorus effect could be applied by two successive helix stretches- or by mixture of two stretches signals- additionally a resonant filter could be applied- a kind of Karplus-Strong algorithm with a non-linear function of past values- e.g. y(t) = f(y(t-d), y(t-2*d))- where d is the tone period and f is non-linear, maybe chaotic function.- In order to limit the appearance of chaotic waveforms,- we could combine this with a lowpass filter.- let attack and release depend on On and Off velocity- tineStereoFM:- continuous control of the modulation index- by linear interpolation of waves between modulations with integral indices.- E.g. modulation index 2.3 means- 0.7*modulation with index 2 and 0.3*modulation with index 3.--effects:- reverb and controllable delay- phaser or Chebyshev filter--continuous sounds:- fly- water/bubbles- when I accidentally did not scale filter frequency with sample rate,- the filter sound much like water bubbles.- I think a control curve consisting of some ramps will do the same.- hail, Geiger counter, pitch applied by comb filter- at a very high impulse rate the impulses itself- can generate an almost periodic signal---Speech sounds improvements (tomatensalat)- use PSOLA for transposition- To this end divide signal into tonal part and residue (noise)- by a comb filter.- Maybe a non-linear comb filter may help,- that selects the center value from the filter window,- if the side values are similar- and returns zero, if the the side values differ too much.- Process the tonal part by PSOLA and- simply mix it with the non-tonal part on replay.--Harmonizer-like:- We like to input an audio signal of speech- and a set of keys, and the speech is extended to chords- according to the pressed keys.- The lowest key is interpreted as base frequency of the input audio speech.- A PSOLA method transposes the audio input.--Resonant filter controlled by keys- applied to an audio input signal- or an ordinary audio signal generated by other keys.- The splitting of keys however could be performed- by a MIDI event stream editor.--}--{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE Rank2Types #-}-module Synthesizer.LLVM.Server.Packed.Instrument (- pingRelease,- pingStereoRelease,- pingStereoReleaseFM,- squareStereoReleaseFM,- bellStereoFM,- bellNoiseStereoFM,- tine,- tineStereo,- softString,- softStringFM,- tineStereoFM,- tineControlledFM,- fenderFM,- tineModulatorBankFM,- tineBankFM,- resonantFMSynth,- softStringDetuneFM,- softStringShapeFM, cosineStringStereoFM,- arcSineStringStereoFM, arcTriangleStringStereoFM,- arcSquareStringStereoFM, arcSawStringStereoFM,- fmStringStereoFM,- wind,- windPhaser,- filterSawStereoFM,- brass,- sampledSound,-- -- * helper functions- stereoNoise,- frequencyFromBendModulation,- modulation,- piecewiseConstantVector,-- -- * for testing- pingReleaseEnvelope,- adsr,- ) where--import qualified Synthesizer.LLVM.Server.Parameter as ParamS-import Synthesizer.LLVM.Server.CommonPacked-import Synthesizer.LLVM.Server.Common-import Synthesizer.LLVM.Server.Parameter- (Number(Number), Signal(Signal), Control(Control))--import qualified Synthesizer.LLVM.Server.SampledSound as Sample-import qualified Synthesizer.LLVM.MIDI.BendModulation as BM-import qualified Synthesizer.MIDI.PiecewiseConstant as PC-import qualified Synthesizer.MIDI.EventList as Ev--import Synthesizer.MIDI.Storable (chunkSizesFromLazyTime)--import qualified Synthesizer.LLVM.Frame.Stereo as Stereo-import qualified Synthesizer.LLVM.Filter.Universal as UniFilterL-import qualified Synthesizer.LLVM.Filter.Allpass as Allpass-import qualified Synthesizer.LLVM.Filter.Moog as MoogL-import qualified Synthesizer.LLVM.MIDI as MIDIL-import qualified Synthesizer.LLVM.CausalParameterized.ControlledPacked as CtrlPS-import qualified Synthesizer.LLVM.CausalParameterized.ProcessPacked as CausalPS-import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP-import qualified Synthesizer.LLVM.CausalParameterized.Functional as F-import qualified Synthesizer.LLVM.Parameterized.SignalPacked as SigPS-import qualified Synthesizer.LLVM.Parameterized.Signal as SigP-import qualified Synthesizer.LLVM.Simple.Signal as Sig-import qualified Synthesizer.LLVM.Storable.Signal as SigStL-import qualified Synthesizer.LLVM.Frame as Frame-import qualified Synthesizer.LLVM.Frame.SerialVector as Serial-import qualified Synthesizer.LLVM.Wave as WaveL-import Synthesizer.LLVM.CausalParameterized.Process (($<), ($>), ($*))-import Synthesizer.LLVM.CausalParameterized.Functional (($&), (&|&))--import qualified LLVM.DSL.Parameter as Param-import LLVM.DSL.Parameter (($#))--import qualified LLVM.Extra.Arithmetic as A-import qualified LLVM.Core as LLVM-import qualified Type.Data.Num.Decimal as TypeNum--import qualified Synthesizer.Generic.Cut as CutG-import qualified Synthesizer.Storable.Signal as SigSt-import qualified Data.StorableVector.Lazy.Pattern as SVP-import qualified Data.StorableVector.Lazy as SVL--import qualified Synthesizer.Plain.Filter.Recursive.Universal as UniFilter--import qualified Control.Monad.HT as M-import Control.Arrow ((<<<), (^<<), (<<^), (&&&), (***), arr, first, second)-import Control.Category (id)-import Control.Applicative (liftA2, liftA3)-import Data.Traversable (traverse)-import qualified Data.Traversable as Trav--import Data.Tuple.HT (fst3, snd3, thd3)--import qualified Numeric.NonNegative.Chunky as NonNegChunky--import qualified Algebra.Additive as Additive--import NumericPrelude.Numeric (zero, one, round, (^?), (+), (-), (*))-import Prelude hiding (Real, round, break, id, (+), (-), (*))----frequencyControl :: (p -> PC.T Real) -> Param p (PC.T Real)-frequencyControl param =- arr (\(SampleRate sampleRate, p) -> fmap (/sampleRate) $ param p)--modulation ::- (p -> (PC.T (BM.T Real), Real)) -> Param p (PC.T (BM.T Real))-modulation param =- arr (\(sr, p) ->- (\(fm,freq) -> transposeModulation sr freq fm) $ param p)--newtype Modulation p = Modulation (Param p (PC.T (BM.T Real)))--instance ParamS.Tuple (Modulation p) where- type Composed (Modulation p) = (PC.T (BM.T Real), Real)- type Source (Modulation p) = p- decompose sampleRate x =- Modulation $- liftA2 (\sr (fm,freq) -> transposeModulation sr freq fm) sampleRate x--detuneModulation ::- (p -> (PC.T Real, PC.T (BM.T Real), Real)) ->- Param p (PC.T Real, PC.T (BM.T Real))-detuneModulation param =- arr $ \(sr, p) ->- case param p of- (det,fm,freq) -> (det, transposeModulation sr freq fm)--newtype- DetuneModulation p =- DetuneModulation (Param p (PC.T Real, PC.T (BM.T Real)))--instance ParamS.Tuple (DetuneModulation p) where- type Composed (DetuneModulation p) = (PC.T Real, PC.T (BM.T Real), Real)- type Source (DetuneModulation p) = p- decompose sampleRate x =- DetuneModulation $- liftA2- (\sr (det,fm,freq) -> (det, transposeModulation sr freq fm))- sampleRate x----frequencyFromBendModulation ::-{-- (Storable a,- Tuple.Value a, ValueTuple a ~ (Value a)) =>--}- Param p Real ->- Param p (PC.T (BM.T Real)) ->- SigP p VectorValue-frequencyFromBendModulation speed fmFreq =- MIDIL.frequencyFromBendModulationPacked speed- $* piecewiseConstant fmFreq--stereoFrequenciesFromDetuneBendModulation ::- Param p Real ->- Param p (PC.T Real, PC.T (BM.T Real)) ->- SigP p (Stereo.T VectorValue)-stereoFrequenciesFromDetuneBendModulation speed detFmFreq =- (CausalP.envelopeStereo- $< frequencyFromBendModulation speed- (fmap (\(_det,fm) -> (fm)) detFmFreq))- <<<- liftA2 Stereo.cons (one + id) (one - id)- $* piecewiseConstantVector- (fmap (\(det,_fm) -> det) detFmFreq)--piecewiseConstantVector ::- Param.T p (PC.T Real) -> SigP.T p VectorValue-{-- (Storable a,- Tuple.Value a, Tuple.ValueOf a ~ al,- Memory.C al am,- LLVM.IsSized am as) =>- Param.T p (PC.T a) -> SigP.T p (Serial.Value n al)--}-piecewiseConstantVector =- piecewiseConstant . fmap (fmap (Serial.replicate))---pingReleaseEnvelope ::- IO (Real -> Real ->- SigSt.ChunkSize ->- SampleRate Real -> Real -> Ev.LazyTime -> SigSt.T Vector)-pingReleaseEnvelope =- liftA2- (\pressed release decay rel vcsize sr vel dur ->- SigStL.continuePacked- (pressed (chunkSizesFromLazyTime dur) (sr, (decay,vel)))- (\x -> release vcsize (sr, (rel,x))))- (SigP.runChunkyPattern $- let decay = time fst- velocity = number snd- in SigPS.exponential2 decay- (amplitudeFromVelocity ^<< velocity))- (SigP.runChunky $- let releaseTime = vectorTime fst * 5- releaseHL = time fst- amplitude = number snd- in CausalP.take (round ^<< releaseTime) $*- SigPS.exponential2 releaseHL amplitude)--pingRelease ::- IO (Real -> Real -> SigSt.ChunkSize -> Instrument Real Vector)-pingRelease =- liftA2- (\osc env dec rel vcsize sr vel freq dur ->- osc (sr,freq) (env dec rel vcsize sr vel dur))- (CausalP.runStorableChunky- (let freq = frequency id- in CausalP.envelope $>- SigPS.osciSimple WaveL.saw zero freq))- pingReleaseEnvelope--pingStereoRelease ::- IO (Real -> Real -> SigSt.ChunkSize -> Instrument Real (Stereo.T Vector))-pingStereoRelease =- liftA2- (\osc env dec rel vcsize sr vel freq dur ->- osc (sr,freq) (env dec rel vcsize sr vel dur))- (CausalP.runStorableChunky- (let freq = frequency id- in CausalP.envelopeStereo $>- liftA2 Stereo.cons- (SigPS.osciSimple WaveL.saw zero (0.999*freq))- (SigPS.osciSimple WaveL.saw zero (1.001*freq))))- pingReleaseEnvelope--pingStereoReleaseFM ::- IO (Real -> Real ->- PC.T Real ->- PC.T Real ->- Real -> Real ->- SigSt.ChunkSize ->- PC.T (BM.T Real) ->- Instrument Real (Stereo.T Vector))-pingStereoReleaseFM =- liftA2- (\osc env dec rel detune shape phase phaseDecay vcsize fm sr vel freq dur ->- osc- (sr, ((phase, phaseDecay), shape, (detune,fm,freq)))- (env dec rel vcsize sr vel dur))- (CausalP.runStorableChunky $- ParamS.withTuple2 $- \((Number phase, ParamS.Time decay),- Control shape, DetuneModulation fm) ->- CausalP.envelopeStereo $>- ((CausalP.stereoFromMonoControlled- (CausalPS.shapeModOsci WaveL.rationalApproxSine1)- $< piecewiseConstantVector shape)- <<^ Stereo.interleave- $< (liftA2 Stereo.cons id (Additive.negate id)- $* SigPS.exponential2 decay phase)- $* stereoFrequenciesFromDetuneBendModulation (frequencyConst 10) fm))- pingReleaseEnvelope--{- |-Square like wave constructed as difference-of two phase shifted sawtooth like oscillations.--}-squareStereoReleaseFM ::- IO (Real -> Real ->- PC.T Real ->- PC.T Real ->- PC.T Real ->- SigSt.ChunkSize ->- PC.T (BM.T Real) ->- Instrument Real (Stereo.T Vector))-squareStereoReleaseFM =- liftA2- (\osc env dec rel detune shape phase vcsize fm sr vel freq dur ->- osc- (sr, ((phase, shape), (detune,fm,freq)))- (env dec rel vcsize sr vel dur))- (CausalP.runStorableChunky $- ParamS.withTuple2 $ \((Control phs, Control shp), DetuneModulation fm) ->- (let chanOsci ::- CausalP p- ((VectorValue, VectorValue), VectorValue)- VectorValue- chanOsci =- ((CausalPS.shapeModOsci WaveL.rationalApproxSine1- <<<- second (first (Additive.negate id)))- -- CausalPS.shapeModOsci WaveL.rationalApproxSine1)- <<^- (\((p,s),f) -> (s,(p,f)))- in CausalP.envelopeStereo $>- ((CausalP.stereoFromMonoControlled chanOsci- $< SigP.zip- (piecewiseConstantVector phs)- (piecewiseConstantVector shp))- $* stereoFrequenciesFromDetuneBendModulation (frequencyConst 10) fm)))- pingReleaseEnvelope---type Triple a = (a, a, a)--bellStereoFM ::- IO (Real -> Real ->- PC.T Real ->- SigSt.ChunkSize ->- PC.T (BM.T Real) ->- Instrument Real (Stereo.T Vector))-bellStereoFM =- liftA2- (\osc env dec rel detune vcsize fm sr vel freq dur ->- osc (sr, ((detune, fm, freq), vel,- (env (dec/4) rel vcsize sr vel dur,- env (dec/7) rel vcsize sr vel dur)))- (env dec rel vcsize sr vel dur))- (CausalP.runStorableChunky $- ParamS.withTuple2 $- \(DetuneModulation fm, Number vel, (Signal env4, Signal env7)) ->- (let osci ::- (Triple VectorValue -> VectorValue) ->- Param.T p Real ->- Param.T p Real ->- CausalP.T p- (Triple VectorValue, Stereo.T VectorValue)- (Stereo.T VectorValue)- osci sel v d =- CausalP.envelopeStereo- <<<- (arr sel ***- (CausalPS.amplifyStereo v- <<<- CausalP.stereoFromMono- (CausalPS.osciSimple WaveL.approxSine4 $< zero)- <<<- CausalPS.amplifyStereo d))- in sumNested- [osci fst3 0.6 1,- osci snd3 (0.02 * 50^?vel) 4,- osci thd3 (0.02 * 100^?vel) 7]- <<<- CausalP.feedSnd (stereoFrequenciesFromDetuneBendModulation (frequencyConst 5) fm)- <<<- arr (\(e1,(e4,e7)) -> (e1,e4,e7))- $> {-- Be careful, those storable vectors shorten the whole sound- if they have shorter release than the main envelope.- -}- SigP.zip- (SigP.fromStorableVectorLazy env4)- (SigP.fromStorableVectorLazy env7)))- pingReleaseEnvelope--bellNoiseStereoFM ::- IO (Real -> Real ->- PC.T Real -> PC.T Real ->- SigSt.ChunkSize ->- PC.T (BM.T Real) ->- Instrument Real (Stereo.T Vector))-bellNoiseStereoFM =- liftA2- (\osc env dec rel noiseAmp noiseReson vcsize fm sr vel freq dur ->- osc (sr,- ((fm, freq),- (noiseAmp,noiseReson),- (vel,- env (dec/4) rel vcsize sr vel dur,- env (dec/7) rel vcsize sr vel dur)))- (env dec rel vcsize sr vel dur))- (CausalP.runStorableChunky $- ParamS.withTuple2 $- \(Modulation fm,- (Control noiseAmp, Control noiseReson),- (Number vel, Signal env4, Signal env7)) ->- (let osci ::- (Triple VectorValue -> VectorValue) ->- Param.T p Real ->- Param.T p Real ->- CausalP.T p- (Triple VectorValue, VectorValue)- VectorValue- osci sel v d =- CausalP.envelope- <<<- (arr sel ***- (CausalPS.amplify v- <<<- (CausalPS.osciSimple WaveL.approxSine4 $< zero)- <<<- CausalPS.amplify d))-- noise ::- (p ~- ((PC.T (BM.T Real), Real),- (PC.T Real, PC.T Real),- (Real, SigSt.T Vector, SigSt.T Vector))) =>- (Triple VectorValue -> VectorValue) ->- Param p Real ->- CausalP p (Triple VectorValue, VectorValue) VectorValue- noise sel d =- (CausalP.envelope $< piecewiseConstantVector noiseAmp)- <<<- CausalP.envelope- <<<- (arr sel ***- ({- UniFilter.lowpass- ^<< -}- (CtrlPS.process- $> SigPS.noise 12 (noiseReference 20000))- <<<-{-- (CausalP.quantizeLift- $# (128 / fromIntegral vectorSize :: Real))- (CausalP.zipWithSimple UniFilterL.parameter)--}- (CausalP.quantizeLift- $# (128 / fromIntegral vectorSize :: Real))- (CausalP.zipWithSimple (MoogL.parameter TypeNum.d8))- <<<- CausalP.feedFst (piecewiseConstant noiseReson)- <<<- CausalP.mapSimple Serial.subsample- <<<- CausalPS.amplify d))- in liftA2 Stereo.cons- (sumNested- [osci fst3 0.6 (1*0.999),- osci snd3 (0.02 * 50^?vel) (4*0.999),- osci thd3 (0.02 * 100^?vel) (7*0.999),- noise fst3 0.999])- (sumNested- [osci fst3 0.6 (1*1.001),- osci snd3 (0.02 * 50^?vel) (4*1.001),- osci thd3 (0.02 * 100^?vel) (7*1.001),- noise fst3 1.001])- <<<- CausalP.feedSnd (frequencyFromBendModulation (frequencyConst 5) fm)- <<<- arr (\(e1,(e4,e7)) -> (e1,e4,e7))- $> {-- Be careful, those storable vectors shorten the whole sound- if they have shorter release than the main envelope.- -}- SigP.zip- (SigP.fromStorableVectorLazy env4)- (SigP.fromStorableVectorLazy env7)))- pingReleaseEnvelope---tine :: IO (Real -> Real -> SigSt.ChunkSize -> Instrument Real Vector)-tine =- liftA2- (\osc env dec rel vcsize sr vel freq dur ->- osc (sr, (vel,freq)) (env dec rel vcsize sr 0 dur))- (CausalP.runStorableChunky- (let freq = frequency snd- vel = number fst- in CausalP.envelope $>- (CausalPS.osciSimple WaveL.approxSine2- $> SigPS.constant freq- $* (CausalP.envelope- $< SigPS.exponential2 (timeConst 1) (vel+1)- $* SigPS.osciSimple WaveL.approxSine2 zero- (2*freq)))))- pingReleaseEnvelope--tineStereo ::- IO (Real -> Real -> SigSt.ChunkSize -> Instrument Real (Stereo.T Vector))-tineStereo =- liftA2- (\osc env dec rel vcsize sr vel freq dur ->- osc (sr, (vel,freq)) (env dec rel vcsize sr 0 dur))- (CausalP.runStorableChunky- (let freq = frequency snd- vel = number fst- chanOsci d =- CausalPS.osciSimple WaveL.approxSine2- $> SigPS.constant (freq*d)- in CausalP.envelopeStereo $>- (liftA2 Stereo.cons- (chanOsci 0.995) (chanOsci 1.005)- $* SigP.envelope- (SigPS.exponential2 (timeConst 1) (vel+1))- (SigPS.osciSimple WaveL.approxSine2 zero- (2*freq)))))- pingReleaseEnvelope---softStringReleaseEnvelope ::- IO (Real -> SampleRate Real -> Real -> Ev.LazyTime -> SigSt.T Vector)-softStringReleaseEnvelope =- liftA2- (\rev env attackTime sr vel dur ->- let attackTimeVector =- round (attackTime * vectorRate sr)- {-- release <- take attackTime beginning- would yield a space leak, thus we first split 'beginning'- and then concatenate it again- -}- {-- We can not easily generate attack and sustain separately,- because we want to use the chunk structure implied by 'dur'.- -}- (attack, sustain) =- SigSt.splitAt attackTimeVector $- env (chunkSizesFromLazyTime dur)- (sr, (amplitudeFromVelocity vel, attackTimeVector))- release = rev attack- in attack `SigSt.append` sustain `SigSt.append` release)- SigStL.makeReversePacked- (let amp = number fst- attackTimeVector = parameter snd- in SigP.runChunkyPattern $- flip SigP.append (SigPS.constant amp) $- (CausalPS.amplify amp <<<- CausalP.take attackTimeVector- $* SigPS.parabolaFadeInInf- (fmap (fromIntegral . (vectorSize*)) attackTimeVector)))--softString :: IO (Instrument Real (Stereo.T Vector))-softString =- liftA2- (\osc env sr vel freq dur ->- osc (sr, freq) (env 1 sr vel dur))- (let freq = frequency id- osci d = SigPS.osciSimple WaveL.saw zero (d * freq)- in CausalP.runStorableChunky $- (CausalP.envelopeStereo $>- (liftA2 Stereo.cons- (osci 1.005 + osci 0.998)- (osci 1.002 + osci 0.995))))- softStringReleaseEnvelope---softStringFM :: IO (PC.T (BM.T Real) -> Instrument Real (Stereo.T Vector))-softStringFM =- liftA2- (\osc env fm sr vel freq dur ->- osc (sr, (fm,freq)) (env 1 sr vel dur))- (let fm = modulation id- osci ::- Param.T fm Real ->- CausalP.T fm VectorValue VectorValue- osci d =- (CausalPS.osciSimple WaveL.saw $< zero) <<<- CausalPS.amplify d- in CausalP.runStorableChunky $- (CausalP.envelopeStereo $>- (liftA2 Stereo.cons- (osci 1.005 + osci 0.998)- (osci 1.002 + osci 0.995)- $* frequencyFromBendModulation (frequencyConst 5) fm)))- softStringReleaseEnvelope---tineStereoFM ::- IO (Real -> Real ->- SigSt.ChunkSize ->- PC.T (BM.T Real) ->- Instrument Real (Stereo.T Vector))-tineStereoFM =- liftA2- (\osc env dec rel vcsize fm sr vel freq dur ->- osc (sr, (vel,(fm,freq))) (env dec rel vcsize sr 0 dur))- (CausalP.runStorableChunky- (let vel = number fst- fm = modulation snd- chanOsci d =- CausalPS.osciSimple WaveL.approxSine2- <<< second (CausalPS.amplify d)- in CausalP.envelopeStereo $>- (liftA2 Stereo.cons- (chanOsci 0.995) (chanOsci 1.005)- <<<- (((CausalP.envelope- $< SigPS.exponential2 (timeConst 1) (vel+1))- <<< (CausalPS.osciSimple WaveL.approxSine2 $< zero)- <<< CausalPS.amplify 2)- &&& id)- $* frequencyFromBendModulation (frequencyConst 5) fm)))- pingReleaseEnvelope---_tineControlledProc, tineControlledFnProc ::- Param p (PC.T Real) ->- Param p (PC.T Real) ->- Param p Real ->- CausalP p- (Stereo.T VectorValue)- (Stereo.T VectorValue)-_tineControlledProc index depth vel =- CausalP.stereoFromMono- (CausalPS.osciSimple WaveL.approxSine2)- <<<- Stereo.interleave- ^<<- ((CausalP.envelopeStereo- $< SigP.envelope- (piecewiseConstantVector depth)- (SigPS.exponential2 (timeConst 1) (vel+1)))- <<<- CausalP.stereoFromMono- (CausalPS.osciSimple WaveL.approxSine2 $< zero)- <<<- (CausalP.envelopeStereo- $< piecewiseConstantVector index))- &&& id--tineControlledFnProc index depth vel =- F.withGuidedArgs F.atom $ \freq ->- CausalP.stereoFromMono- (CausalPS.osciSimple WaveL.approxSine2)- $&- liftA2 (liftA2 (,))- ((CausalP.envelopeStereo- $< SigP.envelope- (piecewiseConstantVector depth)- (SigPS.exponential2 (timeConst 1) (vel+1)))- <<<- CausalP.stereoFromMono- (CausalPS.osciSimple WaveL.approxSine2 $< zero)- <<<- (CausalP.envelopeStereo- $< piecewiseConstantVector index)- $&- freq)- freq--tineControlledFM ::- IO (Real -> Real ->- PC.T Real ->- PC.T Real -> PC.T Real ->- SigSt.ChunkSize ->- PC.T (BM.T Real) ->- Instrument Real (Stereo.T Vector))-tineControlledFM =- liftA2- (\osc env dec rel detune index depth vcsize fm sr vel freq dur ->- osc- (sr, ((index, depth), vel, (detune,fm,freq)))- (env dec rel vcsize sr 0 dur))- (CausalP.runStorableChunky $- ParamS.withTuple2 $- \((Control index, Control depth), Number vel, DetuneModulation fm) ->- CausalP.envelopeStereo $>- (tineControlledFnProc index depth vel $*- stereoFrequenciesFromDetuneBendModulation (frequencyConst 5) fm))- pingReleaseEnvelope---fenderProc ::- Param p (PC.T Real) ->- Param p (PC.T Real) ->- Param p (PC.T Real) ->- Param p Real ->- CausalP p- (Stereo.T VectorValue)- (Stereo.T VectorValue)-fenderProc fade index depth vel =- F.withGuidedArgs F.atom $ \stereoFreq ->- let {-- channel_n_1 ::- FuncP p VectorValue VectorValue ->- FuncP p VectorValue VectorValue- -}- channel_n_1 freq =- CausalPS.osciSimple WaveL.approxSine2- $&- ((CausalP.envelope- $< SigP.envelope- (piecewiseConstantVector depth)- (SigPS.exponential2 (timeConst 1) (vel+1)))- <<<- (CausalPS.osciSimple WaveL.approxSine2 $< zero)- <<<- (CausalP.envelope- $< piecewiseConstantVector index)- $&- freq)- &|&- freq- {-- channel_1_2 ::- FuncP p VectorValue VectorValue ->- FuncP p VectorValue VectorValue- -}- channel_1_2 freq =- CausalPS.osciSimple WaveL.approxSine2- $&- ((CausalP.envelope- $< SigP.envelope- (piecewiseConstantVector depth)- (SigPS.exponential2 (timeConst 1) (vel+1)))- <<<- (CausalPS.osciSimple WaveL.approxSine2 $< zero)- $&- freq)- &|&- (CausalPS.amplify 2 $& freq)- in (CausalP.stereoFromMonoControlled- (fadeProcess- (F.compile $ channel_n_1 $ F.lift id)- (F.compile $ channel_1_2 $ F.lift id))- $< piecewiseConstantVector fade)- $&- stereoFreq--fenderFM ::- IO (Real -> Real ->- PC.T Real ->- PC.T Real -> PC.T Real -> PC.T Real ->- SigSt.ChunkSize ->- PC.T (BM.T Real) ->- Instrument Real (Stereo.T Vector))-fenderFM =- liftA2- (\osc env dec rel detune index depth fade vcsize fm sr vel freq dur ->- osc- (sr, (((index, depth), fade), vel, (detune,fm,freq)))- (env dec rel vcsize sr 0 dur))- (CausalP.runStorableChunky $- ParamS.withTuple2 $- \(((Control index, Control depth), Control fade),- Number vel, DetuneModulation fm) ->- CausalP.envelopeStereo $>- (fenderProc fade index depth vel $*- stereoFrequenciesFromDetuneBendModulation (frequencyConst 5) fm))- pingReleaseEnvelope---fmModulator ::- Param p Real ->- Param p Real ->- Param p (PC.T Real) ->- CausalP p- (Stereo.T VectorValue)- (Stereo.T VectorValue)-fmModulator vel n depth =- (CausalP.envelopeStereo- $< SigP.envelope- (piecewiseConstantVector depth)- (SigPS.exponential2 (timeConst 1) (vel+1)))- <<<- CausalP.stereoFromMono- (CausalPS.osciSimple WaveL.approxSine2 $< zero)- <<<- CausalPS.amplifyStereo n--tineModulatorBankFM ::- IO (Real -> Real ->- PC.T Real ->- PC.T Real -> PC.T Real -> PC.T Real -> PC.T Real ->- SigSt.ChunkSize ->- PC.T (BM.T Real) ->- Instrument Real (Stereo.T Vector))-tineModulatorBankFM =- liftA2- (\osc env- dec rel detune- depth1 depth2 depth3 depth4- vcsize fm sr vel freq dur ->- osc- (sr, ((depth1,(depth2,(depth3,(depth4)))), vel, (detune,fm,freq)))- (env dec rel vcsize sr 0 dur))- (CausalP.runStorableChunky $- ParamS.withTuple2 $- \((Control depth1, (Control depth2, (Control depth3, Control depth4))),- Number vel, DetuneModulation fm) ->- (CausalP.envelopeStereo $>- (CausalP.stereoFromMono- (CausalPS.osciSimple WaveL.approxSine2)- <<<- Stereo.interleave- ^<<- sumNested- [fmModulator vel 1 depth1,- fmModulator vel 2 depth2,- fmModulator vel 3 depth3,- fmModulator vel 4 depth4]- &&& id- $*- stereoFrequenciesFromDetuneBendModulation (frequencyConst 5) fm)))- pingReleaseEnvelope--tineBankFM ::- IO (Real -> Real ->- PC.T Real ->- PC.T Real -> PC.T Real -> PC.T Real -> PC.T Real ->- PC.T Real -> PC.T Real -> PC.T Real -> PC.T Real ->- SigSt.ChunkSize ->- PC.T (BM.T Real) ->- Instrument Real (Stereo.T Vector))-tineBankFM =- liftA2- (\osc env- dec rel detune- depth1 depth2 depth3 depth4- partial1 partial2 partial3 partial4- vcsize fm sr vel freq dur ->- osc- (sr,- ((depth1,(depth2,(depth3,(depth4)))),- (partial1,(partial2,(partial3,(partial4)))),- (vel, (detune,fm,freq))))- (env dec rel vcsize sr 0 dur))- (CausalP.runStorableChunky $- ParamS.withTuple2 $- \((Control depth1, (Control depth2, (Control depth3, Control depth4))),- (Control partial1,(Control partial2, (Control partial3, Control partial4))),- (Number vel, DetuneModulation fm)) ->-- (let partial ::- VectorValue -> Int -> VectorValue ->- LLVM.CodeGenFunction r VectorValue- partial amp n t =- A.mul amp =<<- WaveL.partial WaveL.approxSine2 n t- in CausalP.envelopeStereo $>- (CausalP.stereoFromMono- (CausalPS.shapeModOsci- (\(p1,(p2,(p3,p4))) t -> do- y1 <- A.mul p1 =<< WaveL.approxSine2 t- y2 <- partial p2 2 t- y3 <- partial p3 3 t- y4 <- partial p4 4 t- A.add y1 =<< A.add y2 =<< A.add y3 y4)- $<- (SigP.zip (piecewiseConstantVector partial1) $- SigP.zip (piecewiseConstantVector partial2) $- SigP.zip (piecewiseConstantVector partial3)- (piecewiseConstantVector partial4)))- <<<- Stereo.interleave- ^<<- sumNested- [fmModulator vel 1 depth1,- fmModulator vel 2 depth2,- fmModulator vel 3 depth3,- fmModulator vel 4 depth4]- &&& id- $*- stereoFrequenciesFromDetuneBendModulation (frequencyConst 5) fm)))- pingReleaseEnvelope---{- |-FM synthesis where the modulator is a resonantly filtered sawtooth.-This way we get a sinus-like modulator where the sine frequency-(that is, something like the modulation index) can be controlled continously.--}-resonantFMSynthProc ::- Param p (PC.T Real) ->- Param p (PC.T Real) ->- Param p (PC.T Real) ->- Param p Real ->- CausalP p- (Stereo.T VectorValue)- (Stereo.T VectorValue)-resonantFMSynthProc reson index depth vel =- F.withGuidedArgs (Stereo.cons F.atom F.atom) $ \stereoFreq ->- let -- chan :: FuncP p inp VectorValue -> FuncP p inp VectorValue- chan freq =- CausalPS.osciSimple WaveL.approxSine2- $&- ((CausalP.envelope- $< SigP.envelope- (piecewiseConstantVector depth)- (SigPS.exponential2 (timeConst 1) (vel+1)))- <<<- UniFilter.lowpass- ^<<- CtrlPS.process- $&- (CausalP.zipWithSimple UniFilterL.parameter- <<<- CausalP.feedFst (piecewiseConstant reson)- <<<- (CausalP.envelope $< piecewiseConstant index)- <<<- CausalP.mapSimple Serial.subsample- $&- freq)- &|&- ((CausalPS.osciSimple WaveL.saw $< zero)- $&- freq))- &|&- freq- in Trav.traverse chan stereoFreq--resonantFMSynth ::- IO (Real -> Real ->- PC.T Real ->- PC.T Real -> PC.T Real -> PC.T Real ->- SigSt.ChunkSize ->- PC.T (BM.T Real) ->- Instrument Real (Stereo.T Vector))-resonantFMSynth =- liftA2- (\osc env dec rel detune reson index depth vcsize fm sr vel freq dur ->- osc- (sr, ((reson, index, depth), vel, (detune,fm,freq)))- (env dec rel vcsize sr 0 dur))- (CausalP.runStorableChunky $- ParamS.withTuple2 $- \((Control reson, Control index, Control depth),- Number vel, DetuneModulation fm) ->- CausalP.envelopeStereo $>- (resonantFMSynthProc reson index depth vel $*- stereoFrequenciesFromDetuneBendModulation (frequencyConst 5) fm))- pingReleaseEnvelope---phaserOsci ::- (Param.T p Real -> CausalP.T p a VectorValue) ->- CausalP.T p a (Stereo.T VectorValue)-phaserOsci osci =- CausalPS.amplifyStereo 0.25- <<<- liftA2 Stereo.cons- (sumNested $ map osci [1.0, -0.4, 0.5, -0.7])- (sumNested $ map osci [0.4, -1.0, 0.7, -0.5])---softStringDetuneFM ::- IO (Real ->- PC.T Real ->- PC.T (BM.T Real) ->- Instrument Real (Stereo.T Vector))-softStringDetuneFM =- liftA2- (\osc env att det fm sr vel freq dur ->- osc (sr, (det, (fm,freq))) (env att sr vel dur))- (let det = control fst- fm = modulation snd- osci ::- Param.T (det,fm) Real ->- CausalP.T (det,fm)- (VectorValue, VectorValue)- VectorValue- osci d =- (CausalPS.osciSimple WaveL.saw $< zero)- <<<- CausalP.envelope- <<<- first (one + CausalPS.amplify d)- in CausalP.runStorableChunky $- (CausalP.envelopeStereo $>- (phaserOsci osci- <<<- CausalP.feedFst (piecewiseConstantVector det)- $* frequencyFromBendModulation (frequencyConst 5) fm)))- softStringReleaseEnvelope--{--We might decouple the frequency of the enveloped tone-from the frequency of the envelope,-in order to get something like formants.--}-softStringShapeFM, cosineStringStereoFM,- arcSineStringStereoFM, arcTriangleStringStereoFM,- arcSquareStringStereoFM, arcSawStringStereoFM ::- IO (Real ->- PC.T Real ->- PC.T Real ->- PC.T (BM.T Real) ->- Instrument Real (Stereo.T Vector))-softStringShapeFM =- softStringShapeCore WaveL.rationalApproxSine1-cosineStringStereoFM =- softStringShapeCore- (\k p -> WaveL.approxSine2 =<< WaveL.replicate k p)-arcSawStringStereoFM = arcStringStereoFM WaveL.saw-arcSineStringStereoFM = arcStringStereoFM WaveL.approxSine2-arcSquareStringStereoFM = arcStringStereoFM WaveL.square-arcTriangleStringStereoFM = arcStringStereoFM WaveL.triangle--arcStringStereoFM ::- (forall r.- VectorValue ->- LLVM.CodeGenFunction r VectorValue) ->- IO (Real ->- PC.T Real ->- PC.T Real ->- PC.T (BM.T Real) ->- Instrument Real (Stereo.T Vector))-arcStringStereoFM wave =- softStringShapeCore- (\k p ->- M.liftJoin2 Frame.amplifyMono- (WaveL.approxSine4 =<< WaveL.halfEnvelope p)- (wave =<< WaveL.replicate k p))--softStringShapeCore ::- (forall r.- VectorValue ->- VectorValue ->- LLVM.CodeGenFunction r VectorValue) ->- IO (Real ->- PC.T Real ->- PC.T Real ->- PC.T (BM.T Real) ->- Instrument Real (Stereo.T Vector))-softStringShapeCore wave =- liftA2- (\osc env att det dist fm sr vel freq dur ->- osc (sr, ((det, dist), (fm,freq))) (env att sr vel dur))- (let det = control (fst.fst)- dist = control (snd.fst)- fm = modulation snd- osci ::- Param.T (mod,fm) Real ->- CausalP.T (mod,fm)- (VectorValue,- {- wave shape parameter -}- (VectorValue, VectorValue)- {- detune, frequency modulation -})- VectorValue- osci d =- CausalPS.shapeModOsci wave- <<<- second- (CausalP.feedFst zero- <<<- CausalP.envelope- <<<- first (one + CausalPS.amplify d))- in CausalP.runStorableChunky $- (CausalP.envelopeStereo $>- (phaserOsci osci- $< piecewiseConstantVector dist- $< piecewiseConstantVector det- $* frequencyFromBendModulation (frequencyConst 5) fm)))- softStringReleaseEnvelope--fmStringStereoFM ::- IO (Real ->- PC.T Real ->- PC.T Real ->- PC.T Real ->- PC.T (BM.T Real) ->- Instrument Real (Stereo.T Vector))-fmStringStereoFM =- liftA2- (\osc env att det depth dist fm sr vel freq dur ->- osc (sr, ((det, depth, dist), (fm, freq))) (env att sr vel dur))- (let det = control (fst3.fst)- depth = control (snd3.fst)- dist = control (thd3.fst)- fm = modulation snd- osci ::- Param.T (mod,fm) Real ->- CausalP.T (mod,fm)- ((VectorValue, VectorValue)- {- phase modulation depth, modulator distortion -},- (VectorValue, VectorValue)- {- detune, frequency modulation -})- VectorValue- osci d =- CausalPS.osciSimple WaveL.approxSine2- <<<- (CausalP.envelope- <<<- second- (CausalPS.shapeModOsci WaveL.rationalApproxSine1- <<< second (CausalP.feedFst zero))- <<^- (\((dp, ds), f) -> (dp, (ds, f))))- &&& arr snd- <<<- second- (CausalP.envelope <<<- first (one + CausalPS.amplify d))- in CausalP.runStorableChunky- (CausalP.envelopeStereo <<<- (id &&&- (phaserOsci osci- <<<- CausalP.feedSnd- (SigP.zip- (piecewiseConstantVector det)- (frequencyFromBendModulation (frequencyConst 5) fm))- <<<- CausalP.feedSnd (piecewiseConstantVector dist)- <<<- (CausalP.envelope- $< piecewiseConstantVector depth)))))- softStringReleaseEnvelope---stereoNoise :: SigP p (Stereo.T VectorValue)-stereoNoise =- traverse- (\uid -> SigPS.noise uid (noiseReference 20000))- (Stereo.cons 13 14)--windCore ::- Param p (PC.T Real) ->- Param p (PC.T (BM.T Real)) ->- SigP p (Stereo.T VectorValue)-windCore reson fm =- CausalP.stereoFromMonoControlled CtrlPS.process- $< Sig.zipWith- (MoogL.parameter TypeNum.d8)- (piecewiseConstant reson)- (Sig.map Serial.subsample- (frequencyFromBendModulation (frequencyConst 0.2) fm))- $* stereoNoise--wind ::- IO (Real ->- PC.T Real ->- PC.T (BM.T Real) ->- Instrument Real (Stereo.T Vector))-wind =- liftA2- (\osc env att reson fm sr vel freq dur ->- osc (sr, (reson, (fm,freq))) (env att sr vel dur))- (let reson = control fst- fm = modulation snd- in CausalP.runStorableChunky $- (CausalP.envelopeStereo $> windCore reson fm))- softStringReleaseEnvelope---fadeProcess ::- (A.PseudoRing v, A.IntegerConstant v) =>- CausalP.T p a v ->- CausalP.T p a v ->- CausalP.T p (v, a) v-fadeProcess proc0 proc1 =- let k = arr fst- a0 = proc0 <<^ snd- a1 = proc1 <<^ snd- in (one-k)*a0 + k*a1---windPhaser ::- IO (Real ->- PC.T Real ->- PC.T Real ->- PC.T Real ->- PC.T (BM.T Real) ->- Instrument Real (Stereo.T Vector))-windPhaser =- liftA2- (\osc env att phaserMix phaserFreq reson fm sr vel freq dur ->- osc (sr, ((phaserMix,phaserFreq), reson, (fm,freq))) (env att sr vel dur))- (let phaserMix = control (fst.fst3)- phaserFreq = frequencyControl (snd.fst3)- reson = control snd3- fm = modulation thd3- in CausalP.runStorableChunky $- (CausalP.envelopeStereo $>- ((CausalP.stereoFromMonoControlled- (fadeProcess (arr snd) CtrlPS.process- <<<- first (CausalP.mapSimple Serial.upsample)- <<^- (\((k,p),x) -> (k,(p,x))))- $< SigP.zip- (piecewiseConstant phaserMix)- (piecewiseConstant- (fmap (Allpass.flangerParameterPlain TypeNum.d8)- ^<< phaserFreq)))- $*- windCore reson fm)))- softStringReleaseEnvelope---filterSawStereoFM ::- IO (Real -> Real ->- PC.T Real ->- Real -> Real ->- SigSt.ChunkSize ->- PC.T (BM.T Real) ->- Instrument Real (Stereo.T Vector))-filterSawStereoFM =- liftA2- (\osc env dec rel detune bright brightDecay vcsize fm sr vel freq dur ->- osc- (sr, ((bright, brightDecay), (detune,fm,freq)))- (env dec rel vcsize sr vel dur))- (CausalP.runStorableChunky- (let bright = frequency (fst.fst)- brightDec = time (snd.fst)- fm = detuneModulation snd- in CausalP.envelopeStereo $>- (CausalP.stereoFromMono- (UniFilter.lowpass- ^<<- (CtrlPS.processCtrlRate $# (100::Real))- (\k -> Sig.map- (UniFilterL.parameter (LLVM.valueOf 10))- {- bound control in order to avoid too low resonant frequency,- which makes the filter instable -}- (SigP.exponentialBounded2- (frequencyConst 100)- (brightDec/k)- (bright)))- <<<- CausalPS.osciSimple WaveL.saw $< zero)- $* stereoFrequenciesFromDetuneBendModulation (frequencyConst 10) fm)))- pingReleaseEnvelope---{- |-The ADSR curve is composed from three parts:-Attack, Decay(+Sustain), Release.-Attack starts when the key is pressed-and lasts attackTime seconds-where it reaches height attackPeak*amplitudeOfVelocity.-It should be attackPeak>1 because in the following phase-we want to approach 1 from above.-Say the curve would approach the limit value L-if it would continue after the end of the attack phase,-the slope is determined by the halfLife with respect to this upper bound.-That is, attackHalfLife is the time in seconds where the attack curve-reaches or would reach L/2.-After Attack the Decay part starts at the same level-and decays to amplitudeOfVelocity.-The slope is again a halfLife,-that is, decayHalfLife is the time where the curve-drops from attackPeak*amplitudeOfVelocity to (attackPeak+1)/2*amplitudeOfVelocity.-This phase lasts as long as the key is pressed.-If the key is released the curve decays with half life releaseHalfLife.--}-{--1 - 2^(-attackTime/attackHalfLife) = peak--}-adsr ::- IO (Real -> Real -> Real ->- Real -> Real ->- SigSt.ChunkSize ->- SampleRate Real -> Real -> Ev.LazyTime -> SigSt.T Vector)-adsr =- liftA3- (\attack decay release- attackTime attackPeak attackHalfLife- decayHalfLife releaseHalfLife vcsize sr vel dur ->- let amp = amplitudeFromVelocity vel- (attackDur, decayDur) =- CutG.splitAt (round (attackTime * vectorRate sr)) dur- in SigStL.continuePacked- (attack (chunkSizesFromLazyTime attackDur)- (sr,- (attackHalfLife,- attackPeak * amp / (1 - 2^?(-attackTime/attackHalfLife))))- `SigSt.append`- decay (chunkSizesFromLazyTime decayDur)- (sr,- (decayHalfLife,- ((attackPeak-1)*amp, amp))))- (\x -> release vcsize (sr,(releaseHalfLife,x))))- (SigP.runChunkyPattern $- let halfLife = time fst- amplitude = number snd- in SigPS.constant amplitude -- SigPS.exponential2 halfLife amplitude)- (SigP.runChunkyPattern $- let halfLife = time fst- amplitude = number (fst.snd)- saturation = number (snd.snd)- in SigPS.constant saturation +- SigPS.exponential2 halfLife amplitude)- (SigP.runChunky $- let releaseTime = vectorTime fst * 5- releaseHL = time fst- amplitude = number snd- in CausalP.take (round ^<< releaseTime) $*- SigPS.exponential2 releaseHL amplitude)--brass ::- IO (Real -> Real ->- Real -> Real -> Real -> Real ->- PC.T Real ->- PC.T Real ->- SigSt.ChunkSize ->- PC.T (BM.T Real) ->- Instrument Real (Stereo.T Vector))-brass =- liftA2- (\osc env attTime attPeak attHL dec rel emph det dist vcsize fm sr vel freq dur ->- osc- (sr,- ((det, dist), (fm,freq),- env attTime emph attHL dec rel vcsize sr vel dur))- (env attTime attPeak attHL dec rel vcsize sr vel dur))- (let det = control (fst.fst3)- dist = control (snd.fst3)- fm = modulation snd3- emph = signal thd3- osci ::- Param.T p Real ->- CausalP.T p- (VectorValue,- {- wave shrink/replication factor -}- (VectorValue, VectorValue)- {- detune, frequency modulation -})- VectorValue- osci d =- CausalPS.shapeModOsci WaveL.rationalApproxSine1- <<<- second- (CausalP.feedFst zero- <<<- CausalP.envelope- <<<- first (one + CausalPS.amplify d))- in CausalP.runStorableChunky $- (CausalP.envelopeStereo $>- (phaserOsci osci- <<<- CausalP.feedFst (piecewiseConstantVector dist)- <<<- CausalP.feedSnd (frequencyFromBendModulation (frequencyConst 5) fm)- <<<- (CausalP.envelope $< piecewiseConstantVector det)- $*- SigP.fromStorableVectorLazy emph)))- adsr---sampledSound ::- IO (Sample.T ->- PC.T (BM.T Real) ->- Instrument Real (Stereo.T Vector))-sampledSound =- liftA2- (\osc freqMod smp fm sr vel freq dur ->- {-- We split the frequency modulation signal- in order to get a smooth frequency modulation curve.- Without (periodic) frequency modulation- we could just split the piecewise constant control curve @fm@.- -}- let fmSig =- freqMod- (chunkSizesFromLazyTime (PC.duration fm))- (sr, (fm, freq * Sample.period pos)) :: SigSt.T Vector- pos = Sample.positions smp- amp = 2 * amplitudeFromVelocity vel- (attack, sustain, release) = Sample.parts smp- in (\cont -> osc cont- (sr,- (amp,- attack `SigSt.append`- SVL.cycle (SigSt.take (Sample.loopLength pos) sustain),- chunkSizesFromLazyTime dur))- fmSig)- (osc (const SigSt.empty)- (sr, (amp, release, NonNegChunky.fromChunks (repeat 1000)))))- (CausalP.runStorableChunkyCont- (let amp = number fst3- smp = signal snd3- dur = parameter thd3- in CausalPS.amplifyStereo amp- <<<- CausalP.stereoFromMono- (CausalPS.pack- (CausalP.frequencyModulationLinear- (SigP.fromStorableVectorLazy smp)))- <<<- liftA2 Stereo.cons- (CausalPS.amplify 0.999)- (CausalPS.amplify 1.001)- <<<- arr fst- <<<- CausalP.feedSnd (SigP.lazySize dur)))- (SigP.runChunkyPattern- (frequencyFromBendModulation (frequencyConst 3) (modulation id)))---_sampledSoundLeaky ::- IO (Sample.T ->- PC.T (BM.T Real) ->- Instrument Real (Stereo.T Vector))-_sampledSoundLeaky =- liftA2- (\osc freqMod smp fm sr vel freq dur ->- {-- We split the frequency modulation signal- in order to get a smooth frequency modulation curve.- Without (periodic) frequency modulation- we could just split the piecewise constant control curve @fm@.- -}- let (sustainFM, releaseFM) =- SVP.splitAt (chunkSizesFromLazyTime dur) $- (freqMod- (chunkSizesFromLazyTime (PC.duration fm))- (sr, (fm, freq * Sample.period pos)) :: SigSt.T Vector)- pos = Sample.positions smp- amp = 2 * amplitudeFromVelocity vel- (attack, sustain, release) = Sample.parts smp- in osc- (sr,- (amp,- attack `SigSt.append`- SVL.cycle (SigSt.take (Sample.loopLength pos) sustain)))- sustainFM- `SigSt.append`- osc (sr, (amp,release)) releaseFM)- (CausalP.runStorableChunky- (let smp = signal snd- amp = number fst- in CausalPS.amplifyStereo amp- <<<- CausalP.stereoFromMono- (CausalPS.pack- (CausalP.frequencyModulationLinear- (SigP.fromStorableVectorLazy smp)))- <<<- liftA2 Stereo.cons- (CausalPS.amplify 0.999)- (CausalPS.amplify 1.001)))- (SigP.runChunkyPattern- (frequencyFromBendModulation (frequencyConst 3) (modulation id)))+ tonal noise can be produced by modulating pink noise+ experimental: multiply with waveforms other than sine+ use bits of an ASCII code as waveform+ use a greymap picture as source of waveforms+ mix of detuned noisy-waverforms, try different and uniform waveforms+ mix of sawtooth, where every sawtooth is modulated with red noise+ mix of sine with harmonics where every harmonic is modulated differently+ Flute: sine + filtered noise+ Drum with various parameters+ derive percussive instruments from fmString and arcString (for bass synths)+ an FM sound with a slowly changing timbre+ by using a very slightly detuned frequency for the modulator+ making a tone out of noise using time stretch with helix algorithm+ a chorus effect could be applied by two successive helix stretches+ or by mixture of two stretches signals+ additionally a resonant filter could be applied+ a kind of Karplus-Strong algorithm with a non-linear function of past values+ e.g. y(t) = f(y(t-d), y(t-2*d))+ where d is the tone period and f is non-linear, maybe chaotic function.+ In order to limit the appearance of chaotic waveforms,+ we could combine this with a lowpass filter.+ let attack and release depend on On and Off velocity+ tineStereoFM:+ continuous control of the modulation index+ by linear interpolation of waves between modulations with integral indices.+ E.g. modulation index 2.3 means+ 0.7*modulation with index 2 and 0.3*modulation with index 3.++effects:+ reverb and controllable delay+ phaser or Chebyshev filter+ reverb where many single combs are mixed+ every comb has ever-increasing frequency, but is faded in and out.+ Should give an endless effect where the reverb becomes higher and higher.++continuous sounds:+ fly+ water/bubbles+ when I accidentally did not scale filter frequency with sample rate,+ the filter sound much like water bubbles.+ I think a control curve consisting of some ramps will do the same.+ hail, Geiger counter, pitch applied by comb filter+ at a very high impulse rate the impulses itself+ can generate an almost periodic signal+++Speech sounds improvements (tomatensalat)+ use PSOLA for transposition+ To this end divide signal into tonal part and residue (noise)+ by a comb filter.+ Maybe a non-linear comb filter may help,+ that selects the center value from the filter window,+ if the side values are similar+ and returns zero, if the the side values differ too much.+ Process the tonal part by PSOLA and+ simply mix it with the non-tonal part on replay.++Harmonizer-like:+ We like to input an audio signal of speech+ and a set of keys, and the speech is extended to chords+ according to the pressed keys.+ The lowest key is interpreted as base frequency of the input audio speech.+ A PSOLA method transposes the audio input.++Resonant filter controlled by keys+ applied to an audio input signal+ or an ordinary audio signal generated by other keys.+ The splitting of keys however could be performed+ by a MIDI event stream editor.+-}++{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE EmptyDataDecls #-}+module Synthesizer.LLVM.Server.Packed.Instrument (+ InputArg(..),+ FrequencyControl,+ Modulation,+ DetuneModulation,++ pingRelease,+ pingStereoRelease,+ pingStereoReleaseFM,+ squareStereoReleaseFM,+ bellStereoFM,+ bellNoiseStereoFM,+ tine,+ tineStereo,+ softString,+ softStringFM,+ tineStereoFM,+ tineControlledFM,+ fenderFM,+ tineModulatorBankFM,+ tineBankFM,+ resonantFMSynth,+ softStringDetuneFM,+ softStringShapeFM, cosineStringStereoFM,+ arcSineStringStereoFM, arcTriangleStringStereoFM,+ arcSquareStringStereoFM, arcSawStringStereoFM,+ fmStringStereoFM,+ wind,+ windPhaser,+ filterSawStereoFM,+ brass,+ sampledSound,++ -- * helper functions+ stereoNoise,+ frequencyFromBendModulation,+ piecewiseConstantVector,++ -- * for testing+ pingReleaseEnvelope,+ adsr,+ ) where++import Synthesizer.LLVM.Server.CommonPacked+import Synthesizer.LLVM.Server.Common++import qualified Synthesizer.LLVM.Server.SampledSound as Sample+import qualified Synthesizer.LLVM.MIDI.BendModulation as BM+import qualified Synthesizer.LLVM.ConstantPiece as Const+import qualified Synthesizer.MIDI.PiecewiseConstant as PC+import qualified Synthesizer.MIDI.EventList as Ev++import Synthesizer.MIDI.Storable (chunkSizesFromLazyTime)++import qualified Synthesizer.LLVM.Frame.Stereo as Stereo+import qualified Synthesizer.LLVM.Filter.Universal as UniFilterL+import qualified Synthesizer.LLVM.Filter.Allpass as Allpass+import qualified Synthesizer.LLVM.Filter.Moog as MoogL+import qualified Synthesizer.LLVM.MIDI as MIDIL+import qualified Synthesizer.LLVM.Causal.Render as CausalRender+import qualified Synthesizer.LLVM.Causal.ControlledPacked as CtrlPS+import qualified Synthesizer.LLVM.Causal.ProcessPacked as CausalPS+import qualified Synthesizer.LLVM.Causal.Process as Causal+import qualified Synthesizer.LLVM.Causal.Functional as F+import qualified Synthesizer.LLVM.Generator.Render as Render+import qualified Synthesizer.LLVM.Generator.SignalPacked as SigPS+import qualified Synthesizer.LLVM.Generator.Signal as Sig+import qualified Synthesizer.LLVM.Storable.Signal as SigStL+import qualified Synthesizer.LLVM.Frame.SerialVector as Serial+import qualified Synthesizer.LLVM.Frame as Frame+import qualified Synthesizer.LLVM.Wave as WaveL+import Synthesizer.LLVM.Causal.Process (($<#), ($*), ($<), ($>))+import Synthesizer.LLVM.Causal.Functional (($&), (&|&))++import qualified LLVM.DSL.Expression as Expr+import qualified LLVM.Extra.Multi.Value as MultiValue+import LLVM.DSL.Expression (Exp)++import qualified LLVM.Extra.Arithmetic as A+import qualified LLVM.Core as LLVM+import qualified Type.Data.Num.Decimal as TypeNum++import qualified Synthesizer.Causal.Class as CausalClass+import qualified Synthesizer.Generic.Cut as CutG+import qualified Synthesizer.Storable.Signal as SigSt+import qualified Data.StorableVector.Lazy.Pattern as SVP+import qualified Data.StorableVector.Lazy as SVL++import qualified Synthesizer.Plain.Filter.Recursive.Universal as UniFilter++import qualified Control.Monad.HT as M+import Control.Arrow ((<<<), (^<<), (<<^), (&&&), (***), arr, first, second)+import Control.Category (id)+import Control.Applicative (liftA2, liftA3)++import qualified Data.Traversable as Trav+import Data.Traversable (traverse)+import Data.Semigroup ((<>))++import Data.Tuple.HT (fst3, snd3, thd3)++import qualified Numeric.NonNegative.Chunky as NonNegChunky++import qualified Algebra.Additive as Additive++import NumericPrelude.Numeric (zero, one, round, (^?), (+), (-), (*))+import Prelude hiding (Real, round, break, id, (+), (-), (*))++++frequencyControl ::+ (MultiValue.Field a, MultiValue.RationalConstant a) =>+ SampleRate (Exp a) ->+ Sig.T (Const.T (MultiValue.T a)) ->+ Sig.T (Const.T (MultiValue.T a))+frequencyControl sr xs = Const.causalMap (frequency sr) $* xs++data FrequencyControl a++instance+ (a ~ Exp b, MultiValue.Field b, MultiValue.RationalConstant b) =>+ Input (FrequencyControl b) a where+ data InputArg (FrequencyControl b) a =+ FrequencyControl (Sig.T (Const.T (MultiValue.T b)))+ type InputSource (FrequencyControl b) a =+ Sig.T (Const.T (MultiValue.T b))+ evalInput sampleRate =+ FrequencyControl . frequencyControl sampleRate+++modulation ::+ (MultiValue.Field a, MultiValue.RationalConstant a) =>+ SampleRate (Exp a) ->+ (Sig.T (Const.T (MultiValue.T (BM.T a))), Exp a) ->+ Sig.T (Const.T (BM.T (MultiValue.T a)))+modulation sr (fm,freq) =+ transposeModulation sr freq (fmap BM.unMultiValue <$> fm)++data Modulation a++instance+ (a ~ Exp b, MultiValue.Field b, MultiValue.RationalConstant b) =>+ Input (Modulation b) a where+ data InputArg (Modulation b) a =+ Modulation (Sig.T (Const.T (BM.T (MultiValue.T b))))+ type InputSource (Modulation b) a =+ (Sig.T (Const.T (MultiValue.T (BM.T b))), Exp b)+ evalInput sampleRate (fm,freq) =+ Modulation $ modulation sampleRate (fm,freq)+++detuneModulation ::+ (MultiValue.Field a, MultiValue.RationalConstant a) =>+ SampleRate (Exp a) ->+ (b, Sig.T (Const.T (MultiValue.T (BM.T a))), Exp a) ->+ (b, Sig.T (Const.T (BM.T (MultiValue.T a))))+detuneModulation sr (det,fm,freq) =+ (det, transposeModulation sr freq (fmap BM.unMultiValue <$> fm))++data DetuneModulation a++instance+ (a ~ Exp b, MultiValue.Field b, MultiValue.RationalConstant b) =>+ Input (DetuneModulation b) a where+ data InputArg (DetuneModulation b) a =+ DetuneModulation+ (Sig.T (Const.T (MultiValue.T b)),+ Sig.T (Const.T (BM.T (MultiValue.T b))))+ type InputSource (DetuneModulation b) a =+ (Sig.T (Const.T (MultiValue.T b)),+ Sig.T (Const.T (MultiValue.T (BM.T b))),+ Exp b)+ evalInput sampleRate (det,fm,freq) =+ DetuneModulation $ detuneModulation sampleRate (det,fm,freq)+++type RealValue = MultiValue.T Real++frequencyFromBendModulation ::+ Exp Real ->+ Sig.T (Const.T (BM.T RealValue)) ->+ Sig.T VectorValue+frequencyFromBendModulation speed fmFreq =+ MIDIL.frequencyFromBendModulationPacked speed $* piecewiseConstant fmFreq++stereoFrequenciesFromDetuneBendModulation ::+ Exp Real ->+ (Sig.T (Const.T RealValue), Sig.T (Const.T (BM.T RealValue))) ->+ Sig.T (Stereo.T VectorValue)+stereoFrequenciesFromDetuneBendModulation speed (det,fm) =+ (Causal.envelopeStereo $< frequencyFromBendModulation speed fm)+ <<<+ liftA2 Stereo.cons (one + id) (one - id)+ $* piecewiseConstantVector det++piecewiseConstantVector :: Sig.T (Const.T RealValue) -> Sig.T VectorValue+piecewiseConstantVector xs =+ piecewiseConstant (Const.causalMap Serial.upsample $* xs)++pingReleaseEnvelope ::+ IO (Real -> Real ->+ SigSt.ChunkSize ->+ SampleRate Real -> Real -> Ev.LazyTime -> SigSt.T Vector)+pingReleaseEnvelope =+ liftA2+ (\pressed release decay rel vcsize sr vel dur ->+ SigStL.continuePacked+ (pioApplyToLazyTime (pressed sr decay vel) dur)+ (\x -> release vcsize sr rel x))+ (CausalRender.run $+ wrapped $ \(Time decay) (Number velocity) (SampleRate _sr) ->+ Causal.fromSignal+ (SigPS.exponential2 decay (amplitudeFromVelocity velocity)))+ (Render.run $+ wrapped $ \(Time releaseHL) (Number amplitude) (SampleRate _sr) ->+ let releaseTime = releaseHL * 5 / fromIntegral vectorSize+ in Causal.take (Expr.roundToIntFast releaseTime) $*+ SigPS.exponential2 releaseHL amplitude)++pingRelease ::+ IO (Real -> Real -> SigSt.ChunkSize -> Instrument Real Vector)+pingRelease =+ liftA2+ (\osc env dec rel vcsize sr vel freq dur ->+ pioApply (osc sr freq) (env dec rel vcsize sr vel dur))+ (CausalRender.run $ wrapped $ \(Frequency freq) (SampleRate _sr) ->+ Causal.envelope $> SigPS.osci WaveL.saw zero freq)+ pingReleaseEnvelope++pingStereoRelease ::+ IO (Real -> Real -> SigSt.ChunkSize -> Instrument Real (Stereo.T Vector))+pingStereoRelease =+ liftA2+ (\osc env dec rel vcsize sr vel freq dur ->+ pioApply (osc sr freq) (env dec rel vcsize sr vel dur))+ (CausalRender.run $ wrapped $ \(Frequency freq) (SampleRate _sr) ->+ Stereo.multiValue <$>+ Causal.envelopeStereo $>+ liftA2 Stereo.cons+ (SigPS.osci WaveL.saw zero (0.999*freq))+ (SigPS.osci WaveL.saw zero (1.001*freq)))+ pingReleaseEnvelope++pingStereoReleaseFM ::+ IO (Real -> Real ->+ PC.T Real ->+ PC.T Real ->+ Real -> Real ->+ SigSt.ChunkSize ->+ PC.T (BM.T Real) ->+ Instrument Real (Stereo.T Vector))+pingStereoReleaseFM =+ liftA2+ (\osc env dec rel detune shape phase phaseDecay vcsize fm+ sr vel freq dur ->+ pioApply+ (osc sr (phase, phaseDecay) shape (detune, fm, freq))+ (env dec rel vcsize sr vel dur))+ (CausalRender.run $+ wrapped $+ \(Number phase, Time decay) (Control shape) (DetuneModulation fm) ->+ constant frequency 10 $ \speed _sr ->+ Stereo.multiValue <$>+ Causal.envelopeStereo $>+ ((Causal.stereoFromMonoControlled+ (CausalPS.shapeModOsci WaveL.rationalApproxSine1)+ $< piecewiseConstantVector shape)+ <<^ Stereo.interleave+ $< (liftA2 Stereo.cons id (Additive.negate id)+ $* SigPS.exponential2 decay phase)+ $* stereoFrequenciesFromDetuneBendModulation speed fm))+ pingReleaseEnvelope++{- |+Square like wave constructed as difference+of two phase shifted sawtooth like oscillations.+-}+squareStereoReleaseFM ::+ IO (Real -> Real ->+ PC.T Real ->+ PC.T Real ->+ PC.T Real ->+ SigSt.ChunkSize ->+ PC.T (BM.T Real) ->+ Instrument Real (Stereo.T Vector))+squareStereoReleaseFM =+ liftA2+ (\osc env dec rel detune shape phase vcsize fm sr vel freq dur ->+ pioApply+ (osc sr (phase, shape) (detune, fm, freq))+ (env dec rel vcsize sr vel dur))+ (CausalRender.run $+ wrapped $ \(Control phs, Control shp) (DetuneModulation fm) ->+ constant frequency 10 $ \speed _sr ->+ (let chanOsci ::+ Causal.T+ ((VectorValue, VectorValue), VectorValue)+ VectorValue+ chanOsci =+ ((CausalPS.shapeModOsci WaveL.rationalApproxSine1+ <<<+ second (first (Additive.negate id)))+ -+ CausalPS.shapeModOsci WaveL.rationalApproxSine1)+ <<^+ (\((p,s),f) -> (s,(p,f)))+ in Stereo.multiValue <$>+ Causal.envelopeStereo $>+ ((Causal.stereoFromMonoControlled chanOsci+ $< liftA2 (,)+ (piecewiseConstantVector phs)+ (piecewiseConstantVector shp))+ $* stereoFrequenciesFromDetuneBendModulation speed fm)))+ pingReleaseEnvelope+++type Triple a = (a, a, a)++bellStereoFM ::+ IO (Real -> Real ->+ PC.T Real ->+ SigSt.ChunkSize ->+ PC.T (BM.T Real) ->+ Instrument Real (Stereo.T Vector))+bellStereoFM =+ liftA2+ (\osc env dec rel detune vcsize fm sr vel freq dur ->+ pioApply+ (osc sr (detune, fm, freq) vel+ (env (dec/4) rel vcsize sr vel dur)+ (env (dec/7) rel vcsize sr vel dur))+ (env dec rel vcsize sr vel dur))+ (CausalRender.run $+ wrapped $+ \(DetuneModulation fm) (Number vel) (Signal env4) (Signal env7) ->+ constant frequency 5 $ \speed _sr ->+ (let osci ::+ (Triple VectorValue -> VectorValue) ->+ Exp Real ->+ Exp Real ->+ Causal.T+ (Triple VectorValue, Stereo.T VectorValue)+ (Stereo.T VectorValue)+ osci sel v d =+ Causal.envelopeStereo+ <<<+ (arr sel ***+ (CausalPS.amplifyStereo v+ <<<+ Causal.stereoFromMono+ (CausalPS.osci WaveL.approxSine4 $< zero)+ <<<+ CausalPS.amplifyStereo d))+ in Stereo.multiValue <$>+ sumNested+ [osci fst3 0.6 1,+ osci snd3 (0.02 * 50^?vel) 4,+ osci thd3 (0.02 * 100^?vel) 7]+ <<<+ CausalClass.feedSnd+ (stereoFrequenciesFromDetuneBendModulation speed fm)+ <<<+ arr (\(e1,(e4,e7)) -> (e1,e4,e7))+ $> {-+ Be careful, those storable vectors shorten the whole sound+ if they have shorter release than the main envelope.+ -}+ liftA2 (,) env4 env7))+ pingReleaseEnvelope++bellNoiseStereoFM ::+ IO (Real -> Real ->+ PC.T Real -> PC.T Real ->+ SigSt.ChunkSize ->+ PC.T (BM.T Real) ->+ Instrument Real (Stereo.T Vector))+bellNoiseStereoFM =+ liftA2+ (\osc env dec rel noiseAmp noiseReson vcsize fm sr vel freq dur ->+ pioApply+ (osc sr (fm, freq) (noiseAmp, noiseReson) vel+ (env (dec/4) rel vcsize sr vel dur)+ (env (dec/7) rel vcsize sr vel dur))+ (env dec rel vcsize sr vel dur))+ (CausalRender.run $+ wrapped $+ \(Modulation fm) (Control noiseAmp, Control noiseReson)+ (Number vel) (Signal env4) (Signal env7) ->+ constant noiseReference 20000 $ \noiseRef ->+ constant frequency 5 $ \speed _sr ->+ (let osci ::+ (Triple VectorValue -> VectorValue) ->+ Exp Real ->+ Exp Real ->+ Causal.T (Triple VectorValue, VectorValue) VectorValue+ osci sel v d =+ Causal.envelope+ <<<+ (arr sel ***+ (CausalPS.amplify v+ <<<+ (CausalPS.osci WaveL.approxSine4 $< zero)+ <<<+ CausalPS.amplify d))++ noise ::+ (Triple VectorValue -> VectorValue) ->+ Exp Real ->+ Causal.T (Triple VectorValue, VectorValue) VectorValue+ noise sel d =+ (Causal.envelope $< piecewiseConstantVector noiseAmp)+ <<<+ Causal.envelope+ <<<+ (arr sel ***+ ({- UniFilter.lowpass+ ^<< -}+ (CtrlPS.process $> SigPS.noise 12 noiseRef)+ <<<+{-+ (Causal.quantizeLift+ (Causal.zipWith UniFilterL.parameter)+ $<# (128 / fromIntegral vectorSize :: Real))+-}+ (Causal.quantizeLift+ (Causal.zipWith (MoogL.parameter TypeNum.d8))+ $<# (128 / fromIntegral vectorSize :: Real))+ <<<+ CausalClass.feedFst (piecewiseConstant noiseReson)+ <<<+ Causal.map Serial.subsample+ <<<+ CausalPS.amplify d))+ in liftA2 Stereo.consMultiValue+ (sumNested+ [osci fst3 0.6 (1*0.999),+ osci snd3 (0.02 * 50^?vel) (4*0.999),+ osci thd3 (0.02 * 100^?vel) (7*0.999),+ noise fst3 0.999])+ (sumNested+ [osci fst3 0.6 (1*1.001),+ osci snd3 (0.02 * 50^?vel) (4*1.001),+ osci thd3 (0.02 * 100^?vel) (7*1.001),+ noise fst3 1.001])+ <<<+ CausalClass.feedSnd (frequencyFromBendModulation speed fm)+ <<<+ arr (\(e1,(e4,e7)) -> (e1,e4,e7))+ $> {-+ Be careful, those storable vectors shorten the whole sound+ if they have shorter release than the main envelope.+ -}+ liftA2 (,) env4 env7))+ pingReleaseEnvelope+++tine :: IO (Real -> Real -> SigSt.ChunkSize -> Instrument Real Vector)+tine =+ liftA2+ (\osc env dec rel vcsize sr vel freq dur ->+ pioApply (osc sr vel freq) (env dec rel vcsize sr 0 dur))+ (CausalRender.run $+ wrapped $ \(Number vel) (Frequency freq) ->+ constant time 1 $ \halfLife _sr ->+ (Causal.envelope $>+ (CausalPS.osci WaveL.approxSine2+ $> SigPS.constant freq+ $* (Causal.envelope+ $< SigPS.exponential2 halfLife (vel+1)+ $* SigPS.osci WaveL.approxSine2 zero (2*freq)))))+ pingReleaseEnvelope++tineStereo ::+ IO (Real -> Real -> SigSt.ChunkSize -> Instrument Real (Stereo.T Vector))+tineStereo =+ liftA2+ (\osc env dec rel vcsize sr vel freq dur ->+ pioApply (osc sr vel freq) (env dec rel vcsize sr 0 dur))+ (CausalRender.run $+ wrapped $ \(Number vel) (Frequency freq) ->+ constant time 1 $ \halfLife _sr ->+ (let chanOsci d =+ CausalPS.osci WaveL.approxSine2 $> SigPS.constant (freq*d)+ in Stereo.multiValue <$>+ Causal.envelopeStereo $>+ (liftA2 Stereo.cons (chanOsci 0.995) (chanOsci 1.005)+ $* (SigPS.exponential2 halfLife (vel+1) *+ SigPS.osci WaveL.approxSine2 zero (2*freq)))))+ pingReleaseEnvelope+++softStringReleaseEnvelope ::+ IO (Real -> SampleRate Real -> Real -> Ev.LazyTime -> SigSt.T Vector)+softStringReleaseEnvelope =+ liftA2+ (\rev env attackTime sr vel dur ->+ let attackTimeVector :: Word+ attackTimeVector = round (attackTime * vectorRate sr)+ {-+ release <- take attackTime beginning+ would yield a space leak, thus we first split 'beginning'+ and then concatenate it again+ -}+ {-+ We can not easily generate attack and sustain separately,+ because we want to use the chunk structure implied by 'dur'.+ -}+ (attack, sustain) =+ SigSt.splitAt (fromIntegral attackTimeVector) $+ pioApplyToLazyTime+ (env sr (amplitudeFromVelocity vel) attackTimeVector)+ dur+ release = rev attack+ in attack <> sustain <> release)+ SigStL.makeReversePacked+ (CausalRender.run $+ wrapped $ \(Number amp) (Parameter attackTimeVector) (SampleRate _sr) ->+ Causal.fromSignal $+ (<> SigPS.constant amp) $+ (CausalPS.amplify amp <<<+ Causal.take attackTimeVector+ $* SigPS.parabolaFadeInInf+ (fromIntegral vectorSize *+ Expr.fromIntegral attackTimeVector)))++softString :: IO (Instrument Real (Stereo.T Vector))+softString =+ liftA2+ (\osc env sr vel freq dur ->+ pioApply (osc sr freq) (env 1 sr vel dur))+ (CausalRender.run $+ wrapped $ \(Frequency freq) (SampleRate _sr) ->+ let osci d = SigPS.osci WaveL.saw zero (d * freq)+ in Stereo.multiValue <$>+ Causal.envelopeStereo $>+ (liftA2 Stereo.cons+ (osci 1.005 + osci 0.998)+ (osci 1.002 + osci 0.995)))+ softStringReleaseEnvelope+++softStringFM :: IO (PC.T (BM.T Real) -> Instrument Real (Stereo.T Vector))+softStringFM =+ liftA2+ (\osc env fm sr vel freq dur ->+ pioApply (osc sr (fm, freq)) (env 1 sr vel dur))+ (CausalRender.run $+ wrapped $ \(Modulation fm) ->+ constant frequency 5 $ \speed _sr ->+ let osci d = (CausalPS.osci WaveL.saw $< zero) <<< CausalPS.amplify d+ in Stereo.multiValue <$>+ (Causal.envelopeStereo $>+ (liftA2 Stereo.cons+ (osci 1.005 + osci 0.998)+ (osci 1.002 + osci 0.995)+ $* frequencyFromBendModulation speed fm)))+ softStringReleaseEnvelope+++tineStereoFM ::+ IO (Real -> Real ->+ SigSt.ChunkSize ->+ PC.T (BM.T Real) ->+ Instrument Real (Stereo.T Vector))+tineStereoFM =+ liftA2+ (\osc env dec rel vcsize fm sr vel freq dur ->+ pioApply (osc sr vel (fm, freq)) (env dec rel vcsize sr 0 dur))+ (CausalRender.run $+ wrapped $ \(Number vel) (Modulation fm) ->+ constant time 1 $ \halfLife ->+ constant frequency 5 $ \speed _sr ->+ (let chanOsci d =+ CausalPS.osci WaveL.approxSine2+ <<< second (CausalPS.amplify d)+ in Stereo.multiValue <$>+ Causal.envelopeStereo $>+ (liftA2 Stereo.cons (chanOsci 0.995) (chanOsci 1.005)+ <<<+ (((Causal.envelope+ $< SigPS.exponential2 halfLife (vel+1))+ <<< (CausalPS.osci WaveL.approxSine2 $< zero)+ <<< CausalPS.amplify 2)+ &&& id)+ $* frequencyFromBendModulation speed fm)))+ pingReleaseEnvelope+++_tineControlledProc, tineControlledFnProc ::+ Sig.T (Const.T RealValue) ->+ Sig.T (Const.T RealValue) ->+ Exp Real ->+ SampleRate (Exp Real) ->+ Causal.T (Stereo.T VectorValue) (Stereo.T VectorValue)+_tineControlledProc index depth vel = constant time 1 $ \halfLife _sr ->+ Causal.stereoFromMono (CausalPS.osci WaveL.approxSine2)+ <<<+ Stereo.interleave+ ^<<+ ((Causal.envelopeStereo+ $< (piecewiseConstantVector depth+ *+ SigPS.exponential2 halfLife (vel+1)))+ <<<+ Causal.stereoFromMono (CausalPS.osci WaveL.approxSine2 $< zero)+ <<<+ (Causal.envelopeStereo $< piecewiseConstantVector index))+ &&& id++tineControlledFnProc index depth vel = constant time 1 $ \halfLife _sr ->+ F.withGuidedArgs F.atom $ \freq ->+ Causal.stereoFromMono (CausalPS.osci WaveL.approxSine2)+ $&+ liftA2 (liftA2 (,))+ ((Causal.envelopeStereo+ $< (piecewiseConstantVector depth+ *+ SigPS.exponential2 halfLife (vel+1)))+ <<<+ Causal.stereoFromMono (CausalPS.osci WaveL.approxSine2 $< zero)+ <<<+ (Causal.envelopeStereo $< piecewiseConstantVector index)+ $&+ freq)+ freq++tineControlledFM ::+ IO (Real -> Real ->+ PC.T Real ->+ PC.T Real -> PC.T Real ->+ SigSt.ChunkSize ->+ PC.T (BM.T Real) ->+ Instrument Real (Stereo.T Vector))+tineControlledFM =+ liftA2+ (\osc env dec rel detune index depth vcsize fm sr vel freq dur ->+ pioApply+ (osc sr (index, depth) vel (detune, fm, freq))+ (env dec rel vcsize sr 0 dur))+ (CausalRender.run $+ wrapped $ \(Control index, Control depth)+ (Number vel) (DetuneModulation fm) ->+ constant frequency 5 $ \speed sr ->+ Stereo.multiValue <$>+ Causal.envelopeStereo $>+ (tineControlledFnProc index depth vel sr $*+ stereoFrequenciesFromDetuneBendModulation speed fm))+ pingReleaseEnvelope+++fenderProc ::+ Sig.T (Const.T RealValue) ->+ Sig.T (Const.T RealValue) ->+ Sig.T (Const.T RealValue) ->+ Exp Real ->+ SampleRate (Exp Real) ->+ Causal.T (Stereo.T VectorValue) (Stereo.T VectorValue)+fenderProc fade index depth vel = constant time 1 $ \halfLife _sr ->+ F.withGuidedArgs F.atom $ \stereoFreq ->+ let channel_n_1 ::+ F.T VectorValue VectorValue ->+ F.T VectorValue VectorValue+ channel_n_1 freq =+ CausalPS.osci WaveL.approxSine2+ $&+ ((Causal.envelope+ $< (piecewiseConstantVector depth+ *+ SigPS.exponential2 halfLife (vel+1)))+ <<<+ (CausalPS.osci WaveL.approxSine2 $< zero)+ <<<+ (Causal.envelope $< piecewiseConstantVector index)+ $&+ freq)+ &|&+ freq+ channel_1_2 ::+ F.T VectorValue VectorValue ->+ F.T VectorValue VectorValue+ channel_1_2 freq =+ CausalPS.osci WaveL.approxSine2+ $&+ ((Causal.envelope+ $< (piecewiseConstantVector depth+ *+ SigPS.exponential2 halfLife (vel+1)))+ <<<+ (CausalPS.osci WaveL.approxSine2 $< zero)+ $&+ freq)+ &|&+ (CausalPS.amplify 2 $& freq)+ in (Causal.stereoFromMonoControlled+ (fadeProcess+ (F.compile $ channel_n_1 $ F.lift id)+ (F.compile $ channel_1_2 $ F.lift id))+ $< piecewiseConstantVector fade)+ $&+ stereoFreq++fenderFM ::+ IO (Real -> Real ->+ PC.T Real ->+ PC.T Real -> PC.T Real -> PC.T Real ->+ SigSt.ChunkSize ->+ PC.T (BM.T Real) ->+ Instrument Real (Stereo.T Vector))+fenderFM =+ liftA2+ (\osc env dec rel detune index depth fade vcsize fm sr vel freq dur ->+ pioApply+ (osc sr (index, depth) fade vel (detune, fm, freq))+ (env dec rel vcsize sr 0 dur))+ (CausalRender.run $+ wrapped $ \(Control index, Control depth) (Control fade)+ (Number vel) (DetuneModulation fm) ->+ constant frequency 5 $ \speed sr ->+ Stereo.multiValue <$>+ Causal.envelopeStereo $>+ (fenderProc fade index depth vel sr $*+ stereoFrequenciesFromDetuneBendModulation speed fm))+ pingReleaseEnvelope+++fmModulator ::+ Exp Real ->+ Exp Real ->+ Sig.T (Const.T RealValue) ->+ SampleRate (Exp Real) ->+ Causal.T (Stereo.T VectorValue) (Stereo.T VectorValue)+fmModulator vel n depth = constant time 1 $ \halfLife _sr ->+ (Causal.envelopeStereo+ $< (piecewiseConstantVector depth+ *+ SigPS.exponential2 halfLife (vel+1)))+ <<<+ Causal.stereoFromMono (CausalPS.osci WaveL.approxSine2 $< zero)+ <<<+ CausalPS.amplifyStereo n++tineModulatorBankFM ::+ IO (Real -> Real ->+ PC.T Real ->+ PC.T Real -> PC.T Real -> PC.T Real -> PC.T Real ->+ SigSt.ChunkSize ->+ PC.T (BM.T Real) ->+ Instrument Real (Stereo.T Vector))+tineModulatorBankFM =+ liftA2+ (\osc env+ dec rel detune+ depth1 depth2 depth3 depth4+ vcsize fm sr vel freq dur ->+ pioApply+ (osc sr depth1 depth2 depth3 depth4 vel (detune, fm, freq))+ (env dec rel vcsize sr 0 dur))+ (CausalRender.run $+ wrapped $+ \(Control depth1) (Control depth2) (Control depth3) (Control depth4)+ (Number vel) (DetuneModulation fm) ->+ constant frequency 5 $ \speed sr ->+ Stereo.multiValue <$>+ (Causal.envelopeStereo $>+ (Causal.stereoFromMono (CausalPS.osci WaveL.approxSine2)+ <<<+ Stereo.interleave+ ^<<+ sumNested+ [fmModulator vel 1 depth1 sr,+ fmModulator vel 2 depth2 sr,+ fmModulator vel 3 depth3 sr,+ fmModulator vel 4 depth4 sr]+ &&& id+ $*+ stereoFrequenciesFromDetuneBendModulation speed fm)))+ pingReleaseEnvelope++tineBankFM ::+ IO (Real -> Real ->+ PC.T Real ->+ PC.T Real -> PC.T Real -> PC.T Real -> PC.T Real ->+ PC.T Real -> PC.T Real -> PC.T Real -> PC.T Real ->+ SigSt.ChunkSize ->+ PC.T (BM.T Real) ->+ Instrument Real (Stereo.T Vector))+tineBankFM =+ liftA2+ (\osc env+ dec rel detune+ depth1 depth2 depth3 depth4+ partial1 partial2 partial3 partial4+ vcsize fm sr vel freq dur ->+ pioApply+ (osc sr depth1 depth2 depth3 depth4+ partial1 partial2 partial3 partial4+ vel (detune, fm, freq))+ (env dec rel vcsize sr 0 dur))+ (CausalRender.run $+ wrapped $+ \(Control depth1) (Control depth2) (Control depth3) (Control depth4)+ (Control partial1) (Control partial2)+ (Control partial3) (Control partial4)+ (Number vel) (DetuneModulation fm) ->+ constant frequency 5 $ \speed sr ->++ (let partial ::+ VectorValue -> Int -> VectorValue ->+ LLVM.CodeGenFunction r VectorValue+ partial amp n t =+ A.mul amp =<<+ WaveL.partial WaveL.approxSine2 n t+ in Stereo.multiValue <$>+ Causal.envelopeStereo $>+ (Causal.stereoFromMono+ (CausalPS.shapeModOsci+ (\(p1,(p2,(p3,p4))) t -> do+ y1 <- A.mul p1 =<< WaveL.approxSine2 t+ y2 <- partial p2 2 t+ y3 <- partial p3 3 t+ y4 <- partial p4 4 t+ A.add y1 =<< A.add y2 =<< A.add y3 y4)+ $<+ (liftA2 (,) (piecewiseConstantVector partial1) $+ liftA2 (,) (piecewiseConstantVector partial2) $+ liftA2 (,) (piecewiseConstantVector partial3)+ (piecewiseConstantVector partial4)))+ <<<+ Stereo.interleave+ ^<<+ sumNested+ [fmModulator vel 1 depth1 sr,+ fmModulator vel 2 depth2 sr,+ fmModulator vel 3 depth3 sr,+ fmModulator vel 4 depth4 sr]+ &&& id+ $*+ stereoFrequenciesFromDetuneBendModulation speed fm)))+ pingReleaseEnvelope+++{- |+FM synthesis where the modulator is a resonantly filtered sawtooth.+This way we get a sinus-like modulator where the sine frequency+(that is, something like the modulation index) can be controlled continously.+-}+resonantFMSynthProc ::+ Sig.T (Const.T RealValue) ->+ Sig.T (Const.T RealValue) ->+ Sig.T (Const.T RealValue) ->+ Exp Real ->+ SampleRate (Exp Real) ->+ Causal.T (Stereo.T VectorValue) (Stereo.T VectorValue)+resonantFMSynthProc reson index depth vel =+ constant time 1 $ \halfLife _sr ->+ F.withGuidedArgs (Stereo.cons F.atom F.atom) $ \stereoFreq ->+ let chan :: F.T inp VectorValue -> F.T inp VectorValue+ chan freq =+ CausalPS.osci WaveL.approxSine2+ $&+ ((Causal.envelope+ $< (piecewiseConstantVector depth+ *+ SigPS.exponential2 halfLife (vel+1)))+ <<<+ UniFilter.lowpass+ ^<<+ CtrlPS.process+ $&+ (Causal.zipWith UniFilterL.parameter+ <<<+ CausalClass.feedFst (piecewiseConstant reson)+ <<<+ (Causal.envelope $< piecewiseConstant index)+ <<<+ Causal.map Serial.subsample+ $&+ freq)+ &|&+ ((CausalPS.osci WaveL.saw $< zero)+ $&+ freq))+ &|&+ freq+ in Trav.traverse chan stereoFreq++resonantFMSynth ::+ IO (Real -> Real ->+ PC.T Real ->+ PC.T Real -> PC.T Real -> PC.T Real ->+ SigSt.ChunkSize ->+ PC.T (BM.T Real) ->+ Instrument Real (Stereo.T Vector))+resonantFMSynth =+ liftA2+ (\osc env dec rel detune reson index depth vcsize fm sr vel freq dur ->+ pioApply+ (osc sr (reson, index, depth) vel (detune, fm, freq))+ (env dec rel vcsize sr 0 dur))+ (CausalRender.run $+ wrapped $+ \(Control reson, Control index, Control depth)+ (Number vel) (DetuneModulation fm) ->+ constant frequency 5 $ \speed sr ->+ Stereo.multiValue <$>+ Causal.envelopeStereo $>+ (resonantFMSynthProc reson index depth vel sr $*+ stereoFrequenciesFromDetuneBendModulation speed fm))+ pingReleaseEnvelope+++phaserOsci ::+ (Exp Real -> Causal.T a VectorValue) ->+ Causal.T a (Stereo.T VectorValue)+phaserOsci osci =+ CausalPS.amplifyStereo 0.25+ <<<+ liftA2 Stereo.cons+ (sumNested $ map osci [1.0, -0.4, 0.5, -0.7])+ (sumNested $ map osci [0.4, -1.0, 0.7, -0.5])+++softStringDetuneFM ::+ IO (Real ->+ PC.T Real ->+ PC.T (BM.T Real) ->+ Instrument Real (Stereo.T Vector))+softStringDetuneFM =+ liftA2+ (\osc env att det fm sr vel freq dur ->+ pioApply (osc sr det (fm, freq)) (env att sr vel dur))+ (let osci :: Exp Real -> Causal.T (VectorValue, VectorValue) VectorValue+ osci d =+ (CausalPS.osci WaveL.saw $< zero)+ <<<+ Causal.envelope+ <<<+ first (one + CausalPS.amplify d)+ in CausalRender.run $+ wrapped $ \(Control det) (Modulation fm) ->+ constant frequency 5 $ \speed _sr ->+ Stereo.multiValue <$>+ (Causal.envelopeStereo $>+ (phaserOsci osci+ $< piecewiseConstantVector det+ $* frequencyFromBendModulation speed fm)))+ softStringReleaseEnvelope++{-+We might decouple the frequency of the enveloped tone+from the frequency of the envelope,+in order to get something like formants.+-}+softStringShapeFM, cosineStringStereoFM,+ arcSineStringStereoFM, arcTriangleStringStereoFM,+ arcSquareStringStereoFM, arcSawStringStereoFM ::+ IO (Real ->+ PC.T Real ->+ PC.T Real ->+ PC.T (BM.T Real) ->+ Instrument Real (Stereo.T Vector))+softStringShapeFM =+ softStringShapeCore WaveL.rationalApproxSine1+cosineStringStereoFM =+ softStringShapeCore+ (\k p -> WaveL.approxSine2 =<< WaveL.replicate k p)+arcSawStringStereoFM = arcStringStereoFM WaveL.saw+arcSineStringStereoFM = arcStringStereoFM WaveL.approxSine2+arcSquareStringStereoFM = arcStringStereoFM WaveL.square+arcTriangleStringStereoFM = arcStringStereoFM WaveL.triangle++arcStringStereoFM ::+ (forall r.+ VectorValue ->+ LLVM.CodeGenFunction r VectorValue) ->+ IO (Real ->+ PC.T Real ->+ PC.T Real ->+ PC.T (BM.T Real) ->+ Instrument Real (Stereo.T Vector))+arcStringStereoFM wave =+ softStringShapeCore+ (\k p ->+ M.liftJoin2 Frame.amplifyMono+ (WaveL.approxSine4 =<< WaveL.halfEnvelope p)+ (wave =<< WaveL.replicate k p))++softStringShapeCore ::+ (forall r.+ VectorValue ->+ VectorValue ->+ LLVM.CodeGenFunction r VectorValue) ->+ IO (Real ->+ PC.T Real ->+ PC.T Real ->+ PC.T (BM.T Real) ->+ Instrument Real (Stereo.T Vector))+softStringShapeCore wave =+ liftA2+ (\osc env att det dist fm sr vel freq dur ->+ pioApply (osc sr det dist (fm, freq)) (env att sr vel dur))+ (let osci ::+ Exp Real ->+ Causal.T+ (VectorValue,+ {- wave shape parameter -}+ (VectorValue, VectorValue)+ {- detune, frequency modulation -})+ VectorValue+ osci d =+ CausalPS.shapeModOsci wave+ <<<+ second+ (CausalClass.feedFst zero+ <<<+ Causal.envelope+ <<<+ first (one + CausalPS.amplify d))+ in CausalRender.run $+ wrapped $ \(Control det) (Control dist) (Modulation fm) ->+ constant frequency 5 $ \speed _sr ->+ Stereo.multiValue <$>+ (Causal.envelopeStereo $>+ (phaserOsci osci+ $< piecewiseConstantVector dist+ $< piecewiseConstantVector det+ $* frequencyFromBendModulation speed fm)))+ softStringReleaseEnvelope++fmStringStereoFM ::+ IO (Real ->+ PC.T Real ->+ PC.T Real ->+ PC.T Real ->+ PC.T (BM.T Real) ->+ Instrument Real (Stereo.T Vector))+fmStringStereoFM =+ liftA2+ (\osc env att det depth dist fm sr vel freq dur ->+ pioApply (osc sr det depth dist (fm, freq)) (env att sr vel dur))+ (let osci ::+ Exp Real ->+ Causal.T+ ((VectorValue, VectorValue)+ {- phase modulation depth, modulator distortion -},+ (VectorValue, VectorValue)+ {- detune, frequency modulation -})+ VectorValue+ osci d =+ CausalPS.osci WaveL.approxSine2+ <<<+ (Causal.envelope+ <<<+ second+ (CausalPS.shapeModOsci WaveL.rationalApproxSine1+ <<< second (CausalClass.feedFst zero))+ <<^+ (\((dp, ds), f) -> (dp, (ds, f))))+ &&& arr snd+ <<<+ second (Causal.envelope <<< first (one + CausalPS.amplify d))+ in CausalRender.run $+ wrapped $+ \(Control det) (Control depth) (Control dist) (Modulation fm) ->+ constant frequency 5 $ \speed _sr ->+ Stereo.multiValue <$>+ (Causal.envelopeStereo <<<+ (id &&&+ (phaserOsci osci+ <<<+ CausalClass.feedSnd+ (liftA2 (,)+ (piecewiseConstantVector det)+ (frequencyFromBendModulation speed fm))+ <<<+ CausalClass.feedSnd (piecewiseConstantVector dist)+ <<<+ (Causal.envelope $< piecewiseConstantVector depth)))))+ softStringReleaseEnvelope+++stereoNoise :: SampleRate (Exp Real) -> Sig.T (Stereo.T VectorValue)+stereoNoise =+ constant noiseReference 20000 $ \noiseRef _sr ->+ traverse+ (\uid -> SigPS.noise uid noiseRef)+ (Stereo.cons 13 14)++windCore ::+ Sig.T (Const.T RealValue) ->+ Sig.T (Const.T (BM.T RealValue)) ->+ SampleRate (Exp Real) ->+ Sig.T (Stereo.T VectorValue)+windCore reson fm =+ constant frequency 0.2 $ \speed sr ->+ Causal.stereoFromMonoControlled CtrlPS.process+ $< (Causal.zipWith (MoogL.parameter TypeNum.d8)+ $< piecewiseConstant reson+ $* (Causal.map Serial.subsample $*+ frequencyFromBendModulation speed fm))+ $* stereoNoise sr++wind ::+ IO (Real ->+ PC.T Real ->+ PC.T (BM.T Real) ->+ Instrument Real (Stereo.T Vector))+wind =+ liftA2+ (\osc env att reson fm sr vel freq dur ->+ pioApply (osc sr reson (fm, freq)) (env att sr vel dur))+ (CausalRender.run $+ wrapped $ \(Control reson) (Modulation fm) sr ->+ Stereo.multiValue <$>+ Causal.envelopeStereo $> windCore reson fm sr)+ softStringReleaseEnvelope+++fadeProcess ::+ (A.PseudoRing v, A.IntegerConstant v) =>+ Causal.T a v ->+ Causal.T a v ->+ Causal.T (v, a) v+fadeProcess proc0 proc1 =+ let k = arr fst+ a0 = proc0 <<^ snd+ a1 = proc1 <<^ snd+ in (one-k)*a0 + k*a1+++windPhaser ::+ IO (Real ->+ PC.T Real ->+ PC.T Real ->+ PC.T Real ->+ PC.T (BM.T Real) ->+ Instrument Real (Stereo.T Vector))+windPhaser =+ liftA2+ (\osc env att phaserMix phaserFreq reson fm sr vel freq dur ->+ pioApply+ (osc sr phaserMix phaserFreq reson (fm, freq))+ (env att sr vel dur))+ (CausalRender.run $+ wrapped $+ \(Control phaserMix) (FrequencyControl phaserFreq)+ (Control reson) (Modulation fm) sr ->+ Stereo.multiValue <$>+ (Causal.envelopeStereo $>+ ((Causal.stereoFromMonoControlled+ (fadeProcess (arr snd) CtrlPS.process+ <<<+ first (Causal.map Serial.upsample)+ <<^+ (\((k,p),x) -> (k,(p,x))))+ $< liftA2 (,)+ (piecewiseConstant phaserMix)+ (piecewiseConstant+ (Const.causalMap+ (Allpass.flangerParameter TypeNum.d8)+ $* phaserFreq)))+ $*+ windCore reson fm sr)))+ softStringReleaseEnvelope+++filterSawStereoFM ::+ IO (Real -> Real ->+ PC.T Real ->+ Real -> Real ->+ SigSt.ChunkSize ->+ PC.T (BM.T Real) ->+ Instrument Real (Stereo.T Vector))+filterSawStereoFM =+ liftA2+ (\osc env dec rel detune bright brightDecay vcsize fm sr vel freq dur ->+ pioApply+ (osc sr bright brightDecay (detune, fm, freq))+ (env dec rel vcsize sr vel dur))+ (CausalRender.run $+ wrapped $ \(Frequency bright) (Time brightDec) (DetuneModulation fm) ->+ constant frequency 10 $ \speed ->+ constant frequency 100 $ \cutoff _sr ->+ (Stereo.multiValue <$>+ Causal.envelopeStereo $>+ (Causal.stereoFromMono+ (UniFilter.lowpass+ ^<<+ CtrlPS.processCtrlRate 100+ (\k ->+ Causal.map (UniFilterL.parameter 10) $*+ {- bound control in order to avoid too low resonant frequency,+ which makes the filter instable -}+ Sig.exponentialBounded2+ cutoff (brightDec/k) bright)+ <<<+ CausalPS.osci WaveL.saw $< zero)+ $* stereoFrequenciesFromDetuneBendModulation speed fm)))+ pingReleaseEnvelope+++{- |+The ADSR curve is composed from three parts:+Attack, Decay(+Sustain), Release.+Attack starts when the key is pressed+and lasts attackTime seconds+where it reaches height attackPeak*amplitudeOfVelocity.+It should be attackPeak>1 because in the following phase+we want to approach 1 from above.+Say the curve would approach the limit value L+if it would continue after the end of the attack phase,+the slope is determined by the halfLife with respect to this upper bound.+That is, attackHalfLife is the time in seconds where the attack curve+reaches or would reach L/2.+After Attack the Decay part starts at the same level+and decays to amplitudeOfVelocity.+The slope is again a halfLife,+that is, decayHalfLife is the time where the curve+drops from attackPeak*amplitudeOfVelocity to (attackPeak+1)/2*amplitudeOfVelocity.+This phase lasts as long as the key is pressed.+If the key is released the curve decays with half life releaseHalfLife.+-}+{-+1 - 2^(-attackTime/attackHalfLife) = peak+-}+adsr ::+ IO (Real -> Real -> Real ->+ Real -> Real ->+ SigSt.ChunkSize ->+ SampleRate Real -> Real -> Ev.LazyTime -> SigSt.T Vector)+adsr =+ liftA3+ (\attack decay release+ attackTime attackPeak attackHalfLife+ decayHalfLife releaseHalfLife vcsize sr vel dur ->+ let amp = amplitudeFromVelocity vel+ (attackDur, decayDur) =+ CutG.splitAt (round (attackTime * vectorRate sr)) dur+ in SigStL.continuePacked+ (pioApplyToLazyTime+ (attack sr+ attackHalfLife+ (attackPeak * amp / (1 - 2^?(-attackTime/attackHalfLife))))+ attackDur+ <>+ pioApplyToLazyTime+ (decay sr+ decayHalfLife+ ((attackPeak-1)*amp)+ amp)+ decayDur)+ (\x -> release vcsize sr releaseHalfLife x))+ (CausalRender.run $+ wrapped $ \(Time halfLife) (Number amplitude) (SampleRate _sr) ->+ Causal.fromSignal $+ SigPS.constant amplitude - SigPS.exponential2 halfLife amplitude)+ (CausalRender.run $ wrapped $+ \(Time halfLife) (Number amplitude) (Number saturation)+ (SampleRate _sr) ->+ Causal.fromSignal $+ SigPS.constant saturation + SigPS.exponential2 halfLife amplitude)+ (Render.run $+ wrapped $ \(Time releaseHL) (Number amplitude) (SampleRate _sr) ->+ let releaseTime = releaseHL * 5 / fromIntegral vectorSize+ in Causal.take (Expr.roundToIntFast releaseTime) $*+ SigPS.exponential2 releaseHL amplitude)++brass ::+ IO (Real -> Real ->+ Real -> Real -> Real -> Real ->+ PC.T Real ->+ PC.T Real ->+ SigSt.ChunkSize ->+ PC.T (BM.T Real) ->+ Instrument Real (Stereo.T Vector))+brass =+ liftA2+ (\osc env attTime attPeak attHL+ dec rel emph det dist vcsize fm sr vel freq dur ->+ pioApply+ (osc sr det dist (fm, freq)+ (env attTime emph attHL dec rel vcsize sr vel dur))+ (env attTime attPeak attHL dec rel vcsize sr vel dur))+ (let osci ::+ Exp Real ->+ Causal.T+ (VectorValue,+ {- wave shrink/replication factor -}+ (VectorValue, VectorValue)+ {- detune, frequency modulation -})+ VectorValue+ osci d =+ CausalPS.shapeModOsci WaveL.rationalApproxSine1+ <<<+ second+ (CausalClass.feedFst zero+ <<<+ Causal.envelope+ <<<+ first (one + CausalPS.amplify d))+ in CausalRender.run $+ wrapped $+ \(Control det) (Control dist) (Modulation fm) (Signal emph) ->+ constant frequency 5 $ \speed _sr ->+ Stereo.multiValue <$>+ Causal.envelopeStereo $>+ (phaserOsci osci+ <<<+ CausalClass.feedFst (piecewiseConstantVector dist)+ <<<+ CausalClass.feedSnd (frequencyFromBendModulation speed fm)+ <<<+ (Causal.envelope $< piecewiseConstantVector det)+ $*+ emph))+ adsr+++sampledSound ::+ IO (Sample.T ->+ PC.T (BM.T Real) ->+ Instrument Real (Stereo.T Vector))+sampledSound =+ liftA2+ (\osc freqMod smp fm sr vel freq dur ->+ {-+ We split the frequency modulation signal+ in order to get a smooth frequency modulation curve.+ Without (periodic) frequency modulation+ we could just split the piecewise constant control curve @fm@.+ -}+ let fmSig :: SigSt.T Vector+ fmSig =+ pioApplyToLazyTime+ (freqMod sr (fm, freq * Sample.period pos))+ (PC.duration fm)+ pos = Sample.positions smp+ amp = 2 * amplitudeFromVelocity vel+ (attack, sustain, release) = Sample.parts smp+ in (\cont ->+ pioApplyCont cont+ (osc sr amp+ (attack <>+ SVL.cycle (SigSt.take (Sample.loopLength pos) sustain))+ (chunkSizesFromLazyTime dur))+ fmSig)+ (pioApplyCont (const SigSt.empty)+ (osc sr amp release (NonNegChunky.fromChunks (repeat 1000)))))+ (CausalRender.run $+ wrapped $ \(Number amp) (Signal smp) (Signal dur) (SampleRate _sr) ->+ Stereo.multiValue <$>+ CausalPS.amplifyStereo amp+ <<<+ Causal.stereoFromMono+ (CausalPS.pack (Causal.frequencyModulationLinear smp))+ <<<+ liftA2 Stereo.cons+ (CausalPS.amplify 0.999)+ (CausalPS.amplify 1.001)+ <<<+ arr fst+ <<<+ CausalClass.feedSnd (Const.flatten dur))+ (CausalRender.run $+ wrapped $ \(Modulation fm) ->+ constant frequency 3 $ \speed _sr ->+ Causal.fromSignal $ frequencyFromBendModulation speed fm)+++_sampledSoundLeaky ::+ IO (Sample.T ->+ PC.T (BM.T Real) ->+ Instrument Real (Stereo.T Vector))+_sampledSoundLeaky =+ liftA2+ (\osc freqMod smp fm sr vel freq dur ->+ {-+ We split the frequency modulation signal+ in order to get a smooth frequency modulation curve.+ Without (periodic) frequency modulation+ we could just split the piecewise constant control curve @fm@.+ -}+ let sustainFM, releaseFM :: SigSt.T Vector+ (sustainFM, releaseFM) =+ SVP.splitAt (chunkSizesFromLazyTime dur) $+ pioApplyToLazyTime+ (freqMod sr (fm, freq * Sample.period pos))+ (PC.duration fm)+ pos = Sample.positions smp+ amp = 2 * amplitudeFromVelocity vel+ (attack, sustain, release) = Sample.parts smp+ in pioApply+ (osc sr amp+ (attack <>+ SVL.cycle (SigSt.take (Sample.loopLength pos) sustain)))+ sustainFM+ <>+ pioApply (osc sr amp release) releaseFM)+ (CausalRender.run $+ wrapped $ \(Number amp) (Signal smp) (SampleRate _sr) ->+ Stereo.multiValue <$>+ CausalPS.amplifyStereo amp+ <<<+ Causal.stereoFromMono+ (CausalPS.pack (Causal.frequencyModulationLinear smp))+ <<<+ liftA2 Stereo.cons+ (CausalPS.amplify 0.999)+ (CausalPS.amplify 1.001))+ (CausalRender.run $+ wrapped $ \(Modulation fm) ->+ constant frequency 3 $ \speed _sr ->+ Causal.fromSignal $ frequencyFromBendModulation speed fm)
− src/Synthesizer/LLVM/Server/Parameter.hs
@@ -1,106 +0,0 @@-{-# LANGUAGE TypeFamilies #-}-module Synthesizer.LLVM.Server.Parameter (- Tuple(..),- Frequency(..), Time(..), VectorTime(..), Number(..), Control(..), Signal(..),- withTuple2,- ) where--import Synthesizer.LLVM.Server.CommonPacked (vectorSize)-import Synthesizer.LLVM.Server.Common (Param, Real, SampleRate(SampleRate))--import qualified Synthesizer.PiecewiseConstant.Signal as PC-import qualified Synthesizer.Storable.Signal as SigSt--import qualified LLVM.DSL.Parameter as Param--import qualified Control.Category as Cat-import Control.Applicative ((<$>))--import qualified Data.Tuple.HT as TupleHT--import Prelude hiding (Real)---class Tuple tuple where- type Composed tuple :: *- type Source tuple :: *- decompose ::- Param (Source tuple) (SampleRate Real) ->- Param (Source tuple) (Composed tuple) -> tuple---newtype Number p = Number (Param p Real)--instance Tuple (Number p) where- type Composed (Number p) = Real- type Source (Number p) = p- decompose _sr t = Number t---deconsSampleRate :: Param p (SampleRate a) -> Param p a-deconsSampleRate = fmap (\(SampleRate sr) -> sr)--newtype Time p = Time (Param p Real)--instance Tuple (Time p) where- type Composed (Time p) = Real- type Source (Time p) = p- decompose sr t = Time (t * deconsSampleRate sr)--newtype VectorTime p = VectorTime (Param p Real)--instance Tuple (VectorTime p) where- type Composed (VectorTime p) = Real- type Source (VectorTime p) = p- decompose sr t =- VectorTime (t * deconsSampleRate sr / fromIntegral vectorSize)--newtype Frequency p = Frequency (Param p Real)--instance Tuple (Frequency p) where- type Composed (Frequency p) = Real- type Source (Frequency p) = p- decompose sr freq = Frequency (freq / deconsSampleRate sr)---newtype Control p = Control (Param p (PC.T Real))--instance Tuple (Control p) where- type Composed (Control p) = PC.T Real- type Source (Control p) = p- decompose _sr x = Control x---newtype Signal p a = Signal (Param p (SigSt.T a))--instance Tuple (Signal p a) where- type Composed (Signal p a) = SigSt.T a- type Source (Signal p a) = p- decompose _sr x = Signal x---instance (Tuple a, Tuple b, Source a ~ Source b) => Tuple (a,b) where- type Composed (a,b) = (Composed a, Composed b)- type Source (a,b) = Source a- decompose sr p = (decompose sr $ fst <$> p, decompose sr $ snd <$> p)--instance- (Tuple a, Tuple b, Tuple c, Source a ~ Source b, Source b ~ Source c) =>- Tuple (a,b,c) where- type Composed (a,b,c) = (Composed a, Composed b, Composed c)- type Source (a,b,c) = Source a- decompose sr p =- (decompose sr $ TupleHT.fst3 <$> p,- decompose sr $ TupleHT.snd3 <$> p,- decompose sr $ TupleHT.thd3 <$> p)---withTuple2 ::- (Tuple tuple, Source tuple ~ p, Composed tuple ~ p) =>- (tuple -> f (SampleRate Real, p) a b) -> f (SampleRate Real, p) a b-withTuple2 f =- idFromFunctor2 $ \param -> f $ decompose (fst<$>param) (snd<$>param)---- cf. Param.idFromFunctor2-idFromFunctor2 :: (Param.T p p -> f p a b) -> f p a b-idFromFunctor2 f = f Cat.id
src/Synthesizer/LLVM/Server/Scalar/Instrument.hs view
@@ -14,13 +14,17 @@ import Synthesizer.LLVM.Server.Common import qualified Synthesizer.LLVM.Frame.Stereo as Stereo-import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP-import qualified Synthesizer.LLVM.Parameterized.Signal as SigP+import qualified Synthesizer.LLVM.Causal.Render as CausalRender+import qualified Synthesizer.LLVM.Causal.Process as Causal+import qualified Synthesizer.LLVM.Generator.Render as Render+import qualified Synthesizer.LLVM.Generator.Signal as Sig import qualified Synthesizer.LLVM.Storable.Signal as SigStL import qualified Synthesizer.LLVM.Wave as WaveL-import Synthesizer.LLVM.CausalParameterized.Process (($<), ($>), ($*))+import Synthesizer.Causal.Class (($<), ($>), ($*)) -import qualified LLVM.Core as LLVM+import qualified LLVM.DSL.Expression as Expr+import qualified LLVM.Extra.Multi.Value as MultiValue+import LLVM.DSL.Expression (Exp) import qualified Synthesizer.MIDI.EventList as Ev import Synthesizer.MIDI.Storable (chunkSizesFromLazyTime)@@ -28,33 +32,29 @@ import qualified Synthesizer.Storable.Signal as SigSt import qualified Data.StorableVector.Lazy.Pattern as SigStV -import Control.Arrow ((^<<), arr) import Control.Applicative (liftA, liftA2)+import Data.Semigroup ((<>)) import NumericPrelude.Numeric (zero, round, (+)) import Prelude hiding (Real, round, break, (+)) -pingSig :: SigP.T (SampleRate Real, (Real, Real)) (LLVM.Value Real)+pingSig ::+ SampleRate (Exp Real) -> Exp Real -> Exp Real -> Sig.T (MultiValue.T Real) pingSig =- let vel = number fst- freq = frequency snd- in CausalP.envelope- $< SigP.exponential2 (timeConst 0.2)- (fmap amplitudeFromVelocity vel)- $* SigP.osciSimple WaveL.saw zero freq+ wrapped $ \(Number vel) (Frequency freq) ->+ constant time 0.2 $ \halfLife _sr ->+ Causal.envelope+ $< Sig.exponential2 halfLife (amplitudeFromVelocity vel)+ $* Sig.osci WaveL.saw zero freq ping :: IO (SigSt.ChunkSize -> SampleRate Real -> Real -> Real -> SigSt.T Real)-ping =- fmap (\f chunkSize sr vel freq -> f chunkSize (sr, (vel,freq))) $- SigP.runChunky pingSig+ping = Render.run pingSig pingDur :: IO (Instrument Real Real) pingDur =- fmap- (\sound sr vel freq dur ->- sound (chunkSizesFromLazyTime dur) (sr, (vel, freq))) $- SigP.runChunkyPattern pingSig+ fmap (\sound sr vel freq -> pioApplyToLazyTime $ sound sr vel freq) $+ CausalRender.run (\sr vel freq -> Causal.fromSignal $ pingSig sr vel freq) pingDurTake :: IO (SigSt.ChunkSize -> Instrument Real Real) pingDurTake =@@ -77,41 +77,38 @@ liftA2 (\pressed release decay rel chunkSize sr vel dur -> SigStL.continue- (pressed (chunkSizesFromLazyTime dur) (sr, (decay,vel)))- (\x -> release chunkSize (sr, (rel,x))))- (SigP.runChunkyPattern $- let decay = time fst- velocity = number snd- in SigP.exponential2 decay- (amplitudeFromVelocity ^<< velocity))- (SigP.runChunky $- let release = time fst- amplitude = number snd- in (CausalP.take (round ^<< (release*3)) $*- SigP.exponential2 release amplitude))+ (pioApplyToLazyTime (pressed sr decay vel) dur)+ (\x -> release chunkSize sr rel x))+ (CausalRender.run $+ wrapped $ \(Time halfLife) (Number velocity) (SampleRate _sr) ->+ Causal.fromSignal+ (Sig.exponential2 halfLife (amplitudeFromVelocity velocity)))+ (Render.run $+ wrapped $ \(Time release) (Number amplitude) (SampleRate _sr) ->+ Causal.take (Expr.roundToIntFast (release*3)) $*+ Sig.exponential2 release amplitude) pingRelease :: IO (Real -> Real -> SigSt.ChunkSize -> Instrument Real Real) pingRelease = liftA2 (\osc env dec rel chunkSize sr vel freq dur ->- osc (sr, freq) (env dec rel chunkSize sr vel dur))- (CausalP.runStorableChunky- (let freq = frequency id- in CausalP.envelope $>- SigP.osciSimple WaveL.saw zero freq))+ pioApply (osc sr freq) (env dec rel chunkSize sr vel dur))+ (CausalRender.run $ frequency $+ \freq _sr ->+ Causal.envelope $> Sig.osci WaveL.saw zero freq) pingReleaseEnvelope -pingStereoRelease :: IO (Real -> Real -> SigSt.ChunkSize -> Instrument Real (Stereo.T Real))+pingStereoRelease ::+ IO (Real -> Real -> SigSt.ChunkSize -> Instrument Real (Stereo.T Real)) pingStereoRelease = liftA2 (\osc env dec rel chunkSize sr vel freq dur ->- osc (sr, freq) (env dec rel chunkSize sr vel dur))- (CausalP.runStorableChunky- (let freq = frequency id- in CausalP.envelopeStereo $>- liftA2 Stereo.cons- (SigP.osciSimple WaveL.saw zero (0.999*freq))- (SigP.osciSimple WaveL.saw zero (1.001*freq))))+ pioApply (osc sr freq) (env dec rel chunkSize sr vel dur))+ (CausalRender.run $ frequency $+ \freq _sr ->+ Stereo.multiValue <$>+ Causal.envelopeStereo $>+ liftA2 Stereo.cons+ (Sig.osci WaveL.saw zero (0.999*freq))+ (Sig.osci WaveL.saw zero (1.001*freq))) pingReleaseEnvelope @@ -120,35 +117,35 @@ tine = liftA2 (\osc env dec rel chunkSize sr vel freq dur ->- osc (sr, (vel,freq)) (env dec rel chunkSize sr 0 dur))- (CausalP.runStorableChunky- (let freq = frequency snd- vel = number fst- in CausalP.envelope $>- (CausalP.osciSimple WaveL.approxSine2- $> (SigP.constant freq)- $* (CausalP.envelope- $< SigP.exponential2 (timeConst 1) (vel+1)- $* SigP.osciSimple WaveL.approxSine2 zero (2*freq)))))+ pioApply (osc sr vel freq) (env dec rel chunkSize sr 0 dur))+ (CausalRender.run $+ wrapped $ \(Number vel) (Frequency freq) ->+ constant time 1 $ \halfLife _sr ->+ Causal.envelope $>+ (Causal.osci WaveL.approxSine2+ $> Sig.constant freq+ $* (Causal.envelope+ $< Sig.exponential2 halfLife (vel+1)+ $* Sig.osci WaveL.approxSine2 zero (2*freq)))) pingReleaseEnvelope -tineStereo :: IO (Real -> Real -> SigSt.ChunkSize -> Instrument Real (Stereo.T Real))+tineStereo ::+ IO (Real -> Real -> SigSt.ChunkSize -> Instrument Real (Stereo.T Real)) tineStereo = liftA2 (\osc env dec rel chunkSize sr vel freq dur ->- osc (sr, (vel,freq)) (env dec rel chunkSize sr 0 dur))- (CausalP.runStorableChunky- (let freq = frequency snd- vel = number fst- chanOsci d =- CausalP.osciSimple WaveL.approxSine2- $> SigP.constant (freq*d)- in CausalP.envelopeStereo $>- (liftA2 Stereo.cons- (chanOsci 0.995) (chanOsci 1.005)- $* SigP.envelope- (SigP.exponential2 (timeConst 1) (vel+1))- (SigP.osciSimple WaveL.approxSine2 zero (2*freq)))))+ pioApply (osc sr vel freq) (env dec rel chunkSize sr 0 dur))+ (CausalRender.run $+ wrapped $ \(Number vel) (Frequency freq) ->+ constant time 1 $ \halfLife _sr ->+ let chanOsci d =+ Causal.osci WaveL.approxSine2 $> Sig.constant (freq*d)+ in Stereo.multiValue <$>+ Causal.envelopeStereo $>+ (liftA2 Stereo.cons (chanOsci 0.995) (chanOsci 1.005) $*+ (Causal.envelope+ $< Sig.exponential2 halfLife (vel+1)+ $* Sig.osci WaveL.approxSine2 zero (2*freq)))) pingReleaseEnvelope @@ -158,8 +155,7 @@ softStringReleaseEnvelope = liftA (\env attackTime (SampleRate sampleRate) vel dur ->- let attackTimeInt =- round (attackTime * sampleRate)+ let attackTimeInt = round (attackTime * sampleRate) {- release <- take attackTime beginning would yield a space leak, thus we first split 'beginning'@@ -171,29 +167,25 @@ -} (attack, sustain) = SigSt.splitAt attackTimeInt $- env (chunkSizesFromLazyTime dur)- (fromIntegral attackTimeInt :: Real,- amplitudeFromVelocity vel)+ pioApplyToLazyTime+ (env+ (fromIntegral attackTimeInt :: Word)+ (amplitudeFromVelocity vel))+ dur release = SigSt.reverse attack- in attack `SigSt.append` sustain `SigSt.append` release)- (let amp = arr snd- attackTime = arr fst- in SigP.runChunkyPattern $- flip SigP.append (SigP.constant amp) $- SigP.amplify amp $- (SigP.parabolaFadeIn attackTime))+ in attack <> sustain <> release)+ (CausalRender.run $ \attackTime amp -> Causal.fromSignal $+ Sig.amplify amp (Sig.parabolaFadeIn attackTime) <> Sig.constant amp) softString :: IO (Instrument Real (Stereo.T Real)) softString = liftA2- (\osc env sr vel freq dur ->- osc (sr, freq) (env 1 sr vel dur))- (let freq = frequency id- osci d =- SigP.osciSimple WaveL.saw zero (d * freq)- in CausalP.runStorableChunky $- (CausalP.envelopeStereo $>- (liftA2 Stereo.cons- (osci 1.005 + osci 0.998)- (osci 1.002 + osci 0.995))))+ (\osc env sr vel freq dur -> pioApply (osc sr freq) (env 1 sr vel dur))+ (CausalRender.run $ frequency $+ \freq _sr ->+ let osci d = Sig.osci WaveL.saw zero (d * freq)+ in Stereo.multiValue <$>+ Causal.envelopeStereo $>+ liftA2 Stereo.cons+ (osci 1.005 + osci 0.998)+ (osci 1.002 + osci 0.995)) softStringReleaseEnvelope
− src/Synthesizer/LLVM/Simple/Signal.hs
@@ -1,384 +0,0 @@-{-# LANGUAGE NoImplicitPrelude #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE ExistentialQuantification #-}-{-# LANGUAGE Rank2Types #-}-{-# LANGUAGE ForeignFunctionInterface #-}-module Synthesizer.LLVM.Simple.Signal (- C(simple),- T,- amplify,- amplifyStereo,- constant,- envelope,- envelopeStereo,- exponential2,- iterate,- map,- mapAccum,- mix,- mixExt,- takeWhile,- empty,- append,- osci,- osciPlain,- osciSaw,- zip,- zipWith,-- fromStorableVector,- fromStorableVectorLazy,-- render,- renderChunky,- runChunky,- ) where--import Synthesizer.LLVM.Simple.SignalPrivate hiding (alloca)--import qualified Synthesizer.LLVM.Frame.Stereo as Stereo-import qualified Synthesizer.LLVM.Frame as Frame-import qualified Synthesizer.LLVM.Wave as Wave-import qualified Synthesizer.LLVM.ForeignPtr as ForeignPtr--import qualified Synthesizer.LLVM.Storable.ChunkIterator as ChunkIt-import qualified Synthesizer.LLVM.Storable.Vector as SVU-import qualified Data.StorableVector.Lazy as SVL-import qualified Data.StorableVector as SV-import qualified Data.StorableVector.Base as SVB--import qualified LLVM.DSL.Execution as Exec--import qualified LLVM.Extra.Storable as Storable-import qualified LLVM.Extra.Memory as Memory-import qualified LLVM.Extra.ScalarOrVector as SoV-import qualified LLVM.Extra.MaybeContinuation as MaybeCont-import qualified LLVM.Extra.Maybe as Maybe-import qualified LLVM.Extra.Arithmetic as A-import qualified LLVM.Extra.Tuple as Tuple--import qualified LLVM.Core as LLVM-import LLVM.Core- (CodeGenFunction, ret, Value, valueOf,- IsFirstClass, IsSized, IsConst, IsArithmetic)--import Control.Monad (liftM2)-import Control.Applicative (pure, liftA2, liftA3, (<$>))--import Data.Monoid (Monoid, mappend)--import qualified Algebra.Transcendental as Trans--import qualified System.Unsafe as Unsafe-import Foreign.ForeignPtr (touchForeignPtr)-import Foreign.Ptr (Ptr)-import Data.Word (Word)-import Control.Exception (bracket)--import NumericPrelude.Numeric-import NumericPrelude.Base hiding (and, iterate, map, zip, zipWith, takeWhile)---constant :: (C signal, IsConst a) => a -> signal (Value a)-constant x = pure (valueOf x)--mapAccum ::- (C signal, Memory.C s) =>- (forall r. a -> s -> CodeGenFunction r (b,s)) ->- (forall r. CodeGenFunction r s) ->- signal a -> signal b-mapAccum f startS = alter (\(Core next start stop) ->- Core- (\ioContext (sa0,ss0) -> do- (a,sa1) <- next ioContext sa0- (b,ss1) <- MaybeCont.lift $ f a ss0- return (b, (sa1,ss1)))- (\ioContext ->- liftM2 (,) (start ioContext) startS)- (stop . fst))---{- |-Warning:-This shortens the result to the shorter input signal.-This is consistent with @Causal.mix@ but it may not be what you expect.-Consider using 'mixExt' instead.--}-mix ::- (C signal, A.Additive a) =>- signal a -> signal a -> signal a-mix = zipWith Frame.mix--{- |-The result of mixing is as long as the longer of the two input signals.--}-mixExt ::- (C signal, Monoid (signal (Value Bool, a)),- A.Additive a, Tuple.Phi a, Tuple.Undefined a) =>- signal a -> signal a -> signal a-mixExt xs ys =- let ext zs =- mappend- ((,) (valueOf True) <$> zs)- (pure (valueOf False, A.zero))- in fmap snd $ takeWhile (return . fst) $- zipWith- (\(cx,x) (cy,y) -> liftA2 (,) (A.or cx cy) (A.add x y))- (ext xs) (ext ys)---{--You can apply Causal.takeWhile instead,-but this requires a pretty complex type signature-including a 'process' variable that is not of interest for the user.--}-takeWhile ::- (C signal) =>- (forall r. a -> CodeGenFunction r (Value Bool)) ->- signal a -> signal a-takeWhile p =- alter- (\(Core next start stop) ->- Core- (\context sa0 -> do- (a,sa1) <- next context sa0- MaybeCont.guard =<< MaybeCont.lift (p a)- return (a,sa1))- start- stop)---envelope ::- (C signal, A.PseudoRing a) =>- signal a -> signal a -> signal a-envelope = zipWith Frame.amplifyMono--envelopeStereo ::- (C signal, A.PseudoRing a) =>- signal a -> signal (Stereo.T a) -> signal (Stereo.T a)-envelopeStereo = zipWith Frame.amplifyStereo--amplify ::- (C signal, IsArithmetic a, IsConst a) =>- a -> signal (Value a) -> signal (Value a)-amplify x =- map (Frame.amplifyMono (valueOf x))--amplifyStereo ::- (C signal, IsArithmetic a, IsConst a) =>- a -> signal (Stereo.T (Value a)) -> signal (Stereo.T (Value a))-amplifyStereo x =- map (Frame.amplifyStereo (valueOf x))----iterate ::- (C signal, IsFirstClass a, IsSized a, IsConst a) =>- (forall r. Value a -> CodeGenFunction r (Value a)) ->- Value a -> signal (Value a)-iterate f initial =- simple- (\y -> MaybeCont.lift $ fmap (\y1 -> (y,y1)) (f y))- (return initial)--exponential2 ::- (C signal, Trans.C a, IsArithmetic a, IsSized a, IsConst a) =>- a -> a -> signal (Value a)-exponential2 halfLife =- iterate (\y -> A.mul y (valueOf (0.5 ** recip halfLife))) . valueOf---osciPlain ::- (C signal, SoV.Fraction t, IsSized t, IsConst t) =>- (forall r. Value t -> CodeGenFunction r y) ->- Value t -> Value t -> signal y-osciPlain wave phase freq =- map wave $- iterate (SoV.incPhase freq) $- phase--osci ::- (C signal, SoV.Fraction t, IsSized t, IsConst t) =>- (forall r. Value t -> CodeGenFunction r y) ->- t -> t -> signal y-osci wave phase freq =- osciPlain wave (valueOf phase) (valueOf freq)--osciSaw ::- (C signal, SoV.IntegerConstant a, SoV.Fraction a, IsSized a, IsConst a) =>- a -> a -> signal (Value a)-osciSaw = osci Wave.saw----fromStorableVector ::- (Storable.C a, Tuple.ValueOf a ~ value) => SV.Vector a -> T value-fromStorableVector xs =- let (fp,ptr,l) = SVU.unsafeToPointers xs- in Cons- (\_ () (p0,l0) -> do- cont <- MaybeCont.lift $ A.cmp LLVM.CmpGT l0 A.zero- MaybeCont.withBool cont $ do- y1 <- Storable.load p0- p1 <- Storable.incrementPtr p0- l1 <- A.dec l0- return (y1,(p1,l1)))- (return ())- (const $ return- (valueOf ptr,- valueOf (fromIntegral l :: Word)))- -- keep the foreign ptr alive- (return (fp, ()))- touchForeignPtr--{--This function calls back into the Haskell function 'nextChunk'-that returns a pointer to the data of the next chunk-and advances to the next chunk in the sequence.--}-fromStorableVectorLazy ::- (Storable.C a, Tuple.ValueOf a ~ value) => SVL.Vector a -> T value-fromStorableVectorLazy = flattenChunks . storableVectorChunks--storableVectorChunks ::- (Storable.C a) => SVL.Vector a -> T (Value (Ptr a), Value Word)-storableVectorChunks sig =- Cons- (storableVectorNextChunk "Simple.Signal.fromStorableVectorLazy.nextChunk")- LLVM.alloca- (const $ return ())- ((\stable -> (stable,stable)) <$> ChunkIt.new sig)- ChunkIt.dispose---foreign import ccall safe "dynamic" derefFillPtr ::- Exec.Importer (Word -> Ptr struct -> IO Word)---compile ::- (Storable.C a, Tuple.ValueOf a ~ value, Memory.C state) =>- (forall r z.- (Tuple.Phi z) => local -> state -> MaybeCont.T r z (value, state)) ->- (forall r. CodeGenFunction r local) ->- (forall r. CodeGenFunction r state) ->- IO (Word -> Ptr a -> IO Word)-compile next alloca start =- Exec.compile "signal" $- Exec.createFunction derefFillPtr "fillsignalblock" $ \ size bPtr -> do- s <- start- local <- alloca- (pos,_) <-- Storable.arrayLoopMaybeCont size bPtr s $ \ ptri s0 -> do- (y,s1) <- next local s0- MaybeCont.lift $ Storable.store y ptri- return s1- ret pos--{--This parameter order would allows us to compile the code once-and apply it to different signal lengths.-However, we do not make use of this and instead bake-parts of the IO context into the code to allow constant folding.-The parameter order is consistent with that of @Parameterized.Signal.render@.--}-render ::- (Storable.C a, Tuple.ValueOf a ~ value, Memory.C value) =>- T value -> Int -> SV.Vector a-render (Cons next alloca start createIOContext deleteIOContext) len =- Unsafe.performIO $- bracket createIOContext (deleteIOContext . fst) $ \ (_ioContext, params) ->- SVB.createAndTrim len $ \ ptr ->- do fill <-- compile- (next $ Tuple.valueOf params) alloca (start $ Tuple.valueOf params)- fmap (fromIntegral :: Word -> Int) $ fill (fromIntegral len) ptr---foreign import ccall safe "dynamic" derefStartPtr ::- Exec.Importer (IO (LLVM.Ptr a))--foreign import ccall safe "dynamic" derefStopPtr ::- Exec.Importer (LLVM.Ptr a -> IO ())--foreign import ccall safe "dynamic" derefChunkPtr ::- Exec.Importer (LLVM.Ptr stateStruct -> Word -> Ptr struct -> IO Word)---compileChunky ::- (Storable.C a, Tuple.ValueOf a ~ value,- Memory.C state, Memory.Struct state ~ stateStruct) =>- (forall r z.- (Tuple.Phi z) =>- local -> state -> MaybeCont.T r z (value, state)) ->- (forall r. CodeGenFunction r local) ->- (forall r. CodeGenFunction r state) ->- IO (IO (LLVM.Ptr stateStruct),- Exec.Finalizer stateStruct,- LLVM.Ptr stateStruct -> Word -> Ptr a -> IO Word)-compileChunky next alloca start =- Exec.compile "signal-chunky" $- liftA3 (,,)- (Exec.createFunction derefStartPtr "startsignal" $- do- pptr <- LLVM.malloc- flip Memory.store pptr =<< start- ret pptr)-{- for debugging: allocation with initialization makes type inference difficult- (Exec.createFunPtr "startsignal" $- do- pptr <- malloc- let retn :: CodeGenFunction r state -> Value (Ptr state) -> CodeGenFunction (Ptr state) ()- retn _ ptr = ret ptr- retn undefined pptr)--}- (Exec.createFinalizer derefStopPtr "stopsignal" $- \ pptr -> LLVM.free pptr >> ret ())- (Exec.createFunction derefChunkPtr "fillsignal" $- \ sptr loopLen ptr -> do- sInit <- Memory.load sptr- local <- alloca- (pos,sExit) <-- Storable.arrayLoopMaybeCont loopLen ptr sInit $- \ ptri s0 -> do- (y,s1) <- next local s0- MaybeCont.lift $ Storable.store y ptri- return s1- Memory.store (Maybe.fromJust sExit) sptr- ret pos)---runChunky ::- (Storable.C a, Tuple.ValueOf a ~ value) =>- T value -> SVL.ChunkSize -> IO (SVL.Vector a)-runChunky (Cons next alloca start createIOContext deleteIOContext)- (SVL.ChunkSize size) = do- (ioContext, params) <- createIOContext- (startFunc, stopFunc, fill) <-- compileChunky- (next $ Tuple.valueOf params) alloca (start $ Tuple.valueOf params)-- statePtr <- ForeignPtr.newInit stopFunc startFunc- ioContextPtr <- ForeignPtr.newAux (deleteIOContext ioContext)-- let go =- Unsafe.interleaveIO $ do- v <-- ForeignPtr.with statePtr $ \sptr ->- SVB.createAndTrim size $- fmap (fromIntegral :: Word -> Int) .- fill sptr (fromIntegral size)- touchForeignPtr ioContextPtr- (if SV.length v > 0- then fmap (v:)- else id) $- (if SV.length v < size- then return []- else go)- fmap SVL.fromChunks go--renderChunky ::- (Storable.C a, Tuple.ValueOf a ~ value) =>- SVL.ChunkSize -> T value -> SVL.Vector a-renderChunky size sig =- Unsafe.performIO (runChunky sig size)
− src/Synthesizer/LLVM/Simple/SignalPacked.hs
@@ -1,166 +0,0 @@-{-# LANGUAGE NoImplicitPrelude #-}-{-# LANGUAGE TypeFamilies #-}-module Synthesizer.LLVM.Simple.SignalPacked where--import Synthesizer.LLVM.Simple.SignalPrivate (Core(Core), alter)-import qualified Synthesizer.LLVM.Simple.Signal as Sig-import qualified Synthesizer.LLVM.Frame.SerialVector as Serial--import qualified LLVM.Extra.Memory as Memory-import qualified LLVM.Extra.MaybeContinuation as Maybe-import qualified LLVM.Extra.Control as U-import qualified LLVM.Extra.Arithmetic as A-import qualified LLVM.Extra.Tuple as Tuple--import qualified LLVM.Core as LLVM-import LLVM.Core (valueOf)--import qualified Control.Monad.Trans.Class as MT-import qualified Control.Monad.Trans.State as MS-import Control.Monad (replicateM)--import Data.Word (Word)--import NumericPrelude.Numeric as NP-import NumericPrelude.Base hiding (and, iterate, map, zip, zipWith)----{- |-Convert a signal of scalar values into one using processor vectors.-If the signal length is not divisible by the chunk size,-then the last chunk is dropped.--}-pack, packRotate ::- (Sig.C signal, Serial.C v, a ~ Serial.Element v) =>- signal a -> signal v-pack = packRotate--packRotate = alter (\(Core next start stop) -> Core- (\param s -> do- wInit <- Maybe.lift $ Serial.writeStart- (w2,_,s2) <-- Maybe.fromBool $- U.whileLoop- (valueOf True,- (wInit,- valueOf $ (fromIntegral $ Serial.sizeOfIterator wInit :: Word),- s))- (\(cont,(_w0,i0,_s0)) ->- A.and cont =<<- A.cmp LLVM.CmpGT i0 A.zero)- (\(_,(w0,i0,s0)) -> Maybe.toBool $ do- (a,s1) <- next param s0- Maybe.lift $ do- w1 <- Serial.writeNext a w0- i1 <- A.dec i0- return (w1,i1,s1))- v <- Maybe.lift $ Serial.writeStop w2- return (v, s2))- start- stop)--{--We could reformulate it in terms of WriteIterator-that accesses elements using LLVM.extract.-We might move the loop counter into the Iterator,-but we have to assert that the counter is not duplicated.--packIndex ::- (Sig.C signal, Serial.C v, a ~ Serial.Element v) =>- signal a -> signal v-packIndex = alter (\(Core next start stop) -> Core- (\param s -> do- (v2,_,s2) <-- Maybe.fromBool $- U.whileLoop- (valueOf True, (Tuple.undef, A.zero, s))- (\(cont,(v0,i0,_s0)) ->- A.and cont =<<- A.cmp LLVM.CmpLT i0- (valueOf $ fromIntegral $ Serial.size v0))- (\(_,(v0,i0,s0)) -> Maybe.toBool $ do- (a,s1) <- next param s0- Maybe.lift $ do- v1 <- Vector.insert i0 a v0- i1 <- A.inc i0- return (v1,i1,s1))- return (v2, s2))- start- stop)--}---{- |-Like 'pack' but duplicates the code for creating elements.-That is, for vectors of size n, the code of the input signal-will be emitted n times.-This is efficient only for simple input generators.--}-packSmall ::- (Sig.C signal, Serial.C v, a ~ Serial.Element v) =>- signal a -> signal v-packSmall = alter (\(Core next start stop) -> Core- (\param ->- MS.runStateT $- Serial.withSize $ \n ->- MT.lift . Maybe.lift . Serial.assemble- =<<- replicateM n (MS.StateT $ next param))- start- stop)---unpack, unpackRotate ::- (Sig.C signal,- Serial.Read v, a ~ Serial.Element v, Serial.ReadIt v ~ itv, Memory.C itv) =>- signal v -> signal a-unpack = unpackRotate--unpackRotate = alter (\(Core next start stop) -> Core- (\context (i0,r0,s0) -> do- endOfVector <-- Maybe.lift $ A.cmp LLVM.CmpEQ i0 (valueOf (0::Word))- (i2,r2,s2) <-- Maybe.fromBool $- U.ifThen endOfVector (valueOf True, (i0,r0,s0)) $ do- (cont1, (v1,s1)) <- Maybe.toBool $ next context s0- r1 <- Serial.readStart v1- return (cont1, (valueOf $ fromIntegral $ Serial.size v1, r1, s1))- Maybe.lift $ do- (a,r3) <- Serial.readNext r2- i3 <- A.dec i2- return (a, (i3,r3,s2)))- (fmap (\s -> (A.zero, Tuple.undef, s)) . start)- (\(_,_,state) -> stop state))---{--We could reformulate it in terms of ReadIterator-that accesses elements using LLVM.extract.-We might move the loop counter into the Iterator,-but we have to assert that the counter is not duplicated.--unpackIndex ::- (Serial.C v, a ~ Serial.Element v, Memory.C v) =>- signal v -> signal a-unpackIndex = alter (\(Core next start stop) -> Core- (\param (i0,v0,s0) -> do- endOfVector <-- Maybe.lift $ A.cmp LLVM.CmpGE i0- (valueOf $ fromIntegral $ Serial.size v0)- (i2,v2,s2) <-- Maybe.fromBool $- U.ifThen endOfVector (valueOf True, (i0,v0,s0)) $ do- (cont1, (v1,s1)) <- Maybe.toBool $ next param s0- return (cont1, (A.zero, v1, s1))- Maybe.lift $ do- a <- Vector.extract i2 v2- i3 <- A.inc i2- return (a, (i3,v2,s2)))- (\p -> do- s <- start p- let v = Tuple.undef- return (valueOf $ fromIntegral $ Serial.size v, v, s))- stop)--}
− src/Synthesizer/LLVM/Simple/SignalPrivate.hs
@@ -1,340 +0,0 @@-{-# LANGUAGE NoImplicitPrelude #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE ExistentialQuantification #-}-{-# LANGUAGE Rank2Types #-}-module Synthesizer.LLVM.Simple.SignalPrivate where--import qualified Synthesizer.LLVM.Storable.ChunkIterator as ChunkIt--import qualified LLVM.Extra.Storable as Storable-import qualified LLVM.Extra.Marshal as Marshal-import qualified LLVM.Extra.Memory as Memory-import qualified LLVM.Extra.MaybeContinuation as MaybeCont-import qualified LLVM.Extra.Either as Either-import qualified LLVM.Extra.Maybe as Maybe-import qualified LLVM.Extra.Arithmetic as A-import qualified LLVM.Extra.Tuple as Tuple-import LLVM.Extra.Control (ifThen)--import qualified LLVM.Util.Proxy as LP-import qualified LLVM.Core as LLVM-import LLVM.Core (CodeGenFunction, Value, valueOf)--import Control.Monad (liftM2)-import Control.Applicative (Applicative, pure, liftA2, (<*>), (<$>))--import Foreign.StablePtr (StablePtr)-import Foreign.Ptr (Ptr, nullPtr)--import Data.Tuple.Strict (zipPair)-import Data.Monoid (Monoid, mempty, mappend)-import Data.Semigroup (Semigroup, (<>))-import Data.Word (Word)--import qualified Number.Ratio as Ratio-import qualified Algebra.Field as Field-import qualified Algebra.Ring as Ring-import qualified Algebra.Additive as Additive--import NumericPrelude.Base hiding (and, iterate, map, zip, zipWith)--import qualified Prelude as P---{--We need the forall quantification for 'CodeGenFunction's @r@ parameter.-This type parameter will be unified with the result type of the final function.-Since one piece of code can be used in multiple functions-we cannot yet fix the type @r@ here.---We might avoid code duplication with Causal.Process by defining--> newtype T a = Cons (Causal.T () a)---In earlier versions the createIOContext method created only an ioContext-that was directly used to construct code for 'start' and 'next'.-This had the advantage that we did not need to pass-something via the Memory.C interface to the function.-However, creating both an ioContext and a low-level parameter has those advantages:-We can design Causal.Process such that a process-can be applied to multiple signals without recompilation.-We can lift simple signals and processes to their parameterized counterparts.--}-data T a =- forall state local ioContext parameters.- (Marshal.C parameters, Memory.C state) =>- Cons (forall r c.- (Tuple.Phi c) =>- Tuple.ValueOf parameters -> local ->- state -> MaybeCont.T r c (a, state))- -- compute next value- (forall r.- CodeGenFunction r local)- -- allocate temporary variables before a loop- (forall r.- Tuple.ValueOf parameters ->- CodeGenFunction r state)- -- initial state- (IO (ioContext, parameters))- {- initialization from IO monad- This will be run within Unsafe.performIO,- so no observable In/Out actions please!- -}- (ioContext -> IO ())- -- finalization from IO monad, also run within Unsafe.performIO---data Core context initState exitState a =- forall state.- (Memory.C state) =>- Core (forall r c.- (Tuple.Phi c) =>- context ->- state -> MaybeCont.T r c (a, state))- -- compute next value- (forall r.- initState ->- CodeGenFunction r state)- -- initial state- (state -> exitState)- -- extract final state for cleanup---class Applicative signal => C signal where- simple ::- (Memory.C state) =>- (forall r c. state -> MaybeCont.T r c (a, state)) ->- (forall r. CodeGenFunction r state) ->- signal a- simple next start =- simpleAlloca (\() state -> next state) (return ()) start-- simpleAlloca ::- (Memory.C state) =>- (forall r c. local -> state -> MaybeCont.T r c (a, state)) ->- (forall r. CodeGenFunction r local) ->- (forall r. CodeGenFunction r state) ->- signal a-- alter ::- (forall contextLocal initState exitState.- Core contextLocal initState exitState a0 ->- Core contextLocal initState exitState a1) ->- signal a0 -> signal a1--instance C T where- simpleAlloca next alloca0 start =- Cons- (\() local -> next local)- alloca0- (const start)- (return ((),()))- (const $ return ())-- alter f (Cons next0 alloca0 start0 create delete) =- case f (Core (uncurry next0) start0 id) of- Core next1 start1 _ ->- Cons (curry next1) alloca0 start1 create delete---map ::- (C signal) =>- (forall r. a -> CodeGenFunction r b) -> signal a -> signal b-map f = alter (\(Core next start stop) ->- Core- (\ioContext sa0 -> do- (a,sa1) <- next ioContext sa0- b <- MaybeCont.lift $ f a- return (b, sa1))- start- stop)--zipWith ::- (C signal) =>- (forall r. a -> b -> CodeGenFunction r c) ->- signal a -> signal b -> signal c-zipWith f a b = map (uncurry f) $ liftA2 (,) a b---zip :: T a -> T b -> T (a,b)-zip (Cons nextA allocaA startA createIOContextA deleteIOContextA)- (Cons nextB allocaB startB createIOContextB deleteIOContextB) =- Cons- (\(paramA, paramB) (localA, localB) (sa0,sb0) ->- liftM2 zipPair- (nextA paramA localA sa0)- (nextB paramB localB sb0))- (liftM2 (,) allocaA allocaB)- (combineStart startA startB)- (combineCreate createIOContextA createIOContextB)- (combineDelete deleteIOContextA deleteIOContextB)--combineStart ::- Monad m =>- (paramA -> m stateA) ->- (paramB -> m stateB) ->- (paramA, paramB) -> m (stateA, stateB)-combineStart startA startB (paramA, paramB) =- liftM2 (,) (startA paramA) (startB paramB)--combineCreate ::- Monad m =>- m (ioContextA, contextA) ->- m (ioContextB, contextB) ->- m ((ioContextA, ioContextB), (contextA, contextB))-combineCreate createIOContextA createIOContextB =- liftM2 zipPair createIOContextA createIOContextB--combineDelete :: (Monad m) => (ca -> m ()) -> (cb -> m ()) -> (ca, cb) -> m ()-combineDelete deleteIOContextA deleteIOContextB (ca,cb) =- deleteIOContextA ca >> deleteIOContextB cb---instance Functor T where- fmap f = map (return . f)--{- |-ZipList semantics--}-instance Applicative T where- pure x = simple (\() -> return (x, ())) (return ())- f <*> a = fmap (uncurry ($)) $ zip f a--instance (A.Additive a) => Additive.C (T a) where- zero = pure A.zero- negate = map A.neg- (+) = zipWith A.add- (-) = zipWith A.sub--instance (A.PseudoRing a, A.IntegerConstant a) => Ring.C (T a) where- one = pure A.one- fromInteger n = pure (A.fromInteger' n)- (*) = zipWith A.mul--instance (A.Field a, A.RationalConstant a) => Field.C (T a) where- fromRational' x = pure (A.fromRational' $ Ratio.toRational98 x)- (/) = zipWith A.fdiv---instance (A.PseudoRing a, A.Real a, A.IntegerConstant a) => P.Num (T a) where- fromInteger n = pure (A.fromInteger' n)- negate = map A.neg- (+) = zipWith A.add- (-) = zipWith A.sub- (*) = zipWith A.mul- abs = map A.abs- signum = map A.signum--instance (A.Field a, A.Real a, A.RationalConstant a) => P.Fractional (T a) where- fromRational x = pure (A.fromRational' x)- (/) = zipWith A.fdiv----empty :: (C signal) => signal a-empty = simple (const $ MaybeCont.nothing) (return ())--{- |-Appending many signals is inefficient,-since in cascadingly appended signals the parts are counted in an unary way.-Concatenating infinitely many signals is impossible.-If you want to concatenate a lot of signals,-please render them to lazy storable vectors first.--}-{--We might save a little space by using a union-for the states of the first and the second signal generator.-If the concatenated generators allocate memory,-we could also save some memory by calling @startB@-only after the first generator finished.-However, for correct deallocation-we would need to track which of the @start@ blocks-have been executed so far.-This in turn might be difficult in connection with the garbage collector.--}-append :: (Tuple.Phi a, Tuple.Undefined a) => T a -> T a -> T a-append- (Cons nextA allocaA startA createIOContextA deleteIOContextA)- (Cons nextB allocaB startB createIOContextB deleteIOContextB) =- Cons- (\(parameterA, parameterB) (localA, localB) es0 ->- MaybeCont.fromMaybe $ do- es1 <-- Either.run es0- (\sa0 ->- MaybeCont.resolve- (nextA parameterA localA sa0)- (fmap Either.right $ startB parameterB)- (\(a1,sa1) -> return (Either.left (a1, sa1))))- (return . Either.right)-- Either.run es1- (\(a1,s1) -> return (Maybe.just (a1, Either.left s1)))- (\sb0 ->- MaybeCont.toMaybe $- fmap (\(b,sb1) -> (b, Either.right sb1)) $- nextB parameterB localB sb0))- (liftM2 (,) allocaA allocaB)- (\(parameterA, _parameterB) -> Either.left <$> startA parameterA)- (combineCreate createIOContextA createIOContextB)- (combineDelete deleteIOContextA deleteIOContextB)--instance (Tuple.Phi a, Tuple.Undefined a) => Semigroup (T a) where- (<>) = append--instance (Tuple.Phi a, Tuple.Undefined a) => Monoid (T a) where- mempty = empty- mappend = append----storableVectorNextChunk ::- (Tuple.Phi c, Storable.C a) =>- String ->- Value (StablePtr (ChunkIt.T a)) -> Value (LLVM.Ptr Word) -> () ->- MaybeCont.T r c ((Value (Ptr a), Value Word), ())-storableVectorNextChunk callbackName stable lenPtr () =- MaybeCont.fromBool $ do- nextChunkFn <- LLVM.staticNamedFunction callbackName ChunkIt.nextCallBack- (buffer,len) <-- liftM2 (,)- (LLVM.call nextChunkFn stable lenPtr)- (LLVM.load lenPtr)- valid <- A.cmp LLVM.CmpNE buffer (valueOf nullPtr)- return (valid, ((buffer,len), ()))--flattenChunks ::- (C signal, Storable.C a, Tuple.ValueOf a ~ value) =>- signal (Value (Ptr a), Value Word) -> signal value-flattenChunks = alter $ \(Core next start stop) ->- Core- (\context ((buffer0,length0), state0) -> do- ((buffer1,length1), state1) <- MaybeCont.fromBool $ do- needNext <- A.cmp LLVM.CmpEQ length0 A.zero- ifThen needNext- (valueOf True, ((buffer0,length0), state0))- (MaybeCont.toBool $ next context state0)- MaybeCont.lift $ do- x <- Storable.load buffer1- buffer2 <- Storable.incrementPtr buffer1- length2 <- A.dec length1- return (x, ((buffer2,length2), state1)))- (\p -> (,) (valueOf nullPtr, A.zero) <$> start p)- (stop . snd)--alloca :: (C signal, LLVM.IsSized a) => signal (LLVM.Value (LLVM.Ptr a))-alloca =- simpleAlloca- (\ptr () -> return (ptr, ()))- LLVM.alloca- (return ())---proxyFromElement :: f a -> LP.Proxy a-proxyFromElement _ = LP.Proxy--proxyFromElement2 :: f (g a) -> LP.Proxy a-proxyFromElement2 _ = LP.Proxy
− src/Synthesizer/LLVM/Simple/Value.hs
@@ -1,569 +0,0 @@-{-# LANGUAGE NoImplicitPrelude #-}-{-# LANGUAGE Rank2Types #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE UndecidableInstances #-}-module Synthesizer.LLVM.Simple.Value (- T, decons,- twoPi, square, sqrt,- max, min, limit, fraction,-- (%==), (%/=), (%<), (%<=), (%>), (%>=), not,- (%&&), (%||),- (?), (??),-- lift0, lift1, lift2, lift3,- unlift0, unlift1, unlift2, unlift3, unlift4, unlift5,- constantValue, constant,- fromInteger', fromRational',-- Flatten(flattenCode, unfoldCode), Registers,- flatten, unfold,- flattenCodeTraversable, unfoldCodeTraversable,- flattenFunction,- ) where--import qualified LLVM.Extra.Control as C-import qualified LLVM.Extra.Arithmetic as A-import qualified LLVM.Extra.Tuple as Tuple--import LLVM.Core (CodeGenFunction)-import qualified LLVM.Core as LLVM--import qualified Synthesizer.Basic.Phase as Phase--import qualified Data.Vault.Lazy as Vault-import qualified Control.Monad.Trans.Class as MT-import qualified Control.Monad.Trans.State as MS-import Control.Monad (liftM2, liftM3)-import Control.Applicative (Applicative, pure, (<*>))-import Control.Functor.HT (unzip, unzip3)--import qualified Synthesizer.LLVM.Frame.Stereo as Stereo---- import qualified Algebra.NormedSpace.Maximum as NormedMax-import qualified Algebra.NormedSpace.Euclidean as NormedEuc-import qualified Algebra.NormedSpace.Sum as NormedSum--import qualified Algebra.Transcendental as Trans-import qualified Algebra.Algebraic as Algebraic-import qualified Algebra.RealRing as RealRing-import qualified Algebra.Absolute as Absolute-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 qualified Number.Complex as Complex--import qualified Data.Traversable as Trav-import qualified Data.Foldable as Fold--import qualified System.Unsafe as Unsafe--import qualified Prelude as P-import NumericPrelude.Numeric hiding (pi, sqrt, fromRational', fraction)-import NumericPrelude.Base hiding (min, max, unzip, unzip3, not)---{--The @r@ type parameter must be hidden and forall-quantified-because otherwise we would need an impossible type-where we have to quantify for @r@ and @t@ in different scopes-while having a class constraint that involves both of them.--> osci ::-> (RealRing.C (Value.T r t),-> IsFirstClass t, IsFloating t,-> IsPrimitive t, IsConst t) =>-> (forall r. Wave.T (Value.T r t) (Value.T r y)) ->-> t -> t -> T (Value y)---}-newtype T a = Cons {code :: forall r. Compute r a}--decons :: T a -> (forall r. LLVM.CodeGenFunction r a)-decons value =- MS.evalStateT (code value) Vault.empty--instance Functor T where- fmap f x = consUnique (fmap f (code x))--instance Applicative T where- pure = constantValue- f <*> x = consUnique (code f <*> code x)---type Compute r a =- MS.StateT Vault.Vault (LLVM.CodeGenFunction r) a--consUnique :: (forall r. Compute r a) -> T a-consUnique code0 =- Unsafe.performIO $- fmap (consKey code0) Vault.newKey--consKey :: (forall r. Compute r a) -> Vault.Key a -> T a-consKey code0 key =- Cons (do- ma <- MS.gets (Vault.lookup key)- case ma of- Just a -> return a- Nothing -> do- a <- code0- MS.modify (Vault.insert key a)- return a)--{- |-We do not require a numeric prelude superclass,-thus also LLVM only types like vectors are instances.--}-instance (A.Additive a) => Additive.C (T a) where- zero = constantValue A.zero- (+) = lift2 A.add- (-) = lift2 A.sub- negate = lift1 A.neg--instance (A.PseudoRing a, A.IntegerConstant a) =>- Ring.C (T a) where- one = constantValue A.one- (*) = lift2 A.mul- fromInteger = fromInteger'--{--This instance is enough for Module here.-The difference to Module instances on Haskell tuples is,-that LLVM vectors cannot be nested.--}-instance (a ~ A.Scalar v, A.PseudoModule v, A.IntegerConstant a) =>- Module.C (T a) (T v) where- (*>) = lift2 A.scale--instance (A.Additive a, A.IntegerConstant a) => Enum (T a) where- succ x = x + constantValue A.one- pred x = x - constantValue A.one- fromEnum _ = error "CodeGenFunction Value: fromEnum"- toEnum = constantValue . A.fromInteger' . fromIntegral--{--instance (IsArithmetic a, Cmp a b, Num a, IsConst a) => Real (T a) where- toRational _ = error "CodeGenFunction Value: toRational"--instance (Cmp a b, Num a, IsConst a, IsInteger a) => Integral (T a) where- quot = lift2 idiv- rem = lift2 irem- quotRem x y = (quot x y, rem x y)- toInteger _ = error "CodeGenFunction Value: toInteger"--}--instance (A.Field a, A.RationalConstant a) => Field.C (T a) where- (/) = lift2 A.fdiv- fromRational' = fromRational' . Field.fromRational'--{--instance (Cmp a b, Fractional a, IsConst a, IsFloating a) => RealFrac (T a) where- properFraction _ = error "CodeGenFunction Value: properFraction"--}--instance (A.Transcendental a, A.RationalConstant a) => Algebraic.C (T a) where- sqrt = lift1 A.sqrt- root n x = lift2 A.pow x (1 / fromInteger n)- x^/r = lift2 A.pow x (Field.fromRational' r)--instance (A.Transcendental a, A.RationalConstant a) => Trans.C (T a) where- pi = lift0 A.pi- sin = lift1 A.sin- cos = lift1 A.cos- (**) = lift2 A.pow- exp = lift1 A.exp- log = lift1 A.log-- asin _ = error "LLVM missing intrinsic: asin"- acos _ = error "LLVM missing intrinsic: acos"- atan _ = error "LLVM missing intrinsic: atan"---instance- (A.PseudoRing a, A.Real a, A.IntegerConstant a) =>- P.Num (T a) where- fromInteger = fromInteger'- (+) = lift2 A.add- (-) = lift2 A.sub- (*) = lift2 A.mul- negate = lift1 A.neg- abs = lift1 A.abs- signum = lift1 A.signum--instance- (A.Field a, A.Real a, A.RationalConstant a) =>- P.Fractional (T a) where- fromRational = fromRational'- (/) = lift2 A.fdiv--instance- (A.Transcendental a, A.Real a, A.RationalConstant a) =>- P.Floating (T a) where- pi = lift0 A.pi- sin = lift1 A.sin- cos = lift1 A.cos- (**) = lift2 A.pow- exp = lift1 A.exp- log = lift1 A.log-- asin _ = error "LLVM missing intrinsic: asin"- acos _ = error "LLVM missing intrinsic: acos"- atan _ = error "LLVM missing intrinsic: atan"-- sinh x = (exp x - exp (-x)) / 2- cosh x = (exp x + exp (-x)) / 2- asinh x = log (x + sqrt (x*x + 1))- acosh x = log (x + sqrt (x*x - 1))- atanh x = (log (1 + x) - log (1 - x)) / 2---twoPi ::- (A.Transcendental a, A.RationalConstant a) =>- T a-twoPi = 2 * Trans.pi--square ::- (A.PseudoRing a) =>- T a -> T a-square = lift1 A.square--{- |-The same as 'Algebraic.sqrt',-but needs only Algebraic constraint, not Transcendental.--}-sqrt ::- (A.Algebraic a) =>- T a -> T a-sqrt = lift1 A.sqrt---min, max :: (A.Real a) => T a -> T a -> T a-min = lift2 A.min-max = lift2 A.max--limit :: (A.Real a) => (T a, T a) -> T a -> T a-limit (l,u) = max l . min u--fraction :: (A.Fraction a) => T a -> T a-fraction = lift1 A.fraction---instance (A.Real a, A.PseudoRing a, A.IntegerConstant a) =>- Absolute.C (T a) where- abs = lift1 A.abs- signum = lift1 A.signum--{--For useful instances with different scalar and vector type,-we would need a more flexible superclass.--}-instance (A.Real a, A.IntegerConstant a, a ~ A.Scalar a, A.PseudoModule a) =>- NormedSum.C (T a) (T a) where- norm = lift1 A.abs--instance (A.Real a, A.IntegerConstant a, a ~ A.Scalar a, A.PseudoModule a) =>- NormedEuc.Sqr (T a) (T a) where- normSqr = lift1 A.square--instance- (NormedEuc.Sqr (T a) (T v),- A.RationalConstant a, A.Algebraic a) =>- NormedEuc.C (T a) (T v) where- norm = lift1 A.sqrt . NormedEuc.normSqr--{--instance (A.Real a, A.IntegerConstant a, A.PseudoModule a a) =>- NormedMax.C (T a) (T a) where- norm = lift1 A.abs--}---infix 4 %==, %/=, %<, %<=, %>=, %>--(%==), (%/=), (%<), (%<=), (%>), (%>=) ::- (LLVM.CmpRet a) =>- T (LLVM.Value a) -> T (LLVM.Value a) -> T (LLVM.Value (LLVM.CmpResult a))-(%==) = lift2 $ LLVM.cmp LLVM.CmpEQ-(%/=) = lift2 $ LLVM.cmp LLVM.CmpNE-(%>) = lift2 $ LLVM.cmp LLVM.CmpGT-(%>=) = lift2 $ LLVM.cmp LLVM.CmpGE-(%<) = lift2 $ LLVM.cmp LLVM.CmpLT-(%<=) = lift2 $ LLVM.cmp LLVM.CmpLE--infixr 3 %&&-infixr 2 %||---- | Lazy AND-(%&&) :: T (LLVM.Value Bool) -> T (LLVM.Value Bool) -> T (LLVM.Value Bool)-a %&& b = a ? (b, constant False)---- | Lazy OR-(%||) :: T (LLVM.Value Bool) -> T (LLVM.Value Bool) -> T (LLVM.Value Bool)-a %|| b = a ? (constant True, b)--not :: T (LLVM.Value Bool) -> T (LLVM.Value Bool)-not = lift1 LLVM.inv---infix 0 ?-{- |-@true ? (t,f)@ evaluates @t@,-@false ? (t,f)@ evaluates @f@.-@t@ and @f@ can reuse interim results,-but they cannot contribute shared results,-since only one of them will be run.-Cf. '(??)'--}-(?) ::- (Flatten value, Registers value ~ a, Tuple.Phi a) =>- T (LLVM.Value Bool) -> (value, value) -> value-c ? (t, f) =- unfoldCode $ consUnique $ do- b <- code c- shared <- MS.get- MT.lift $- C.ifThenElse b- (MS.evalStateT (flattenCode t) shared)- (MS.evalStateT (flattenCode f) shared)--infix 0 ??-{- |-The expression @c ?? (t,f)@ evaluates both @t@ and @f@-and selects components from @t@ and @f@ according to @c@.-It is useful for vector values and-for sharing @t@ or @f@ with other branches of an expression.--}-(??) ::- (LLVM.IsFirstClass a, LLVM.CmpRet a) =>- T (LLVM.Value (LLVM.CmpResult a)) ->- (T (LLVM.Value a), T (LLVM.Value a)) ->- T (LLVM.Value a)-c ?? (t, f) = lift3 LLVM.select c t f----lift0 ::- (forall r. CodeGenFunction r a) ->- T a-lift0 f =- consUnique $ MT.lift $ f--lift1 ::- (forall r. a -> CodeGenFunction r b) ->- T a -> T b-lift1 f x =- consUnique $ MT.lift . f =<< code x--lift2 ::- (forall r. a -> b -> CodeGenFunction r c) ->- T a -> T b -> T c-lift2 f x y =- consUnique $ do- xv <- code x- yv <- code y- MT.lift $ f xv yv--lift3 ::- (forall r. a -> b -> c -> CodeGenFunction r d) ->- T a -> T b -> T c -> T d-lift3 f x y z =- consUnique $ do- xv <- code x- yv <- code y- zv <- code z- MT.lift $ f xv yv zv---_unlift0 ::- T a ->- (forall r. CodeGenFunction r a)-_unlift0 = decons--unlift0 ::- (Flatten value) =>- value ->- (forall r. CodeGenFunction r (Registers value))-unlift0 = flatten--_unlift1 ::- (T a -> T b) ->- (forall r. a -> CodeGenFunction r b)-_unlift1 = unlift1--{--Better type inference than flattenFunction.--}-unlift1 ::- (Flatten value) =>- (T a -> value) ->- (forall r. a -> CodeGenFunction r (Registers value))-unlift1 f a =- flatten (f (constantValue a))--_unlift2 ::- (T a -> T b -> T c) ->- (forall r. a -> b -> CodeGenFunction r c)-_unlift2 = unlift2--unlift2 ::- (Flatten value) =>- (T a -> T b -> value) ->- (forall r. a -> b -> CodeGenFunction r (Registers value))-unlift2 f a b =- flatten (f (constantValue a) (constantValue b))--unlift3 ::- (Flatten value) =>- (T a -> T b -> T c -> value) ->- (forall r. a -> b -> c -> CodeGenFunction r (Registers value))-unlift3 f a b c =- flatten (f (constantValue a) (constantValue b) (constantValue c))--unlift4 ::- (Flatten value) =>- (T a -> T b -> T c -> T d -> value) ->- (forall r. a -> b -> c -> d -> CodeGenFunction r (Registers value))-unlift4 f a b c d =- flatten $- f (constantValue a) (constantValue b) (constantValue c) (constantValue d)--unlift5 ::- (Flatten value) =>- (T a -> T b -> T c -> T d -> T e -> value) ->- (forall r. a -> b -> c -> d -> e -> CodeGenFunction r (Registers value))-unlift5 f a b c d e =- flatten $- f (constantValue a) (constantValue b) (constantValue c)- (constantValue d) (constantValue e)---constantValue :: a -> T a-constantValue x =- consUnique (return x)--constant :: (LLVM.IsConst a) => a -> T (LLVM.Value a)-constant = constantValue . LLVM.valueOf--fromInteger' :: (A.IntegerConstant a) => Integer -> T a-fromInteger' = constantValue . A.fromInteger'--fromRational' :: (A.RationalConstant a) => P.Rational -> T a-fromRational' = constantValue . A.fromRational'---class Flatten value where- type Registers value :: *- flattenCode :: value -> Compute r (Registers value)- unfoldCode :: T (Registers value) -> value--flatten ::- (Flatten value) =>- value -> CodeGenFunction r (Registers value)-flatten x = MS.evalStateT (flattenCode x) Vault.empty--unfold ::- (Flatten value) =>- (Registers value) -> value-unfold x = unfoldCode $ pure x--flattenCodeTraversable ::- (Flatten value, Trav.Traversable f) =>- f value -> Compute r (f (Registers value))-flattenCodeTraversable =- Trav.mapM flattenCode--unfoldCodeTraversable ::- (Flatten value, Trav.Traversable f, Applicative f) =>- T (f (Registers value)) -> f value-unfoldCodeTraversable =- unfoldFromGetters getters--unfoldFromGetters ::- (Functor f, Flatten b) =>- f (a -> Registers b) -> T a -> f b-unfoldFromGetters g x =- fmap (unfoldCode . flip fmap x) g--getters ::- (Trav.Traversable f, Applicative f) =>- f (f a -> a)-getters =- fmap (\n x -> Fold.toList x !! n) $- MS.evalState (Trav.sequenceA (pure (MS.state $ \n -> (n, succ n)))) 0---flattenFunction ::- (Flatten a, Flatten b) =>- (a -> b) -> (Registers a -> CodeGenFunction r (Registers b))-flattenFunction f =- flatten . f . unfold--{--This function is hardly useful,-since most functions are not of type-@(Registers a -> (forall r. CodeGenFunction r (Registers b)))@-but of type-@(forall r. Registers a -> CodeGenFunction r (Registers b))@.-We would also need a method unfoldF.-See ValueUnfoldF for some implementations.--unfoldFunction ::- (Flatten a, Flatten b) =>- (Registers a -> (forall r. CodeGenFunction r (Registers b))) -> (a -> b)-unfoldFunction f x =- unfoldF (f =<< flatten x)--}---instance (Flatten a, Flatten b) => Flatten (a,b) where- type Registers (a,b) = (Registers a, Registers b)- flattenCode (a,b) =- liftM2 (,) (flattenCode a) (flattenCode b)- unfoldCode x =- case unzip x of- (a,b) -> (unfoldCode a, unfoldCode b)--instance (Flatten a, Flatten b, Flatten c) => Flatten (a,b,c) where- type Registers (a,b,c) = (Registers a, Registers b, Registers c)- flattenCode (a,b,c) =- liftM3 (,,) (flattenCode a) (flattenCode b) (flattenCode c)- unfoldCode x =- case unzip3 x of- (a,b,c) -> (unfoldCode a, unfoldCode b, unfoldCode c)--instance Flatten a => Flatten (Stereo.T a) where- type Registers (Stereo.T a) = Stereo.T (Registers a)- flattenCode = flattenCodeTraversable- unfoldCode = unfoldCodeTraversable--instance Flatten a => Flatten (Complex.T a) where- type Registers (Complex.T a) = Complex.T (Registers a)- flattenCode s =- liftM2 (Complex.+:)- (flattenCode $ Complex.real s)- (flattenCode $ Complex.imag s)- unfoldCode =- unfoldFromGetters $ Complex.real Complex.+: Complex.imag--instance (RealRing.C a, Flatten a) => Flatten (Phase.T a) where- type Registers (Phase.T a) = Registers a- flattenCode s =- flattenCode $ Phase.toRepresentative s- unfoldCode s =- -- could also be unsafeFromRepresentative- Phase.fromRepresentative $ unfoldCode s---instance Flatten (T a) where- type Registers (T a) = a- flattenCode = code- unfoldCode = id--instance Flatten () where- type Registers () = ()- flattenCode = return- unfoldCode _ = ()
− src/Synthesizer/LLVM/Simple/Vanilla.hs
@@ -1,86 +0,0 @@-{-# LANGUAGE NoImplicitPrelude #-}-{-# LANGUAGE TypeFamilies #-}-module Synthesizer.LLVM.Simple.Vanilla where--import qualified Synthesizer.LLVM.Simple.Signal as Sig-import qualified Synthesizer.LLVM.Simple.Value as Value--import qualified Synthesizer.Basic.Phase as Phase-import qualified Synthesizer.Basic.Wave as Wave--import qualified LLVM.Extra.MaybeContinuation as Maybe-import qualified LLVM.Extra.ScalarOrVector as SoV-import qualified LLVM.Extra.Memory as Memory-import LLVM.Core (IsArithmetic, IsConst, IsFirstClass, IsSized, Value)--import qualified Algebra.RealRing as RealRing--import NumericPrelude.Base hiding (and, iterate, map, zipWith)---iterateVal ::- (Memory.C a) =>- (Value.T a -> Value.T a) ->- Value.T a -> Sig.T (Value.T a)-iterateVal f initial =- Sig.simple- (\y ->- Maybe.lift $- fmap (\y1 -> (Value.constantValue y, y1))- (Value.unlift1 f y))- (Value.decons initial)--iterate ::- (Value.Flatten a, Value.Registers a ~ reg, Memory.C reg) =>- (a -> a) ->- (a -> Sig.T a)-iterate f initial =- Sig.simple- (\y ->- Maybe.lift $- fmap (\y1 -> (Value.unfold y, y1))- (Value.flattenFunction f y))- (Value.flatten initial)----map ::- (a -> b) ->- Sig.T a -> Sig.T b-map f = Sig.map (return . f)---osciReg ::- (RealRing.C tv, tv ~ Value.T (Value t),- SoV.Fraction t, IsConst t, IsSized t,- IsFirstClass y) =>- Wave.T (Value.T (Value t)) (Value.T (Value y)) ->- Value t -> Value t -> Sig.T (Value y)-osciReg wave phase freq =- Sig.map- (Value.unlift1 $ Wave.apply wave . Phase.fromRepresentative) $- Sig.iterate (SoV.incPhase freq) phase--osciVal ::- (RealRing.C tv, tv ~ Value.T (Value t),- SoV.Fraction t, IsConst t, IsSized t) =>- Wave.T (Value.T (Value t)) y ->- Value.T (Value t) -> Value.T (Value t) -> Sig.T y-osciVal wave phase freq =- map (Wave.apply wave . Phase.fromRepresentative) $- iterateVal (incPhaseVal freq) phase--incPhaseVal ::- (SoV.Fraction a, IsArithmetic a) =>- Value.T (Value a) -> Value.T (Value a) -> Value.T (Value a)-incPhaseVal = Value.lift2 SoV.incPhase--osci ::- (RealRing.C t,- Value.Flatten t, Value.Registers t ~ reg, Memory.C reg,- SoV.Fraction t, IsConst t) =>- Wave.T t y ->- Phase.T t -> t -> Sig.T y-osci wave phase freq =- map (Wave.apply wave) $- iterate (Phase.increment freq) phase
src/Synthesizer/LLVM/Storable/ChunkIterator.hs view
@@ -6,11 +6,10 @@ import qualified Data.StorableVector.Lazy as SVL import qualified Data.StorableVector.Base as SVB -import qualified LLVM.Extra.Storable as Storable import qualified LLVM.Core as LLVM import Data.Word (Word)-import Foreign.Storable (poke)+import Foreign.Storable (Storable, poke) import Foreign.Ptr (FunPtr, Ptr, nullPtr) import Control.Monad (liftM2)@@ -23,7 +22,7 @@ FFI declarations must not have constraints. Thus we put them in the iterator datatype. -}-data T a = (Storable.C a) => Cons (IORef [SVB.Vector a]) (IORef (SVB.Vector a))+data T a = (Storable a) => Cons (IORef [SVB.Vector a]) (IORef (SVB.Vector a)) foreign import ccall "&nextChunk"@@ -33,7 +32,7 @@ next :: StablePtr (T a) -> Ptr Word -> IO (Ptr a) -new :: (Storable.C a) => SVL.Vector a -> IO (StablePtr (T a))+new :: (Storable a) => SVL.Vector a -> IO (StablePtr (T a)) new sig = newStablePtr =<< liftM2 Cons
src/Synthesizer/LLVM/Storable/Process.hs view
@@ -8,10 +8,9 @@ continuePacked, ) where -import qualified Synthesizer.LLVM.Frame.SerialVector as Serial+import qualified Synthesizer.LLVM.Frame.SerialVector.Code as Serial import qualified Synthesizer.LLVM.Storable.Signal as SigStL import qualified Synthesizer.CausalIO.Process as PIO- import qualified Synthesizer.Generic.Cut as CutG import qualified Data.StorableVector as SV@@ -21,12 +20,10 @@ import qualified Data.EventList.Relative.TimeTime as EventListTT import qualified Data.EventList.Relative.TimeMixed as EventListTM import qualified Data.EventList.Absolute.TimeBody as AbsEventList-import qualified Number.NonNegative as NonNeg +import qualified LLVM.Extra.Multi.Value.Storable as Storable+import qualified LLVM.Extra.Multi.Value as MultiValue import qualified LLVM.Extra.Arithmetic as A-import qualified LLVM.Extra.Storable as Storable-import qualified LLVM.Extra.Tuple as Tuple-import qualified LLVM.Core as LLVM import qualified Type.Data.Num.Decimal as TypeNum @@ -36,6 +33,8 @@ import qualified System.Unsafe as Unsafe +import qualified Number.NonNegative as NonNeg+ import NumericPrelude.Numeric import NumericPrelude.Base @@ -49,7 +48,7 @@ must fit into the length of the event list. -} makeArranger ::- (Arr.Arrow arrow, Storable.C a, Tuple.ValueOf a ~ value, A.Additive value) =>+ (Arr.Arrow arrow, Storable.C a, MultiValue.Additive a) => IO (arrow (EventListTT.T NonNeg.Int (SV.Vector a)) (SV.Vector a))@@ -79,10 +78,10 @@ continuePacked ::- (CutG.Transform a, Storable.C b, LLVM.IsPrimitive b, TypeNum.Positive n) =>- PIO.T a (SV.Vector (Serial.Plain n b)) ->- (b -> PIO.T a (SV.Vector (Serial.Plain n b))) ->- PIO.T a (SV.Vector (Serial.Plain n b))+ (CutG.Transform a, Storable.Vector b, TypeNum.Positive n) =>+ PIO.T a (SV.Vector (Serial.T n b)) ->+ (b -> PIO.T a (SV.Vector (Serial.T n b))) ->+ PIO.T a (SV.Vector (Serial.T n b)) continuePacked proc0 proc1 = PIO.continueChunk proc0 (proc1 Arr.<<^ SV.last . SigStL.unpackStrict)
src/Synthesizer/LLVM/Storable/Signal.hs view
@@ -1,27 +1,22 @@-{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeOperators #-} {-# LANGUAGE ForeignFunctionInterface #-} {- |-Functions on lazy storable vectors that are implemented using LLVM.+Functions on storable vectors that are implemented using LLVM. -} module Synthesizer.LLVM.Storable.Signal ( unpackStrict, unpack, unpackStereoStrict, unpackStereo,- makeUnpackGenericStrict, makeUnpackGeneric, makeReversePackedStrict, makeReversePacked, continue, continuePacked, continuePackedGeneric,- -- should be moved to a private module- fillBuffer, makeMixer, addToBuffer,- makeArranger, arrange,+ fillBuffer, makeMixer,+ makeArranger, ) where -import qualified Synthesizer.LLVM.Parameterized.Signal as SigP-import qualified Synthesizer.LLVM.Parameterized.SignalPacked as SigPS+import qualified Synthesizer.LLVM.Frame.SerialVector.Code as Serial -import qualified Synthesizer.LLVM.Frame.SerialVector as Serial-import qualified Synthesizer.LLVM.Frame.Stereo as Stereo import qualified Synthesizer.LLVM.Frame.StereoInterleaved as StereoVector+import qualified Synthesizer.LLVM.Frame.Stereo as Stereo import qualified Data.StorableVector.Lazy as SVL import qualified Data.StorableVector as SV@@ -33,33 +28,22 @@ import qualified Number.NonNegative as NonNeg import qualified LLVM.DSL.Execution as Exec--import qualified LLVM.Extra.Storable as Storable-import qualified LLVM.Extra.Memory as Memory-import qualified LLVM.Extra.Arithmetic as A-import qualified LLVM.Extra.Tuple as Tuple-+import qualified LLVM.Extra.Multi.Value.Storable as Storable+import qualified LLVM.Extra.Multi.Value as MultiValue import qualified LLVM.Core as LLVM-import LLVM.Core (IsPrimitive, ret) import qualified Type.Data.Num.Decimal as TypeNum -import qualified Control.Category as Cat--import qualified Data.List.HT as ListHT-import Data.Word (Word)+import Control.Monad.HT (void) -import Foreign.Ptr (Ptr)+import Foreign.Marshal.Array (advancePtr) import Foreign.ForeignPtr (castForeignPtr) import Foreign.Storable (Storable)-import Foreign.Marshal.Array (advancePtr)+import Foreign.Ptr (Ptr) import qualified System.Unsafe as Unsafe -import NumericPrelude.Numeric-import NumericPrelude.Base - {- | This function needs only constant time in contrast to 'Synthesizer.LLVM.Parameterized.SignalPacked.unpack'.@@ -68,27 +52,32 @@ since the array size may not line up. It would also need copying since the source data may not be aligned properly. -}-unpackStrict ::- (Storable.C a, IsPrimitive a, TypeNum.Positive n) =>- SV.Vector (Serial.Plain n a) -> SV.Vector a-unpackStrict v =+unpackChunk ::+ (Storable.C a, TypeNum.Positive n) =>+ SV.Vector (Serial.T n a) -> SV.Vector a+unpackChunk v = let getDim :: (TypeNum.Positive n) =>- SV.Vector (Serial.Plain n a) -> TypeNum.Singleton n -> Int+ SV.Vector (Serial.T n a) -> TypeNum.Singleton n -> Int getDim _ = TypeNum.integralFromSingleton d = getDim v TypeNum.singleton (fptr,s,l) = SVB.toForeignPtr v in SVB.SV (castForeignPtr fptr) (s*d) (l*d) ++unpackStrict ::+ (TypeNum.Positive n, Storable.Vector a) =>+ SV.Vector (Serial.T n a) -> SV.Vector a+unpackStrict = unpackChunk+ unpack ::- (Storable.C a, IsPrimitive a, TypeNum.Positive n) =>- SVL.Vector (Serial.Plain n a) -> SVL.Vector a-unpack =- SVL.fromChunks . map unpackStrict . SVL.chunks+ (TypeNum.Positive n, Storable.Vector a) =>+ SVL.Vector (Serial.T n a) -> SVL.Vector a+unpack = SVL.fromChunks . map unpackChunk . SVL.chunks unpackStereoStrict ::- (Storable.C a, IsPrimitive a, TypeNum.Positive n) =>+ (TypeNum.Positive n, Storable.C a) => SV.Vector (StereoVector.T n a) -> SV.Vector (Stereo.T a) unpackStereoStrict v = let getDim ::@@ -100,67 +89,30 @@ in SVB.SV (castForeignPtr fptr) (s*d) (l*d) unpackStereo ::- (Storable.C a, IsPrimitive a, TypeNum.Positive n) =>+ (TypeNum.Positive n, Storable.C a) => SVL.Vector (StereoVector.T n a) -> SVL.Vector (Stereo.T a) unpackStereo = SVL.fromChunks . map unpackStereoStrict . SVL.chunks -{- |-This is similar to 'unpackStrict' but performs rearrangement of data.-This is for instance necessary for stereo signals-where the data layout of packed and unpacked data is different,-thus simple casting of the data is not possible.-However, for vectorized Stereo data the StereoInterleaved type-still uses vector operations for interleaving and thus is more efficient.--}-makeUnpackGenericStrict ::- (Serial.C vv, n ~ Serial.Size vv, va ~ Serial.Element vv,- Memory.C (Serial.ReadIt vv),- Storable.C a, Tuple.ValueOf a ~ va,- Storable.C v, Tuple.ValueOf v ~ vv) =>- IO (SV.Vector v -> SV.Vector a)-makeUnpackGenericStrict =- let vectorSize ::- (Serial.C vl, n ~ Serial.Size vl, al ~ Serial.Element vl,- Storable.C v, Tuple.ValueOf v ~ vl) =>- SV.Vector v -> TypeNum.Singleton n- vectorSize _ = TypeNum.singleton- in fmap (\f v -> f (TypeNum.integralFromSingleton (vectorSize v) * SV.length v) v) $- SigP.run (SigPS.unpack $ SigP.fromStorableVector Cat.id) -makeUnpackGeneric ::- (Serial.C vv, n ~ Serial.Size vv, va ~ Serial.Element vv,- Memory.C (Serial.ReadIt vv),- Storable.C a, Tuple.ValueOf a ~ va,- Storable.C v, Tuple.ValueOf v ~ vv) =>- IO (SVL.Vector v -> SVL.Vector a)-makeUnpackGeneric =- fmap (\f -> SVL.fromChunks . map f . SVL.chunks) $- makeUnpackGenericStrict-- makeReverser ::- (Storable.C a, Tuple.ValueOf a ~ value) =>+ (Storable.C a, MultiValue.T a ~ value) => (value -> LLVM.CodeGenFunction () value) -> IO (Word -> Ptr a -> Ptr a -> IO ())--- (Memory.C a struct, Serial.C a) =>--- IO (Word -> Ptr struct -> Ptr struct -> IO ()) makeReverser rev = Exec.compile "reverse" $ Exec.createFunction derefMixPtr "reverse" $ \ size ptrA ptrB -> do sizeInt <- LLVM.bitcast size ptrAEnd <- Storable.advancePtr sizeInt ptrA- _ <- Storable.arrayLoop size ptrB ptrAEnd $ \ ptrBi ptrAj0 -> do+ void $ Storable.arrayLoop size ptrB ptrAEnd $ \ ptrBi ptrAj0 -> do ptrAj1 <- Storable.decrementPtr ptrAj0 flip Storable.store ptrBi =<< rev =<< Storable.load ptrAj1 return ptrAj1- ret () makeReversePackedStrict ::- (Serial.C vv, n ~ Serial.Size vv, va ~ Serial.Element vv,- Storable.C v, Tuple.ValueOf v ~ vv) =>+ (TypeNum.Positive n, Storable.Vector a, v ~ Serial.T n a) => IO (SV.Vector v -> SV.Vector v) makeReversePackedStrict = do rev <- makeReverser Serial.reverse@@ -171,14 +123,14 @@ rev (fromIntegral len) ptrA ptrB makeReversePacked ::- (Serial.C vv, n ~ Serial.Size vv, va ~ Serial.Element vv,- Storable.C v, Tuple.ValueOf v ~ vv) =>+ (TypeNum.Positive n, Storable.Vector a, v ~ Serial.T n a) => IO (SVL.Vector v -> SVL.Vector v) makeReversePacked = fmap (\f -> SVL.fromChunks . reverse . map f . SVL.chunks) $ makeReversePackedStrict +-- ToDo: move to synthesizer-core or storablevector {- | Append two signals where the second signal gets the last value of the first signal as parameter.@@ -195,24 +147,16 @@ (SVL.chunks x) (SV.switchR [] $ \_ -> SVL.chunks . y) -_continueNeglectLast ::- (Storable a) =>- SVL.Vector a -> (a -> SVL.Vector a) -> SVL.Vector a-_continueNeglectLast x y =- SVL.switchR SVL.empty- (\body l -> SVL.append body (y l)) x- continuePacked ::- (TypeNum.Positive n, Storable.C a, IsPrimitive a) =>- SVL.Vector (Serial.Plain n a) ->- (a -> SVL.Vector (Serial.Plain n a)) ->- SVL.Vector (Serial.Plain n a)+ (TypeNum.Positive n, Storable.Vector a) =>+ SVL.Vector (Serial.T n a) ->+ (a -> SVL.Vector (Serial.T n a)) ->+ SVL.Vector (Serial.T n a) continuePacked x y = SVL.fromChunks $ withLast SV.empty (SVL.chunks x)- (SV.switchR [] (\_ -> SVL.chunks . y) .- unpackStrict)+ (SV.switchR [] (\_ -> SVL.chunks . y) . unpackStrict) {- This function reduces the last chunk to size one, repacks that@@ -229,10 +173,6 @@ > return (continuePackedGeneric unpackGeneric x y) -} continuePackedGeneric ::-{-- (Storable v, Serial.C v, n ~ Serial.Size v, a ~ Serial.Element v,- Tuple.Value v, Tuple.ValueOf v ~ vv, Memory.C vv) =>--} (Storable v, Storable a) => (SV.Vector v -> SV.Vector a) -> SVL.Vector v -> (a -> SVL.Vector v) -> SVL.Vector v@@ -245,24 +185,14 @@ SV.drop (SV.length lastChunk - 1) $ lastChunk) --- candidate for utility-ht+-- ToDo: candidate for utility-ht withLast :: a -> [a] -> (a -> [a]) -> [a] withLast deflt x y = foldr (\a cont _ -> a : cont a) y x deflt -{--This version is too strict, since it looks one element ahead.--}-_withLast :: [a] -> (a -> [a]) -> [a]-_withLast x y =- ListHT.switchR []- (\body end -> body ++ end : y end)- x -- foreign import ccall safe "dynamic" derefFillPtr :: Exec.Importer (Word -> Ptr a -> IO ()) @@ -271,31 +201,28 @@ it also simplifies type inference. -} fillBuffer ::- (Storable.C a, Tuple.ValueOf a ~ value) =>+ (Storable.C a, MultiValue.T a ~ value) => value -> IO (Word -> Ptr a -> IO ()) fillBuffer x = Exec.compile "constant" $- Exec.createFunction derefFillPtr "constantfill" $ \ size ptr -> do+ Exec.createFunction derefFillPtr "constantfill" $ \ size ptr -> Storable.arrayLoop size ptr () $ \ ptri () -> Storable.store x ptri- ret () foreign import ccall safe "dynamic" derefMixPtr :: Exec.Importer (Word -> Ptr a -> Ptr a -> IO ()) makeMixer ::- (Storable.C a, Tuple.ValueOf a ~ value) =>+ (Storable.C a, MultiValue.T a ~ value) => (value -> value -> LLVM.CodeGenFunction () value) -> IO (Word -> Ptr a -> Ptr a -> IO ()) makeMixer add = Exec.compile "mixer" $- Exec.createFunction derefMixPtr "mix" $ \ size srcPtr dstPtr -> do- _ <-- Storable.arrayLoop2 size srcPtr dstPtr () $+ Exec.createFunction derefMixPtr "mix" $ \ size srcPtr dstPtr ->+ void $ Storable.arrayLoop2 size srcPtr dstPtr () $ \srcPtri dstPtri () -> do y <- Storable.load srcPtri Storable.modify (add y) dstPtri- ret () addToBuffer ::@@ -316,13 +243,13 @@ Same algorithm as in Synthesizer.Storable.Cut.arrangeEquidist -} makeArranger ::- (Storable.C a, Tuple.ValueOf a ~ value, A.Additive value) =>+ (Storable.C a, MultiValue.Additive a) => IO (SVL.ChunkSize -> EventList.T NonNeg.Int (SVL.Vector a) -> SVL.Vector a) makeArranger = do- mixer <- makeMixer A.add- fill <- fillBuffer A.zero+ mixer <- makeMixer MultiValue.add+ fill <- fillBuffer MultiValue.zero return $ \ (SVL.ChunkSize sz) -> let sznn = NonNeg.fromNumberMsg "arrange" sz go acc evs =@@ -351,20 +278,3 @@ then [] else chunk : go newAcc future in SVL.fromChunks . go []--{- |-This is unsafe since it relies on the prior initialization of the LLVM JIT.-Better use 'makeArranger'.--}-{-# DEPRECATED arrange "better use makeArranger" #-}-arrange ::- (Storable.C a, Tuple.ValueOf a ~ value, A.Additive value) =>- SVL.ChunkSize- -> EventList.T NonNeg.Int (SVL.Vector a)- {-^ A list of pairs: (relative start time, signal part),- The start time is relative to the start time- of the previous event. -}- -> SVL.Vector a- {-^ The mixed signal. -}-arrange =- Unsafe.performIO makeArranger
src/Synthesizer/LLVM/Storable/Vector.hs view
@@ -1,18 +1,17 @@ {-# LANGUAGE TypeFamilies #-} module Synthesizer.LLVM.Storable.Vector where -import qualified LLVM.Extra.Storable as Storable- import qualified Data.StorableVector as SV import qualified Data.StorableVector.Base as SVB import Foreign.Marshal.Array (advancePtr)+import Foreign.Storable (Storable) import Foreign.ForeignPtr (ForeignPtr) import Foreign.Ptr (Ptr) import qualified System.Unsafe as Unsafe -unsafeToPointers :: (Storable.C a) => SV.Vector a -> (ForeignPtr a, Ptr a, Int)+unsafeToPointers :: (Storable a) => SV.Vector a -> (ForeignPtr a, Ptr a, Int) unsafeToPointers v = let (fp,s,l) = SVB.toForeignPtr v in (fp, Unsafe.foreignPtrToPtr fp `advancePtr` s, l)
+ src/Synthesizer/LLVM/Value.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE TypeFamilies #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+module Synthesizer.LLVM.Value (+ T, decons,+ tau, square, sqrt,+ max, min, limit, fraction,++ (%==), (%/=), (%<), (%<=), (%>), (%>=), not,+ (%&&), (%||),+ (?), (??),++ lift0, lift1, lift2, lift3,+ unlift0, unlift1, unlift2, unlift3, unlift4, unlift5,+ constantValue, constant,+ fromInteger', fromRational',++ Flatten(flattenCode, unfoldCode), Registers,+ flatten, unfold,+ flattenCodeTraversable, unfoldCodeTraversable,+ flattenFunction,+ ) where++import LLVM.DSL.Value++import qualified Synthesizer.LLVM.Frame.Stereo as Stereo ()+import qualified Synthesizer.Basic.Phase as Phase++import qualified Algebra.RealRing as RealRing++import qualified Prelude as P ()+import NumericPrelude.Base hiding (min, max, unzip, unzip3, not)+++instance (RealRing.C a, Flatten a) => Flatten (Phase.T a) where+ type Registers (Phase.T a) = Registers a+ flattenCode s = flattenCode $ Phase.toRepresentative s+ unfoldCode s =+ -- could also be unsafeFromRepresentative+ Phase.fromRepresentative $ unfoldCode s
src/Synthesizer/LLVM/Wave.hs view
@@ -2,7 +2,7 @@ {-# LANGUAGE TypeFamilies #-} module Synthesizer.LLVM.Wave where -import qualified Synthesizer.LLVM.Simple.Value as Value+import qualified Synthesizer.LLVM.Value as Value import qualified LLVM.Extra.Arithmetic as A @@ -147,11 +147,24 @@ A.sub (A.fromInteger' 1) <=< A.mul (A.fromInteger' 2) +{- |+> trapezoidSlope steepness = trapezoidSkew (recip steepness)+-}+trapezoidSlope ::+ (A.PseudoRing a, A.RationalConstant a, A.Real a) =>+ a -> a -> CodeGenFunction r a+trapezoidSlope p =+ A.max (A.fromInteger' (-1)) <=<+ A.min (A.fromInteger' 1) <=<+ A.mul p <=<+ A.sub (A.fromInteger' 1) <=<+ A.mul (A.fromInteger' 2)+ sine :: (A.Transcendental a, A.RationalConstant a) => a -> CodeGenFunction r a sine t =- A.sin =<< A.mul t =<< Value.decons Value.twoPi+ A.sin =<< A.mul t =<< Value.decons Value.tau
synthesizer-llvm.cabal view
@@ -1,6 +1,6 @@ Cabal-Version: 2.2 Name: synthesizer-llvm-Version: 0.9+Version: 1.0 License: GPL-3.0-only License-File: LICENSE Author: Henning Thielemann <haskell@henning-thielemann.de>@@ -58,7 +58,7 @@ default: False Source-Repository this- Tag: 0.9+ Tag: 1.0 Type: darcs Location: http://code.haskell.org/synthesizer/llvm/ @@ -69,9 +69,9 @@ Library Build-Depends:- llvm-dsl >=0.0 && <0.1,- llvm-extra >=0.10 && <0.11,- llvm-tf >=9.0 && <9.3,+ llvm-dsl >=0.1 && <0.2,+ llvm-extra >=0.11 && <0.12,+ llvm-tf >=9.0 && <13.0, tfp >=1.0 && <1.1, vault >=0.3 && <0.4, synthesizer-core >=0.8 && <0.9,@@ -86,9 +86,9 @@ non-empty >=0.2.1 && <0.4, event-list >=0.1 && <0.2, pathtype >=0.8 && <0.9,- random >=1.0 && <1.2,+ random >=1.0 && <1.3, containers >=0.1 && <0.7,- transformers >=0.2 && <0.6,+ transformers >=0.2 && <0.7, semigroups >=0.1 && <1.0, utility-ht >=0.0.15 && <0.1 @@ -109,12 +109,11 @@ Hs-source-dirs: src Exposed-Modules:- Synthesizer.LLVM.Simple.Signal- Synthesizer.LLVM.Simple.SignalPacked- Synthesizer.LLVM.Simple.Value- Synthesizer.LLVM.Parameterized.Signal- Synthesizer.LLVM.Parameterized.SignalPacked- Synthesizer.LLVM.Parameter+ Synthesizer.LLVM.Generator.Signal+ Synthesizer.LLVM.Generator.SignalPacked+ Synthesizer.LLVM.Generator.Core+ Synthesizer.LLVM.Generator.Source+ Synthesizer.LLVM.Generator.Render Synthesizer.LLVM.Storable.Signal Synthesizer.LLVM.Storable.Process Synthesizer.LLVM.Causal.Process@@ -122,16 +121,12 @@ Synthesizer.LLVM.Causal.ProcessPacked Synthesizer.LLVM.Causal.Controlled Synthesizer.LLVM.Causal.ControlledPacked- Synthesizer.LLVM.CausalParameterized.Process- Synthesizer.LLVM.CausalParameterized.ProcessValue- Synthesizer.LLVM.CausalParameterized.ProcessPacked- Synthesizer.LLVM.CausalParameterized.Controlled- Synthesizer.LLVM.CausalParameterized.ControlledPacked- Synthesizer.LLVM.CausalParameterized.Functional- Synthesizer.LLVM.CausalParameterized.FunctionalPlug- Synthesizer.LLVM.CausalParameterized.RingBuffer- Synthesizer.LLVM.CausalParameterized.RingBufferForward- Synthesizer.LLVM.CausalParameterized.Helix+ Synthesizer.LLVM.Causal.Exponential2+ Synthesizer.LLVM.Causal.FunctionalPlug+ Synthesizer.LLVM.Causal.Functional+ Synthesizer.LLVM.Causal.RingBufferForward+ Synthesizer.LLVM.Causal.Helix+ Synthesizer.LLVM.Causal.Render Synthesizer.LLVM.Fold Synthesizer.LLVM.Plug.Input Synthesizer.LLVM.Plug.Output@@ -147,13 +142,15 @@ Synthesizer.LLVM.Filter.Moog Synthesizer.LLVM.Filter.Universal Synthesizer.LLVM.Filter.NonRecursive- Synthesizer.LLVM.Generator.Exponential2 Synthesizer.LLVM.Interpolation Synthesizer.LLVM.Frame.SerialVector- Synthesizer.LLVM.Frame- Synthesizer.LLVM.Frame.Stereo+ Synthesizer.LLVM.Frame.SerialVector.Class+ Synthesizer.LLVM.Frame.SerialVector.Code+ Synthesizer.LLVM.Frame.SerialVector.Plain Synthesizer.LLVM.Frame.StereoInterleaved+ Synthesizer.LLVM.Frame.Stereo Synthesizer.LLVM.Frame.Binary+ Synthesizer.LLVM.Frame Synthesizer.LLVM.Complex Synthesizer.LLVM.Wave Synthesizer.LLVM.MIDI@@ -163,13 +160,14 @@ Synthesizer.LLVM.Server.CausalPacked.Instrument Synthesizer.LLVM.Server.CausalPacked.InstrumentPlug Synthesizer.LLVM.Server.CausalPacked.Speech+ Synthesizer.LLVM.Server.CausalPacked.Common Synthesizer.LLVM.Server.SampledSound Synthesizer.LLVM.Server.Common Synthesizer.LLVM.Server.CommonPacked- Synthesizer.LLVM.Server.Parameter+ Synthesizer.LLVM.ConstantPiece+ Synthesizer.LLVM.Value Other-Modules:- Synthesizer.LLVM.ConstantPiece Synthesizer.LLVM.ForeignPtr Synthesizer.LLVM.Random Synthesizer.LLVM.EventIterator@@ -177,13 +175,12 @@ Synthesizer.LLVM.Storable.ChunkIterator Synthesizer.LLVM.Storable.LazySizeIterator Synthesizer.LLVM.RingBuffer- Synthesizer.LLVM.Simple.SignalPrivate- Synthesizer.LLVM.Parameterized.SignalPrivate- Synthesizer.LLVM.Causal.ProcessPrivate- Synthesizer.LLVM.CausalParameterized.ProcessPrivate- -- experimental- Synthesizer.LLVM.Simple.Vanilla- -- Synthesizer.LLVM.Parameterized.Value+ Synthesizer.LLVM.Causal.Parameterized+ Synthesizer.LLVM.Causal.Private+ Synthesizer.LLVM.Frame.StereoInterleavedCode+ Synthesizer.LLVM.Generator.Extra+ Synthesizer.LLVM.Generator.Private+ Synthesizer.LLVM.Private Library server If flag(buildExamples)@@ -199,7 +196,7 @@ event-list, shell-utility >=0.0 && <0.2, pathtype,- optparse-applicative >=0.11 && <0.16,+ optparse-applicative >=0.11 && <0.19, containers, utility-ht, base@@ -225,6 +222,7 @@ server, synthesizer-llvm, + llvm-dsl, llvm-extra, llvm-tf, tfp,@@ -238,6 +236,7 @@ non-empty, utility-ht, pathtype,+ unsafe, base Else Buildable: False@@ -256,12 +255,14 @@ Main-Is: Synthesizer/LLVM/Test.hs Other-Modules: Synthesizer.LLVM.LAC2011+ Synthesizer.LLVM.ExampleUtility Executable synthi-llvm-lndw If flag(buildExamples) && flag(alsa) Build-Depends: synthesizer-llvm, + llvm-dsl, llvm-extra, llvm-tf, tfp,@@ -300,6 +301,7 @@ Main-Is: Synthesizer/LLVM/TestALSA.hs Other-Modules: Synthesizer.LLVM.LNdW2011+ Synthesizer.LLVM.ExampleUtility Executable synthi-llvm-alsa If flag(buildExamples) && flag(alsa)@@ -307,6 +309,8 @@ server, synthesizer-llvm, + unsafe,+ llvm-dsl, llvm-tf, synthesizer-core, synthesizer-midi,@@ -358,6 +362,7 @@ Build-Depends: server, synthesizer-llvm,+ tfp, jack >=0.7 && <0.8, @@ -367,7 +372,7 @@ storablevector, non-negative, random,- explicit-exception >=0.1.7 && <0.2,+ explicit-exception >=0.1.7 && <0.3, event-list, pathtype, optparse-applicative,@@ -458,6 +463,7 @@ gnuplot >=0.5 && <0.6, pathtype, sox,+ llvm-dsl, synthesizer-llvm, synthesizer-core, numeric-prelude,@@ -481,8 +487,10 @@ Test-Suite synthi-llvm-test Type: exitcode-stdio-1.0 Build-Depends:+ doctest-exitcode-stdio >=0.0 && <0.1, synthesizer-llvm, + llvm-dsl, llvm-extra, llvm-tf, tfp,@@ -493,6 +501,7 @@ utility-ht, QuickCheck >=1 && <3,+ unsafe, base Default-Language: Haskell98 GHC-Options: -Wall
testsuite/Test/Main.hs view
@@ -7,20 +7,26 @@ import qualified LLVM.Core as LLVM +import Control.Monad.IO.Class (liftIO)+ import Data.Tuple.HT (mapFst) +import qualified Test.DocTest.Driver as DocTest -prefix :: String -> [(String, IO ())] -> [(String, IO ())]++prefix :: String -> [(String, prop)] -> [(String, prop)] prefix msg = map (mapFst (\str -> msg ++ "." ++ str)) main :: IO () main = do LLVM.initializeNativeTarget- mapM_ (\(name,test) -> putStr (name ++ ": ") >> test) $- concat $- prefix "Helix" Helix.tests :- prefix "RingBufferForward" RingBufferForward.tests :- prefix "Filter" Filter.tests :- prefix "Packed" Packed.tests :+ DocTest.run $ mapM_+ (\(name,prop) -> do+ DocTest.printPrefix (name++": ")+ DocTest.property =<< liftIO prop) $+ prefix "Helix" Helix.tests +++ prefix "RingBufferForward" RingBufferForward.tests +++ prefix "Filter" Filter.tests +++ prefix "Packed" Packed.tests ++ []
testsuite/Test/Synthesizer/LLVM/Filter.hs view
@@ -1,33 +1,33 @@ {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE Rank2Types #-} module Test.Synthesizer.LLVM.Filter (tests) where +import qualified Synthesizer.LLVM.Filter.ComplexFirstOrderPacked+ as ComplexFilterP+import qualified Synthesizer.LLVM.Filter.ComplexFirstOrder as ComplexFilter import qualified Synthesizer.LLVM.Filter.Allpass as Allpass import qualified Synthesizer.LLVM.Filter.FirstOrder as FirstOrder import qualified Synthesizer.LLVM.Filter.SecondOrder as SecondOrder import qualified Synthesizer.LLVM.Filter.SecondOrderPacked as SecondOrderP-import qualified Synthesizer.LLVM.Filter.Universal as UniFilter import qualified Synthesizer.LLVM.Filter.Moog as Moog-import qualified Synthesizer.LLVM.Filter.ComplexFirstOrder as ComplexFilter-import qualified Synthesizer.LLVM.Filter.ComplexFirstOrderPacked as ComplexFilterP+import qualified Synthesizer.LLVM.Filter.Universal as UniFilter import qualified Synthesizer.LLVM.Filter.NonRecursive as FiltNR import qualified Synthesizer.Plain.Filter.Recursive.Allpass as AllpassCore import qualified Synthesizer.Plain.Filter.Recursive.FirstOrder as FirstOrderCore import qualified Synthesizer.Plain.Filter.Recursive.Universal as UniFilterCore import qualified Synthesizer.Plain.Filter.Recursive.Moog as MoogCore-import qualified Synthesizer.Plain.Filter.Recursive.FirstOrderComplex as ComplexFilterCore+import qualified Synthesizer.Plain.Filter.Recursive.FirstOrderComplex+ as ComplexFilterCore -import qualified Synthesizer.LLVM.Frame.SerialVector as Serial-import qualified Synthesizer.LLVM.Parameter as Param+import qualified Synthesizer.LLVM.Frame.SerialVector.Code as Serial import qualified Synthesizer.LLVM.Wave as Wave-import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP-import qualified Synthesizer.LLVM.Parameterized.SignalPacked as SigPS-import qualified Synthesizer.LLVM.Parameterized.Signal as SigP-import qualified Synthesizer.LLVM.Simple.Signal as Sig-import Synthesizer.LLVM.CausalParameterized.Process (($<), ($*))-import Synthesizer.LLVM.Parameter (($#))+import qualified Synthesizer.LLVM.Causal.Process as Causal+import qualified Synthesizer.LLVM.Generator.SignalPacked as SigPS+import qualified Synthesizer.LLVM.Generator.Render as Render+import qualified Synthesizer.LLVM.Generator.Core as Core+import qualified Synthesizer.LLVM.Generator.Signal as Sig+import Synthesizer.LLVM.Causal.Process (($<), ($*)) import Synthesizer.Plain.Filter.Recursive (Pole(Pole)) import qualified Synthesizer.Interpolation.Module as Ip@@ -52,16 +52,17 @@ randomStorableVector, checkSimilarityPacked) import qualified Control.Category as Cat-import Control.Category ((<<<))-import Control.Arrow ((&&&), (^<<), (<<^))+import Control.Category ((.), (<<<))+import Control.Arrow ((&&&), (^<<)) import Control.Applicative (liftA2, (<$>)) +import qualified LLVM.DSL.Expression as Expr+import LLVM.DSL.Expression (Exp)++import qualified LLVM.Extra.Multi.Value as MultiValue import qualified LLVM.Extra.Arithmetic as A import qualified LLVM.Extra.Memory as Memory -import qualified LLVM.Core as LLVM-import LLVM.Core (Value)- import qualified Type.Data.Num.Decimal as TypeNum import Type.Data.Num.Decimal (D4) import Type.Base.Proxy (Proxy)@@ -75,7 +76,7 @@ import qualified Test.QuickCheck as QC import NumericPrelude.Numeric-import NumericPrelude.Base+import NumericPrelude.Base hiding ((.)) type SimFloat = CheckSimilarity Float@@ -96,63 +97,58 @@ lfoSine ::- (Memory.C a) =>- (forall r. Value Float -> LLVM.CodeGenFunction r a) ->- Param.T p Float ->- SigP.T p a+ (Memory.C a, Expr.Aggregate ae a) =>+ (Exp Float -> ae) ->+ Exp Float ->+ Sig.T a lfoSine f reduct =- SigP.interpolateConstant reduct $- Sig.map f $- CausalP.apply (CausalP.mapExponential 2 0.01) $- SigP.osciSimple Wave.sine 0 (fmap (* (0.1/44100)) reduct)+ Sig.interpolateConstant reduct $+ (Causal.map f . Causal.mapExponential 2 0.01 $*+ Sig.osci Wave.sine 0 (reduct * (0.1/44100))) allpassControl :: (TypeNum.Natural n) => Proxy n ->- Param.T p Float ->- SigP.T p (Allpass.CascadeParameter n (Value Float))+ Exp Float ->+ Sig.T (Allpass.CascadeParameter n (MultiValue.T Float)) allpassControl order = lfoSine (Allpass.flangerParameter order) allpassPhaserCausal, allpassPhaserPipeline ::- Param.T p Float ->- SigP.T p (Value Float) ->- SigP.T p (Value Float)-allpassPhaserCausal reduct =- CausalP.apply- (Allpass.phaser- $< allpassControl TypeNum.d16 reduct)+ Exp Float ->+ Sig.T (MultiValue.T Float) ->+ Sig.T (MultiValue.T Float)+allpassPhaserCausal reduct xs =+ Allpass.phaser+ $< allpassControl TypeNum.d16 reduct+ $* xs allpassPhaserPipeline reduct xs = let order = TypeNum.d16- in (SigP.drop $# TypeNum.integralFromProxy order) $+ in (Sig.drop (TypeNum.integralFromProxy order)) $ (Allpass.phaserPipeline $< allpassControl order reduct $* xs) -genOsci :: Gen.T (Param.T p) (Float, Float) (Param.T p Float, Param.T p Float)+genOsci :: QC.Gen (Float, Float) genOsci = pair (Gen.choose (0.001, 0.01)) (Gen.choose (0, 0.99)) -genOsciReduct ::- Gen.T- (Param.T p) ((Float, Float), Float)- ((Param.T p Float, Param.T p Float), Param.T p Float)+genOsciReduct :: QC.Gen ((Float, Float), Float) genOsciReduct = pair genOsci (Gen.choose (10, 100)) -genOsciReductPacked ::- Gen.T- (Param.T p) ((Float, Float), Float)- ((Param.T p Float, Param.T p Float), Param.T p Float)+genOsciReductPacked :: QC.Gen ((Float, Float), Float) genOsciReductPacked = pair genOsci (arg $ (4*) <$> QC.choose (1, 25)) allpassPipeline :: Gen.Test ((Float,Float), Float) SimFloat allpassPipeline =- withGenArgs genOsciReduct $ \((freq,phase), reduct) ->- let tone = SigP.osciSimple Wave.triangle phase freq- in checkSimilarity 1e-2 limitFloat- (allpassPhaserCausal reduct tone)- (allpassPhaserPipeline reduct tone)+ withGenArgs genOsciReduct $+ let tone (freq,phase) = Sig.osci Wave.triangle phase freq+ in checkSimilarity 1e-2 limitFloat+ (\(freqPhase, reduct) ->+ allpassPhaserCausal reduct $ tone freqPhase)+ (\(freqPhase, reduct) ->+ allpassPhaserPipeline reduct $ tone freqPhase) @@ -162,33 +158,33 @@ -} applyPacked :: (Memory.C c) =>- CausalP.T p (c, VectorValue) VectorValue ->- SigP.T p c ->- SigP.T p VectorValue ->- SigP.T p VectorValue+ Causal.T (c, VectorValue) VectorValue ->+ Sig.T c ->+ Sig.T VectorValue ->+ Sig.T VectorValue applyPacked proc cs xs = proc- $< ((SigP.interpolateConstant $#- (recip $ TypeNum.integralFromProxy TypeNum.d4 :: Float)) cs)+ $< Sig.interpolateConstant+ (recip $ TypeNum.integralFromProxy TypeNum.d4 :: Exp Float) cs $* xs allpassPhaserPacked ::- Param.T p Float ->- SigP.T p VectorValue ->- SigP.T p VectorValue+ Exp Float ->+ Sig.T VectorValue ->+ Sig.T VectorValue allpassPhaserPacked reduct = applyPacked Allpass.phaserPacked (allpassControl TypeNum.d16 reduct) allpassPacked :: Gen.Test ((Float,Float), Float) SimFloat allpassPacked =- withGenArgs genOsciReductPacked $ \((freq,phase), reduct) ->- let tone = SigP.osciSimple Wave.triangle phase freq- toneP = SigPS.osciSimple Wave.triangle phase freq+ withGenArgs genOsciReductPacked $+ let tone (freq,phase) = Sig.osci Wave.triangle phase freq+ toneP (freq,phase) = SigPS.osci Wave.triangle phase freq in checkSimilarityPacked 1e-2 limitFloat- (allpassPhaserCausal reduct tone)- (allpassPhaserPacked reduct toneP)+ (\(freqPhase, reduct) -> allpassPhaserCausal reduct $ tone freqPhase)+ (\(freqPhase, reduct) -> allpassPhaserPacked reduct $ toneP freqPhase) interpolateConstant :: Float -> SigS.T a -> SigS.T a@@ -225,44 +221,43 @@ allpassCore :: Gen.Test ((Float,Float), Float) SimStateFloat allpassCore =- withGenArgs genOsciReduct $ \((freq,phase), reduct) ->- let tone = SigP.osciSimple Wave.triangle phase freq- toneS p =+ withGenArgs genOsciReduct $+ let tone (freq,phase) = Sig.osci Wave.triangle phase freq+ toneS (freq,phase) = OsciS.static WaveCore.triangle- (Phase.fromRepresentative (Param.get phase p)) (Param.get freq p)+ (Phase.fromRepresentative phase) freq in checkSimilarityState 1e-2 limitFloat- (allpassPhaserCausal reduct tone)- (\p -> allpassPhaserCore (Param.get reduct p) (toneS p))+ (\(freqPhase, reduct) -> allpassPhaserCausal reduct $ tone freqPhase)+ (\(freqPhase, reduct) -> allpassPhaserCore reduct $ toneS freqPhase) -diracImpulse :: SigP.T p (Value Float)-diracImpulse =- (CausalP.delay1 $# (one::Float)) $*- (SigP.constant $# (zero::Float))+diracImpulse :: Sig.T (MultiValue.T Float)+diracImpulse = Causal.delay1 one $* Sig.constant zero firstOrderConstant ::- Param.T p Float ->- SigP.T p (Value Float) ->- SigP.T p (Value Float)+ Exp Float ->+ Sig.T (MultiValue.T Float) ->+ Sig.T (MultiValue.T Float) firstOrderConstant cutOff xs = FirstOrder.lowpassCausal- $< SigP.constant (FirstOrderCore.parameter ^<< cutOff)+ $< Sig.constant (FirstOrderCore.parameter cutOff) $* xs firstOrderExponential :: Gen.Test Float SimFloat firstOrderExponential =- withGenArgs (Gen.choose (0.001, 0.01)) $ \cutOff ->- let gain = exp(-2*pi*cutOff)+ withGenArgs (Gen.choose (0.001, 0.01)) $+ let gain cutOff = exp(-2*pi*cutOff) in checkSimilarity 1e-2 limitFloat- (SigP.amplify (recip (1 - gain)) $- firstOrderConstant cutOff diracImpulse)- (SigP.exponentialCore gain $# (one :: Float))+ (\cutOff ->+ Causal.amplify (recip (1 - gain cutOff)) $*+ firstOrderConstant cutOff diracImpulse)+ (\cutOff -> Core.exponential (gain cutOff) one) firstOrderCausal ::- Param.T p Float ->- SigP.T p (Value Float) ->- SigP.T p (Value Float)+ Exp Float ->+ Sig.T (MultiValue.T Float) ->+ Sig.T (MultiValue.T Float) firstOrderCausal reduct xs = FirstOrder.lowpassCausal $< lfoSine FirstOrder.parameter reduct@@ -280,19 +275,19 @@ firstOrder :: Gen.Test ((Float,Float), Float) SimStateFloat firstOrder =- withGenArgs genOsciReduct $ \((freq,phase), reduct) ->- let tone = SigP.osciSimple Wave.triangle phase freq- toneS p =+ withGenArgs genOsciReduct $+ let tone (freq,phase) = Sig.osci Wave.triangle phase freq+ toneS (freq,phase) = OsciS.static WaveCore.triangle- (Phase.fromRepresentative (Param.get phase p)) (Param.get freq p)+ (Phase.fromRepresentative phase) freq in checkSimilarityState 1e-2 limitFloat- (firstOrderCausal reduct tone)- (\p -> firstOrderCore (Param.get reduct p) (toneS p))+ (\(freqPhase, reduct) -> firstOrderCausal reduct $ tone freqPhase)+ (\(freqPhase, reduct) -> firstOrderCore reduct $ toneS freqPhase) firstOrderCausalPacked ::- Param.T p Float ->- SigP.T p VectorValue ->- SigP.T p VectorValue+ Exp Float ->+ Sig.T VectorValue ->+ Sig.T VectorValue firstOrderCausalPacked reduct = applyPacked FirstOrder.lowpassCausalPacked@@ -300,56 +295,62 @@ firstOrderPacked :: Gen.Test ((Float,Float), Float) SimFloat firstOrderPacked =- withGenArgs genOsciReductPacked $ \((freq,phase), reduct) ->- let tone = SigP.osciSimple Wave.triangle phase freq- toneP = SigPS.osciSimple Wave.triangle phase freq+ withGenArgs genOsciReductPacked $+ let tone (freq,phase) = Sig.osci Wave.triangle phase freq+ toneP (freq,phase) = SigPS.osci Wave.triangle phase freq in checkSimilarityPacked 1e-2 limitFloat- (firstOrderCausal reduct tone)- (firstOrderCausalPacked reduct toneP)+ (\(freqPhase, reduct) ->+ firstOrderCausal reduct $ tone freqPhase)+ (\(freqPhase, reduct) ->+ firstOrderCausalPacked reduct $ toneP freqPhase) secondOrderCausal ::- Param.T p Float ->- SigP.T p (Value Float) ->- SigP.T p (Value Float)+ Exp Float ->+ Sig.T (MultiValue.T Float) ->+ Sig.T (MultiValue.T Float) secondOrderCausal reduct xs = SecondOrder.causal- $< lfoSine (SecondOrder.bandpassParameter (LLVM.valueOf (10::Float))) reduct+ $< lfoSine (SecondOrder.bandpassParameter 10) reduct $* xs secondOrderCausalPacked ::- Param.T p Float ->- SigP.T p VectorValue ->- SigP.T p VectorValue+ Exp Float ->+ Sig.T VectorValue ->+ Sig.T VectorValue secondOrderCausalPacked reduct = applyPacked SecondOrder.causalPacked- (lfoSine (SecondOrder.bandpassParameter (LLVM.valueOf (10::Float))) reduct)+ (lfoSine (SecondOrder.bandpassParameter 10) reduct) secondOrderPacked :: Gen.Test ((Float,Float), Float) SimFloat secondOrderPacked =- withGenArgs genOsciReductPacked $ \((freq,phase), reduct) ->- let tone = SigP.osciSimple Wave.triangle phase freq- toneP = SigPS.osciSimple Wave.triangle phase freq+ withGenArgs genOsciReductPacked $+ let tone (freq,phase) = Sig.osci Wave.triangle phase freq+ toneP (freq,phase) = SigPS.osci Wave.triangle phase freq in checkSimilarityPacked 1e-2 limitFloat- (secondOrderCausal reduct tone)- (secondOrderCausalPacked reduct toneP)+ (\(freqPhase, reduct) ->+ secondOrderCausal reduct $ tone freqPhase)+ (\(freqPhase, reduct) ->+ secondOrderCausalPacked reduct $ toneP freqPhase) secondOrderCausalPacked2 ::- Param.T p Float ->- SigP.T p (Value Float) ->- SigP.T p (Value Float)+ Exp Float ->+ Sig.T (MultiValue.T Float) ->+ Sig.T (MultiValue.T Float) secondOrderCausalPacked2 reduct xs = SecondOrderP.causal- $< lfoSine (SecondOrderP.bandpassParameter (LLVM.valueOf (10::Float))) reduct+ $< lfoSine (SecondOrderP.bandpassParameter 10) reduct $* xs secondOrderPacked2 :: Gen.Test ((Float,Float), Float) SimFloat secondOrderPacked2 =- withGenArgs genOsciReduct $ \((freq,phase), reduct) ->- let tone = SigP.osciSimple Wave.triangle phase freq+ withGenArgs genOsciReduct $+ let tone (freq,phase) = Sig.osci Wave.triangle phase freq in checkSimilarity 1e-2 limitFloat- (secondOrderCausal reduct tone)- (secondOrderCausalPacked2 reduct tone)+ (\(freqPhase, reduct) ->+ secondOrderCausal reduct $ tone freqPhase)+ (\(freqPhase, reduct) ->+ secondOrderCausalPacked2 reduct $ tone freqPhase) {-@@ -360,12 +361,12 @@ -} universalCausal ::- Param.T p Float ->- SigP.T p (Value Float) ->- SigP.T p (UniFilter.Result (Value Float))+ Exp Float ->+ Sig.T (MultiValue.T Float) ->+ Sig.T (UniFilter.Result (MultiValue.T Float)) universalCausal reduct xs = UniFilter.causal- $< lfoSine (UniFilter.parameter (LLVM.valueOf (10::Float))) reduct+ $< lfoSine (UniFilter.parameter 10) reduct $* xs {-# INLINE universalCore #-}@@ -380,17 +381,18 @@ universal :: Gen.Test ((Float,Float), Float) SimStateFloat universal =- withGenArgs genOsciReduct $ \((freq,phase), reduct) ->- let tone = SigP.osciSimple Wave.triangle phase freq- toneS p =+ withGenArgs genOsciReduct $+ let tone (freq,phase) = Sig.osci Wave.triangle phase freq+ toneS (freq,phase) = OsciS.static WaveCore.triangle- (Phase.fromRepresentative (Param.get phase p)) (Param.get freq p)+ (Phase.fromRepresentative phase) freq in checkSimilarityState 1e-2 limitFloat- (fmap UniFilter.lowpass $- universalCausal reduct tone)- (\p ->+ (\(freqPhase, reduct) ->+ fmap UniFilter.lowpass $+ universalCausal reduct $ tone freqPhase)+ (\(freqPhase, reduct) -> SigS.map UniFilterCore.lowpass $- universalCore (Param.get reduct p) (toneS p))+ universalCore reduct $ toneS freqPhase) {- checkSimilarityState 1e-2 limitUniFilter (universalCausal reduct tone)@@ -401,12 +403,12 @@ moogCausal :: (TypeNum.Natural n) => Proxy n ->- Param.T p Float ->- SigP.T p (Value Float) ->- SigP.T p (Value Float)+ Exp Float ->+ Sig.T (MultiValue.T Float) ->+ Sig.T (MultiValue.T Float) moogCausal order reduct xs = Moog.causal- $< lfoSine (Moog.parameter order (LLVM.valueOf (10::Float))) reduct+ $< lfoSine (Moog.parameter order 10) reduct $* xs {-# INLINE moogCore #-}@@ -422,46 +424,49 @@ moog :: Gen.Test ((Float,Float), Float) SimStateFloat moog =- withGenArgs genOsciReduct $ \((freq,phase), reduct) ->+ withGenArgs genOsciReduct $ let order = TypeNum.d6- tone = SigP.osciSimple Wave.triangle phase freq- toneS p =+ tone (freq,phase) = Sig.osci Wave.triangle phase freq+ toneS (freq,phase) = OsciS.static WaveCore.triangle- (Phase.fromRepresentative (Param.get phase p)) (Param.get freq p)+ (Phase.fromRepresentative phase) freq in checkSimilarityState 1e-2 limitFloat- (moogCausal order reduct tone)- (\p -> moogCore (TypeNum.integralFromProxy order) (Param.get reduct p) (toneS p))+ (\(freqPhase, reduct) ->+ moogCausal order reduct $ tone freqPhase)+ (\(freqPhase, reduct) ->+ moogCore (TypeNum.integralFromProxy order) reduct $+ toneS freqPhase) complexCausal ::- Param.T p Float ->- SigP.T p (Value Float) ->- SigP.T p (Stereo.T (Value Float))-complexCausal reduct =- CausalP.apply $- (ComplexFilter.causal- $< lfoSine (ComplexFilter.parameter (LLVM.valueOf (10::Float))) reduct)- <<^ (\x -> Stereo.cons x A.zero)+ Exp Float ->+ Sig.T (MultiValue.T Float) ->+ Sig.T (Stereo.T (MultiValue.T Float))+complexCausal reduct xs =+ ComplexFilter.causal+ $< lfoSine (ComplexFilter.parameter 10) reduct+ $* ((\x -> Stereo.cons x A.zero) <$> xs) complexCausalPacked ::- Param.T p Float ->- SigP.T p (Value Float) ->- SigP.T p (Stereo.T (Value Float))-complexCausalPacked reduct =- CausalP.apply $- (ComplexFilterP.causal- $< lfoSine (ComplexFilterP.parameter (LLVM.valueOf (10::Float))) reduct)- <<^ (\x -> Stereo.cons x A.zero)+ Exp Float ->+ Sig.T (MultiValue.T Float) ->+ Sig.T (Stereo.T (MultiValue.T Float))+complexCausalPacked reduct xs =+ ComplexFilterP.causal+ $< lfoSine (ComplexFilterP.parameter 10) reduct+ $* ((\x -> Stereo.cons x A.zero) <$> xs) complexPacked :: Gen.Test ((Float,Float), Float) SimFloat complexPacked =- withGenArgs genOsciReduct $ \((freq,phase), reduct) ->- let tone = SigP.osciSimple Wave.triangle phase freq+ withGenArgs genOsciReduct $+ let tone (freq,phase) = Sig.osci Wave.triangle phase freq in checkSimilarity 1e-2 limitFloat- (fmap Stereo.left $- complexCausal reduct tone)- (fmap Stereo.left $- complexCausalPacked reduct tone)+ (\(freqPhase, reduct) ->+ fmap Stereo.left $+ complexCausal reduct $ tone freqPhase)+ (\(freqPhase, reduct) ->+ fmap Stereo.left $+ complexCausalPacked reduct $ tone freqPhase) {-# INLINE complexCore #-} complexCore ::@@ -476,17 +481,18 @@ complex :: Gen.Test ((Float,Float), Float) SimStateFloat complex =- withGenArgs genOsciReduct $ \((freq,phase), reduct) ->- let tone = SigP.osciSimple Wave.triangle phase freq- toneS p =+ withGenArgs genOsciReduct $+ let tone (freq,phase) = Sig.osci Wave.triangle phase freq+ toneS (freq,phase) = OsciS.static WaveCore.triangle- (Phase.fromRepresentative (Param.get phase p)) (Param.get freq p)+ (Phase.fromRepresentative phase) freq in checkSimilarityState 1e-2 limitFloat- (fmap Stereo.left $- complexCausal reduct tone)- (\p ->+ (\(freqPhase, reduct) ->+ fmap Stereo.left $+ complexCausal reduct $ tone freqPhase)+ (\(freqPhase, reduct) -> SigS.map ((0.1*) . Stereo.left) $- complexCore (Param.get reduct p) (toneS p))+ complexCore reduct $ toneS freqPhase) {- in checkSimilarityState 1e-2 limitStereoFloat (complexCausal reduct tone)@@ -501,16 +507,17 @@ (arg $ liftA2 (,) (QC.choose (1,20)) (Rnd.mkStdGen <$> QC.arbitrary)) Gen.arbitrary) $- \(rnd, seed) ->- let mask = randomStorableVector (-1,1::Float) <$> rnd- noise = SigP.noise seed 1- noiseP = SigPS.noise seed 1- in checkSimilarityPacked 1e-3 limitFloat- (FiltNR.convolve mask $* noise)- (FiltNR.convolvePacked mask $* noiseP)+ fmap+ (\f chunkSize (rnd, seed) ->+ f chunkSize+ (Render.buffer $ randomStorableVector (-1,1::Float) rnd, seed))+ $+ checkSimilarityPacked 1e-3 limitFloat+ (\(mask, seed) -> FiltNR.convolve mask $* Sig.noise seed 1)+ (\(mask, seed) -> FiltNR.convolvePacked mask $* SigPS.noise seed 1) -tests :: [(String, IO ())]+tests :: [(String, IO QC.Property)] tests = ("secondOrderPacked", checkWithParam secondOrderPacked) : ("secondOrderPacked2", checkWithParam secondOrderPacked2) :
testsuite/Test/Synthesizer/LLVM/Generator.hs view
@@ -1,7 +1,5 @@ module Test.Synthesizer.LLVM.Generator where -import qualified Synthesizer.LLVM.Parameter as Param-import qualified Synthesizer.LLVM.CausalParameterized.Functional as F import Data.StorableVector.Lazy (ChunkSize) @@ -15,50 +13,33 @@ import Prelude hiding (id) -data T f p a = Cons (QC.Gen p) (F.PrepareArguments f p a)+type T f p a = QC.Gen p -arg :: QC.Gen a -> T f a (f a)-arg gen = Cons gen F.atomArg+type Param p = (->) p -arbitrary :: (QC.Arbitrary a) => T f a (f a)-arbitrary = arg QC.arbitrary+arg :: QC.Gen a -> QC.Gen a+arg = id -choose :: (Random a) => (a,a) -> T f a (f a)-choose rng = arg $ QC.choose rng+arbitrary :: (QC.Arbitrary a) => QC.Gen a+arbitrary = QC.arbitrary +choose :: (Random a) => (a,a) -> QC.Gen a+choose = QC.choose -pair ::- (Functor f) =>- T f a0 b0 ->- T f a1 b1 ->- T f (a0,a1) (b0,b1)-pair (Cons g0 p0) (Cons g1 p1) =- Cons (liftA2 (,) g0 g1) (F.pairArgs p0 p1) -triple ::- (Functor f) =>- T f a0 b0 ->- T f a1 b1 ->- T f a2 b2 ->- T f (a0,a1,a2) (b0,b1,b2)-triple (Cons g0 p0) (Cons g1 p1) (Cons g2 p2) =- Cons (liftA3 (,,) g0 g1 g2) (F.tripleArgs p0 p1 p2)--withGenArgs ::- T (Param.T p) p a ->- (a -> IO (ChunkSize -> p -> test)) -> Test p test-withGenArgs (Cons gen prepArgs) f =- (gen, withPreparedArgs prepArgs f)+pair :: QC.Gen a -> QC.Gen b -> QC.Gen (a,b)+pair = liftA2 (,) +triple :: QC.Gen a -> QC.Gen b -> QC.Gen c -> QC.Gen (a,b,c)+triple = liftA3 (,,) -withPreparedArgs ::- F.PrepareArguments (Param.T p) p a -> (a -> test) -> test-withPreparedArgs (F.PrepareArguments prepare) f = f $ prepare id+withGenArgs :: QC.Gen p -> (IO (ChunkSize -> p -> test)) -> Test p test+withGenArgs = (,) type Test p test = (QC.Gen p, IO (ChunkSize -> p -> test)) -checkWithParam :: (Show p, QC.Testable test) => Test p test -> IO ()+checkWithParam :: (Show p, QC.Testable test) => Test p test -> IO QC.Property checkWithParam (gen, test) = do f <- test- QC.quickCheck (QC.forAll gen $ flip f)+ return $ QC.property (QC.forAll gen $ flip f)
testsuite/Test/Synthesizer/LLVM/Helix.hs view
@@ -1,41 +1,42 @@ {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE Rank2Types #-} module Test.Synthesizer.LLVM.Helix (tests) where -import qualified Synthesizer.LLVM.CausalParameterized.Helix as Helix-import qualified Synthesizer.LLVM.CausalParameterized.Functional as Func-import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP-import qualified Synthesizer.LLVM.Parameterized.Signal as SigP-import qualified Synthesizer.LLVM.Parameter as Param+import qualified Synthesizer.LLVM.Causal.Helix as Helix+import qualified Synthesizer.LLVM.Causal.Functional as Func+import qualified Synthesizer.LLVM.Causal.Process as Causal+import qualified Synthesizer.LLVM.Generator.Render as Render+import qualified Synthesizer.LLVM.Generator.Source as Source+import qualified Synthesizer.LLVM.Generator.Signal as Sig import qualified Synthesizer.LLVM.Interpolation as Interpolation-import Synthesizer.LLVM.CausalParameterized.Functional (($&), (&|&))-import Synthesizer.LLVM.CausalParameterized.Process (($*))-import Synthesizer.LLVM.Parameter (($#))+import Synthesizer.LLVM.Causal.Functional (($&), (&|&))+import Synthesizer.LLVM.Causal.Process (($*)) import qualified Data.StorableVector.Lazy as SVL-import qualified Data.StorableVector as SV import Data.StorableVector.Lazy (ChunkSize) -import Test.Synthesizer.LLVM.Generator (withPreparedArgs, checkWithParam)+import Test.Synthesizer.LLVM.Generator (checkWithParam) import Test.Synthesizer.LLVM.Utility (CheckSimilarity, checkSimilarity,- genRandomVectorParam, randomSignal)+ genRandomVectorParam, randomStorableVectorLoop) -import Control.Arrow (arr)-import Control.Applicative (pure, liftA2)+import qualified LLVM.DSL.Expression as Expr+import LLVM.DSL.Expression (Exp) -import LLVM.Core (Value)+import qualified LLVM.Extra.Multi.Value as MultiValue import Foreign.Storable (Storable) import qualified System.Random as Rnd import Data.Word (Word32) +import Control.Applicative (liftA2)+ -- import qualified Graphics.Gnuplot.Simple as Gnuplot import qualified Test.QuickCheck as QC +import qualified Algebra.Ring as Ring import NumericPrelude.Numeric import NumericPrelude.Base @@ -50,11 +51,11 @@ limitFloat = SVL.take signalLength -randomSpeed :: Param.T p (Int, Rnd.StdGen) -> SigP.T p (Value Float)-randomSpeed = randomSignal (0,10::Float)+randomSpeed :: (Int, Rnd.StdGen) -> SVL.Vector Float+randomSpeed = randomStorableVectorLoop (0,10) -randomPhase :: Param.T p (Int, Rnd.StdGen) -> SigP.T p (Value Float)-randomPhase = randomSignal (0,1::Float)+randomPhase :: (Int, Rnd.StdGen) -> SVL.Vector Float+randomPhase = randomStorableVectorLoop (0,1) genStaticDynamic :: QC.Gen (((Int, Rnd.StdGen), (Int, Rnd.StdGen)), (Float, Word32))@@ -67,36 +68,44 @@ IO (ChunkSize -> (((Int, Rnd.StdGen), (Int, Rnd.StdGen)), (Float, Word32)) -> SimFloat) staticDynamic =- withPreparedArgs- (Func.pairArgs- (Func.pairArgs Func.atomArg Func.atomArg)- (Func.pairArgs Func.atomArg Func.atomArg)) $- \((speedParam, phaseParam), (period, noiseParam)) ->- let len = 1000- noise :: Param.T p Word32 -> SigP.T p (Value Float)- noise seed = CausalP.take (pure len) $* SigP.noise seed 1+ let len :: (Ring.C a) => a+ len = 1000+ noise :: Exp Word32 -> Sig.T (MultiValue.T Float)+ noise seed = Sig.noise seed 1 - static =+ static, dynamic ::+ ((Sig.T (MultiValue.T Float), Sig.T (MultiValue.T Float)),+ Exp Float,+ (Exp Word32, Exp (Source.StorableVector Float))) ->+ Func.T inp (MultiValue.T Float)+ static ((speedSig, phaseSig), period, (_, noiseSig)) = Helix.static Interpolation.linear Interpolation.linear- (fmap round period) period- (fmap (\seed -> SigP.render (noise (arr id)) len seed :: SV.Vector Float) noiseParam)+ (Expr.roundToIntFast period) period noiseSig $&- Func.fromSignal- ((CausalP.integrate $# (0::Float)) $* randomSpeed speedParam)+ Func.fromSignal (Causal.integrate zero $* speedSig) &|&- Func.fromSignal (randomPhase phaseParam)+ Func.fromSignal phaseSig - dynamic =+ dynamic ((speedSig, phaseSig), period, (noiseParam, _)) = Helix.dynamic Interpolation.linear Interpolation.linear- (fmap round period) period (noise noiseParam)+ (Expr.roundToIntFast period) period+ (Causal.take len $* noise noiseParam) $&- Func.fromSignal (randomSpeed speedParam)+ Func.fromSignal speedSig &|&- Func.fromSignal (randomPhase phaseParam)+ Func.fromSignal phaseSig - in checkSimilarity 5e-3 limitFloat- (Func.compileSignal static)- (Func.compileSignal dynamic)+ in liftA2+ (\noiseSig f chunkSize+ ((speedParam, phaseParam), (period, noiseParam)) ->+ f chunkSize+ ((randomSpeed speedParam, randomPhase phaseParam),+ period,+ (noiseParam, Render.buffer (noiseSig len noiseParam))))+ (Render.run noise)+ (checkSimilarity 5e-3 limitFloat+ (Func.compileSignal . static)+ (Func.compileSignal . dynamic)) {- plot :: IO ()@@ -111,7 +120,7 @@ -} -tests :: [(String, IO ())]+tests :: [(String, IO QC.Property)] tests = ("staticDynamic", checkWithParam (genStaticDynamic, staticDynamic)) : []
testsuite/Test/Synthesizer/LLVM/Packed.hs view
@@ -9,36 +9,39 @@ CheckSimilarity, CheckEquality, checkSimilarityPacked) import qualified Synthesizer.LLVM.Wave as Wave-import qualified Synthesizer.LLVM.Parameter as Param+import LLVM.DSL.Expression (Exp) import Type.Data.Num.Decimal (D4) import qualified Type.Data.Num.Decimal as TypeNum -import qualified Synthesizer.LLVM.Frame.SerialVector as Serial-import qualified Synthesizer.LLVM.Generator.Exponential2 as Exp-import qualified Synthesizer.LLVM.Parameterized.SignalPacked as SigPS-import qualified Synthesizer.LLVM.Parameterized.Signal as SigP-import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP-import Synthesizer.LLVM.CausalParameterized.Process (($*))+import qualified Synthesizer.LLVM.Frame.SerialVector.Plain as SerialPlain+import qualified Synthesizer.LLVM.Frame.SerialVector.Code as SerialCode+import qualified Synthesizer.LLVM.Generator.SignalPacked as SigPS+import qualified Synthesizer.LLVM.Generator.Core as SigCore+import qualified Synthesizer.LLVM.Generator.Signal as Sig+import qualified Synthesizer.LLVM.Causal.Exponential2 as Exp+import qualified Synthesizer.LLVM.Causal.Process as Causal+import Synthesizer.LLVM.Causal.Process (($*)) import qualified Synthesizer.LLVM.Storable.Signal as SigStL import qualified Data.StorableVector.Lazy as SVL import Data.StorableVector.Lazy (ChunkSize) -import Control.Arrow (arr, (<<<))+import Control.Arrow ((<<<)) import Control.Applicative ((<$>)) -import Data.Word (Word32)+import Data.Word (Word, Word32) import qualified Test.QuickCheck as QC-import Test.QuickCheck (quickCheck) +import qualified Algebra.Ring as Ring+ import NumericPrelude.Numeric import NumericPrelude.Base type SimFloat = CheckSimilarity Float-type VectorValue = Serial.Value D4 Float+type VectorValue = SerialCode.Value D4 Float signalLength :: Int signalLength = 10000@@ -48,87 +51,87 @@ limitFloat = SVL.take signalLength -withDur ::- (Param.T Float Float -> IO (ChunkSize -> Float -> test)) ->- Test Float test+withDur :: (Ring.C a) => IO (ChunkSize -> a -> b) -> Test a b withDur = withGenArgs (arg (fromIntegral <$> QC.choose (signalLength, 2*signalLength))) {- limitPackedFloat ::- SVL.Vector (Serial.Plain D4 Float) -> SVL.Vector (Serial.Plain D4 Float)+ SVL.Vector (SerialPlain.T D4 Float) -> SVL.Vector (SerialPlain.T D4 Float) limitPackedFloat = SVL.take (div signalLength 4) -} constant :: Test Float SimFloat constant =- withGenArgs (Gen.choose (-1, 1)) $ \y ->+ withGenArgs (Gen.choose (-1, 1)) $ checkSimilarityPacked 1e-3 limitFloat- (SigP.constant y) (SigPS.constant y)+ (\y -> Sig.constant y) (\y -> SigPS.constant y) ramp :: Test Float SimFloat ramp =- withDur $ \dur ->+ withDur $ checkSimilarityPacked 1e-3 limitFloat- (SigP.rampInf dur) (SigPS.rampInf dur)+ (\dur -> Sig.rampInf dur) (\dur -> SigPS.rampInf dur) parabolaFadeIn :: Test Float SimFloat parabolaFadeIn =- withDur $ \dur ->+ withDur $ checkSimilarityPacked 1e-3 limitFloat- (SigP.parabolaFadeInInf dur)- (SigPS.parabolaFadeInInf dur)+ (\dur -> Sig.parabolaFadeInInf dur)+ (\dur -> SigPS.parabolaFadeInInf dur) parabolaFadeOut :: Test Float SimFloat parabolaFadeOut =- withDur $ \dur ->+ withDur $ checkSimilarityPacked 1e-3 limitFloat- (SigP.parabolaFadeOutInf dur)- (SigPS.parabolaFadeOutInf dur)+ (\dur -> Sig.parabolaFadeOutInf dur)+ (\dur -> SigPS.parabolaFadeOutInf dur) -parabolaFadeInMap :: Test Float SimFloat+parabolaFadeInMap :: Test Word SimFloat parabolaFadeInMap =- withDur $ \dur ->+ withDur $ checkSimilarity 1e-3 limitFloat- (SigP.parabolaFadeIn dur)- (SigP.parabolaFadeInMap dur)+ (\dur -> Sig.parabolaFadeIn dur)+ (\dur -> Sig.parabolaFadeInMap dur) -parabolaFadeOutMap :: Test Float SimFloat+parabolaFadeOutMap :: Test Word SimFloat parabolaFadeOutMap =- withDur $ \dur ->+ withDur $ checkSimilarity 1e-3 limitFloat- (SigP.parabolaFadeOut dur)- (SigP.parabolaFadeOutMap dur)+ (\dur -> Sig.parabolaFadeOut dur)+ (\dur -> Sig.parabolaFadeOutMap dur) -genExp :: Gen.T (Param.T p) (Float, Float) (Param.T p Float, Param.T p Float)+genExp :: QC.Gen (Float, Float) genExp = pair (Gen.choose (1000,10000)) (Gen.choose (-1,1)) exponential2 :: Test (Float,Float) SimFloat exponential2 =- withGenArgs genExp $ \(halfLife,start) ->+ withGenArgs genExp $ checkSimilarityPacked 1e-3 limitFloat- (SigP.exponential2 halfLife start)- (SigPS.exponential2 halfLife start)+ (\(halfLife,start) -> Sig.exponential2 halfLife start)+ (\(halfLife,start) -> SigPS.exponential2 halfLife start) exponential2Static :: Test (Float,Float) SimFloat exponential2Static =- withGenArgs genExp $ \(halfLife,start) ->+ withGenArgs genExp $ checkSimilarity 1e-3 limitFloat- (SigP.exponential2 halfLife start)- (Exp.causalP start <<<- CausalP.mapSimple Exp.parameter $*- SigP.constant halfLife)+ (\(halfLife,start) -> Sig.exponential2 halfLife start)+ (\(halfLife,start) ->+ Exp.causal start <<<+ Causal.map Exp.parameterPlain $*+ Sig.constant halfLife) exponential2PackedStatic :: Test (Float,Float) SimFloat exponential2PackedStatic =- withGenArgs genExp $ \(halfLife,start) ->+ withGenArgs genExp $ checkSimilarity 1e-3 (limitFloat . SigStL.unpack)- (SigPS.exponential2 halfLife start ::- SigP.T (Float,Float) VectorValue)- (Exp.causalPackedP start <<<- CausalP.mapSimple Exp.parameterPacked $*- SigP.constant halfLife)+ (\(halfLife,start) ->+ SigPS.exponential2 halfLife start :: Sig.T VectorValue)+ (\(halfLife,start) ->+ Exp.causalPacked start <<<+ Causal.map Exp.parameterPackedExp $*+ Sig.constant halfLife) exponential2Controlled :: Test ((Float,Float), (Float,Float)) SimFloat exponential2Controlled =@@ -136,19 +139,20 @@ (pair genExp (pair (Gen.choose (0.0001, 0.001)) (Gen.choose (0, 0.99 :: Float)))) $ - -- 'freq' is the LFO frequency measured at vector-rate- \((halfLife,start), (freq,phase)) ->- let lfo =- CausalP.mapExponential 2 halfLife $*- SigP.osciSimple Wave.approxSine2 phase freq+ let lfo halfLife freq phase =+ Causal.mapExponential 2 halfLife $*+ Sig.osci Wave.approxSine2 phase freq in checkSimilarityPacked 1e-3 limitFloat- (Exp.causalP start <<<- CausalP.mapSimple Exp.parameter $*- SigP.interpolateConstant- (TypeNum.integralFromProxy TypeNum.d4 :: Param.T p Float)- lfo)- (Exp.causalPackedP start <<<- CausalP.mapSimple Exp.parameterPacked $* lfo)+ (-- 'freq' is the LFO frequency measured at vector-rate+ \((halfLife,start), (freq,phase)) ->+ Exp.causal start <<<+ Causal.map Exp.parameterPlain $*+ Sig.interpolateConstant+ (TypeNum.integralFromProxy TypeNum.d4 :: Exp Float)+ (lfo halfLife freq phase))+ (\((halfLife,start), (freq,phase)) ->+ Exp.causalPacked start <<<+ Causal.map Exp.parameterPackedExp $* lfo halfLife freq phase) osci :: Test (Float,Float) SimFloat osci =@@ -156,10 +160,9 @@ (pair (Gen.choose (0.001, 0.01)) (Gen.choose (0, 0.99))) $- \(freq,phase) ->- checkSimilarityPacked 1e-2 limitFloat- (SigP.osciSimple Wave.approxSine2 phase freq)- (SigPS.osciSimple Wave.approxSine2 phase freq)+ checkSimilarityPacked 1e-2 limitFloat+ (\(freq,phase) -> Sig.osci Wave.approxSine2 phase freq)+ (\(freq,phase) -> SigPS.osci Wave.approxSine2 phase freq) @@ -167,30 +170,28 @@ limitWord32 = SVL.take signalLength limitPackedWord32 ::- SVL.Vector (Serial.Plain D4 Word32) -> SVL.Vector (Serial.Plain D4 Word32)+ SVL.Vector (SerialPlain.T D4 Word32) -> SVL.Vector (SerialPlain.T D4 Word32) limitPackedWord32 = SVL.take (div signalLength 4) noise :: IO (ChunkSize -> Word32 -> CheckEquality Word32) noise =- checkEquality limitWord32- (SigP.noiseCore (arr id))- (SigP.noiseCoreAlt (arr id))+ checkEquality limitWord32 SigCore.noise SigCore.noiseAlt -noiseVector :: IO (ChunkSize -> Word32 -> CheckEquality (Serial.Plain D4 Word32))+noiseVector ::+ IO (ChunkSize -> Word32 -> CheckEquality (SerialPlain.T D4 Word32)) noiseVector =- checkEquality limitPackedWord32- (SigPS.noiseCore (arr id))- (SigPS.noiseCoreAlt (arr id))+ checkEquality limitPackedWord32 SigPS.noiseCore SigPS.noiseCoreAlt -noiseScalarVector :: IO (ChunkSize -> Word32 -> CheckEquality (Serial.Plain D4 Word32))+noiseScalarVector ::+ IO (ChunkSize -> Word32 -> CheckEquality (SerialPlain.T D4 Word32)) noiseScalarVector = checkEquality limitPackedWord32- (SigPS.noiseCore (arr id))- (SigPS.packSmall (SigP.noiseCore (arr id)))+ SigPS.noiseCore+ (SigPS.packSmall . SigCore.noise) -tests :: [(String, IO ())]+tests :: [(String, IO QC.Property)] tests = ("constant", checkWithParam constant) : ("ramp", checkWithParam ramp) :@@ -203,7 +204,7 @@ ("exponential2PackedStatic", checkWithParam exponential2PackedStatic) : ("exponential2Controlled", checkWithParam exponential2Controlled) : ("osci", checkWithParam osci) :- ("noise", quickCheck =<< noise) :- ("noiseVector", quickCheck =<< noiseVector) :- ("noiseScalarVector", quickCheck =<< noiseScalarVector) :+ ("noise", QC.property <$> noise) :+ ("noiseVector", QC.property <$> noiseVector) :+ ("noiseScalarVector", QC.property <$> noiseScalarVector) : []
testsuite/Test/Synthesizer/LLVM/RingBufferForward.hs view
@@ -1,12 +1,10 @@ {-# LANGUAGE NoImplicitPrelude #-}-{-# LANGUAGE Rank2Types #-} module Test.Synthesizer.LLVM.RingBufferForward (tests) where -import qualified Synthesizer.LLVM.Parameter as Param-import qualified Synthesizer.LLVM.CausalParameterized.RingBufferForward as RingBuffer-import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP-import qualified Synthesizer.LLVM.Parameterized.Signal as SigP-import Synthesizer.LLVM.CausalParameterized.Process (($*))+import qualified Synthesizer.LLVM.Causal.RingBufferForward as RingBuffer+import qualified Synthesizer.LLVM.Causal.Process as Causal+import qualified Synthesizer.LLVM.Generator.Signal as Sig+import Synthesizer.LLVM.Causal.Process (($*)) import qualified Data.StorableVector.Lazy as SVL @@ -15,20 +13,23 @@ (Test, checkWithParam, arg, pair, triple, withGenArgs) import Test.Synthesizer.LLVM.Utility (CheckEquality, CheckEquality2, checkEquality, checkEquality2,- genRandomVectorParam, randomSignal)+ genRandomVectorParam, randomStorableVectorLoop) -import Control.Applicative (pure)+import qualified Control.Arrow as Arrow+import Control.Arrow ((<<^))+import Control.Applicative ((<$>)) -import qualified LLVM.Extra.Arithmetic as A+import qualified LLVM.DSL.Expression as Expr -import qualified LLVM.Core as LLVM-import LLVM.Core (Value)+import qualified LLVM.Extra.Multi.Value as MultiValue import Foreign.Storable (Storable) import qualified System.Random as Rnd import Data.Word (Word, Word32) +import qualified Test.QuickCheck as QC+ import NumericPrelude.Numeric import NumericPrelude.Base @@ -43,65 +44,67 @@ limitFloat = SVL.take signalLength -trackId :: Test (Int, Word32) EquFloat+trackId :: Test (Word, Word32) EquFloat trackId = withGenArgs (pair (Gen.choose (1,1000)) Gen.arbitrary) $- \(bufferSize, seed) ->- let noise = SigP.noise seed 1+ let noise seed = Sig.noise seed 1 in checkEquality limitFloat- noise- (CausalP.mapSimple (RingBuffer.index A.zero) $*- RingBuffer.track bufferSize noise)+ (\(_bufferSize, seed) -> noise seed)+ (\(bufferSize, seed) ->+ RingBuffer.mapIndex zero+ $* RingBuffer.track bufferSize (noise seed)) -trackTail :: Test (Int, Word32) EquFloat+trackTail :: Test (Word, Word32) EquFloat trackTail = withGenArgs (pair (Gen.choose (2,1000)) Gen.arbitrary) $- \(bufferSize, seed) ->- let noise = SigP.noise seed 1+ let noise seed = Sig.noise seed 1 in checkEquality limitFloat- (SigP.tail noise)- (CausalP.mapSimple (RingBuffer.index A.one) $*- RingBuffer.track bufferSize noise)+ (\(_bufferSize, seed) -> Sig.tail $ noise seed)+ (\(bufferSize, seed) ->+ RingBuffer.mapIndex one+ $* RingBuffer.track bufferSize (noise seed)) -trackDrop :: Test (Int, Word32) EquFloat+trackDrop :: Test (Word, Word32) EquFloat trackDrop = withGenArgs (pair (Gen.choose (0,1000)) Gen.arbitrary) $- \(n, seed) ->- let noise = SigP.noise seed 1+ let noise seed = Sig.noise seed 1 in checkEquality limitFloat- (SigP.drop n noise)- (CausalP.map RingBuffer.index (fmap (fromIntegral :: Int -> Word) n) $*- RingBuffer.track (fmap succ n) noise)+ (\(n, seed) -> Sig.drop n $ noise seed)+ (\(n, seed) ->+ RingBuffer.mapIndex n $* RingBuffer.track (n+1) (noise seed)) -randomSkips :: Param.T p (Int, Rnd.StdGen) -> SigP.T p (Value Word)-randomSkips = randomSignal (0,10::Word)+randomSkips :: (Int, Rnd.StdGen) -> SVL.Vector Word+randomSkips = randomStorableVectorLoop (0,10) trackSkip :: Test ((Int, Rnd.StdGen), Word32) EquFloat trackSkip = withGenArgs (pair (arg genRandomVectorParam) Gen.arbitrary) $- \(sk, seed) ->- let skips = randomSkips sk- noise = SigP.noise seed 1- in checkEquality limitFloat- (CausalP.skip noise $* skips)- (CausalP.mapSimple (RingBuffer.index A.one) $*- (RingBuffer.trackSkip 1 noise $* skips))+ let noise seed = Sig.noise seed 1+ in (\f chunkSize (sk, seed) -> f chunkSize (randomSkips sk, seed))+ <$>+ checkEquality limitFloat+ (\(skips, seed) -> Causal.skip (noise seed) $* skips)+ (\(skips, seed) ->+ RingBuffer.mapIndex one+ $* (RingBuffer.trackSkip 1 (noise seed) $* skips)) trackSkip1 :: Test (Word, Word32) EquFloat trackSkip1 =- let bufferSize :: Int- bufferSize = 1000+ let bufferSize = 1000 in withGenArgs (pair (Gen.choose (0, fromIntegral bufferSize - 1)) Gen.arbitrary) $- \(k, seed) ->- let noise = SigP.noise seed 1++ let noise seed = Sig.noise seed 1 in checkEquality limitFloat- (CausalP.map RingBuffer.index k $*- (RingBuffer.track (pure bufferSize) noise))- (CausalP.map RingBuffer.index k $*- (RingBuffer.trackSkip (pure bufferSize) noise $* 1))+ (\(k, seed) ->+ RingBuffer.mapIndex k $*+ RingBuffer.track (Expr.cons bufferSize) (noise seed))+ (\(k, seed) ->+ RingBuffer.mapIndex k $*+ (RingBuffer.trackSkip (Expr.cons bufferSize) (noise seed)+ $* 1)) trackSkipHold :: Test ((Int, Rnd.StdGen), Word, Word32) (CheckEquality2 Bool Float)@@ -112,17 +115,24 @@ (arg genRandomVectorParam) (Gen.choose (0, fromIntegral bufferSize - 1)) Gen.arbitrary) $- \(sk, k, seed) ->- let skips = randomSkips sk- noise = SigP.noise seed 1- in checkEquality2 limitFloat limitFloat- (fmap ((,) (LLVM.valueOf True)) $- (CausalP.map RingBuffer.index k $*- (RingBuffer.trackSkip (pure bufferSize) noise $* skips)))- (CausalP.map- (\ki ((b,_s),buf) -> fmap ((,) b) $ RingBuffer.index ki buf) k $*- (RingBuffer.trackSkipHold (pure bufferSize) noise $* skips)) + let noise seed = Sig.noise seed 1+ in (\f chunkSize (sk, k, seed) ->+ f chunkSize (randomSkips sk, k, seed))+ <$>+ checkEquality2 limitFloat limitFloat+ (\(skips, k, seed) ->+ (,) (MultiValue.cons True) <$>+ (RingBuffer.mapIndex k $*+ (RingBuffer.trackSkip (Expr.cons bufferSize) (noise seed)+ $* skips)))+ (\(skips, k, seed) ->+ (Arrow.second (RingBuffer.mapIndex k)+ <<^ (\((b,_s),buf) -> (b,buf)))+ $*+ (RingBuffer.trackSkipHold (Expr.cons bufferSize) (noise seed)+ $* skips))+ {- To do: @@ -130,7 +140,7 @@ -} -tests :: [(String, IO ())]+tests :: [(String, IO QC.Property)] tests = ("trackId", checkWithParam trackId) : ("trackTail", checkWithParam trackTail) :
testsuite/Test/Synthesizer/LLVM/Utility.hs view
@@ -1,13 +1,18 @@ {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-} module Test.Synthesizer.LLVM.Utility where -import qualified Synthesizer.LLVM.Parameterized.SignalPacked as SigPS-import qualified Synthesizer.LLVM.Parameterized.Signal as SigP-import qualified Synthesizer.LLVM.Parameter as Param-import qualified Synthesizer.LLVM.Plug.Output as POut-import qualified Synthesizer.LLVM.Frame.SerialVector as Serial+import qualified Synthesizer.LLVM.Causal.Render as CausalRender+import qualified Synthesizer.LLVM.Generator.Render as Render+import qualified Synthesizer.LLVM.Generator.SignalPacked as SigPS+import qualified Synthesizer.LLVM.Generator.Signal as Sig+import qualified Synthesizer.LLVM.Frame.SerialVector.Code as SerialCode+import Synthesizer.LLVM.Causal.Process () +import qualified Synthesizer.CausalIO.Process as PIO+import qualified Synthesizer.Causal.Class as CausalClass+import qualified Synthesizer.Generic.Signal as SigG import qualified Synthesizer.State.Signal as SigS import qualified Synthesizer.Zip as Zip @@ -19,9 +24,8 @@ import Data.StorableVector.Lazy (ChunkSize) import Foreign.Storable (Storable) -import qualified LLVM.Extra.Storable as Storable-import qualified LLVM.Extra.Tuple as Tuple-import qualified LLVM.Core as LLVM+import qualified LLVM.Extra.Multi.Value.Storable as Storable+import qualified LLVM.Extra.Multi.Value as MultiValue import qualified Type.Data.Num.Decimal as TypeNum @@ -31,6 +35,8 @@ import qualified Test.QuickCheck as QC +import qualified System.Unsafe as Unsafe+ import qualified Algebra.RealRing as RealRing import qualified Algebra.Absolute as Absolute @@ -54,30 +60,28 @@ randomStorableVectorLoop range param = SVL.cycle $ SVL.fromChunks [randomStorableVector range param] -randomSignal ::- (Storable.C a, Tuple.ValueOf a ~ al, Random a) =>- (a, a) -> Param.T p (Int, StdGen) -> SigP.T p al-randomSignal range p =- SigP.fromStorableVectorLazy (randomStorableVectorLoop range <$> p) - render ::- (Storable.C a, Tuple.ValueOf a ~ al) =>+ (Render.RunArg p) =>+ (Storable.C a, MultiValue.T a ~ al) => (SVL.Vector a -> sig) ->- SigP.T p al -> IO (ChunkSize -> p -> sig)+ (Render.DSLArg p -> Sig.T al) -> IO (ChunkSize -> p -> sig) render limit sig =- fmap (\func chunkSize -> limit . func chunkSize) $ SigP.runChunky sig+ fmap (\func chunkSize -> limit . func chunkSize) $ Render.run sig render2 ::- (Storable.C a, Tuple.ValueOf a ~ al) =>- (Storable.C b, Tuple.ValueOf b ~ bl) =>+ (Render.RunArg p) =>+ (Storable.C a, MultiValue.T a ~ al) =>+ (Storable.C b, MultiValue.T b ~ bl) => ((SVL.Vector a, SVL.Vector b) -> sig) ->- SigP.T p (al, bl) -> IO (ChunkSize -> p -> sig)-render2 limit sig =- fmap (\func chunkSize ->- limit . mapPair (SVL.fromChunks, SVL.fromChunks) .- unzip . map (\(Zip.Cons a b) -> (a,b)) . func chunkSize) $- SigP.runChunkyPlugged sig POut.deflt+ (Render.DSLArg p -> Sig.T (al, bl)) -> IO (ChunkSize -> p -> sig)+render2 limit sig = do+ proc <- CausalRender.run (CausalClass.fromSignal . sig)+ return $ \(SVL.ChunkSize chunkSize) p ->+ limit . mapPair (SVL.fromChunks, SVL.fromChunks) .+ unzip . map (\(Zip.Cons a b) -> (a,b)) $+ Unsafe.performIO (PIO.runCont (proc p)) (const [])+ (repeat $ SigG.LazySize chunkSize) data CheckSimilarityState a =@@ -94,10 +98,11 @@ {-# INLINE checkSimilarityState #-} checkSimilarityState ::- (RealRing.C a, Storable.C a, Tuple.ValueOf a ~ av) =>+ (Render.RunArg p) =>+ (RealRing.C a, Storable.C a, MultiValue.T a ~ av) => a -> (SVL.Vector a -> SVL.Vector a) ->- SigP.T p av ->+ (Render.DSLArg p -> Sig.T av) -> (p -> SigS.T a) -> IO (ChunkSize -> p -> CheckSimilarityState a) checkSimilarityState tol limit gen0 sig1 =@@ -110,7 +115,9 @@ data CheckSimilarity a = CheckSimilarity a (SVL.Vector a) (SVL.Vector a) -instance (Storable a, Ord a, Absolute.C a) => QC.Testable (CheckSimilarity a) where+instance+ (Storable a, Ord a, Absolute.C a) =>+ QC.Testable (CheckSimilarity a) where property (CheckSimilarity tol xs ys) = QC.property $ SigS.foldR (&&) True $@@ -121,11 +128,13 @@ {-# INLINE checkSimilarity #-} checkSimilarity ::+ (Render.RunArg p) => (RealRing.C b, Storable.C b,- Storable.C a, Tuple.ValueOf a ~ av) =>+ Storable.C a, MultiValue.T a ~ av) => b -> (SVL.Vector a -> SVL.Vector b) ->- SigP.T p av -> SigP.T p av ->+ (Render.DSLArg p -> Sig.T av) ->+ (Render.DSLArg p -> Sig.T av) -> IO (ChunkSize -> p -> CheckSimilarity b) checkSimilarity tol limit gen0 gen1 = liftM2@@ -135,13 +144,14 @@ (render limit gen1) checkSimilarityPacked ::+ (Render.RunArg p) => Float -> (SVL.Vector Float -> SVL.Vector Float) ->- SigP.T p (LLVM.Value Float) ->- SigP.T p (Serial.Value TypeNum.D4 Float) ->+ (Render.DSLArg p -> Sig.T (MultiValue.T Float)) ->+ (Render.DSLArg p -> Sig.T (SerialCode.Value TypeNum.D4 Float)) -> IO (ChunkSize -> p -> CheckSimilarity Float) checkSimilarityPacked tol limit scalar vector =- checkSimilarity tol limit scalar (SigPS.unpack vector)+ checkSimilarity tol limit scalar (SigPS.unpack . vector) {- |@@ -158,9 +168,11 @@ property (CheckEqualityGen x y) = QC.property (x==y) checkEquality ::- (Eq a, Storable.C a, Tuple.ValueOf a ~ av) =>+ (Render.RunArg p) =>+ (Eq a, Storable.C a, MultiValue.T a ~ av) => (SVL.Vector a -> SVL.Vector a) ->- SigP.T p av -> SigP.T p av ->+ (Render.DSLArg p -> Sig.T av) ->+ (Render.DSLArg p -> Sig.T av) -> IO (ChunkSize -> p -> CheckEquality a) checkEquality limit gen0 gen1 = liftM2@@ -170,11 +182,13 @@ (render limit gen1) checkEquality2 ::- (Eq a, Storable.C a, Tuple.ValueOf a ~ al) =>- (Eq b, Storable.C b, Tuple.ValueOf b ~ bl) =>+ (Render.RunArg p) =>+ (Eq a, Storable.C a, MultiValue.T a ~ al) =>+ (Eq b, Storable.C b, MultiValue.T b ~ bl) => (SVL.Vector a -> SVL.Vector a) -> (SVL.Vector b -> SVL.Vector b) ->- SigP.T p (al,bl) -> SigP.T p (al,bl) ->+ (Render.DSLArg p -> Sig.T (al,bl)) ->+ (Render.DSLArg p -> Sig.T (al,bl)) -> IO (ChunkSize -> p -> CheckEquality2 a b) checkEquality2 limitA limitB gen0 gen1 = liftM2