packages feed

hommage-ds-0.0.5: Sound/Hommage/DSPlayer/VoicePlayer.hs

{- 2009 Daniel van den Eijkel <dvde@gmx.net> -}

module Sound.Hommage.DSPlayer.VoicePlayer
 ( Voice
 , VoicePlayer (..)
 , mkVoicePlayer
 )
 where

import Data.IORef

-- | A Voice is an action that gets the current index of the output buffer. 
--   Usually a voice updates the output buffer at the given index, and returns True.
--   False indicates that the voice is inactive and should be removed.
type Voice = Int -> IO Bool

-- | A VoicePlayer encapsulates a list of voices that are active at the moment.
data VoicePlayer = VoicePlayer 
 { startVoice :: Voice -> IO ()     -- ^ Starts a voice (by adding it to the list of active voices)
 , stepVoicePlayer :: Int -> IO ()  -- ^ Runs all voices with the given ouput array index, and removes inactive voices.
 , clearVoicePlayer :: IO ()        -- ^ Removes all voices.
 } 
 
-- | Creates a VoicePlayer
mkVoicePlayer :: IO VoicePlayer
mkVoicePlayer = do
 vref <- newIORef []
 let addVoice v = atomicModifyIORef vref (\vs -> (v : vs, ()))
     vloop i vs = let vloop' []     = return []
                      vloop' (v:vs) = v i >>= \b -> 
                                      if b then vloop' vs >>= return . (v:) 
                                           else vloop' vs
                  in vloop' vs
     step i = do voices <- readIORef vref         
                 voices' <- vloop i voices
                 writeIORef vref $! voices'
     stopAll = atomicModifyIORef vref (\_ -> ([], ()))
 return $ VoicePlayer addVoice step stopAll