synthesizer-llvm-1.2: example/Synthesizer/LLVM/LNdW2011.hs
{-# 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 Nice
import qualified Synthesizer.ALSA.CausalIO.Process as PALSA
import qualified Synthesizer.CausalIO.Process as PIO
import qualified Synthesizer.Zip as Zip
import Synthesizer.ALSA.EventList (ClientName(ClientName))
import qualified Sound.MIDI.Controller as Ctrl
import qualified Sound.MIDI.Message.Channel as ChannelMsg
import qualified Sound.MIDI.Message.Class.Check as MidiCheck
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.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 LLVM.DSL.Expression as Expr
import LLVM.DSL.Expression (Exp)
import qualified LLVM.Extra.Nice.Value as NiceValue
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 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.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
import qualified Synthesizer.Plain.Filter.Recursive.SecondOrder as Filt2Core
import qualified Synthesizer.Causal.Spatial as Spatial
import qualified Control.Monad.Trans.State as State
import qualified Control.Arrow as Arr
import Control.Arrow (Arrow, arr, (&&&), (***), (^<<), (^>>), (>>^))
import Control.Category ((<<<), (.), id, (>>>))
import Control.Monad (liftM2, (<=<))
import Control.Applicative (liftA2, pure, (<$>))
import Control.Functor.HT (void)
import Data.Tuple.HT (mapPair)
import Data.Traversable (traverse)
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 Data.EventList.Relative.TimeTime as EventListTT
import qualified Numeric.NonNegative.Wrapper as NonNegW
import qualified Numeric.NonNegative.Class as NonNeg
import qualified Synthesizer.LLVM.Frame.Stereo as Stereo
import qualified Synthesizer.LLVM.Frame.StereoInterleaved as StereoInt
import qualified Sound.Sox.Option.Format as SoxOption
import qualified Sound.Sox.Frame as SoxFrame
import qualified Sound.Sox.Play as SoxPlay
import qualified Sound.ALSA.PCM as ALSA
import qualified Synthesizer.ALSA.Storable.Play as Play
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
import qualified Algebra.IntegralDomain as Integral
import NumericPrelude.Numeric
import NumericPrelude.Base hiding (fst, snd, id, (.))
import qualified NumericPrelude.Base as P
playStereo :: Gen.T (Stereo.T (NiceValue.T Float)) -> IO ()
playStereo sig =
playStereoStream . ($ SVL.chunkSize 100000) =<<
SigRender.run (fmap Stereo.niceValue sig)
playStereoStream :: SVL.Vector (Stereo.T Float) -> IO ()
playStereoStream = playStreamSox
playMono :: Gen.Nice Float -> IO ()
playMono sig =
playMonoStream . ($ SVL.chunkSize 100000) =<< SigRender.run sig
playMonoPacked :: Gen.T VectorValue -> IO ()
playMonoPacked =
playMonoStream .
SigStL.unpack .
($ SVL.chunkSize 100000) <=<
SigRender.run
playMonoStream :: SVL.Vector Float -> IO ()
playMonoStream = playStreamSox
playStreamALSA ::
(Additive.C y, ALSA.SampleFmt y) =>
SVL.Vector y -> IO ()
playStreamALSA =
Play.auto (Play.makeSink Play.defaultDevice (0.05::Double) sampleRate)
-- reacts faster to CTRL-C
playStreamSox ::
(Storable y, SoxFrame.C y) =>
SVL.Vector y -> IO ()
playStreamSox =
void . SoxPlay.simple SVL.hPut SoxOption.none sampleRate
sampleRate :: Ring.C a => a
sampleRate = 44100
type Vector = Serial.T VectorSize Float
type VectorSize = TypeNum.D4
type VectorValue = NiceValue.T Vector
vectorSize :: Int
vectorSize =
TypeNum.integralFromSingleton
(TypeNum.singleton :: TypeNum.Singleton VectorSize)
vectorRate :: Field.C a => a
vectorRate = sampleRate / fromIntegral vectorSize
intSecond :: Ring.C a => Float -> a
intSecond t = fromInteger $ round $ t * sampleRate
second :: Field.C a => a -> a
second t = t * sampleRate
hertz :: Field.C a => a -> a
hertz f = f / sampleRate
fst :: Arrow arrow => arrow (a,b) a
fst = arr P.fst
snd :: Arrow arrow => arrow (a,b) b
snd = arr P.snd
playFromEvents ::
(ALSA.SampleFmt a, Additive.C a) =>
Double ->
Double ->
PIO.T PALSA.Events (SV.Vector a) ->
IO ()
playFromEvents latency period =
PALSA.playFromEvents
Play.defaultDevice (ClientName "Haskell-LLVM-demo")
latency period sampleRate
modulation :: IO ()
modulation = do
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))
.
PMIDI.controllerExponential
(ChannelMsg.toChannel 0)
Ctrl.modulation
(hertz 500, hertz 2000) (hertz 1000))
vectorBlockSize :: Double
vectorBlockSize = fromIntegral $ 150*vectorSize
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))
modulationPacked :: IO ()
modulationPacked = do
proc <-
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))
.
arr subsampleBT
.
PMIDI.controllerExponential
(ChannelMsg.toChannel 0)
Ctrl.modulation
(hertz 500, hertz 2000) (hertz 1000))
bubbles :: IO ()
bubbles = do
proc <-
Render.run
(0.95 * (Causal.osci Wave.sine $< 0)
.
(fst.fst * (1 + snd.fst * snd))
.
Arr.second (Causal.osci Wave.saw $< 0))
playFromEvents 0.01 (0.015::Double)
((proc ::
PIO.T
(Zip.T
(Zip.T
(EventListBT.T NonNegW.Int Float)
(EventListBT.T NonNegW.Int Float))
(EventListBT.T NonNegW.Int Float))
(SV.Vector Float))
.
PIO.zip
(PIO.zip
(PMIDI.controllerExponential
(ChannelMsg.toChannel 0)
Ctrl.modulation
(hertz 500, hertz 2000) (hertz 1000))
(PMIDI.controllerLinear
(ChannelMsg.toChannel 0)
Ctrl.timbre
(-1, 1) (-0.1)))
(PMIDI.controllerExponential
(ChannelMsg.toChannel 0)
Ctrl.soundVariation
(hertz 1, hertz 10) (hertz 1)))
bubbleControl ::
(MidiCheck.C event) =>
PIO.T (EventListTT.T Ev.StrictTime [event]) (PCS.T Int Float)
bubbleControl =
MCS.filter [
MCS.controllerExponential Ctrl.volume (0.001, 0.99) 0.5,
MCS.controllerExponential Ctrl.modulation (hertz 500, hertz 2000) (hertz 1000),
MCS.controllerLinear Ctrl.soundVariation (-1, 1) 0.7,
MCS.controllerExponential Ctrl.timbre (hertz 0.2, hertz 5) (hertz 1),
MCS.controllerLinear Ctrl.soundController5 (-1, 1) 0.5,
MCS.controllerExponential Ctrl.soundController7 (hertz 2, hertz 20) (hertz 10)]
.
MCS.fromChannel (ChannelMsg.toChannel 0)
bubblesSet :: IO ()
bubblesSet = do
proc <-
Render.runPlugged
(PIn.controllerSet d6)
(Causal.arrayElement d0 *
(Causal.osci Wave.sine $< 0)
.
(Causal.arrayElement d1
*
(1 - Causal.arrayElement d2 *
(Causal.osci Wave.saw $< 0) .
Causal.arrayElement d3)
*
(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))
.
bubbleControl)
subsamplePCS :: PCS.T key a -> PCS.T key a
subsamplePCS =
PCS.mapStream $
flip State.evalState NonNeg.zero .
EventListTT.mapTimeM (subsample (NonNegW.fromNumberMsg "vectorSize" $ fromIntegral vectorSize))
bubblesPacked :: IO ()
bubblesPacked = do
proc <-
Render.runPlugged
(PIn.controllerSet d6)
(CausalP.arrayElement d0 *
(CausalP.osci Wave.approxSine4 $< 0)
.
(CausalP.arrayElement d1
*
(1 - CausalP.arrayElement d2 *
(CausalP.osci Wave.saw $< 0) .
CausalP.arrayElement d3)
*
(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))
.
arr subsamplePCS
.
bubbleControl)
{-
Implementation of 'moveAround' that just lifts the corresponding plain function
in the @Spatial@ module from @synthesizer-core@.
Unfortunately, this way we get a @PseudoModule v v@ constraint
that cannot be satisfied with @LLVM.Vector@s.
-}
moveAround2dLifted ::
(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 (Spatial.moveAround att sonicDelay ear)
moveAround2d ::
(ve ~ Exp v, vl ~ NiceValue.T v,
NiceValue.Algebraic v, NiceValue.RationalConstant v) =>
ve -> ve -> (ve, ve) -> Causal.T (vl, vl) (vl, vl)
moveAround2d att sonicDelay ear =
Causal.map $
(\dist -> (sonicDelay*dist, 1/(att+dist)^2)) .
euclideanNorm2d . subtract ear
euclideanNorm2d ::
(NiceValue.Algebraic a) =>
(Exp a, Exp a) -> Exp a
euclideanNorm2d (x,y) = Expr.sqrt $ Expr.sqr x + Expr.sqr y
flyChannel ::
(ae ~ Exp Float, al ~ NiceValue.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 * (Causal.differentiate (0,0) >>> Causal.map euclideanNorm2d))
>>>
Causal.mix))
>>>
arr (\((phase,volume), speed) -> (volume, (phase,speed)))
>>>
Arr.second (Causal.osci Wave.saw)
>>>
(Causal.envelope * 10)
fly :: IO ()
fly = do
let slow, fast :: Causal.T (NiceValue.T Float) (NiceValue.T Float)
slow =
Filt1.lowpassCausal $<
Gen.constant (Filt1Core.parameter (1/sampleRate :: Exp Float))
fast =
Filt1.lowpassCausal $<
Gen.constant (Filt1Core.parameter (30/sampleRate :: Exp Float))
proc <-
Render.runPlugged
(PIn.controllerSet d5)
((Causal.arrayElement d0 &&&
(liftA2 (,)
(Causal.arrayElement d2)
(liftA2 (,)
((Causal.arrayElement d3 >>> slow)
+
Causal.arrayElement d1 *
(CausalClass.fromSignal (Gen.noise 366210 0.3)
>>> fast >>> fast))
((Causal.arrayElement d4 >>> slow)
+
Causal.arrayElement d1 *
(CausalClass.fromSignal (Gen.noise 234298 0.3)
>>> fast >>> fast)))
>>>
liftA2 Stereo.cons
(flyChannel (-1,0))
(flyChannel ( 1,0))))
>>>
Causal.envelopeStereo
>>^
Stereo.niceValue)
POut.storableVector
playFromEvents 0.01 (0.015::Double)
((proc :: PIO.T (PCS.T Int Float) (SV.Vector (Stereo.T Float)))
.
MCS.filter [
MCS.controllerExponential Ctrl.volume (0.001, 0.99) 0.2,
MCS.controllerLinear Ctrl.modulation (0, 5) 2,
MCS.pitchBend 2 (hertz 250),
MCS.controllerLinear Ctrl.vectorX (-10, 10) 0,
MCS.controllerLinear Ctrl.vectorY (-10, 10) 0]
.
MCS.fromChannel (ChannelMsg.toChannel 0))
flyChannelPacked ::
(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 * (CausalP.differentiate 0 *** CausalP.differentiate 0
>>>
Causal.map euclideanNorm2d))
>>>
Causal.mix))
>>>
arr (\((phase,volume), speed) -> (volume, (phase,speed)))
>>>
Arr.second (CausalP.osci Wave.saw)
>>>
Causal.envelope
>>>
CausalP.amplify 10
flyPacked :: IO ()
flyPacked = do
let slow, fast :: Causal.T VectorValue VectorValue
slow =
Filt1.lowpassCausalPacked $<
Gen.constant (Filt1Core.parameter (1/sampleRate :: Exp Float))
fast =
Filt1.lowpassCausalPacked $<
Gen.constant (Filt1Core.parameter (30/sampleRate :: Exp Float))
proc <-
Render.runPlugged
(PIn.controllerSet d5)
((CausalP.arrayElement d0 &&&
(liftA2 (,)
(CausalP.arrayElement d2)
(liftA2 (,)
((CausalP.arrayElement d3 >>> slow)
+
CausalP.arrayElement d1 *
(CausalClass.fromSignal (GenP.noise 366210 0.3)
>>> fast >>> fast))
((CausalP.arrayElement d4 >>> slow)
+
CausalP.arrayElement d1 *
(CausalClass.fromSignal (GenP.noise 234298 0.3)
>>> fast >>> fast)))
>>>
liftA2 Stereo.cons
(flyChannelPacked (-1,0))
(flyChannelPacked ( 1,0))))
>>>
Causal.envelopeStereo
>>^
Stereo.niceValueSerial)
POut.storableVector
playFromEvents 0.01 (vectorBlockSize/sampleRate)
(arr SigStL.unpackStrict
.
(proc :: PIO.T (PCS.T Int Float) (SV.Vector (Serial.T VectorSize (Stereo.T Float))))
.
arr subsamplePCS
.
MCS.filter [
MCS.controllerExponential Ctrl.volume (0.001, 0.99) 0.2,
MCS.controllerLinear Ctrl.modulation (0, 5) 2,
MCS.pitchBend 2 (hertz 250),
MCS.controllerLinear Ctrl.vectorX (-10, 10) 0,
MCS.controllerLinear Ctrl.vectorY (-10, 10) 0]
.
MCS.fromChannel (ChannelMsg.toChannel 0))