packages feed

synthesizer-alsa-0.6: server/Synthesizer/ALSA/Storable/Server/Run.hs

module Synthesizer.ALSA.Storable.Server.Run where

import qualified Synthesizer.MIDI.Example.Instrument as Instr
import Synthesizer.ALSA.Storable.Server.Common
          (Real, withMIDIEvents, play, device, clientName,
           sampleRate, chunkSize, periodTime, channel, )

import qualified Synthesizer.MIDI.CausalIO.Process as MIO
import qualified Synthesizer.MIDI.Storable as MidiSt
import Synthesizer.MIDI.Storable (applyModulation, )

import qualified Synthesizer.ALSA.CausalIO.Process as PAlsa
import qualified Synthesizer.CausalIO.Process as PIO

import qualified Synthesizer.Causal.Oscillator as OsciC
import qualified Synthesizer.Causal.Process as Causal
import qualified Synthesizer.Causal.Filter.NonRecursive as FiltNRC

import qualified Synthesizer.Basic.Wave          as Wave

import qualified Synthesizer.Interpolation.Module as Ip

import qualified Synthesizer.Storable.Oscillator  as OsciSt
import qualified Synthesizer.Storable.Signal      as SigSt
import qualified Data.StorableVector.Lazy.Typed   as SVT
import qualified Data.StorableVector.Lazy         as SVL
import qualified Data.StorableVector              as SV
import Foreign.Storable (Storable, )

import qualified Synthesizer.Generic.Loop      as LoopG
import qualified Synthesizer.Generic.Signal    as SigG
import qualified Synthesizer.State.Signal      as SigS
import qualified Synthesizer.Plain.Filter.Recursive    as FiltR
import qualified Synthesizer.Plain.Filter.Recursive.Universal as UniFilter

import qualified Sound.MIDI.Message.Channel.Voice as VoiceMsg

import Control.Monad.Trans.State (evalState, )
import Control.Category ((.), )
import Control.Arrow (arr, second, (&&&), )

import Data.Function.HT (Id, )
import Data.Tuple.HT (mapSnd, )

import NumericPrelude.Numeric
import NumericPrelude.Base hiding ((.), )
import Prelude ()



volume :: IO ()
volume =
   putStrLn "run 'aconnect' to connect to the MIDI controller" >>
   (withMIDIEvents play $
      SigSt.zipWith (*)
         (OsciSt.static chunkSize Wave.sine zero (800/sampleRate)) .
      evalState (MidiSt.controllerLinear channel VoiceMsg.mainVolume (0,1) (0.2::Real)))

frequency :: IO ()
frequency =
   withMIDIEvents play $
      OsciSt.freqMod chunkSize Wave.sine zero .
      evalState (MidiSt.controllerExponential channel VoiceMsg.modulation
         (400/sampleRate, 1600/sampleRate) (800/sampleRate::Real))


