libcm is a C development framework with an emphasis on audio signal processing applications.
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  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. kMsgSerializeFailAsRC,
  74. kStateBufFailAsRC,
  75. kInvalidArgAsRC,
  76. kNotInitAsRC
  77. };
  78. enum
  79. {
  80. kAsDfltMsgQueueByteCnt = 0xffff,
  81. kAsDfltDevFramesPerCycle = 512,
  82. kAsDfltDspFramesPerCycle = 64,
  83. kAsDfltBufCnt = 3,
  84. kAsDfltSrate = 44100,
  85. kAsDfltSyncToInputFl = 1,
  86. kAsDfltMinMeterMs = 10,
  87. kAsDfltMeterMs = 50,
  88. kAsDfltMaxMeterMs = 1000
  89. };
  90. typedef cmHandle_t cmAudioSysH_t; //< Audio system handle type
  91. typedef unsigned cmAsRC_t; //< Audio system result code
  92. struct cmAudioSysCtx_str;
  93. //
  94. // DSP system callback function.
  95. //
  96. // This is the sole point of entry into the DSP system while the audio system is running.
  97. //
  98. // ctxPtr is pointer to a cmAudioSysCtx_t record.
  99. //
  100. // This function is called under two circumstances:
  101. //
  102. // 1) To notify the DSP system that the audio input/output buffers need to be serviced.
  103. // This is a perioidic request which the DSP system uses as its execution trigger.
  104. // cmAudioSysCtx_t.audioRateFl is set to true to indicate this type of callback.
  105. //
  106. // 2) To pass messages from the host application to the DSP system.
  107. // The DSP system is asyncronous with the host because it executes in the
  108. // audio system thread rather than the host thread. The cmAudioSysDeliverMsg()
  109. // function synchronizes incoming messages with the internal audio system
  110. // thread to prevent thread collisions.
  111. //
  112. // Notes:
  113. // This callback is always made with the internal audio system mutex locked.
  114. //
  115. // The signal time covered by the callback is from
  116. // ctx->begSmpIdx to ctx->begSmpIdx+cfg->dspFramesPerCycle.
  117. //
  118. // The return value is currently not used.
  119. typedef cmRC_t (*cmAsCallback_t)(void* ctxPtr, unsigned msgByteCnt, const void* msgDataPtr );
  120. // Audio device sub-sytem configuration record
  121. typedef struct cmAudioSysArgs_str
  122. {
  123. cmRpt_t* rpt; // system console object
  124. unsigned inDevIdx; // input audio device
  125. unsigned outDevIdx; // output audio device
  126. bool syncInputFl; // true/false sync the DSP update callbacks with audio input/output
  127. unsigned msgQueueByteCnt; // Size of the internal msg queue used to buffer msgs arriving via cmAudioSysDeliverMsg().
  128. unsigned devFramesPerCycle; // (512) Audio device samples per channel per device update buffer.
  129. unsigned dspFramesPerCycle; // (64) Audio samples per channel per DSP cycle.
  130. unsigned audioBufCnt; // (3) Audio device buffers.
  131. double srate; // Audio sample rate.
  132. } cmAudioSysArgs_t;
  133. // Audio sub-system configuration record.
  134. // This record is provided by the host to configure the audio system
  135. // via cmAudioSystemAllocate() or cmAudioSystemInitialize().
  136. typedef struct cmAudioSysSubSys_str
  137. {
  138. cmAudioSysArgs_t args; // Audio device configuration
  139. cmAsCallback_t cbFunc; // DSP system entry point function.
  140. void* cbDataPtr; // Host provided data for the DSP system callback.
  141. } cmAudioSysSubSys_t;
  142. // Signature of a callback function provided by the audio system to receive messages
  143. // from the DSP system for later dispatch to the host application.
  144. // This declaration is used by the DSP system implementation and the audio system.
  145. // Note that this function is intended to convey one message broken into multiple parts.
  146. // See cmTsQueueEnqueueSegMsg() for the equivalent interface.
  147. typedef cmAsRC_t (*cmAsDspToHostFunc_t)(struct cmAudioSysCtx_str* p, const void* msgDataPtrArray[], unsigned msgByteCntArray[], unsigned msgSegCnt);
  148. // Record passed with each call to the DSP callback function cmAsCallback_t
  149. typedef struct cmAudioSysCtx_str
  150. {
  151. void* reserved; // used internally by the audio system
  152. bool audioRateFl; // true if this is an audio update callback
  153. unsigned srcNetNodeId; // Source net node if this is a msg callback originating from a remote network node.
  154. unsigned asSubIdx; // index of the sub-system this DSP process is serving
  155. cmAudioSysSubSys_t* ss; // ptr to a copy of the cfg recd used to initialize the audio system
  156. unsigned begSmpIdx; // gives signal time as a sample count
  157. cmAsDspToHostFunc_t dspToHostFunc; // Callback used by the DSP process to send messages to the host
  158. // via the audio system. Returns a cmAsRC_t result code.
  159. // output (playback) buffers
  160. cmSample_t** oChArray; // each ele is a ptr to buffer with cfg.dspFramesPerCycle samples
  161. unsigned oChCnt; // count of output channels (ele's in oChArray[])
  162. cmTimeSpec_t oTimeStamp;
  163. // input (recording) buffers
  164. cmSample_t** iChArray; // each ele is a ptr to buffer with cfg.dspFramesPerCycle samples
  165. unsigned iChCnt; // count of input channels (ele's in iChArray[])
  166. cmTimeSpec_t iTimeStamp;
  167. } cmAudioSysCtx_t;
  168. // Audio system configuration record used by cmAudioSysAllocate().
  169. typedef struct cmAudioSysCfg_str
  170. {
  171. cmAudioSysSubSys_t* ssArray; // sub-system cfg record array
  172. unsigned ssCnt; // count of sub-systems
  173. unsigned meterMs; // Meter sample period in milliseconds
  174. void* clientCbData; // User arg. for clientCbFunc().
  175. cmTsQueueCb_t clientCbFunc; // Called by cmAudioSysReceiveMsg() to deliver internally generated msg's to the host.
  176. // Set to NULL if msg's will be directly returned by buffers passed to cmAudioSysReceiveMsg().
  177. cmUdpNetH_t netH;
  178. } cmAudioSysCfg_t;
  179. extern cmAudioSysH_t cmAudioSysNullHandle;
  180. // Allocate and initialize an audio system as a collection of 'cfgCnt' sub-systems.
  181. // Prior to call this function the audio audio ports system must be initalized
  182. // (via cmApInitialize()) and the MIDI port system must be initialized
  183. // (via cmMpInitialize()). Note also that cmApFinalize() and cmMpFinalize()
  184. // cannot be called prior to cmAudioSysFree().
  185. // See cmAudioSystemTest() for a complete example.
  186. cmAsRC_t cmAudioSysAllocate( cmAudioSysH_t* hp, cmRpt_t* rpt, const cmAudioSysCfg_t* cfg );
  187. // Finalize and release any resources held by the audio system.
  188. cmAsRC_t cmAudioSysFree( cmAudioSysH_t* hp );
  189. // Returns true if 'h' is a handle which was successfully allocated by
  190. // cmAudioSysAllocate().
  191. bool cmAudioSysHandleIsValid( cmAudioSysH_t h );
  192. // Reinitialize a previously allocated audio system. This function
  193. // begins with a call to cmAudioSysFinalize().
  194. // Use cmAudioSysEnable(h,true) to begin processing audio following this call.
  195. cmAsRC_t cmAudioSysInitialize( cmAudioSysH_t h, const cmAudioSysCfg_t* cfg );
  196. // Complements cmAudioSysInitialize(). In general there is no need to call this function
  197. // since calls to cmAudioSysInitialize() and cmAudioSysFree() automaticatically call it.
  198. cmAsRC_t cmAudioSysFinalize( cmAudioSysH_t h );
  199. // Returns true if the audio system has been successfully initialized.
  200. bool cmAudioSysIsInitialized( cmAudioSysH_t );
  201. // Returns true if the audio system is enabled.
  202. bool cmAudioSysIsEnabled( cmAudioSysH_t h );
  203. // Enable/disable the audio system. Enabling the starts audio stream
  204. // in/out of the system.
  205. cmAsRC_t cmAudioSysEnable( cmAudioSysH_t h, bool enableFl );
  206. //
  207. // Host to DSP delivery functions
  208. //
  209. // Deliver a message from the host application to the DSP process. (host -> DSP);
  210. // The message is formed as a concatenation of the bytes in each of the segments
  211. // pointed to by 'msgDataPtrArrary[segCnt][msgByteCntArray[segCnt]'.
  212. // This is the canonical msg delivery function in so far as the other host->DSP
  213. // msg delivery function are written in terms of this function.
  214. // The first 4 bytes in the first segment must contain the index of the audio sub-system
  215. // which is to receive the message.
  216. cmAsRC_t cmAudioSysDeliverSegMsg( cmAudioSysH_t h, const void* msgDataPtrArray[], unsigned msgByteCntArray[], unsigned msgSegCnt, unsigned srcNetNodeId );
  217. // Deliver a single message from the host to the DSP system.
  218. cmAsRC_t cmAudioSysDeliverMsg( cmAudioSysH_t h, const void* msgPtr, unsigned msgByteCnt, unsigned srcNetNodeId );
  219. // Deliver a single message from the host to the DSP system.
  220. // Prior to delivery the 'id' is prepended to the message.
  221. cmAsRC_t cmAudioSysDeliverIdMsg( cmAudioSysH_t h, unsigned asSubIdx, unsigned id, const void* msgPtr, unsigned msgByteCnt, unsigned srcNetNodeId );
  222. //
  223. // DSP to Host message functions
  224. //
  225. // Is a msg from the DSP waiting to be picked up by the host? (host <- DSP)
  226. // 0 = no msgs are waiting or the msg queue is locked by the DSP process.
  227. // >0 = the size of the buffer required to hold the next msg returned via
  228. // cmAudioSysReceiveMsg().
  229. unsigned cmAudioSysIsMsgWaiting( cmAudioSysH_t h );
  230. // Copy the next available msg sent from the DSP process to the host into the host supplied msg buffer
  231. // pointed to by 'msgBufPtr'. Set 'msgDataPtr' to NULL to receive msg by callback from cmAudioSysCfg_t.clientCbFunc.
  232. // Returns kBufTooSmallAsRC if msgDataPtr[msgByteCnt] is too small to hold the msg.
  233. // Returns kNoMsgWaitingAsRC if no messages are waiting for delivery or the msg queue is locked by the DSP process.
  234. // Returns kOkAsRC if a msg was delivered.
  235. // Call cmAudioSysIsMsgWaiting() prior to calling this function to get
  236. // the size of the data buffer required to hold the next message.
  237. cmAsRC_t cmAudioSysReceiveMsg( cmAudioSysH_t h, void* msgDataPtr, unsigned msgByteCnt );
  238. // Fill an audio system status record.
  239. void cmAudioSysStatus( cmAudioSysH_t h, unsigned asSubIdx, cmAudioSysStatus_t* statusPtr );
  240. // Enable cmAudioSysStatus_t notifications to be sent periodically to the host.
  241. // Set asSubIdx to cmInvalidIdx to enable/disable all sub-systems.
  242. // The notifications occur approximately every cmAudioSysCfg_t.meterMs milliseconds.
  243. void cmAudioSysStatusNotifyEnable( cmAudioSysH_t, unsigned asSubIdx, bool enableFl );
  244. // Return a pointer the context record associated with a sub-system
  245. cmAudioSysCtx_t* cmAudioSysContext( cmAudioSysH_t h, unsigned asSubIdx );
  246. // Return the count of audio sub-systems.
  247. // This is the same as the count of cfg recds passed to cmAudioSystemInitialize().
  248. unsigned cmAudioSysSubSystemCount( cmAudioSysH_t h );
  249. // Audio system test and example function.
  250. void cmAudioSysTest( cmRpt_t* rpt, int argc, const char* argv[] );
  251. //)
  252. #ifdef __cplusplus
  253. }
  254. #endif
  255. #endif