{-# LANGUAGE Arrows #-} module LiveCoding.Pulse where -- base import Control.Arrow as X import Control.Concurrent import Control.Monad (forever) import Control.Monad.Fix -- transformers import Control.Monad.Trans.Reader -- pulse-simple import Sound.Pulse.Simple -- essence-of-live-coding import LiveCoding type PulseCell = Cell IO () Float playPulseCell :: PulseCell -> IO (MVar PulseCell) playPulseCell pulseCell = do var <- newMVar pulseCell pulseClient <- simpleNew Nothing "example" Play Nothing "this is an example application" (SampleSpec (F32 LittleEndian) 44100 1) Nothing Nothing forkIO $ forever $ do cell <- takeMVar var (samples, cell') <- steps cell $ replicate 1024 () simpleWrite pulseClient samples putMVar var cell' return var -- TODO Generalisable updatePulse :: MVar PulseCell -> PulseCell -> IO () updatePulse var newCell = do oldCell <- takeMVar var putMVar var $ hotCodeSwapCell newCell oldCell -- Returns the sum between -1 and 1 wrapSum :: (Monad m, Data a, RealFloat a) => Cell m a a wrapSum = Cell { cellState = 0 , cellStep = \accum a -> let (_, accum') = properFraction $ accum + a in return (accum', accum') } modSum :: (Monad m, Data a, Integral a) => a -> Cell m a a modSum denominator = Cell { cellState = 0 , cellStep = \accum a -> let accum' = (accum + a) `mod` denominator in return (accum', accum') } clamp :: (Ord a, Num a) => a -> a -> a -> a clamp lower upper a = min upper $ max lower a osc :: (Data a, RealFloat a, MonadFix m) => Cell (ReaderT a m) () a osc = proc _ -> do f <- constM ask -< () phase <- wrapSum -< f / 44100 returnA -< sin $ 2 * pi * phase osc' :: (Data a, RealFloat a, MonadFix m) => Cell m a a osc' = proc a -> do runReaderC' osc -< (a, ()) data Note = A | Bb | B | C | Cis | D | Dis | E | F | Fis | G | Gis deriving (Enum, Show) f :: Note -> Float f note = 220 * (2 ** (fromIntegral (fromEnum note) / 12)) o :: Float -> Float o = (* 2)