{- 2009 Daniel van den Eijkel -} 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