module Synthesizer.LLVM.Server.Common ( Real, SampleRate(SampleRate), Instrument, frequency, time, number, control, signal, parameter, frequencyConst, timeConst, ($/), play, startMessage, piecewiseConstant, transposeModulation, amplitudeFromVelocity, makeNote, ) where import qualified Synthesizer.LLVM.Server.Option as Option import Synthesizer.LLVM.Server.Option (SampleRate(SampleRate), ) import qualified Sound.ALSA.Sequencer.Event as Event import qualified Sound.ALSA.Sequencer.Address as Addr import qualified Sound.ALSA.Sequencer.Client as Client import qualified Sound.ALSA.Sequencer.Port as Port import qualified Sound.ALSA.Sequencer.Queue as Queue import qualified Sound.ALSA.Sequencer.RealTime as RealTime import qualified Sound.ALSA.PCM as ALSA import qualified Synthesizer.Storable.ALSA.Play as Play import qualified Synthesizer.Storable.ALSA.MIDI as AlsaSt import qualified Synthesizer.PiecewiseConstant.Signal as PC import qualified Synthesizer.LLVM.ALSA.BendModulation as BM import qualified Synthesizer.LLVM.Parameterized.Signal as SigP import qualified Synthesizer.LLVM.Parameter as Param import qualified LLVM.Extra.Memory as Memory import qualified LLVM.Extra.Class as Class import qualified LLVM.Core as LLVM import qualified Synthesizer.Storable.Signal as SigSt import Foreign.Storable (Storable, ) import Control.Arrow (arr, (^<<), ) import qualified Algebra.Additive as Additive import Data.Word (Word8, ) import NumericPrelude.Numeric (zero, round, ) import Prelude hiding (Real, round, break, ) type Real = Float type Instrument a sig = SampleRate a -> AlsaSt.Instrument a sig frequency :: (p -> Real) -> Param.T (SampleRate Real, p) Real frequency param = arr (\(SampleRate sampleRate, p) -> param p / sampleRate) time :: (p -> Real) -> Param.T (SampleRate Real, p) Real time param = arr (\(SampleRate sampleRate, p) -> param p * sampleRate) number :: (p -> Real) -> Param.T (SampleRate Real, p) Real number param = arr (param . snd) control :: (p -> PC.T Real) -> Param.T (SampleRate Real, p) (PC.T Real) control param = arr (param . snd) signal :: (p -> SigSt.T a) -> Param.T (SampleRate Real, p) (SigSt.T a) signal param = arr (param . snd) parameter :: (p -> a) -> Param.T (SampleRate Real, p) a parameter param = arr (param . snd) frequencyConst :: Real -> Param.T (SampleRate Real, p) Real frequencyConst param = arr (\(SampleRate sampleRate, _p) -> param / sampleRate) timeConst :: Real -> Param.T (SampleRate Real, p) Real timeConst param = arr (\(SampleRate sampleRate, _p) -> param * sampleRate) ($/) :: (Functor f) => f (a -> b) -> a -> f b f $/ x = fmap ($x) f -- ToDo: do not record the empty chunk that is inserted for latency {-# INLINE play #-} play :: (Additive.C y, ALSA.SampleFmt y) => Option.T -> Double -> SigSt.T y -> IO () play opts rate = Play.auto (Play.makeSink (Option.device opts) (Option.periodTime opts) (round rate)) . SigSt.append (SigSt.replicate (Option.chunkSize opts) (Option.latency opts) zero) -- FiltG.delayPosLazySize (Option.chunkSize opts) (Option.latency opts) -- FiltG.delayPos (Option.latency opts) startMessage :: String startMessage = "run 'aconnect' to connect to the MIDI controller" piecewiseConstant :: (Storable a, Class.MakeValueTuple a al, Memory.C al am, LLVM.IsSized am as) => Param.T p (PC.T a) -> SigP.T p al piecewiseConstant pc = SigP.piecewiseConstant (PC.subdivideLongStrict ^<< pc) transposeModulation :: (Functor stream) => SampleRate Real -> Real -> stream (BM.T Real) -> stream (BM.T Real) transposeModulation (SampleRate sampleRate) freq = fmap (BM.shift (freq/sampleRate)) {-# INLINE amplitudeFromVelocity #-} amplitudeFromVelocity :: Real -> Real amplitudeFromVelocity vel = 4**vel -- cf. synthesizer-alsa:Synthesizer.Storable.ALSA.Server.Test makeNote :: Event.NoteEv -> Word8 -> Event.T makeNote typ pit = Event.Cons { Event.highPriority = False , Event.tag = 0 , Event.queue = Queue.direct , Event.timestamp = Event.RealTime $ RealTime.fromInteger 0 , Event.source = Addr.Cons { Addr.client = Client.subscribers, Addr.port = Port.unknown } , Event.dest = Addr.Cons { Addr.client = Client.subscribers, Addr.port = Port.unknown } , Event.body = Event.NoteEv typ (Event.simpleNote 0 pit 64) }