packages feed

hCsound-0.2.2: src/Sound/Csound.hs

-- |Sound.Csound provides a Haskell interface to the Csound API (defined in
-- csound.h). (almost) all functions from the API are wrapped and marshalled
-- in Sound.CSound.Interface.
-- In addition to the raw functions provided there, Sound.CSound provides
-- many more convenient to use when calling csound, as well as marshalling
-- for some functions that return vectors.
--
-- C++ class files, such as CSoundFile.hpp, are not yet wrapped.
-- Also support for cscore is currently very limited.

module Sound.Csound
	(
                CsoundMonad, --exported from Interface
                csoundCreate,
                csoundCompile,
                csoundPerform,
                CsoundPerformStatus,
                csoundPreCompile,
                csoundSetHostImplementedAudioIO,

-- defined in this module
                csoundPerformKsmpsIO,
                csoundPerformBufferIO,
                withOpcodeList,
                withUtilityList,
                listUtilityNames,
                withChannelList
	)
where

import Sound.Csound.Interface
import Foreign.Marshal.Array (peekArray, pokeArray)
import Control.Monad.Error (liftIO, throwError)
import Control.Exception (bracket)

-- Functions to perform a score with input and output from the host.

-- |Perform an entire score using csoundPerformKsmps, with handling of
-- input and output buffers spin and spout.  Note that
-- csoundSetHostImplementedIO must be called before csoundCompile.
csoundPerformKsmpsIO ::
        CsoundPtr -- ^Pointer to csound instance
        -> (Int -> Int -> IO [CsndFlt]) -- ^Function that takes buffer size
                                        -- and starting position (in samples)
                                        -- and returns a list of length
                                        -- buffersize of input to use.
        -> (Int -> Int -> [CsndFlt] -> IO ()) -- ^Function that takes
                                              -- buffer size, starting
                                              -- position (in samples),
                                              -- and list of CsndFlt
                                              -- and performs an IO action
                                              -- with the [CsndFlt]
        -> CsoundMonad ()
csoundPerformKsmpsIO csPtr inBuf outBuf = csoundPerformKsmpsIO' 0
        where
        bufSize = csoundGetKsmps csPtr
        ifn = inBuf bufSize
        ofn = outBuf bufSize
        peekFn = peekArray bufSize
        csoundPerformKsmpsIO' :: Int -> CsoundMonad ()
        csoundPerformKsmpsIO' iposAcc = do
                liftIO $ csoundGetSpin' csPtr >>= \iptr ->
                         ifn iposAcc >>= pokeArray iptr
                res <- csoundPerformKsmps csPtr
                liftIO $ csoundGetSpout' csPtr >>= peekFn >>= ofn iposAcc
                case res of
                        PerformStopped -> let newPosAcc = iposAcc + bufSize in
                                csoundPerformKsmpsIO' newPosAcc
                        PerformFinished -> return ()
                        _ -> throwError $ show res 

-- |Perform an entire score using csoundPerformBuffer, with handling of
-- input and output buffers.
csoundPerformBufferIO ::
  CsoundPtr -- ^Pointer to Csound struct
  -> (Int -> Int -> IO [CsndFlt]) -- ^Function that takes buffer size and
                                  -- starting position (in samples) and
                                  -- returns a list of length buffersize
                                  -- of input to use.
  -> (Int -> Int -> [CsndFlt] -> IO ()) -- ^Function that takes buffer
                                        -- size, starting position
                                        -- (in samples), and list of CsndFlt
                                        -- and performs an IO action
                                        -- with the [CsndFlt]
  -> CsoundMonad ()
csoundPerformBufferIO csp inBuf outBuf = csoundPerformBufferIO' 0
        where
        inBufSize = csoundGetInputBufferSize csp
        ifn = inBuf inBufSize
        outBufSize = csoundGetOutputBufferSize csp
        ofn = outBuf outBufSize
        peekFn = peekArray $ csoundGetInputBufferSize csp
        csoundPerformBufferIO' :: Int -> CsoundMonad ()
        csoundPerformBufferIO' iposAcc = do
                liftIO $ csoundGetInputBuffer' csp >>=
                         \iptr -> ifn iposAcc >>= pokeArray iptr
                res <- csoundPerformBuffer csp
                liftIO $ csoundGetOutputBuffer' csp >>= peekFn >>= ofn iposAcc
                case res of
                        PerformStopped -> let newPosAcc = iposAcc+inBufSize in
                                csoundPerformBufferIO' newPosAcc
                        PerformFinished -> return ()
                        _ -> throwError $ show res --Again, this should never happen

-- |Perform an IO action with the current csound opcode list,
-- properly disposing of the list after completing the action.
withOpcodeList :: CsoundPtr -> ([OpcodeListEntry] -> IO b) -> CsoundMonad b
withOpcodeList csPtr func = do
        openRes <- csoundNewOpcodeList csPtr
        liftIO $ bracket (return openRes) disposeFunc procFunc
        where
        disposeFunc (ptr, _) = csoundDisposeOpcodeList csPtr ptr
        procFunc (_, list) = func list

-- |Perform an action within the IO monad, using the list of named utilities.
withUtilityList :: CsoundPtr -> ([String] -> IO b) -> CsoundMonad b
withUtilityList csPtr func = do
        openRes <- csoundListUtilities csPtr
        case openRes of
                (_, []) -> throwError "No utilities found."
                _ -> liftIO $ bracket (return openRes) disposeFunc procFunc
        where
        disposeFunc (ptr, _) = csoundDeleteUtilityList csPtr ptr
        procFunc (_, list) = func list

-- |Get a list of all the registered csound utilities.  This should be used instead of csoundListUtilities.
-- because this function calls csoundDeleteUtilityList after use.
listUtilityNames :: CsoundPtr -> CsoundMonad [String]
listUtilityNames csPtr = withUtilityList csPtr return

-- |Perform an action within the IO monad, using the list of channels.
withChannelList :: CsoundPtr -> ([CsoundChannelListEntry] -> IO a) -> CsoundMonad a
withChannelList csPtr func = do
        openRes <- csoundListChannels csPtr
        case openRes of
                (_, []) -> throwError "No open channels"
                _ -> liftIO $ bracket (return openRes) disposeFunc procFunc
        where
        disposeFunc (ptr, _) = csoundDeleteChannelList csPtr ptr
        procFunc (_, list) = func list

-- |Perform a simple run of csound, with no special handling.
{-
runCsoundSimple :: String -> CsoundMonad CsoundPerformStatus
runCsoundSimple argList = do
        perfStatus <- liftIO $ bracket (csoundCreate nullPtr) csoundDestroy perform
	where
        perform csPtr = do
                res <- csoundCompile csPtr argv argc
                case res of
                        CsoundSuccess -> csoundPerform csPtr
                        otherwise -> return $ PerformError res
        argc = "csound" : words argList
	argv = length argc
-}