packages feed

synthesizer-llvm-0.3: src/Synthesizer/LLVM/LAC2011.hs

{-# LANGUAGE NoImplicitPrelude #-}
{-# OPTIONS_GHC -fno-warn-unused-imports #-}
module Synthesizer.LLVM.LAC2011 where

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.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.Storable.Signal as SigStL
import qualified Synthesizer.LLVM.Frame as Frame
import qualified Synthesizer.LLVM.Wave as Wave
import qualified Synthesizer.LLVM.Parameter as Param

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.Class as C
import LLVM.Core (Value, value, valueOf, Vector, constVector, constOf, )
import LLVM.Util.Arithmetic () -- Floating instance for TValue
import qualified LLVM.Core as LLVM
import Data.TypeLevel.Num (D4, D8, D16, d0, d1, d2, d3, d4, d5, d6, d7, d8, )
import qualified Data.TypeLevel.Num as TypeNum

import qualified Synthesizer.LLVM.Parameterized.SignalPacked as GenPS
import qualified Synthesizer.LLVM.Parameterized.Signal as GenP
import Synthesizer.LLVM.CausalParameterized.Process (($<), ($*), ($*#), )
import Synthesizer.LLVM.Parameterized.Signal (($#), )

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.Monad ((<=<), )
import Control.Applicative (liftA2, pure, )
import Data.Traversable (traverse, )

import Foreign.Storable (Storable, )
import qualified Data.StorableVector.Lazy as SVL
import qualified Data.StorableVector as SV

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 Synthesizer.LLVM.Frame.Stereo as Stereo

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.Storable.ALSA.Play as Play

import Data.Word (Word32, )
-- import qualified Data.Function.HT as F
import Data.List (genericLength, )
import System.Random (randomRs, mkStdGen, )

import qualified System.IO as IO
-- import System.Exit (ExitCode, )

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 (fst, snd, id, (.), )
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)

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

playMonoPacked :: GenP.T () (Value (Vector D4 Float)) -> IO ()
playMonoPacked =
   playMonoStream .
   SigStL.unpack .
   ($ ()) .
   ($ SVL.chunkSize 100000) <=<
   GenP.runChunky

playMonoStream :: SVL.Vector Float -> IO ()
playMonoStream = playStreamSox


{-
play ::
   (C.MakeValueTuple y a, Memory.C a struct) =>
   Gen.T a -> IO ()
play =
   playStreamSox .
   Gen.renderChunky (SVL.chunkSize 100000)
-}

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 =
   fmap (const ()) .
   SoxPlay.simple SVL.hPut SoxOption.none 44100


sampleRate :: Ring.C a => a
sampleRate = 44100

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

{-
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))

ping :: IO ()
ping =
   playMono (Gen.exponential2 (second 1) 1 * Gen.osci Wave.triangle 0 (hertz 440))

tremolo :: IO ()
tremolo =
   playMono (Gen.osci Wave.sine 0 (hertz 0.3) * Gen.osci Wave.triangle 0 (hertz 440))


stereo :: IO ()
stereo =
   playStereo (liftA2 Stereo.cons (Gen.osci Wave.triangle 0 (hertz 439)) (Gen.osci Wave.triangle 0 (hertz 441)))

stereoFancy :: IO ()
stereoFancy =
   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

playPingParam :: IO ()
playPingParam = do
   png <- pingParam
   playMonoStream (SVL.take (intSecond 1) $ png (hertz 880))

melody :: IO (SVL.Vector Float)
melody = do
   png <- pingParam
   return $ SVL.concat $ map (SVL.take (intSecond 0.2) . png . hertz) $ cycle [440, 550, 660, 880]

playMelody :: IO ()
playMelody = do
   mel <- melody
   playMonoStream mel

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

playMelody2 :: IO ()
playMelody2 = do
   png <- pingParam2
   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 xs =
   CausalP.frequencyModulationLinear xs .
   CausalP.mapSimple (A.fdiv (LLVM.valueOf 1)) $*
   GenP.rampCore (1 / second 10) 1

playRetarded :: IO ()
playRetarded = do
   mel <- melody
   playMonoParam $ retard $ GenP.fromStorableVectorLazy $ pure $ mel



pingGen :: GenP.T p (Value Float)
pingGen =
   GenP.exponential2 (second 0.5) 0.7 *
   GenP.osciSimple Wave.triangle 0 (hertz 440)

zerop :: Param.T p Float
zerop = pure zero

delayp :: Param.T p Int -> CausalP.T p (Value Float) (Value Float)
delayp = CausalP.delay zerop

delay :: IO ()
delay =
   playMonoParam $
      pingGen + 0.7 * (delayp (intSecond 0.5) $* pingGen)

delayArrow :: IO ()
delayArrow =
   playMonoParam
      ((id + 0.7 * delayp (intSecond 0.5)) $* pingGen)

comb :: IO ()
comb =
   playMonoParam $
      (CausalP.loop zerop
          (id  &&&  0.7 * delayp (intSecond 0.5)
             <<< CausalP.mix) $*
       pingGen)


lfoSine ::
   Param.T p Float ->
   GenP.T p (Moog.Parameter D8 (Value Float))
lfoSine reduct =
   CausalP.mapSimple (Moog.parameter d8 (valueOf (30::Float))) .
   CausalP.mapExponential 2 (hertz 700) $*
   GenP.osciSimple Wave.sine 0 (reduct * hertz 0.1)

filterSweep :: IO ()
filterSweep =
   playMonoParam $
      (0.2 * CtrlP.processCtrlRate 128 lfoSine
       $* GenP.noise 0 0.3)


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.
-}