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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. //| Copyright: (C) 2009-2020 Kevin Larke <contact AT larke DOT org>
  2. //| License: GNU GPL version 3.0 or above. See the accompanying LICENSE file.
  3. //( { file_desc:"Improved real-time audio processing engine." kw:[rtsys] }
  4. //
  5. // The audio system is composed a collection of independent sub-systems.
  6. // Each sub-system maintains a thread which runs asynchrounsly
  7. // from the application, the MIDI devices, and the audio devices.
  8. // To faciliate communication between these components each sub-system maintains
  9. // two thread-safe data buffers one for control information and a second
  10. // for audio data.
  11. //
  12. // The audio devices are the primary driver for the system.
  13. // Callbacks from the audio devices (See #cmApCallbackPtr_t)
  14. // inserts incoming audio samples into the audio
  15. // record buffers and extracts samples from the playback buffer.
  16. // When sufficient incoming samples and outgoing empty buffer space exists
  17. // a sub-system thread is waken up by the callback. This triggers a DSP audio
  18. // processing cycle which empties/fills the audio buffers. During a DSP
  19. // processing cycle control messages from the application and MIDI are blocked and
  20. // buffered. Upon completetion of the DSP cycle a control message
  21. // transfer cycles occurs - buffered incoming messages are passed to
  22. // the DSP system and messages originating in the DSP system are
  23. // buffered by the audio system for later pickup by the application
  24. // or MIDI system.
  25. //
  26. // Note that control messages that arrive when the DSP cycle is not
  27. // occurring can pass directly through to the DSP system.
  28. //
  29. // The DSP system sends messages back to the host by calling
  30. // cmRtDspToHostFunc_t provided by cmRtSysCtx_t. These
  31. // calls are always made from within an audio system call to
  32. // audio or control update within cmRtCallback_t. cmRtDspToHostFunc_t
  33. // simply stores the message in a message buffer. The host picks
  34. // up the message at some later time when it notices that messages
  35. // are waiting via polling cmRtSysIsMsgWaiting().
  36. //
  37. // Implementation: \n
  38. // The audio sub-systems work by maintaining an internal thread
  39. // which blocks on a mutex condition variable.
  40. // While the thread is blocked the mutex is unlocked allowing messages
  41. // to pass directly through to the DSP procedure via cmRtCallback().
  42. //
  43. // Periodic calls from running audio devices update the audio buffer.
  44. // When the audio buffer has input samples waiting and output space
  45. // available the condition variable is signaled, the mutex is
  46. // then automatically locked by the system, and the DSP execution
  47. // procedure is called via cmRtCallback().
  48. //
  49. // Messages arriving while the mutex is locked are queued and
  50. // delivered to the DSP procedure at the end of the DSP execution
  51. // procedure.
  52. //)
  53. #ifndef cmRtSys_h
  54. #define cmRtSys_h
  55. #ifdef __cplusplus
  56. extern "C" {
  57. #endif
  58. //(
  59. // Audio system result codes
  60. enum
  61. {
  62. kOkRtRC = cmOkRC,
  63. kThreadErrRtRC,
  64. kMutexErrRtRC,
  65. kTsQueueErrRtRC,
  66. kMsgEnqueueFailRtRC,
  67. kAudioDevSetupErrRtRC,
  68. kAudioBufSetupErrRtRC,
  69. kAudioDevStartFailRtRC,
  70. kAudioDevStopFailRtRC,
  71. kBufTooSmallRtRC,
  72. kNoMsgWaitingRtRC,
  73. kMidiSysFailRtRC,
  74. kMsgSerializeFailRtRC,
  75. kStateBufFailRtRC,
  76. kInvalidArgRtRC,
  77. kNotInitRtRC,
  78. kTimeOutErrRtRC,
  79. kNetErrRtRC
  80. };
  81. enum
  82. {
  83. kAsDfltMsgQueueByteCnt = 0xffff,
  84. kAsDfltDevFramesPerCycle = 512,
  85. kAsDfltDspFramesPerCycle = 64,
  86. kAsDfltBufCnt = 3,
  87. kAsDfltSrate = 44100,
  88. kAsDfltSyncToInputFl = 1,
  89. kAsDfltMinMeterMs = 10,
  90. kAsDfltMeterMs = 50,
  91. kAsDfltMaxMeterMs = 1000
  92. };
  93. typedef cmHandle_t cmRtSysH_t; //< Audio system handle type
  94. typedef unsigned cmRtRC_t; //< Audio system result code
  95. struct cmRtSysCtx_str;
  96. //
  97. // DSP system callback function.
  98. //
  99. // This is the sole point of entry into the DSP system while the audio system is running.
  100. //
  101. // ctxPtr is pointer to a cmRtSysCtx_t record.
  102. //
  103. // This function is called under two circumstances:
  104. //
  105. // 1) To notify the DSP system that the audio input/output buffers need to be serviced.
  106. // This is a perioidic request which the DSP system uses as its execution trigger.
  107. // cmRtSysCtx_t.audioRateFl is set to true to indicate this type of callback.
  108. //
  109. // 2) To pass messages from the host application to the DSP system.
  110. // The DSP system is asyncronous with the host because it executes in the
  111. // audio system thread rather than the host thread. The cmRtSysDeliverMsg()
  112. // function synchronizes incoming messages with the internal audio system
  113. // thread to prevent thread collisions.
  114. //
  115. // Notes:
  116. // This callback is always made with the internal audio system mutex locked.
  117. //
  118. // The signal time covered by the callback is from
  119. // ctx->begSmpIdx to ctx->begSmpIdx+cfg->dspFramesPerCycle.
  120. //
  121. // The return value is currently not used.
  122. typedef cmRC_t (*cmRtCallback_t)(void* ctxPtr, unsigned msgByteCnt, const void* msgDataPtr );
  123. // Network nodes
  124. typedef struct
  125. {
  126. const cmChar_t* label; // Remote node label or NULL if this is the local node.
  127. const cmChar_t* ipAddr; // IP address in xxx.xxx.xxx.xxx form or NULL for 'localhost'.
  128. cmUdpPort_t ipPort; // IP port
  129. } cmRtSysNetNode_t;
  130. // Local endpoints.
  131. typedef struct
  132. {
  133. const cmChar_t* label; // Local endpoint label
  134. unsigned id; // Local endpoint id
  135. } cmRtSysNetEndpt_t;
  136. // Audio device sub-sytem configuration record
  137. typedef struct cmRtSysArgs_str
  138. {
  139. cmRpt_t* rpt; // system console object
  140. unsigned inDevIdx; // input audio device
  141. unsigned outDevIdx; // output audio device
  142. bool syncInputFl; // true/false sync the DSP update callbacks with audio input/output
  143. unsigned msgQueueByteCnt; // Size of the internal msg queue used to buffer msgs arriving via cmRtSysDeliverMsg().
  144. unsigned devFramesPerCycle; // (512) Audio device samples per channel per device update buffer.
  145. unsigned dspFramesPerCycle; // (64) Audio samples per channel per DSP cycle.
  146. unsigned audioBufCnt; // (3) Audio device buffers.
  147. double srate; // Audio sample rate.
  148. int srateMult;
  149. } cmRtSysArgs_t;
  150. // Audio sub-system configuration record.
  151. // This record is provided by the host to configure the audio system
  152. // via cmRtSystemAllocate() or cmRtSystemInitialize().
  153. typedef struct cmRtSysSubSys_str
  154. {
  155. cmRtSysArgs_t args; // Audio device configuration
  156. cmRtCallback_t cbFunc; // DSP system entry point function.
  157. void* cbDataPtr; // Host provided data for the DSP system callback.
  158. const cmChar_t* bcastAddr; // Network broadcast address.
  159. const cmChar_t* localNodeLabel; // Network local node address.
  160. const cmChar_t* localIpAddr; // Network local IP address (default:NULL to use any available address)
  161. cmUdpPort_t localIpPort; // Network local socket port address
  162. cmRtSysNetEndpt_t* endptArray; // Local end points
  163. unsigned endptCnt; // Count of local endpoints.
  164. } cmRtSysSubSys_t;
  165. // Signature of a callback function provided by the audio system to receive messages
  166. // from the DSP system for later dispatch to the host application.
  167. // This declaration is used by the DSP system implementation and the audio system.
  168. // Note that this function is intended to convey one message broken into multiple parts.
  169. // See cmTsQueueEnqueueSegMsg() for the equivalent interface.
  170. typedef cmRtRC_t (*cmRtDspToHostFunc_t)(struct cmRtSysCtx_str* p, const void* msgDataPtrArray[], unsigned msgByteCntArray[], unsigned msgSegCnt);
  171. // Record passed with each call to the DSP callback function cmRtCallback_t
  172. typedef struct cmRtSysCtx_str
  173. {
  174. void* reserved; // used internally by the audio system
  175. bool audioRateFl; // true if this is an audio update callback
  176. unsigned srcNetNodeId; // Source net node if this is a msg callback originating from a remote network node.
  177. unsigned rtSubIdx; // index of the sub-system this DSP process is serving
  178. cmRtSysSubSys_t* ss; // ptr to a copy of the cfg recd used to initialize the audio system
  179. unsigned begSmpIdx; // gives signal time as a sample count
  180. cmRtDspToHostFunc_t dspToHostFunc; // Callback used by the DSP process to send messages to the host
  181. // via the audio system. Returns a cmRtRC_t result code.
  182. // output (playback) buffers
  183. cmSample_t** oChArray; // each ele is a ptr to buffer with cfg.dspFramesPerCycle samples
  184. unsigned oChCnt; // count of output channels (ele's in oChArray[])
  185. cmTimeSpec_t oTimeStamp;
  186. // input (recording) buffers
  187. cmSample_t** iChArray; // each ele is a ptr to buffer with cfg.dspFramesPerCycle samples
  188. unsigned iChCnt; // count of input channels (ele's in iChArray[])
  189. cmTimeSpec_t iTimeStamp;
  190. } cmRtSysCtx_t;
  191. extern cmRtSysH_t cmRtSysNullHandle;
  192. // Allocate and initialize an audio system as a collection of 'cfgCnt' sub-systems.
  193. // Prior to call this function the audio audio ports system must be initalized
  194. // (via cmApInitialize()) and the MIDI port system must be initialized
  195. // (via cmMpInitialize()). Note also that cmApFinalize() and cmMpFinalize()
  196. // cannot be called prior to cmRtSysFree().
  197. // See cmRtSystemTest() for a complete example.
  198. cmRtRC_t cmRtSysAllocate( cmRtSysH_t* hp, cmCtx_t* ctx );
  199. // Finalize and release any resources held by the audio system.
  200. cmRtRC_t cmRtSysFree( cmRtSysH_t* hp );
  201. // Returns true if 'h' is a handle which was successfully allocated by
  202. // cmRtSysAllocate().
  203. bool cmRtSysHandleIsValid( cmRtSysH_t h );
  204. // clientCbFunc is Called by cmRtSysReceiveMsg() to deliver internally generated msg's to the host.
  205. // Set to NULL if msg's will be directly returned by buffers passed to cmRtSysReceiveMsg().
  206. cmRtRC_t cmRtSysBeginCfg( cmRtSysH_t h, cmTsQueueCb_t clientCbFunc, void* clientCbArg, unsigned meterMs, unsigned ssCnt );
  207. // Reinitialize a previously allocated audio system. This function
  208. // begins with a call to cmRtSysFinalize().
  209. // Use cmRtSysEnable(h,true) to begin processing audio following this call.
  210. cmRtRC_t cmRtSysCfg( cmRtSysH_t h, const cmRtSysSubSys_t* ss, unsigned rtSubIdx );
  211. cmRtRC_t cmRtSysEndCfg( cmRtSysH_t h );
  212. // Complements cmRtSysInitialize(). In general there is no need to call this function
  213. // since calls to cmRtSysInitialize() and cmRtSysFree() automaticatically call it.
  214. cmRtRC_t cmRtSysFinalize( cmRtSysH_t h );
  215. // Returns true if the audio system has been successfully initialized.
  216. bool cmRtSysIsInitialized( cmRtSysH_t );
  217. // Returns true if the audio system is enabled.
  218. bool cmRtSysIsEnabled( cmRtSysH_t h );
  219. // Enable/disable the audio system. Enabling the starts audio stream
  220. // in/out of the system.
  221. cmRtRC_t cmRtSysEnable( cmRtSysH_t h, bool enableFl );
  222. //
  223. // DSP to Host delivery function
  224. //
  225. // This function is used to pass messages from a DSP process to the HOST it
  226. // is always called from within the real-time thread.
  227. cmRtRC_t cmRtSysDspToHostSegMsg( cmRtSysH_t h, const void* msgDataPtrArray[], unsigned msgByteCntArray[], unsigned msgSegCnt);
  228. cmRtRC_t cmRtSysDspToHost( cmRtSysH_t h, const void* msgDataPtr, unsigned msgByteCnt);
  229. //
  230. // Host to DSP delivery functions
  231. //
  232. // Deliver a message from the host application to the DSP process. (host -> DSP);
  233. // The message is formed as a concatenation of the bytes in each of the segments
  234. // pointed to by 'msgDataPtrArrary[segCnt][msgByteCntArray[segCnt]'.
  235. // This is the canonical msg delivery function in so far as the other host->DSP
  236. // msg delivery function are written in terms of this function.
  237. // The first 4 bytes in the first segment must contain the index of the audio sub-system
  238. // which is to receive the message.
  239. cmRtRC_t cmRtSysDeliverSegMsg( cmRtSysH_t h, const void* msgDataPtrArray[], unsigned msgByteCntArray[], unsigned msgSegCnt, unsigned srcNetNodeId );
  240. // Deliver a single message from the host to the DSP system.
  241. cmRtRC_t cmRtSysDeliverMsg( cmRtSysH_t h, const void* msgPtr, unsigned msgByteCnt, unsigned srcNetNodeId );
  242. // Deliver a single message from the host to the DSP system.
  243. // Prior to delivery the 'id' is prepended to the message.
  244. cmRtRC_t cmRtSysDeliverIdMsg( cmRtSysH_t h, unsigned rtSubIdx, unsigned id, const void* msgPtr, unsigned msgByteCnt, unsigned srcNetNodeId );
  245. //
  246. // DSP to Host message functions
  247. //
  248. // Is a msg from the DSP waiting to be picked up by the host? (host <- DSP)
  249. // 0 = no msgs are waiting or the msg queue is locked by the DSP process.
  250. // >0 = the size of the buffer required to hold the next msg returned via
  251. // cmRtSysReceiveMsg().
  252. unsigned cmRtSysIsMsgWaiting( cmRtSysH_t h );
  253. // Copy the next available msg sent from the DSP process to the host into the host supplied msg buffer
  254. // pointed to by 'msgBufPtr'. Set 'msgDataPtr' to NULL to receive msg by callback from cmRtSysCfg_t.clientCbFunc.
  255. // Returns kBufTooSmallRtRC if msgDataPtr[msgByteCnt] is too small to hold the msg.
  256. // Returns kNoMsgWaitingRtRC if no messages are waiting for delivery or the msg queue is locked by the DSP process.
  257. // Returns kOkRtRC if a msg was delivered.
  258. // Call cmRtSysIsMsgWaiting() prior to calling this function to get
  259. // the size of the data buffer required to hold the next message.
  260. cmRtRC_t cmRtSysReceiveMsg( cmRtSysH_t h, void* msgDataPtr, unsigned msgByteCnt );
  261. // Fill an audio system status record.
  262. void cmRtSysStatus( cmRtSysH_t h, unsigned rtSubIdx, cmRtSysStatus_t* statusPtr );
  263. // Enable cmRtSysStatus_t notifications to be sent periodically to the host.
  264. // Set rtSubIdx to cmInvalidIdx to enable/disable all sub-systems.
  265. // The notifications occur approximately every cmRtSysCfg_t.meterMs milliseconds.
  266. void cmRtSysStatusNotifyEnable( cmRtSysH_t, unsigned rtSubIdx, bool enableFl );
  267. // Return a pointer the context record associated with a sub-system
  268. cmRtSysCtx_t* cmRtSysContext( cmRtSysH_t h, unsigned rtSubIdx );
  269. // Enable non-block mode. In this mode audio I/O is disabled
  270. // and the DSP callback is made every noBlockSleepMs milliseconds.
  271. cmRtRC_t cmRtSysEnableNoBlockMode( cmRtSysH_t h, unsigned rtSubIdx, bool enaFl, unsigned noBlockSleepMs );
  272. // Return the count of audio sub-systems.
  273. // This is the same as the count of cfg recds passed to cmRtSystemInitialize().
  274. unsigned cmRtSysSubSystemCount( cmRtSysH_t h );
  275. // Audio system test and example function.
  276. void cmRtSysTest( cmCtx_t* ctx, int argc, const char* argv[] );
  277. bool cmRtSysNetIsInitialized( cmRtSysH_t h );
  278. cmRtRC_t cmRtSysNetDoSync( cmRtSysH_t h );
  279. cmRtRC_t cmRtSysNetReport( cmRtSysH_t h );
  280. cmRtRC_t cmRtSysNetReportSyncEnable( cmRtSysH_t h, bool enableFl );
  281. cmRtRC_t cmRtSysNetGetHandle( cmRtSysH_t h, unsigned rtSubIdx, cmRtNetH_t* hp );
  282. //)
  283. #ifdef __cplusplus
  284. }
  285. #endif
  286. #endif