{-# LANGUAGE Arrows #-} {-# LANGUAGE TupleSections #-} module Main where -- base import Control.Arrow as X import Control.Concurrent import Control.Monad (void) import Control.Monad.Fix import qualified Data.List.NonEmpty as NonEmpty import Data.List.NonEmpty (NonEmpty) import Prelude hiding ((!)) -- transformers import Control.Monad.Trans.Reader -- vector import qualified Data.Vector as Vector import Data.Vector ((!)) -- pulse-simple import Sound.Pulse.Simple -- essence-of-live-coding import LiveCoding -- essence-of-live-coding-pulse import LiveCoding.Pulse fastSine :: (Data a, Floating a, MonadFix m) => Cell (ReaderT a m) () a fastSine = proc _ -> do t <- constM ask -< () rec let acc = - (2 * pi / t) ^ 2 * pos vel <- sumC' <<< delay 0 -< acc pos <- arr (+ 1) <<< sumC' -< vel returnA -< pos sumC' :: (Monad m, Data a, Num a) => Cell m a a sumC' = Cell { cellState = 0 , cellStep = \accum a -> let accum' = accum + a in return (accum', accum') } cellA :: MonadFix m => Cell m () Float cellA = runReaderC (44100 / 440) fastSine cellB :: MonadFix m => Cell m () Float cellB = proc _ -> do fDelta <- runReaderC 10 osc -< () runReaderC' osc -< (440 + 5 * fDelta, ()) short :: Monad m => Float -> CellExcept m () Float () short frequency = try $ proc _ -> do count <- sumC -< 1 :: Int if count > 8000 then throwC -< () else returnA -< frequency frequencies :: Monad m => Cell m () Float frequencies = foreverC $ runCellExcept $ sequence $ (short . f) <$> [C, E, G] cycleThrough :: Monad m => NonEmpty a -> Int -> Cell m () a cycleThrough bs cycleLength = let vector = Vector.fromList (NonEmpty.toList bs) in proc _ -> do n <- modSum (cycleLength * length bs) -< 1 returnA -< vector ! (n `div` cycleLength) frequencies' :: Monad m => Cell m () Float frequencies' = cycleThrough (NonEmpty.fromList $ [f D, f G, o $ f Bb]) 8000 pulseCell :: Monad m => PulseCell m () () pulseCell = frequencies' >>> osc' >>> addSample liveProgram :: LiveProgram (HandlingStateT IO) liveProgram = liveCell $ pulseWrapC 1024 pulseCell >>> arr (const ()) main :: IO () main = runHandlingStateT $ foreground liveProgram