{-# INLINE storableChunk #-}
storableChunk ::
   (SigG.Consume sig a, Storable a) =>
   sig a -> SV.Vector a
storableChunk chunk =
   SigS.toStrictStorableSignal (SigG.length chunk) $
   SigG.toState chunk

frequencyCausal :: IO ()
frequencyCausal =
   PAlsa.playFromEvents device clientName 0.01 (periodTime::Double) sampleRate
      ((PIO.fromCausal $
        Causal.applyStorableChunk $
        OsciC.freqMod (fmap (0.99*) Wave.sine) zero)
       .
       arr storableChunk
       .
       (MIO.controllerExponential channel VoiceMsg.modulation
          (400/sampleRate, 1600/sampleRate) (800/sampleRate::Real)))


pitchBend :: IO ()
pitchBend =
   withMIDIEvents play $
      OsciSt.freqMod chunkSize Wave.sine zero .
      evalState (MidiSt.pitchBend channel 2 (880/sampleRate::Real))

volumeFrequency :: IO ()
volumeFrequency =
   putStrLn "run 'aconnect' to connect to the MIDI controller" >>
   (withMIDIEvents play $
      evalState (do
         vol  <- MidiSt.controllerLinear channel VoiceMsg.mainVolume (0,1) 0.5
         freq <- MidiSt.pitchBend channel 2 (880/sampleRate::Real)
         return $
            SigSt.zipWith (*) vol
               (OsciSt.freqMod chunkSize Wave.sine zero freq)))

volumeFrequencyCausal :: IO ()
volumeFrequencyCausal =
   PAlsa.playFromEvents device clientName 0.01 (periodTime::Double) sampleRate
      ((PIO.fromCausal $
        Causal.applyStorableChunk $
        FiltNRC.envelope
        .
        second (OsciC.freqMod Wave.sine zero))
       .
       arr (uncurry (SV.zipWith (,)))
       .
       (arr storableChunk
        .
        MIO.controllerLinear channel VoiceMsg.mainVolume (0,0.99) (0.5::Real)
        &&&
        arr storableChunk
        .
        MIO.pitchBend channel 2 (880/sampleRate::Real)))


keyboard :: IO ()
keyboard =
   withMIDIEvents play $
--      playALSA (Bld.put :: Int16 -> Bld.Builder Int16) (sampleRate::Real) .
      SigSt.map (0.2*) .
      evalState (MidiSt.sequence chunkSize channel Instr.tine)

keyboardMulti :: IO ()
keyboardMulti =
   withMIDIEvents play $
--      playALSA (Bld.put :: Int16 -> Bld.Builder Int16) (sampleRate::Real) .
      SigSt.map (0.2*) .
      evalState (MidiSt.sequenceMultiProgram chunkSize channel
         (VoiceMsg.toProgram 2)
         [Instr.pingDur, Instr.pingRelease, Instr.tine])

keyboardStereo :: IO ()
keyboardStereo =
   withMIDIEvents play $
--      playALSA (Bld.put :: Int16 -> Bld.Builder Int16) (sampleRate::Real) .
      SigSt.map ((0.2::Real)*>) .
      evalState (MidiSt.sequenceMultiProgram chunkSize channel
         (VoiceMsg.toProgram 1)
         [Instr.pingStereoRelease, Instr.tineStereo,
          Instr.softString, Instr.softStringCausal])

keyboardPitchbend :: IO ()
keyboardPitchbend =
   withMIDIEvents play $
      SigSt.map ((0.2::Real)*>) .
      evalState
         (do bend <- MidiSt.pitchBend channel (2^?(2/12)) 1
             MidiSt.sequenceModulated chunkSize bend channel Instr.stringStereoFM)

keyboardFM :: IO ()
keyboardFM =
   withMIDIEvents play $
      SigSt.map ((0.2::Real)*>) .
      evalState
         (do fm <- MidiSt.bendWheelPressure channel
                      2 (10/sampleRate) 0.04 0.03
             MidiSt.sequenceModulated chunkSize fm channel Instr.stringStereoFM)

keyboardDetuneFM :: IO ()
keyboardDetuneFM =
   withMIDIEvents play $
      SigSt.map ((0.2::Real)*>) .
      evalState
         (do fm <- MidiSt.bendWheelPressure channel
                      2 (10/sampleRate) 0.04 0.03
             detune <- MidiSt.controllerLinear channel
                          VoiceMsg.vectorX (0,0.005) 0
             MidiSt.sequenceMultiModulated
                chunkSize channel Instr.stringStereoDetuneFM
                (applyModulation fm .
                 applyModulation detune))


keyboardFilter :: IO ()
keyboardFilter =
   withMIDIEvents play $
      SigSt.map (0.2*) .
      evalState
         (do music <- MidiSt.sequence chunkSize channel Instr.pingRelease
             freq  <- MidiSt.controllerLinear channel
                         -- VoiceMsg.vectorY
                         (VoiceMsg.toController 21)
                         (100/sampleRate, 5000/sampleRate)
                         (700/sampleRate)
             return $
                SigS.toStorableSignal chunkSize $
                SigS.map UniFilter.lowpass $
                SigS.modifyModulated
                   UniFilter.modifier
                   (SigS.map UniFilter.parameter $
                    SigS.zipWith FiltR.Pole
                       (SigS.repeat (5 :: Real))
                       (SigS.fromStorableSignal freq)) $
                SigS.fromStorableSignal music)


makeLoop ::
   LoopG.TimeControl Real -> Real -> Real ->
   (Real, SigSt.T Real) -> (Real, SigSt.T Real)
makeLoop timeCtrlWave loopLen loopStart =
   mapSnd SVT.toVectorLazy .
   LoopG.timeReverse Ip.linear Ip.linear timeCtrlWave loopLen loopStart .
   mapSnd ((id :: Id (SVT.DefaultVector a)) . SVT.fromVectorLazy)

keyboardSample :: IO ()
keyboardSample =
   do piano <- Instr.readPianoSample
      string <- Instr.readStringSample
      let loopedString     = mapSnd (LoopG.simple 8750 500) string
          fadedString      = mapSnd (LoopG.fade (undefined::Real) 8750 500) string
          timeSineString   = makeLoop LoopG.timeControlSine 8750 500 string
          timeZigZagString = makeLoop LoopG.timeControlZigZag 8750 500 string
      withMIDIEvents play $
         SigSt.map (0.2*) .
         evalState (MidiSt.sequenceMultiProgram chunkSize channel
               (VoiceMsg.toProgram 5) $
            Instr.sampledSound piano :
            Instr.sampledSound string :
            Instr.sampledSound loopedString :
            Instr.sampledSound fadedString :
            Instr.sampledSound timeSineString :
            Instr.sampledSound timeZigZagString :
            Instr.sampledSoundTimeLoop Instr.loopTimeModSine string 8750 500 :
            Instr.sampledSoundTimeLoop Instr.loopTimeModZigZag string 8750 500 :
            [])


keyboardVariousStereo :: IO ()
keyboardVariousStereo =
   do piano <- Instr.readPianoSample
      string <- Instr.readStringSample
      let loopedString = makeLoop LoopG.timeControlZigZag 8750 500 string
      withMIDIEvents play $
         SigSt.map ((0.2::Real)*>) .
         evalState (MidiSt.sequenceMultiProgram chunkSize channel
               (VoiceMsg.toProgram 0) $
            Instr.pingStereoRelease :
            Instr.tineStereo :
            Instr.softString :
            Instr.sampledSoundDetuneStereo 0.001 piano :
            Instr.sampledSoundDetuneStereo 0.002 loopedString :
            Instr.sampledSoundDetuneStereoRelease 0.1 0.001 piano :
            Instr.sampledSoundDetuneStereoRelease 0.3 0.002 loopedString :
            [])


keyboardSampleTFM :: IO ()
keyboardSampleTFM =
   do instr <- Instr.readPianoSample
      withMIDIEvents play $
         evalState
            (do fm <- MidiSt.bendWheelPressure channel
                         2 (10/sampleRate) 0.04 0.03
                speed <- MidiSt.controllerLinear channel
                             (VoiceMsg.toController 22)
                             (0,2) 1
                offset <- MidiSt.controllerLinear channel
                             (VoiceMsg.toController 21)
                             (0, fromIntegral (SVL.length (snd instr))) 0
                MidiSt.sequenceMultiModulated
                   chunkSize channel (Instr.timeModulatedSample instr)
                   (applyModulation fm .
                    applyModulation speed .
                    applyModulation offset))


keyboardNoisePipe :: IO ()
keyboardNoisePipe =
   withMIDIEvents play $
      evalState
         (do fm <- MidiSt.bendWheelPressure channel
                      2 (10/sampleRate) 0.04 0.03
             resonance <-
                   MidiSt.controllerExponential channel
                      (VoiceMsg.toController 23)
                      (1, 100) 10
             MidiSt.sequenceMultiModulated
                chunkSize channel Instr.colourNoise
                (applyModulation fm .
                 applyModulation resonance))


keyboardNoisyTone :: IO ()
keyboardNoisyTone =
   withMIDIEvents play $
      evalState
         (do fm <- MidiSt.bendWheelPressure channel
                      2 (10/sampleRate) 0.04 0.03
             speed <- MidiSt.controllerLinear channel
                          (VoiceMsg.toController 21)
                          (0,0.5) 0.1
             MidiSt.sequenceMultiModulated
                chunkSize channel Instr.toneFromNoise
                (applyModulation fm .
                 applyModulation speed))


keyboardFilteredNoisyTone :: IO ()
keyboardFilteredNoisyTone =
   withMIDIEvents play $
      evalState
         (do fm <- MidiSt.bendWheelPressure channel
                      2 (10/sampleRate) 0.04 0.03
             {-
             speed must never be zero,
             since this requires to fetch unlimited data from future.
             -}
             speed <- MidiSt.controllerLinear channel
                          (VoiceMsg.toController 21)
                          (0.05,0.5) 0.1
             cutoff <- MidiSt.controllerExponential channel
                          (VoiceMsg.toController 22)
                          (1, 30) 10
             resonance <- MidiSt.controllerExponential channel
                          (VoiceMsg.toController 23)
                          (1, 20) 5
             MidiSt.sequenceMultiModulated
                chunkSize channel Instr.toneFromFilteredNoise
                (applyModulation fm .
                 applyModulation speed .
                 applyModulation cutoff .
                 applyModulation resonance))



keyboardCausal :: IO ()
keyboardCausal =
   PAlsa.playFromEvents device clientName 0.01 (periodTime::Double) sampleRate $
      arr (SV.map (0.2*))
      .
      MIO.sequenceStorable channel (\ _pgm -> Instr.pingReleaseCausal)