{-# LANGUAGE ForeignFunctionInterface, GeneralizedNewtypeDeriving #-} -- |Interface to csound.h -- This module contains all foreign import statements, Haskell -- representations of most csound datatypes -- and their Storable instances, and some extra marshalling functions. module Sound.Csound.Interface where import Prelude import C2HS import Control.Monad (liftM) import Control.Monad.Error (ErrorT, liftIO, throwError) import Data.Bits import Data.List ( foldl') import qualified Control.Monad.Cont as Cont #include -- **Haskell representations of basic csound types. -- |Type for one audio sample value. CsndFlt is a double regardless of the size of CSNDFLT type CsndFlt = Double #ifndef USE_DOUBLE -- |C representation of CSNDFLT, depending on if USE_DOUBLE is defined. type CCsndFlt = CFloat #else type CCsndFlt = CDouble #endif type IntLeast64T = {#type int_least64_t#} type UInt32T = {#type uint32_t#} type UIntPtrT = {#type uintptr_t#} -- **The CsoundMonad and associated functions type CsoundMonad = ErrorT String IO -- ^Wrap IO and produce error messages as applicable. -- |Wrap functions that return CsoundStatus into the CsoundMonad -- for error handling csoundStatusWrapper :: IO CsoundStatus -> CsoundMonad () csoundStatusWrapper csoundFunc = do res <- liftIO csoundFunc case res of CsoundSuccess -> return () _ -> throwError $ show res -- |Wrap functions that return a CsoundStatus and one other value into the -- CsoundMonad for error handling. csoundStatValWrapper :: IO (CsoundStatus, a) -> CsoundMonad a csoundStatValWrapper func = do (stat, output) <- liftIO func case stat of CsoundSuccess -> return output _ -> throwError $ show stat -- |Wrap functions that return CsoundPerformStatus into the CsoundMonad. csPerformStatusWrapper :: IO CsoundPerformStatus -> CsoundMonad CsoundPerformStatus csPerformStatusWrapper csoundFunc = do res <- liftIO csoundFunc case res of PerformError _ -> throwError $ show res _ -> return res -- |Wrap any function from IO monad to CsoundMonad csoundWrapper :: (a -> IO b) -> a -> CsoundMonad b csoundWrapper fn v = liftIO $ fn v {-# INLINE csoundWrapper #-} -- |Wrap functions that return Bool into the CsoundMonad boolWrapper :: String -> IO Bool -> CsoundMonad () boolWrapper errStr action = do res <- liftIO action case res of True -> return () False -> throwError errStr {#pointer *CSOUND as CsoundPtr newtype#} {#pointer *FILE as FilePtr newtype#} {#pointer *PVSDATEXT as PvsDatExtPtr -> PvsDatExt#} -- **Enumerations. -- | Flags for csoundInitialize(). data CsoundInit = CsoundInitNoSignalHandler | CsoundInitNoAtExit -- rather than hardwiring the enums, I should probably use cpp on this file -- to get the values directly from the header. instance Enum CsoundInit where fromEnum CsoundInitNoSignalHandler = 1 fromEnum CsoundInitNoAtExit = 2 toEnum 1 = CsoundInitNoSignalHandler toEnum 2 = CsoundInitNoAtExit toEnum unmatched = error ("CsoundInit.toEnum: Cannot match " ++ show unmatched) -- |Csound Languages. {#enum cslanguage_t as CsLanguage {underscoreToCase} deriving (Eq, Show)#} -- |CSound status. {#enum CSOUND_STATUS as CsoundStatus {underscoreToCase} deriving (Eq, Show)#} -- |CsoundPerform results data CsoundPerformStatus = PerformFinished | PerformStopped | PerformError CsoundStatus deriving Show -- |The return values of the csoundSetCallback function. data CsoundSetCallbackStatus = SetCallbackOk | SetCallbackError CsoundStatus | SetCallbackIgnored Int deriving (Eq, Show) -- |Csound callback function types. -- A callback function will receive one of these types to specify the type -- of event calling it. -- when setting a callback, the bitwise 'or' of all desired types should -- be used (or the special 'alltypes' value). data CsoundCallbackFunctionType = CsoundCallbackAllTypes | CsoundCallbackKbdEvent | CsoundCallbackKbdText deriving (Eq) instance Enum CsoundCallbackFunctionType where fromEnum CsoundCallbackAllTypes = 0 fromEnum CsoundCallbackKbdEvent = 1 fromEnum CsoundCallbackKbdText = 2 toEnum 0 = CsoundCallbackAllTypes toEnum 1 = CsoundCallbackKbdEvent toEnum 2 = CsoundCallbackKbdText toEnum unmatched = error ("CsoundCallbackFunctionType.toEnum: Cannot match " ++ show unmatched) newtype CsoundCallbackFunctionTypeMask = CsoundCallbackFunctionTypeMask Int deriving (Eq, Num, Ord, Show, Real, Enum, Integral, Bits) typeToMask :: CsoundCallbackFunctionType -> CsoundCallbackFunctionTypeMask typeToMask CsoundCallbackAllTypes = 0 typeToMask typ = fromIntegral $ fromEnum typ -- |Create a TypeMask from a list of CsoundCallbackFunctionType createTypeMask :: [CsoundCallbackFunctionType] -> CsoundCallbackFunctionTypeMask createTypeMask = foldl' orFunc (-1) where orFunc (-1) r = typeToMask r --ignore a (-1) type orFunc _ CsoundCallbackAllTypes = 0 orFunc 0 _ = 0 orFunc l r = l .|. typeToMask r -- | Filetypes recognized by CSound {#enum CSOUND_FILETYPES as CsoundFiletypes {underscoreToCase} deriving (Eq, Show)#} -- **Utility marshalling functions -- |Marshal an enumeration to a CInt cIntFromEnum :: Enum a => a -> CInt cIntFromEnum = cIntConv . fromEnum -- |Marshal a CInt to an enumeration cIntToEnum :: Enum a => CInt -> a cIntToEnum = toEnum . cIntConv -- |Marshal a CInt to Bool. False if CInt== 0, otherwise true. cIntToBool :: CInt -> Bool cIntToBool val | val == 0 = False | otherwise = True -- |Marshal a CInt to Bool. True if CInt== 0, otherwise false. -- Some standardization of the underlying library would be nice. -- Even better is knowing that it will never be fixed. cIntToBoolSwitch :: CInt -> Bool cIntToBoolSwitch val | val == 0 = True | otherwise = False -- |Marshal a CInt to a Maybe Int, Nothing if CInt <0 maybeCInt :: CInt -> Maybe Int maybeCInt i | i >= 0 = Just $ cIntConv i | otherwise = Nothing -- |Check if a Ptr () is valid or not. checkNullPtr :: Ptr () -> Maybe (Ptr ()) checkNullPtr ptr | ptr == nullPtr = Nothing | otherwise = Just ptr -- |Create a CsoundPerformStatus toCsoundPerformStatus :: CInt -> CsoundPerformStatus toCsoundPerformStatus a | a == 0 = PerformStopped | a < 0 = PerformError $ cIntToEnum a | otherwise = PerformFinished cIntToSetCallbackStatus :: CInt -> CsoundSetCallbackStatus cIntToSetCallbackStatus 0 = SetCallbackOk cIntToSetCallbackStatus val = case (val < 0) of True -> SetCallbackError $ cIntToEnum val False -> SetCallbackIgnored $ cIntConv val -- |Marshal a list of CsndFlt to an array of MYFLT. withCsndFltArray :: (Storable b, RealFloat b, RealFloat a) => [a] -> (Ptr b -> IO b1) -> IO b1 withCsndFltArray = withArray . map (cFloatConv) nest :: [(r -> a) -> a] -> ([r] -> a) -> a nest xs = Cont.runCont (sequence (map Cont.Cont xs)) -- |Marshal a [String] to a (Ptr (Ptr CChar)) withStringList :: [String] -> (Ptr CString -> IO a) -> IO a withStringList strings act = nest (map withCString strings) (\rs -> withArray0 nullPtr rs act) -- |Marshal (Ptr (Ptr CChar)) to [String]. -- Keep track of the original pointer because it will often -- need to be manually freed. peekStringArrayPtr :: Ptr (Ptr (CChar)) -> IO (Ptr (CString), [String]) peekStringArrayPtr ptrPtr = do strAry <- peekStringArray ptrPtr return (ptrPtr, strAry) peekStringArray :: Ptr CString -> IO [String] peekStringArray ptrPtr = withCString "" (\nul-> do cstrAry <- peekArray0 nul ptrPtr mapM peekCAString cstrAry ) -- |since c2hs doesn't allow "with" as an input marshaller, -- withObject is a synonym. withObject :: Storable a => a -> (Ptr a -> IO b) -> IO b withObject = with -- |Peek from a Ptr CFloat to a CsndFloat peekCsndFlt :: Ptr CCsndFlt -> IO CsndFlt peekCsndFlt a = peek a >>= \x -> return $ cFloatConv x -- |Marshal a Ptr (Ptr CFloat) to a Ptr (CsndFlt). -- This is very likely broken. peekCsndOutAry :: Ptr (Ptr CCsndFlt) -> IO (Ptr CsndFlt) peekCsndOutAry ptrPtr = peek ptrPtr >>= \ptr -> return $ castPtr ptr -- |Variation on PVSDAT used in the pvs bus interface. -- The two parameters sliding and nb are only present -- #ifdef SDFT. If compiled with SDFT support, the fields will be Just a, -- otherwise they will be Nothing. -- hCsound does not currently implement SDFT. data PvsDatExt = PvsDatExt { n :: Int, sliding :: Maybe Int, nb :: Maybe Int, overlap :: Int, winsize :: Int, wintype :: Int, format :: Int, framecount :: Int, frame :: Ptr CFloat } instance Storable (PvsDatExt) where alignment _ = alignment (undefined :: CInt) sizeOf _ = {#sizeof PVSDATEXT#} peek p = do nV <- liftM fromIntegral $ {#get PVSDATEXT.N#} p #ifdef SDFT slidingV <- liftM Just . fromIntegral $ {#get PVSDATEXT.sliding#} p nbV <- liftM Just . fromIntegral $ {#get PVSDATEXT.NB#} p #else let slidingV = Nothing let nbV = Nothing #endif overlapV <- liftM fromIntegral $ {#get PVSDATEXT.overlap#} p winsizeV <- liftM fromIntegral $ {#get PVSDATEXT.winsize#} p wintypeV <- liftM fromIntegral $ {#get PVSDATEXT.wintype#} p formatV <- liftM fromIntegral $ {#get PVSDATEXT.format#} p framecountV <- liftM fromIntegral $ {#get PVSDATEXT.framecount#} p frameV <- {#get PVSDATEXT.frame#} p return $ PvsDatExt nV slidingV nbV overlapV winsizeV wintypeV formatV framecountV frameV poke p pvs = do {#set PVSDATEXT.N#} p $ fromIntegral $ n pvs #ifdef SDFT -- If the structure was marshalled from C, these will have a -- value. If these are Nothing and SDFT is defined, -- it should be an error anyway. {#set PVSDATEXT.sliding#} p $ fromIntegral . fromJust $ sliding pvs {#set PVSDATEXT.NB#} p $ fromIntegral . fromJust $ nb pvs #endif {#set PVSDATEXT.overlap#} p $ fromIntegral $ overlap pvs {#set PVSDATEXT.winsize#} p $ fromIntegral $ winsize pvs {#set PVSDATEXT.wintype#} p $ fromIntegral $ wintype pvs {#set PVSDATEXT.format#} p $ fromIntegral $ format pvs {#set PVSDATEXT.framecount#} p $ fromIntegral $ framecount pvs {#set PVSDATEXT.frame#} p $ frame pvs -- *Csound Initialization functions {- I don't want to do this yet; I don't know if the input values are retained by the csound library. {#fun unsafe csoundInitialize as ^ { `Int', strAryInMarshal* `[String]', `Int' } -> `Int'#} -} csoundCreate :: CsoundMonad CsoundPtr csoundCreate = liftIO $ unsafeCsoundCreate nullPtr unsafeCsoundCreate :: Ptr () -> IO (CsoundPtr) unsafeCsoundCreate = {#call unsafe csoundCreate as uCsoundCreate_#} csoundPreCompile :: CsoundPtr -> CsoundMonad () csoundPreCompile csPtr = csoundStatusWrapper $ unsafeCsoundPreCompile csPtr {#fun unsafe csoundPreCompile as unsafeCsoundPreCompile {id `CsoundPtr'} -> `CsoundStatus' cIntToEnum #} csoundInitializeCscore :: CsoundPtr -> FilePtr -> FilePtr -> CsoundMonad () csoundInitializeCscore csPtr iScore oScore = csoundStatusWrapper $ unsafeCsoundInitializeCscore csPtr iScore oScore {#fun unsafe csoundInitializeCscore as unsafeCsoundInitializeCscore { id `CsoundPtr', id `FilePtr', id `FilePtr' } -> `CsoundStatus' cIntToEnum#} csoundQueryInterface :: String -> CsoundMonad (CsoundStatus, Ptr (), Int) csoundQueryInterface str = do res <- liftIO $ csoundQueryInterface' str case res of (CsoundSuccess, _, _) -> return res (errCode, _, _) -> throwError $ show errCode -- |Returns (Result, ptr to interface, version number) if the interface is available. {#fun csoundQueryInterface as csoundQueryInterface' { `String', alloca- `Ptr ()' peek*, alloca- `Int' peekIntConv* } -> `CsoundStatus' cIntToEnum#} csoundDestroy :: CsoundPtr -> CsoundMonad () csoundDestroy = csoundWrapper {#call unsafe csoundDestroy as uCsoundDestroy_#} {#fun pure unsafe csoundGetVersion {} -> `Int'#} {#fun pure unsafe csoundGetAPIVersion as csoundGetApiVersion {} -> `Int'#} csoundGetHostData :: CsoundPtr -> CsoundMonad (Ptr ()) csoundGetHostData = csoundWrapper {#call csoundGetHostData as csoundGetHostData_#} csoundSetHostData :: CsoundPtr -> Ptr () -> CsoundMonad () csoundSetHostData csp p = liftIO $ {#call csoundSetHostData as csoundSetHostData_#} csp p {#fun csoundGetEnv {id `CsoundPtr', `String'} -> `String'#} csoundSetGlobalEnv :: String -> String -> CsoundMonad () csoundSetGlobalEnv name value = csoundStatusWrapper $ csoundSetGlobalEnv' name value {#fun csoundSetGlobalEnv as csoundSetGlobalEnv' {`String', `String'} -> `CsoundStatus' cIntToEnum#} -- *Performance functions csoundCompile :: CsoundPtr -> String -> CsoundMonad () csoundCompile csPtr argList = csoundStatusWrapper $ csoundCompile' csPtr argv argc where argc = "csound" : words argList argv = length argc {#fun unsafe csoundCompile as csoundCompile' { id `CsoundPtr', `Int', withStringList* `[String]' } -> `CsoundStatus' cIntToEnum#} csoundPerform :: CsoundPtr -> CsoundMonad CsoundPerformStatus csoundPerform csPtr = csPerformStatusWrapper $ csoundPerform' csPtr {#fun csoundPerform as csoundPerform' {id `CsoundPtr'} -> `CsoundPerformStatus' toCsoundPerformStatus#} csoundPerformKsmps :: CsoundPtr -> CsoundMonad CsoundPerformStatus csoundPerformKsmps csPtr = csPerformStatusWrapper $ csoundPerformKsmps' csPtr {#fun csoundPerformKsmps as csoundPerformKsmps' {id `CsoundPtr'} -> `CsoundPerformStatus' toCsoundPerformStatus#} csoundPerformKsmpsAbsolute :: CsoundPtr -> CsoundMonad CsoundPerformStatus csoundPerformKsmpsAbsolute csPtr = csPerformStatusWrapper $ csoundPerformKsmpsAbsolute' csPtr {#fun csoundPerformKsmpsAbsolute as csoundPerformKsmpsAbsolute' {id `CsoundPtr'} -> `CsoundPerformStatus' toCsoundPerformStatus#} csoundPerformBuffer :: CsoundPtr -> CsoundMonad CsoundPerformStatus csoundPerformBuffer csPtr = csPerformStatusWrapper $ csoundPerformBuffer' csPtr {#fun csoundPerformBuffer as csoundPerformBuffer' {id `CsoundPtr'} -> `CsoundPerformStatus' toCsoundPerformStatus#} {#fun csoundStop {id `CsoundPtr'} -> `()'#} {#fun csoundCleanup {id `CsoundPtr'} -> `Int'#} {#fun csoundReset {id `CsoundPtr'} -> `()'#} -- *Csound Attributes {#fun pure unsafe csoundGetSr { id `CsoundPtr'} -> `CsndFlt' cFloatConv#} {#fun pure unsafe csoundGetKr { id `CsoundPtr'} -> `CsndFlt' cFloatConv#} {#fun pure unsafe csoundGetKsmps { id `CsoundPtr'} -> `Int'#} {#fun pure unsafe csoundGetNchnls { id `CsoundPtr'} -> `Int'#} {#fun pure unsafe csoundGet0dBFS { id `CsoundPtr'} -> `CsndFlt' cFloatConv#} {#fun pure unsafe csoundGetStrVarMaxLen { id `CsoundPtr'} -> `Int'#} {#fun pure unsafe csoundGetSampleFormat { id `CsoundPtr'} -> `Int'#} {#fun pure unsafe csoundGetSampleSize { id `CsoundPtr'} -> `Int'#} {#fun pure unsafe csoundGetInputBufferSize { id `CsoundPtr'} -> `Int'#} {#fun pure unsafe csoundGetOutputBufferSize { id `CsoundPtr'} -> `Int'#} -- *Input\/output functions -- **These functions return a MYFLT array. To marshall this to haskell, -- you need to first get the size of the array (using getInputBufferSize, -- getOutputBufferSize, or getKsmps), -- then the output can be marshalled with -- Foreign.Marshal.Array.peekArray -- There are some convience functions in Sound.Csound that do some of this. {#fun unsafe csoundGetInputBuffer as csoundGetInputBuffer' { id `CsoundPtr'} -> `Ptr CsndFlt' castPtr#} {#fun unsafe csoundGetOutputBuffer as csoundGetOutputBuffer' { id `CsoundPtr'} -> `Ptr CsndFlt' castPtr#} {#fun unsafe csoundGetSpin as csoundGetSpin' { id `CsoundPtr'} -> `Ptr CsndFlt' castPtr#} {#fun unsafe csoundGetSpout as csoundGetSpout' { id `CsoundPtr'} -> `Ptr CsndFlt' castPtr#} {#fun unsafe csoundGetOutputFileName { id `CsoundPtr'} -> `String'#} -- |Call between csoundPreCompile and csoundCompile to set Host Implemented IO {#fun unsafe csoundSetHostImplementedAudioIO { id `CsoundPtr', `Int', `Int' } -> `()'#} -- *Score handling functions. {#fun unsafe csoundGetScoreTime { id `CsoundPtr'} -> `CsndFlt' cFloatConv#} {#fun unsafe csoundIsScorePending { id `CsoundPtr'} -> `Int'#} {#fun unsafe csoundSetScorePending { id `CsoundPtr', `Int'} -> `()'#} {#fun unsafe csoundGetScoreOffsetSeconds { id `CsoundPtr'} -> `CsndFlt' cFloatConv#} {#fun unsafe csoundSetScoreOffsetSeconds { id `CsoundPtr', cFloatConv `CsndFlt' } -> `()'#} csoundRewindScore :: CsoundPtr -> IO () csoundRewindScore = {#call csoundRewindScore as csoundRewindScore_#} csoundSetCscoreCallback :: CsoundPtr -> FunPtr (CsoundPtr -> IO ()) -> IO () csoundSetCscoreCallback = {#call csoundSetCscoreCallback as csoundSetCscoreCallback_#} csoundScoreSort :: CsoundPtr -> FilePtr -> FilePtr -> CsoundMonad () csoundScoreSort csPtr inFile outFile = csoundStatusWrapper $ csoundScoreSort' csPtr inFile outFile {#fun csoundScoreSort as csoundScoreSort' { id `CsoundPtr', id `FilePtr', id `FilePtr' } -> `CsoundStatus' cIntToEnum#} csoundScoreExtract :: CsoundPtr -> FilePtr -> FilePtr -> FilePtr -> CsoundMonad () csoundScoreExtract csPtr inFile outFile extractFile = csoundStatusWrapper $ csoundScoreExtract' csPtr inFile outFile extractFile {#fun csoundScoreExtract as csoundScoreExtract' { id `CsoundPtr', id `FilePtr', id `FilePtr', id `FilePtr' } -> `CsoundStatus' cIntToEnum#} -- *Messages and Text {#fun pure unsafe csoundGetMessageLevel {id `CsoundPtr'} -> `Int'#} {#fun unsafe csoundSetMessageLevel { id `CsoundPtr', `Int' } -> `()'#} {#fun unsafe csoundInputMessage { id `CsoundPtr', `String' } -> `()'#} {#fun csoundKeyPress { id `CsoundPtr', castCharToCChar `Char' } -> `()'#} -- *Control and events -- these functions are used by the \'invalue\' and \'outvalue\' opcodes. -- **Callback types -- |Csound Instance, Channel name, Value read (in csound) from channel type InputValueCallback = FunPtr ( CsoundPtr -> CString -> Ptr CCsndFlt -> IO () ) -- |Csound instance, channel name, value to write (from csound) to channel type OutputValueCallback = FunPtr ( CsoundPtr -> CString -> CCsndFlt -> IO ()) -- **Set csound callbacks -- |called by 'invalue' opcode. csoundSetInputValueCallback :: CsoundPtr -> InputValueCallback -> IO () csoundSetInputValueCallback = {#call csoundSetInputValueCallback as csoundSetInputValueCallback_#} -- |called by 'outvalue' opcode. csoundSetOutputValueCallback :: CsoundPtr -> OutputValueCallback -> IO () csoundSetOutputValueCallback = {#call csoundSetOutputValueCallback as csoundSetOutputValueCallback_#} {#fun csoundScoreEvent { id `CsoundPtr', castCharToCChar `Char', withCsndFltArray* `[CsndFlt]', `Int' } -> `Int'#} -- *MIDI -- **MIDI callback function types -- |Csound instance, **UserData, Device name type ExternalMidiOpenCallback = FunPtr ( CsoundPtr -> Ptr (Ptr ()) -> CString -> IO CInt) -- |Csound instance, *UserData, Buffer, number of bytes type ExternalMidiReadCallback = FunPtr ( CsoundPtr -> Ptr () -> Ptr CUChar -> CInt -> IO CInt) type ExternalMidiWriteCallback = ExternalMidiReadCallback -- |Csound instance -> *UserData type ExternalMidiCloseCallback = FunPtr ( CsoundPtr -> Ptr () -> IO CInt) -- |MIDI error code -> string representation type ExternalMidiErrorStringCallback = FunPtr ( CInt -> IO CString) -- **Csound MIDI functions csoundSetExternalMidiInOpenCallback :: CsoundPtr -> ExternalMidiOpenCallback -> IO () csoundSetExternalMidiInOpenCallback = {#call csoundSetExternalMidiInOpenCallback as csoundSetExternalMidiInOpenCallback_#} csoundSetExternalMidiReadCallback :: CsoundPtr -> ExternalMidiReadCallback -> IO () csoundSetExternalMidiReadCallback = {#call csoundSetExternalMidiReadCallback as csoundSetExternalMidiReadCallback_#} csoundSetExternalMidiInCloseCallback :: CsoundPtr -> ExternalMidiCloseCallback -> IO () csoundSetExternalMidiInCloseCallback = {#call csoundSetExternalMidiInCloseCallback as csoundSetExternalMidiInCloseCallback_#} csoundSetExternalMidiOutOpenCallback :: CsoundPtr -> ExternalMidiOpenCallback -> IO () csoundSetExternalMidiOutOpenCallback = {#call csoundSetExternalMidiOutOpenCallback as csoundSetExternalMidiOutOpenCallback_#} csoundSetExternalMidiWriteCallback :: CsoundPtr -> ExternalMidiWriteCallback -> IO () csoundSetExternalMidiWriteCallback = {#call csoundSetExternalMidiWriteCallback as csoundSetExternalMidiWriteCallback_#} csoundSetExternalMidiOutCloseCallback :: CsoundPtr -> ExternalMidiCloseCallback -> IO () csoundSetExternalMidiOutCloseCallback = {#call csoundSetExternalMidiOutCloseCallback as csoundSetExternalMidiOutCloseCallback_#} csoundSetExternalMidiErrorStringCallback :: CsoundPtr -> ExternalMidiErrorStringCallback -> IO () csoundSetExternalMidiErrorStringCallback = {#call csoundSetExternalMidiErrorStringCallback as csoundSetExternalMidiErrorStringCallback_#} -- *Function table display -- **Callback function types -- |Ptr to a WINDAT struct. I haven't made a haskell representation of this. {#pointer *WINDAT as WinDatPtr#} type MakeGraphCallback = FunPtr (CsoundPtr -> WinDatPtr -> CString -> IO ()) type DrawGraphCallback = FunPtr (CsoundPtr -> WinDatPtr -> IO ()) type KillGraphCallback = FunPtr (CsoundPtr -> WinDatPtr -> IO ()) type MakeXYinCallback = FunPtr (CsoundPtr -> WinDatPtr -> CCsndFlt -> CCsndFlt -> IO ()) type ReadXYinCallback = FunPtr (CsoundPtr -> WinDatPtr -> IO ()) type KillXYinCallback = FunPtr (CsoundPtr -> WinDatPtr -> IO ()) type ExitGraphCallback = FunPtr (CsoundPtr -> IO CInt) -- **Csound functions {#fun csoundSetIsGraphable {id `CsoundPtr', `Int' } -> `Int'#} csoundSetMakeGraphCallback :: CsoundPtr -> MakeGraphCallback -> IO () csoundSetMakeGraphCallback = {#call csoundSetMakeGraphCallback as csoundSetMakeGraphCallback_#} csoundSetDrawGraphCallback :: CsoundPtr -> DrawGraphCallback -> IO () csoundSetDrawGraphCallback = {#call csoundSetDrawGraphCallback as csoundSetDrawGraphCallback_#} csoundSetKillGraphCallback :: CsoundPtr -> KillGraphCallback -> IO () csoundSetKillGraphCallback = {#call csoundSetKillGraphCallback as csoundSetKillGraphCallback_#} csoundSetMakeXYinCallback :: CsoundPtr -> MakeXYinCallback -> IO () csoundSetMakeXYinCallback = {#call csoundSetMakeXYinCallback as csoundSetMakeXYinCallback_#} csoundSetReadXYinCallback :: CsoundPtr -> ReadXYinCallback -> IO () csoundSetReadXYinCallback = {#call csoundSetReadXYinCallback as csoundSetReadXYinCallback_#} csoundSetKillXYinCallback :: CsoundPtr -> KillXYinCallback -> IO () csoundSetKillXYinCallback = {#call csoundSetKillXYinCallback as csoundSetKillXYinCallback_#} csoundSetExitGraphCallback :: CsoundPtr -> ExitGraphCallback -> IO () csoundSetExitGraphCallback = {#call csoundSetExitGraphCallback as csoundSetExitGraphCallback_#} -- *Csound opcodes -- **Opcode data types {#pointer *opcodeListEntry as OpcodeListEntryPtr -> OpcodeListEntry#} data OpcodeListEntry = OpcodeListEntry { opcodeName :: CString, -- ^Name of opcode ouTypes :: CString, -- ^Output types inTypes :: CString -- ^Input types } instance Storable (OpcodeListEntry) where alignment _ = 16 sizeOf _ = {#sizeof opcodeListEntry#} peek p = do nameV <- {#get opcodeListEntry.opname#} p otypesV <- {#get opcodeListEntry.outypes#} p itypesV <- {#get opcodeListEntry.intypes#} p return $ OpcodeListEntry nameV otypesV itypesV poke p li = do {#set opcodeListEntry.opname#} p $ opcodeName li {#set opcodeListEntry.outypes#} p $ ouTypes li {#set opcodeListEntry.intypes#} p $ inTypes li -- **opcode function types -- |Type for a callback function of a new csound opcode. type OpcodeFunction = FunPtr (CsoundPtr -> Ptr () -> IO CInt) -- **Csound opcode manipulation functions csoundNewOpcodeList :: CsoundPtr -> CsoundMonad (OpcodeListEntryPtr, [OpcodeListEntry]) csoundNewOpcodeList csptr = do (arrayLen, ptr) <- liftIO $ csoundNewOpcodeList' csptr case (arrayLen >= 0) of True -> do outAry <- liftIO $ peekArray arrayLen ptr return (ptr, outAry) False -> throwError $ show ((toEnum arrayLen) :: CsoundStatus) {#fun unsafe csoundNewOpcodeList as csoundNewOpcodeList' { id `CsoundPtr', alloca- `OpcodeListEntryPtr' peek* } -> `Int' #} csoundDisposeOpcodeList :: CsoundPtr -> OpcodeListEntryPtr -> IO () csoundDisposeOpcodeList = {#call unsafe csoundDisposeOpcodeList as csoundDisposeOpcodeList_#} csoundAppendOpcode :: CsoundPtr -- ^Pointer to csound instance -> String -- ^Name of opcode to append -> Int -- ^dsblksize -> Int -- ^thread id -> String -- ^outypes -> String -- ^intypes -> OpcodeFunction -- ^iopadr -> OpcodeFunction -- ^kopadr -> OpcodeFunction -- ^aopadr -> CsoundMonad () csoundAppendOpcode csPtr opName dsblksz thread outypes intypes iopadr kopadr aopadr = csoundStatusWrapper $ csoundAppendOpcode' csPtr opName dsblksz thread outypes intypes iopadr kopadr aopadr {#fun csoundAppendOpcode as csoundAppendOpcode' { id `CsoundPtr', `String', `Int', `Int', `String', `String', id `OpcodeFunction', id `OpcodeFunction', id `OpcodeFunction' } -> `CsoundStatus' cIntToEnum#} -- *Csound library functions. {#fun csoundOpenLibrary { alloca- `Ptr ()' peek*, `String' } -> `Int'#} {#fun csoundCloseLibrary { id `Ptr ()' } -> `Int'#} {#fun csoundGetLibrarySymbol { id `Ptr ()', `String' } -> `Ptr ()' id#} -- *Real-time Audio Play and Record -- **Real-time data types {#pointer *csRtAudioParams as CsRtAudioParamsPtr -> CsRtAudioParams#} {#pointer *RTCLOCK as RtClockPtr -> RtClock#} -- |Real-time audio parameters. -- The sampleFormat should actually be an enum, as defined in soundio.h. data CsRtAudioParams = CsRtAudioParams { devName :: CString, -- ^ Name of device devNum :: Int, -- ^ Device number bufSampSW :: Int, -- ^ Software buffer size in sample frames bufSampHW :: Int, -- ^ Hardware buffer size in sample frames nChannels :: Int, -- ^ Number of channels sampleFormat :: Int, -- ^ Sample format (AE_SHORT etc.) sampleRate :: Float -- ^ Sample rate in Hz } instance Storable (CsRtAudioParams) where --alignment _ = alignment (undefined :: CInt) -- I know there's a better value... alignment _ = 16 sizeOf _ = {#sizeof csRtAudioParams#} peek p = do dName <- {#get csRtAudioParams.devName#} p dNum <- liftM fromIntegral $ {#get csRtAudioParams.devNum#} p bufSampSw <- liftM fromIntegral $ {#get csRtAudioParams.bufSamp_SW#} p bufSampHw <- liftM fromIntegral $ {#get csRtAudioParams.bufSamp_HW#} p chns <- liftM fromIntegral $ {#get csRtAudioParams.nChannels#} p sf <- liftM fromIntegral $ {#get csRtAudioParams.sampleFormat#} p sr <- liftM (fromRational . toRational) $ {#get csRtAudioParams.sampleRate#} p return $ CsRtAudioParams dName dNum bufSampSw bufSampHw chns sf sr poke p params = do {#set csRtAudioParams.devName#} p $ devName params {#set csRtAudioParams.devNum#} p $ fromIntegral . devNum $ params {#set csRtAudioParams.bufSamp_SW#} p $ fromIntegral . bufSampSW $ params {#set csRtAudioParams.bufSamp_HW#} p $ fromIntegral . bufSampHW $ params {#set csRtAudioParams.nChannels#} p $ fromIntegral . nChannels $ params {#set csRtAudioParams.sampleFormat#} p $ fromIntegral . sampleFormat $ params {#set csRtAudioParams.sampleRate#} p $ fromRational . toRational . sampleRate $ params data RtClock = RtClock { startTimeReal :: IntLeast64T, startTimeCPU :: IntLeast64T } instance Storable (RtClock) where alignment _ = alignment (undefined ::CInt) sizeOf _ = {#sizeof RTCLOCK#} peek p = do real <- liftM fromIntegral $ {#get RTCLOCK.starttime_real#} p cpu <- liftM fromIntegral $ {#get RTCLOCK.starttime_CPU#} p return $ RtClock real cpu poke p rt = do {#set RTCLOCK.starttime_real#} p $ fromIntegral . startTimeReal $ rt {#set RTCLOCK.starttime_CPU#} p $ fromIntegral . startTimeCPU $ rt type YieldCallback = FunPtr (CsoundPtr -> IO CInt) type PlayopenCallback = FunPtr (CsoundPtr -> CsRtAudioParamsPtr -> IO CInt) type RtplayCallback = FunPtr (CsoundPtr -> Ptr CCsndFlt -> CInt -> IO ()) type RecopenCallback = FunPtr (CsoundPtr -> CsRtAudioParamsPtr -> IO CInt) type RtrecordCallback = FunPtr (CsoundPtr -> Ptr CCsndFlt -> CInt -> IO CInt) type RtcloseCallback = FunPtr (CsoundPtr -> IO ()) -- **wrappers to csound real-time audio functions. csoundSetYieldCallback :: CsoundPtr -> YieldCallback -> IO () csoundSetYieldCallback = {#call csoundSetYieldCallback as csoundSetYieldCallback_#} csoundSetPlayopenCallback :: CsoundPtr -> PlayopenCallback -> IO () csoundSetPlayopenCallback = {#call csoundSetPlayopenCallback as csoundSetPlayopenCallback_#} csoundSetRtplayCallback :: CsoundPtr -> RtplayCallback -> IO () csoundSetRtplayCallback = {#call csoundSetRtplayCallback as csoundSetRtplayCallback_#} csoundSetRecopenCallback :: CsoundPtr -> RecopenCallback -> IO () csoundSetRecopenCallback = {#call csoundSetRecopenCallback as csoundSetRecopenCallback_#} csoundSetRtrecordCallback :: CsoundPtr -> RtrecordCallback -> IO () csoundSetRtrecordCallback = {#call csoundSetRtrecordCallback as csoundSetRtrecordCallback_#} csoundSetRtcloseCallback :: CsoundPtr -> RtcloseCallback -> IO () csoundSetRtcloseCallback = {#call unsafe csoundSetRtcloseCallback as csoundSetRtcloseCallback_#} csoundGetRtRecordUserData :: CsoundPtr -> IO (Ptr (Ptr ())) csoundGetRtRecordUserData = {#call csoundGetRtRecordUserData as csoundGetRtRecordUserData_#} csoundGetRtPlayUserData :: CsoundPtr -> IO (Ptr (Ptr ())) csoundGetRtPlayUserData = {#call csoundGetRtPlayUserData as csoundGetRtPlayUserData_#} csoundRegisterSenseEventCallback :: CsoundPtr -> FunPtr ( CsoundPtr -> Ptr () -> IO () ) -> Ptr () -> CsoundMonad () csoundRegisterSenseEventCallback csPtr funPtr dataPtr = boolWrapper "RegisterSenseEventCallback failed." $ csoundRegisterSenseEventCallback' csPtr funPtr dataPtr {#fun csoundRegisterSenseEventCallback as csoundRegisterSenseEventCallback' { id `CsoundPtr', id `FunPtr (CsoundPtr -> Ptr () -> IO ())', id `Ptr ()' } -> `Bool' cIntToBoolSwitch#} {#fun pure unsafe csoundGetDebug { id `CsoundPtr' } -> `Bool' cIntToBool#} {#fun unsafe csoundSetDebug { id `CsoundPtr', cIntFromEnum `Bool' } -> `()'#} -- *Functions to set and retrieve information from csound function tables. csoundTableLength :: CsoundPtr -> Int -> CsoundMonad Int csoundTableLength csPtr tblNum = do tableLen <- liftIO $ csoundTableLength' csPtr tblNum case (tableLen > 0) of True -> return tableLen False -> throwError "Table not found." {#fun unsafe csoundTableLength as csoundTableLength' { id `CsoundPtr', `Int' } -> `Int'#} {#fun unsafe csoundTableGet { id `CsoundPtr', `Int', `Int' } -> `CsndFlt' cFloatConv#} {#fun unsafe csoundTableSet { id `CsoundPtr', `Int', `Int', cFloatConv `CsndFlt' } -> `()'#} csoundGetTable :: CsoundPtr -> Int -> CsoundMonad [CsndFlt] csoundGetTable csptr tableNum = do (arrayLen, ptr) <- liftIO $ csoundGetTable' csptr tableNum --Adding 1 to the length to account for the guard point. case arrayLen of Just val -> liftIO $ peekArray (val+1) ptr Nothing -> throwError $ "Table " ++ show tableNum ++ " not found." {#fun unsafe csoundGetTable as csoundGetTable' { id `CsoundPtr', alloca- `Ptr CsndFlt' peekCsndOutAry*, `Int' } -> `Maybe Int' maybeCInt#} -- *Csound threading -- **Threading data types -- |Signify if a function was able to acquire a mutex object. data AcquiredMutex = AcMutexYes | AcMutexNo deriving (Eq) -- **Csound threading functions -- |Determine if csoundLockMutexNoWait was successful mutexSuccessful :: CInt -> AcquiredMutex mutexSuccessful 0 = AcMutexYes mutexSuccessful _ = AcMutexNo csoundCreateThread :: FunPtr (Ptr () -> IO UIntPtrT) -> Ptr () -> IO (Ptr ()) csoundCreateThread = {#call csoundCreateThread as csoundCreateThread_#} csoundGetCurrentThreadId :: IO (Ptr ()) csoundGetCurrentThreadId = {#call csoundGetCurrentThreadId as csoundGetCurrentThreadId_#} csoundJoinThread :: Ptr () -> IO UIntPtrT csoundJoinThread = {#call csoundJoinThread as csoundJoinThread_#} csoundRunCommand :: [String] -> Bool -> CsoundMonad Int csoundRunCommand args noWait = do output <- liftIO $ csoundRunCommand' args noWait if (output < 0) then throwError $ show output else return output {#fun csoundRunCommand as csoundRunCommand' { withStringList* `[String]', cIntFromEnum `Bool' } -> `Int'#} csoundCreateThreadLock :: IO (Ptr ()) csoundCreateThreadLock = {#call csoundCreateThreadLock as csoundCreateThreadLock_#} {#fun csoundWaitThreadLock { id `Ptr ()' id, `Int' } -> `Bool' cIntToBool#} csoundWaitThreadLockNoTimeout :: Ptr () -> IO () csoundWaitThreadLockNoTimeout = {#call csoundWaitThreadLockNoTimeout as csoundWaitThreadLockNoTimeout_#} csoundNotifyThreadLock :: Ptr () -> IO () csoundNotifyThreadLock = {#call csoundNotifyThreadLock as csoundNotifyThreadLock_#} csoundDestroyThreadLock :: Ptr () -> IO () csoundDestroyThreadLock = {#call csoundDestroyThreadLock as csoundDestroyThreadLock_#} csoundCreateMutex :: CInt -> IO (Ptr ()) csoundCreateMutex = {#call csoundCreateMutex as csoundCreateMutex_#} csoundLockMutex :: Ptr () -> IO () csoundLockMutex = {#call csoundLockMutex as csoundLockMutex_#} {#fun csoundLockMutexNoWait {id `Ptr ()'}-> `AcquiredMutex' mutexSuccessful#} csoundUnlockMutex :: Ptr () -> IO () csoundUnlockMutex = {#call csoundUnlockMutex as csoundUnlockMutex_#} csoundDestroyMutex :: Ptr () -> IO () csoundDestroyMutex = {#call csoundDestroyMutex as csoundDestroyMutex_#} {#fun csoundCreateBarrier {`Int'} -> `Ptr ()' id #} {#fun csoundDestroyBarrier {id `Ptr ()'} -> `Int'#} {#fun csoundWaitBarrier {id `Ptr ()'} -> `Int'#} {#fun unsafe csoundSleep {`Int'} -> `()'#} -- *Functions to manipulate time\/locale csoundInitTimerStruct :: IO (RtClockPtr) csoundInitTimerStruct = do ptr <- malloc {#call unsafe csoundInitTimerStruct as csoundInitTimerStruct_#} ptr return ptr {#fun pure unsafe csoundGetRealTime { id `RtClockPtr'} -> `Double'#} {#fun pure unsafe csoundGetCPUTime {id `RtClockPtr'} -> `Double'#} {#fun unsafe csoundGetRandomSeedFromTime { } -> `UInt32T' cIntConv #} {#fun unsafe csoundSetLanguage { cIntFromEnum `CsLanguage' } -> `()'#} {#fun unsafe csoundLocalizeString {`String'} -> `String'#} -- *Csound global variable manipulations csoundCreateGlobalVariable :: CsoundPtr -> String -> Int -> CsoundMonad () csoundCreateGlobalVariable csPtr name sz = csoundStatusWrapper $ csoundCreateGlobalVariable' csPtr name sz {#fun unsafe csoundCreateGlobalVariable as csoundCreateGlobalVariable' { id `CsoundPtr', `String', `Int' } -> `CsoundStatus' cIntToEnum#} csoundQueryGlobalVariable :: CsoundPtr -> String -> CsoundMonad (Ptr ()) csoundQueryGlobalVariable csPtr name = do maybePtr <- liftIO $ csoundQueryGlobalVariable' csPtr name case maybePtr of Just val -> return val Nothing -> throwError $ "Global variable " ++ name ++ " not found." {#fun unsafe csoundQueryGlobalVariable as csoundQueryGlobalVariable' { id `CsoundPtr', `String' } -> `Maybe (Ptr ())' checkNullPtr#} -- |Even if the returned pointer is not null, it may not be a valid -- pointer if the name was invalid. {#fun unsafe csoundQueryGlobalVariableNoCheck as csoundQueryGlobalVariableNoCheck' { id `CsoundPtr', `String' } -> `Ptr ()' id#} csoundDestroyGlobalVariable :: CsoundPtr -> String -> CsoundMonad () csoundDestroyGlobalVariable csPtr name = csoundStatusWrapper $ csoundDestroyGlobalVariable' csPtr name {#fun unsafe csoundDestroyGlobalVariable as csoundDestroyGlobalVariable' { id `CsoundPtr', `String' } -> `CsoundStatus' cIntToEnum#} {#fun pure unsafe csoundGetSizeOfMYFLT {} -> `Int'#} -- *Csound utility functions csoundRunUtility :: CsoundPtr -> String -> String -> CsoundMonad () csoundRunUtility csPtr name args = boolWrapper errStr $ csoundRunUtility' csPtr name argv argc where errStr = "Attempt to run utility " ++ name ++ " failed." argc = words args argv = length argc {#fun csoundRunUtility as csoundRunUtility' { id `CsoundPtr', `String', `Int', withStringList* `[String]' } -> `Bool' cIntToBoolSwitch#} csoundListUtilities :: CsoundPtr -> CsoundMonad (Ptr CString, [String]) csoundListUtilities csPtr = liftIO $ unsafeCsoundListUtilities csPtr {#fun unsafe csoundListUtilities as unsafeCsoundListUtilities { id `CsoundPtr' } -> `(Ptr CString, [String])' peekStringArrayPtr*#} csoundDeleteUtilityList :: CsoundPtr -> Ptr (Ptr CChar) -> IO () csoundDeleteUtilityList = {#call unsafe csoundDeleteUtilityList as uCsoundDeleteUtilityList_#} {#fun pure unsafe csoundGetUtilityDescription { id `CsoundPtr', `String' } -> `String'#} -- *Csound channel functions -- **Channel data types {#pointer *CsoundChannelListEntry as CsoundChannelListEntryPtr -> CsoundChannelListEntry#} {#pointer CsoundChannelIOCallback_t as CsoundChannelIOCallbackT#} data CsoundChannelListEntry = CsoundChannelListEntry { cliName :: CString, -- ^Name of Csound channel cliType :: Int -- ^Type of Csound channel } -- Can't use the hooks for names with type in them :( instance Storable (CsoundChannelListEntry) where alignment _ = alignment (undefined :: CInt) sizeOf _ = {#sizeof CsoundChannelListEntry#} peek p = do cliname <- {#get CsoundChannelListEntry.name#} p cliTypeV <- liftM fromIntegral $ (\ptr -> do {peekByteOff ptr 4 ::IO CInt}) p return $ CsoundChannelListEntry cliname cliTypeV poke p cli = do {#set CsoundChannelListEntry.name#} p $ cliName cli (\ptr val -> do {pokeByteOff ptr 4 (val::CInt)}) p $ fromIntegral $ cliType cli -- |Type of a channel data CsoundChannelType = CsoundControlChannel | CsoundAudioChannel | CsoundStringChannel deriving (Eq, Show) instance Enum CsoundChannelType where fromEnum CsoundControlChannel = 1 fromEnum CsoundAudioChannel = 2 fromEnum CsoundStringChannel = 3 toEnum 1 = CsoundControlChannel toEnum 2 = CsoundAudioChannel toEnum 3 = CsoundStringChannel toEnum unmatched = error ("CsoundChannelType.toEnum: Cannot match " ++ show unmatched) -- |Direction of a channel data CsoundChannelDirection = CsoundInputChannel | CsoundOutputChannel | CsoundBiDirectionalChannel deriving (Eq, Show) instance Enum CsoundChannelDirection where fromEnum CsoundInputChannel = 16 fromEnum CsoundOutputChannel = 32 fromEnum CsoundBiDirectionalChannel = 48 toEnum 16 = CsoundInputChannel toEnum 32 = CsoundOutputChannel toEnum 48 = CsoundBiDirectionalChannel toEnum unmatched = error ("CsoundChannelDirection.toEnum: Cannot match " ++ show unmatched) -- |Specify both direction and type of a channel. data CsoundChannelDirectionalType = CsoundChannelDirectionalType CsoundChannelType CsoundChannelDirection deriving (Eq, Show) -- |Specify the type of a control channel. data CsoundControlChannelType = CsoundControlChannelClear | CsoundControlChannelInt | CsoundControlChannelLin | CsoundControlChannelExp deriving (Eq, Show) instance Enum CsoundControlChannelType where fromEnum CsoundControlChannelClear = 0 fromEnum CsoundControlChannelInt = 1 fromEnum CsoundControlChannelLin = 2 fromEnum CsoundControlChannelExp = 3 toEnum 0 = CsoundControlChannelClear toEnum 1 = CsoundControlChannelInt toEnum 2 = CsoundControlChannelLin toEnum 3 = CsoundControlChannelExp toEnum unmatched = error ("CsoundControlChannelType.toEnum: Cannot match " ++ show unmatched) -- |Status of ListChannels return value data CsoundListChannelStatus = NumChannels Int | ChanError CsoundStatus -- |Decode channel information decodeChannelInfo :: CInt -> (CsoundChannelType, CsoundChannelDirection) decodeChannelInfo val = (chanType, chanDir) where chanType = toEnum $ (.&.) 15 $ cIntConv val chanDir = case (testBit val 5, testBit val 6) of (True, False) -> CsoundInputChannel (False, True) -> CsoundOutputChannel (True, True) -> CsoundBiDirectionalChannel _ -> error "Invalid channel direction." toChannelListStatus :: CInt -> CsoundListChannelStatus toChannelListStatus val = case (val >= 0) of True -> NumChannels $ cIntConv val False -> ChanError $ cIntToEnum val csoundChannelDirectionalTypeToCInt :: CsoundChannelDirectionalType -> CInt csoundChannelDirectionalTypeToCInt (CsoundChannelDirectionalType typ dir) = fromIntegral $ (fromEnum typ) .|. (fromEnum dir) -- **Functions for the 'chan' family of opcodes csoundGetChannelPtr :: CsoundPtr -> String -> CsoundChannelDirectionalType -> CsoundMonad (Ptr CsndFlt) csoundGetChannelPtr csPtr name chantype = do res <- liftIO $ csoundGetChannelPtr' csPtr name chantype case res of (CsoundSuccess, myPtr) -> return myPtr (err, _) -> throwError $ "Error '" ++ show err ++ "' getting channel pointer " ++ name ++ "." {#fun unsafe csoundGetChannelPtr as csoundGetChannelPtr' { id `CsoundPtr', alloca- `Ptr CsndFlt' peekCsndOutAry*, `String', csoundChannelDirectionalTypeToCInt `CsoundChannelDirectionalType' } -> `CsoundStatus' cIntToEnum#} csoundListChannels :: CsoundPtr -> CsoundMonad (CsoundChannelListEntryPtr, [CsoundChannelListEntry]) csoundListChannels csPtr = do (arrayLen, ptr) <- liftIO $ csoundListChannels' csPtr case arrayLen of NumChannels 0 -> return (ptr, []) NumChannels nC -> do vals <- liftIO $ peekArray nC ptr return (ptr, vals) ChanError err -> throwError $ show err {#fun unsafe csoundListChannels as csoundListChannels' { id `CsoundPtr', alloca- `CsoundChannelListEntryPtr' peek* } -> `CsoundListChannelStatus' toChannelListStatus#} csoundDeleteChannelList :: CsoundPtr -> CsoundChannelListEntryPtr -> IO () csoundDeleteChannelList = {#call unsafe csoundDeleteChannelList as csoundDeleteChannelList_#} csoundSetControlChannelParams :: CsoundPtr -- ^Pointer to Csound instance. -> String -- ^Name of channel to write to -> CsoundControlChannelType -- ^Type of channel -> CsndFlt -- ^Default value for channel -> CsndFlt -- ^Minimum value for channel -> CsndFlt -- ^Maximum value for channel -> CsoundMonad () csoundSetControlChannelParams csPtr chanName chanType defVal minVal maxVal = csoundStatusWrapper $ csoundSetControlChannelParams' csPtr chanName chanType defVal minVal maxVal {#fun unsafe csoundSetControlChannelParams as csoundSetControlChannelParams' { id `CsoundPtr', `String', cIntFromEnum `CsoundControlChannelType', cFloatConv `CsndFlt', cFloatConv `CsndFlt', cFloatConv `CsndFlt' } -> `CsoundStatus' cIntToEnum#} -- |Query a control channel to get special parameters (as specified by -- csoundSetControlChannelParams). If the channel exists and the params -- are set, the type of the control channel, default, minimum and -- maximum are returned. If the control channel exists but no special params -- are defined, this function will have a value of Nothing. -- Otherwise the error code will be specified in CsoundMonad. csoundGetControlChannelParams :: CsoundPtr -- ^Pointer to this csound instance -> String -- ^Name of channel to query -> CsoundMonad (Maybe (CsoundControlChannelType, CsndFlt, CsndFlt, CsndFlt)) csoundGetControlChannelParams csPtr chanName = do (typ, d, mn, mx) <- liftIO $ csoundGetControlChannelParams' csPtr chanName case (typ < 0, toEnum typ) of (True, _) -> throwError $ "csoundGetControlChannelParams returned error " ++ show typ (False, CsoundControlChannelClear) -> return Nothing (False, realTyp) -> return $ Just (realTyp, d, mn, mx) {#fun unsafe csoundGetControlChannelParams as csoundGetControlChannelParams' { id `CsoundPtr', `String', alloca- `CsndFlt' peekCsndFlt*, alloca- `CsndFlt' peekCsndFlt*, alloca- `CsndFlt' peekCsndFlt* } -> `Int'#} csoundSetChannelIOCallback :: CsoundPtr -> CsoundChannelIOCallbackT -> IO () csoundSetChannelIOCallback = {#call csoundSetChannelIOCallback as csoundSetChannelIOCallback_#} -- **functions for the 'ichannel' family of opcodes csoundChanIKSet :: CsoundPtr -- ^Pointer to this csound instance -> CsndFlt -- ^Value to set -> Int -- ^Channel number to access. -> CsoundMonad () csoundChanIKSet csPtr val chan = csoundStatusWrapper $ csoundChanIKSet' csPtr val chan {#fun unsafe csoundChanIKSet as csoundChanIKSet' { id `CsoundPtr', cFloatConv `CsndFlt', `Int' } -> `CsoundStatus' cIntToEnum#} csoundChanOKGet :: CsoundPtr -- ^Pointer to this csound instance -> Int -- ^Index of channel -> CsoundMonad CsndFlt -- ^current value of the channel csoundChanOKGet csPtr chan = csoundStatValWrapper $ csoundChanOKGet' csPtr chan {#fun unsafe csoundChanOKGet as csoundChanOKGet' { id `CsoundPtr', alloca- `CsndFlt' peekCsndFlt*, `Int' } -> `CsoundStatus' cIntToEnum#} csoundChanIASet :: CsoundPtr -- ^Pointer to this csound instance. -> [CsndFlt] -- ^Array of value (of length ksmps) to write to a channel -> Int -- ^Index of channel -> CsoundMonad () csoundChanIASet csPtr ary chan = csoundStatusWrapper $ csoundChanIASet' csPtr ary chan {#fun unsafe csoundChanIASet as csoundChanIASet' { id `CsoundPtr', withCsndFltArray* `[CsndFlt]', `Int' } -> `CsoundStatus' cIntToEnum#} -- |TODO: Possible bug- it's likely that a buffer ksmps long will need to be -- allocated, instead of -- the single pointer actually allocated within unsafeCsoundChanOAGet csoundChanOAGet :: CsoundPtr -- ^Pointer to this csound instance. -> Int -- ^Length of audio array (ksmps) -> Int -- ^Index of channel -> CsoundMonad [CsndFlt] csoundChanOAGet csPtr len chan = do (stat, ptr) <- liftIO $ unsafeCsoundChanOAGet csPtr chan case (stat) of CsoundSuccess -> liftIO $ fmap (map cFloatConv) $ peekArray len ptr err -> throwError $ show err {#fun unsafe csoundChanOAGet as unsafeCsoundChanOAGet { id `CsoundPtr', alloca- `Ptr CCsndFlt' id, `Int' } -> `CsoundStatus' cIntToEnum#} -- **Functions for PvsIn and PvsOut csoundPvsinSet :: CsoundPtr -- ^Pointer to this csound instance. -> PvsDatExt -- ^PvsDatExt object to send -> Int -- ^Index of channel -> CsoundMonad () csoundPvsinSet csPtr pvs chan = csoundStatusWrapper $ unsafeCsoundPvsinSet csPtr pvs chan {#fun unsafe csoundPvsinSet as unsafeCsoundPvsinSet { id `CsoundPtr', withObject* `PvsDatExt', `Int' } -> `CsoundStatus' cIntToEnum#} csoundPvsoutGet :: CsoundPtr -- ^Pointer to this csound instance -> Int -- ^Index of channel -> CsoundMonad PvsDatExt csoundPvsoutGet csPtr chan = csoundStatValWrapper $ unsafeCsoundPvsoutGet csPtr chan {#fun unsafe csoundPvsoutGet as unsafeCsoundPvsoutGet { id `CsoundPtr', alloca- `PvsDatExt' peek*, `Int' } -> `CsoundStatus' cIntToEnum#} -- *Csound randomization functions. -- **Randomization state data types -- |This uses some pointer magic, there's a good chance that there -- are bugs in the Storable instance. data CsoundRandMtState = CsoundRandMtState { mti :: Int, mt :: [UInt32T] } instance Storable (CsoundRandMtState) where alignment _ = alignment (undefined :: CInt) sizeOf _ = {#sizeof CsoundRandMTState#} peek p = do mtiV <- liftM fromIntegral $ {#get CsoundRandMTState.mti#} p aryPtr <- {#get CsoundRandMTState.mt#} p mtV <- peekArray 624 aryPtr return $ CsoundRandMtState mtiV mtV poke p mtstate = do {#set CsoundRandMTState.mti#} p $ fromIntegral . mti $ mtstate let aryPtr = plusPtr p $ sizeOf (1 :: CInt) pokeArray aryPtr $ mt mtstate -- **Csound functions {#fun pure unsafe csoundRand31 { `Int' } -> `Int'#} {- * Initialise Mersenne Twister (MT19937) random number generator, * using 'keyLength' unsigned 32 bit values from 'initKey' as seed. * If the array is NULL, the length parameter is used for seeding. */ PUBLIC void csoundSeedRandMT(CsoundRandMTState *p, const uint32_t *initKey, uint32_t keyLength); /** * Returns next random number from MT19937 generator. * The PRNG must be initialised first by calling csoundSeedRandMT(). */ PUBLIC uint32_t csoundRandMT(CsoundRandMTState *p); -} -- *Csound generic callback functions type CsoundCallbackFunction = FunPtr (Ptr () -> Ptr () -> CUInt -> IO CInt) csoundSetCallback :: CsoundPtr -- ^Pointer to this csound instance. -> CsoundCallbackFunction -- ^Callback function -> Ptr () -- ^Pointer to "userdata" -> CsoundCallbackFunctionTypeMask -> CsoundMonad CsoundSetCallbackStatus csoundSetCallback csPtr fnPtr dataPtr typeMask = do res <- liftIO $ fmap cIntToSetCallbackStatus $ {#call csoundSetCallback as csoundSetCallback_#} csPtr fnPtr dataPtr $ cIntConv typeMask case res of SetCallbackOk -> return SetCallbackOk err -> throwError $ show err csoundRemoveCallback :: CsoundPtr -> CsoundCallbackFunction -> IO () csoundRemoveCallback = {#call csoundRemoveCallback as csoundRemoveCallback_#} -- *Csound messaging functions csoundEnableMessageBuffer :: CsoundPtr -> Int -> IO () csoundEnableMessageBuffer csPtr toStdOut = {#call csoundEnableMessageBuffer as csoundEnableMessageBuffer_#} csPtr $ cIntConv toStdOut {#fun csoundGetFirstMessage { id `CsoundPtr'} -> `String'#} csoundGetFirstMessageAttr :: CsoundPtr -> IO Int csoundGetFirstMessageAttr csPtr = liftM cIntConv $ {#call csoundGetFirstMessageAttr as csoundGetFirstMessageAttr_#} csPtr csoundPopFirstMessage :: CsoundPtr -> IO () csoundPopFirstMessage = {#call csoundPopFirstMessage as csoundPopFirstMessage_#} csoundGetMessageCnt :: CsoundPtr -> Int csoundGetMessageCnt csPtr = cIntConv $ {#call pure unsafe csoundGetMessageCnt as csoundGetMessageCnt_#} csPtr csoundDestroyMessageBuffer :: CsoundPtr -> IO () csoundDestroyMessageBuffer csPtr = {#call csoundDestroyMessageBuffer as csoundDestroyMessageBuffer_#} csPtr -- |Not doing sigcpy now, it looks like a utility function and I don't know -- if I'll need it. #if !defined(SWIG) type CsoundFileOpenCallback = FunPtr (CsoundPtr -> CString -> CInt -> CInt -> CInt -> IO ()) csoundSetFileOpenCallback :: CsoundPtr -> CsoundFileOpenCallback -> IO () csoundSetFileOpenCallback csPtr funPtr = {#call unsafe csoundSetFileOpenCallback as csoundSetFileOpenCallback_#} csPtr funPtr #endif