module Synthesizer.LLVM.Server.Common where 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.Sequencer.Event as Event import qualified Sound.ALSA.PCM as ALSA import qualified Synthesizer.Storable.ALSA.Play as Play import qualified Synthesizer.PiecewiseConstant.ALSA.MIDI as PC import qualified Synthesizer.PiecewiseConstant.ALSA.MIDIControllerSet as PCS import qualified Synthesizer.LLVM.Parameterized.Signal as SigP import qualified Synthesizer.LLVM.Parameter as Param import qualified LLVM.Extra.Representation as Rep import qualified LLVM.Core as LLVM import qualified Data.EventList.Relative.BodyTime as EventListBT import qualified Synthesizer.Storable.Signal as SigSt import qualified Data.StorableVector.Lazy as SVL import Foreign.Storable (Storable, ) import qualified Synthesizer.Generic.Signal as SigG import qualified Sound.MIDI.Message.Channel as ChannelMsg import qualified Sound.Sox.Frame as SoxFrame import Control.Arrow ((^<<), ) import qualified Numeric.NonNegative.Wrapper as NonNegW import qualified Algebra.RealRing as RealRing import qualified Algebra.Field as Field import qualified Algebra.Ring as Ring import qualified Algebra.ToInteger as ToInteger import qualified Algebra.Additive as Additive import Data.Word (Word8, ) import NumericPrelude.Numeric (zero, round, ) import Prelude hiding (Real, round, break, ) channel :: ChannelMsg.Channel channel = ChannelMsg.toChannel 0 sampleRate :: Num a => a -- sampleRate = 24000 -- sampleRate = 48000 sampleRate = 44100 latency :: Int latency = 0 -- latency = 256 -- latency = 480 chunkSize :: SVL.ChunkSize chunkSize = Play.defaultChunkSize lazySize :: SigG.LazySize lazySize = let (SVL.ChunkSize size) = chunkSize in SigG.LazySize size periodTime :: Field.C t => t periodTime = let (SVL.ChunkSize size) = chunkSize in ToInteger.fromIntegral size Field./ Ring.fromInteger sampleRate type Real = Float ($/) :: (Functor f) => f (a -> b) -> a -> f b f $/ x = fmap ($x) f {-# INLINE play #-} play :: (RealRing.C t, Additive.C y, ALSA.SampleFmt y) => t -> t -> SigSt.T y -> IO () play period rate = Play.auto period (round rate) . SigSt.append (SigSt.replicate chunkSize latency zero) -- FiltG.delayPosLazySize chunkSize latency -- FiltG.delayPos latency -- ToDo: do not record the empty chunk that is inserted for latency {-# INLINE playAndRecord #-} playAndRecord :: (RealRing.C t, Additive.C y, ALSA.SampleFmt y, SoxFrame.C y) => FilePath -> t -> t -> SigSt.T y -> IO () playAndRecord fileName period rate = Play.autoAndRecord period fileName (round rate) . SigSt.append (SigSt.replicate chunkSize latency zero) piecewiseConstant :: (Storable a, LLVM.MakeValueTuple a al, Rep.Memory al am, LLVM.IsSized am as) => Param.T p (PC.T a) -> SigP.T p al piecewiseConstant pc = SigP.piecewiseConstant (EventListBT.mapTime (NonNegW.fromNumber . fromIntegral . NonNegW.toNumber) ^<< pc) -- SigP.piecewiseConstant (PC.subdivideInt ^<< pc) transposeModulation :: (Functor stream) => Real -> stream (PC.BendModulation Real) -> stream (PC.BendModulation Real) transposeModulation freq = fmap (PC.shiftBendModulation (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) }