libcm is a C development framework with an emphasis on audio signal processing applications.
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

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