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