libcm is a C development framework with an emphasis on audio signal processing applications.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

cmAudioSys.h 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. //( { file_desc: "This is the kernel of a real-time audio processing engine." kw:[audio rt] }
  2. //
  3. // The audio system is composed a collection of independent sub-systems.
  4. // Each sub-system maintains a thread which runs asynchrounsly
  5. // from the application, the MIDI devices, and the audio devices.
  6. // To faciliate communication between these components each sub-system maintains
  7. // two thread-safe data buffers one for control information and a second
  8. // for audio data.
  9. //
  10. // The audio devices are the primary driver for the system.
  11. // Callbacks from the audio devices (See #cmApCallbackPtr_t)
  12. // inserts incoming audio samples into the audio
  13. // record buffers and extracts samples from the playback buffer.
  14. // When sufficient incoming samples and outgoing empty buffer space exists
  15. // a sub-system thread is waken up by the callback. This triggers a DSP audio
  16. // processing cycle which empties/fills the audio buffers. During a DSP
  17. // processing cycle control messages from the application and MIDI are blocked and
  18. // buffered. Upon completetion of the DSP cycle a control message
  19. // transfer cycles occurs - buffered incoming messages are passed to
  20. // the DSP system and messages originating in the DSP system are
  21. // buffered by the audio system for later pickup by the application
  22. // or MIDI system.
  23. //
  24. // Note that control messages that arrive when the DSP cycle is not
  25. // occurring can pass directly through to the DSP system.
  26. //
  27. // The DSP system sends messages back to the host by calling
  28. // cmAsDspToHostFunc_t provided by cmAudioSysCtx_t. These
  29. // calls are always made from within an audio system call to
  30. // audio or control update within cmAsCallback_t. cmAsDspToHostFunc_t
  31. // simply stores the message in a message buffer. The host picks
  32. // up the message at some later time when it notices that messages
  33. // are waiting via polling cmAudioSysIsMsgWaiting().
  34. //
  35. // Implementation: \n
  36. // The audio sub-systems work by maintaining an internal thread
  37. // which blocks on a mutex condition variable.
  38. // While the thread is blocked the mutex is unlocked allowing messages
  39. // to pass directly through to the DSP procedure via cmAsCallback().
  40. //
  41. // Periodic calls from running audio devices update the audio buffer.
  42. // When the audio buffer has input samples waiting and output space
  43. // available the condition variable is signaled, the mutex is
  44. // then automatically locked by the system, and the DSP execution
  45. // procedure is called via cmAsCallback().
  46. //
  47. // Messages arriving while the mutex is locked are queued and
  48. // delivered to the DSP procedure at the end of the DSP execution
  49. // procedure.
  50. //
  51. //)
  52. #ifndef cmAudioSys_h
  53. #define cmAudioSys_h
  54. #ifdef __cplusplus
  55. extern "C" {
  56. #endif
  57. //(
  58. // Audio system result codes
  59. enum
  60. {
  61. kOkAsRC = cmOkRC,
  62. kThreadErrAsRC,
  63. kMutexErrAsRC,
  64. kTsQueueErrAsRC,
  65. kMsgEnqueueFailAsRC,
  66. kAudioDevSetupErrAsRC,
  67. kAudioBufSetupErrAsRC,
  68. kAudioDevStartFailAsRC,
  69. kAudioDevStopFailAsRC,
  70. kBufTooSmallAsRC,
  71. kNoMsgWaitingAsRC,
  72. kMidiSysFailAsRC,
  73. kSerialPortFailAsRC,
  74. kMsgSerializeFailAsRC,
  75. kStateBufFailAsRC,
  76. kInvalidArgAsRC,
  77. kNotInitAsRC
  78. };
  79. enum
  80. {
  81. kAsDfltMsgQueueByteCnt = 0xffff,
  82. kAsDfltDevFramesPerCycle = 512,
  83. kAsDfltDspFramesPerCycle = 64,
  84. kAsDfltBufCnt = 3,
  85. kAsDfltSrate = 44100,
  86. kAsDfltSyncToInputFl = 1,
  87. kAsDfltMinMeterMs = 10,
  88. kAsDfltMeterMs = 50,
  89. kAsDfltMaxMeterMs = 1000
  90. };
  91. typedef cmHandle_t cmAudioSysH_t; //< Audio system handle type
  92. typedef unsigned cmAsRC_t; //< Audio system result code
  93. struct cmAudioSysCtx_str;
  94. //
  95. // DSP system callback function.
  96. //
  97. // This is the sole point of entry into the DSP system while the audio system is running.
  98. //
  99. // ctxPtr is pointer to a cmAudioSysCtx_t record.
  100. //
  101. // This function is called under two circumstances:
  102. //
  103. // 1) To notify the DSP system that the audio input/output buffers need to be serviced.
  104. // This is a perioidic request which the DSP system uses as its execution trigger.
  105. // cmAudioSysCtx_t.audioRateFl is set to true to indicate this type of callback.
  106. //
  107. // 2) To pass messages from the host application to the DSP system.
  108. // The DSP system is asyncronous with the host because it executes in the
  109. // audio system thread rather than the host thread. The cmAudioSysDeliverMsg()
  110. // function synchronizes incoming messages with the internal audio system
  111. // thread to prevent thread collisions.
  112. //
  113. // Notes:
  114. // This callback is always made with the internal audio system mutex locked.
  115. //
  116. // The signal time covered by the callback is from
  117. // ctx->begSmpIdx to ctx->begSmpIdx+cfg->dspFramesPerCycle.
  118. //
  119. // The return value is currently not used.
  120. typedef cmRC_t (*cmAsCallback_t)(void* ctxPtr, unsigned msgByteCnt, const void* msgDataPtr );
  121. // Audio device sub-sytem configuration record
  122. typedef struct cmAudioSysArgs_str
  123. {
  124. cmRpt_t* rpt; // system console object
  125. unsigned inDevIdx; // input audio device
  126. unsigned outDevIdx; // output audio device
  127. bool syncInputFl; // true/false sync the DSP update callbacks with audio input/output
  128. unsigned msgQueueByteCnt; // Size of the internal msg queue used to buffer msgs arriving via cmAudioSysDeliverMsg().
  129. unsigned devFramesPerCycle; // (512) Audio device samples per channel per device update buffer.
  130. unsigned dspFramesPerCycle; // (64) Audio samples per channel per DSP cycle.
  131. unsigned audioBufCnt; // (3) Audio device buffers.
  132. double srate; // Audio sample rate.
  133. int srateMult; // Sample rate multiplication factor (negative for divide)
  134. } cmAudioSysArgs_t;
  135. // Audio sub-system configuration record.
  136. // This record is provided by the host to configure the audio system
  137. // via cmAudioSystemAllocate() or cmAudioSystemInitialize().
  138. typedef struct cmAudioSysSubSys_str
  139. {
  140. cmAudioSysArgs_t args; // Audio device configuration
  141. cmAsCallback_t cbFunc; // DSP system entry point function.
  142. void* cbDataPtr; // Host provided data for the DSP system callback.
  143. } cmAudioSysSubSys_t;
  144. // Signature of a callback function provided by the audio system to receive messages
  145. // from the DSP system for later dispatch to the host application.
  146. // This declaration is used by the DSP system implementation and the audio system.
  147. // Note that this function is intended to convey one message broken into multiple parts.
  148. // See cmTsQueueEnqueueSegMsg() for the equivalent interface.
  149. typedef cmAsRC_t (*cmAsDspToHostFunc_t)(struct cmAudioSysCtx_str* p, const void* msgDataPtrArray[], unsigned msgByteCntArray[], unsigned msgSegCnt);
  150. // Record passed with each call to the DSP callback function cmAsCallback_t
  151. typedef struct cmAudioSysCtx_str
  152. {
  153. void* reserved; // used internally by the audio system
  154. bool audioRateFl; // true if this is an audio update callback
  155. unsigned srcNetNodeId; // Source net node if this is a msg callback originating from a remote network node.
  156. unsigned asSubIdx; // index of the sub-system this DSP process is serving
  157. cmAudioSysSubSys_t* ss; // ptr to a copy of the cfg recd used to initialize the audio system
  158. unsigned begSmpIdx; // gives signal time as a sample count
  159. cmAsDspToHostFunc_t dspToHostFunc; // Callback used by the DSP process to send messages to the host
  160. // via the audio system. Returns a cmAsRC_t result code.
  161. // output (playback) buffers
  162. cmSample_t** oChArray; // each ele is a ptr to buffer with cfg.dspFramesPerCycle samples
  163. unsigned oChCnt; // count of output channels (ele's in oChArray[])
  164. cmTimeSpec_t oTimeStamp;
  165. // input (recording) buffers
  166. cmSample_t** iChArray; // each ele is a ptr to buffer with cfg.dspFramesPerCycle samples
  167. unsigned iChCnt; // count of input channels (ele's in iChArray[])
  168. cmTimeSpec_t iTimeStamp;
  169. } cmAudioSysCtx_t;
  170. // Audio system configuration record used by cmAudioSysAllocate().
  171. typedef struct cmAudioSysCfg_str
  172. {
  173. cmAudioSysSubSys_t* ssArray; // sub-system cfg record array
  174. unsigned ssCnt; // count of sub-systems
  175. unsigned meterMs; // Meter sample period in milliseconds
  176. void* clientCbData; // User arg. for clientCbFunc().
  177. cmTsQueueCb_t clientCbFunc; // Called by cmAudioSysReceiveMsg() to deliver internally generated msg's to the host.
  178. // Set to NULL if msg's will be directly returned by buffers passed to cmAudioSysReceiveMsg().
  179. cmUdpNetH_t netH;
  180. cmSeH_t serialPortH;
  181. } cmAudioSysCfg_t;
  182. extern cmAudioSysH_t cmAudioSysNullHandle;
  183. // Allocate and initialize an audio system as a collection of 'cfgCnt' sub-systems.
  184. // Prior to call this function the audio audio ports system must be initalized
  185. // (via cmApInitialize()) and the MIDI port system must be initialized
  186. // (via cmMpInitialize()). Note also that cmApFinalize() and cmMpFinalize()
  187. // cannot be called prior to cmAudioSysFree().
  188. // See cmAudioSystemTest() for a complete example.
  189. cmAsRC_t cmAudioSysAllocate( cmAudioSysH_t* hp, cmRpt_t* rpt, const cmAudioSysCfg_t* cfg );
  190. // Finalize and release any resources held by the audio system.
  191. cmAsRC_t cmAudioSysFree( cmAudioSysH_t* hp );
  192. // Returns true if 'h' is a handle which was successfully allocated by
  193. // cmAudioSysAllocate().
  194. bool cmAudioSysHandleIsValid( cmAudioSysH_t h );
  195. // Reinitialize a previously allocated audio system. This function
  196. // begins with a call to cmAudioSysFinalize().
  197. // Use cmAudioSysEnable(h,true) to begin processing audio following this call.
  198. cmAsRC_t cmAudioSysInitialize( cmAudioSysH_t h, const cmAudioSysCfg_t* cfg );
  199. // Complements cmAudioSysInitialize(). In general there is no need to call this function
  200. // since calls to cmAudioSysInitialize() and cmAudioSysFree() automaticatically call it.
  201. cmAsRC_t cmAudioSysFinalize( cmAudioSysH_t h );
  202. // Returns true if the audio system has been successfully initialized.
  203. bool cmAudioSysIsInitialized( cmAudioSysH_t );
  204. // Returns true if the audio system is enabled.
  205. bool cmAudioSysIsEnabled( cmAudioSysH_t h );
  206. // Enable/disable the audio system. Enabling the starts audio stream
  207. // in/out of the system.
  208. cmAsRC_t cmAudioSysEnable( cmAudioSysH_t h, bool enableFl );
  209. //
  210. // Host to DSP delivery functions
  211. //
  212. // Deliver a message from the host application to the DSP process. (host -> DSP);
  213. // The message is formed as a concatenation of the bytes in each of the segments
  214. // pointed to by 'msgDataPtrArrary[segCnt][msgByteCntArray[segCnt]'.
  215. // This is the canonical msg delivery function in so far as the other host->DSP
  216. // msg delivery function are written in terms of this function.
  217. // The first 4 bytes in the first segment must contain the index of the audio sub-system
  218. // which is to receive the message.
  219. cmAsRC_t cmAudioSysDeliverSegMsg( cmAudioSysH_t h, const void* msgDataPtrArray[], unsigned msgByteCntArray[], unsigned msgSegCnt, unsigned srcNetNodeId );
  220. // Deliver a single message from the host to the DSP system.
  221. cmAsRC_t cmAudioSysDeliverMsg( cmAudioSysH_t h, const void* msgPtr, unsigned msgByteCnt, unsigned srcNetNodeId );
  222. // Deliver a single message from the host to the DSP system.
  223. // Prior to delivery the 'id' is prepended to the message.
  224. cmAsRC_t cmAudioSysDeliverIdMsg( cmAudioSysH_t h, unsigned asSubIdx, unsigned id, const void* msgPtr, unsigned msgByteCnt, unsigned srcNetNodeId );
  225. //
  226. // DSP to Host message functions
  227. //
  228. // Is a msg from the DSP waiting to be picked up by the host? (host <- DSP)
  229. // 0 = no msgs are waiting or the msg queue is locked by the DSP process.
  230. // >0 = the size of the buffer required to hold the next msg returned via
  231. // cmAudioSysReceiveMsg().
  232. unsigned cmAudioSysIsMsgWaiting( cmAudioSysH_t h );
  233. // Copy the next available msg sent from the DSP process to the host into the host supplied msg buffer
  234. // pointed to by 'msgBufPtr'. Set 'msgDataPtr' to NULL to receive msg by callback from cmAudioSysCfg_t.clientCbFunc.
  235. // Returns kBufTooSmallAsRC if msgDataPtr[msgByteCnt] is too small to hold the msg.
  236. // Returns kNoMsgWaitingAsRC if no messages are waiting for delivery or the msg queue is locked by the DSP process.
  237. // Returns kOkAsRC if a msg was delivered.
  238. // Call cmAudioSysIsMsgWaiting() prior to calling this function to get
  239. // the size of the data buffer required to hold the next message.
  240. cmAsRC_t cmAudioSysReceiveMsg( cmAudioSysH_t h, void* msgDataPtr, unsigned msgByteCnt );
  241. // Fill an audio system status record.
  242. void cmAudioSysStatus( cmAudioSysH_t h, unsigned asSubIdx, cmAudioSysStatus_t* statusPtr );
  243. // Enable cmAudioSysStatus_t notifications to be sent periodically to the host.
  244. // Set asSubIdx to cmInvalidIdx to enable/disable all sub-systems.
  245. // The notifications occur approximately every cmAudioSysCfg_t.meterMs milliseconds.
  246. void cmAudioSysStatusNotifyEnable( cmAudioSysH_t, unsigned asSubIdx, bool enableFl );
  247. // Return a pointer the context record associated with a sub-system
  248. cmAudioSysCtx_t* cmAudioSysContext( cmAudioSysH_t h, unsigned asSubIdx );
  249. // Return the count of audio sub-systems.
  250. // This is the same as the count of cfg recds passed to cmAudioSystemInitialize().
  251. unsigned cmAudioSysSubSystemCount( cmAudioSysH_t h );
  252. // Audio system test and example function.
  253. void cmAudioSysTest( cmRpt_t* rpt, int argc, const char* argv[] );
  254. //)
  255. #ifdef __cplusplus
  256. }
  257. #endif
  258. #endif