hCsound-0.2.2: src/Sound/Csound/Interface.chs
{-# 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 <csound.h>
-- **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