libcm is a C development framework with an emphasis on audio signal processing applications.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

cmAudDsp.c 37KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344
  1. #include "cmPrefix.h"
  2. #include "cmGlobal.h"
  3. #include "cmFloatTypes.h"
  4. #include "cmRpt.h"
  5. #include "cmErr.h"
  6. #include "cmCtx.h"
  7. #include "cmMem.h"
  8. #include "cmMallocDebug.h"
  9. #include "cmLinkedHeap.h"
  10. #include "cmSymTbl.h"
  11. #include "cmJson.h"
  12. #include "cmFileSys.h"
  13. #include "cmPrefs.h"
  14. #include "cmTime.h"
  15. #include "cmAudioPort.h"
  16. #include "cmAudioAggDev.h"
  17. #include "cmAudioNrtDev.h"
  18. #include "cmAudioPortFile.h"
  19. #include "cmApBuf.h"
  20. #include "cmMidi.h"
  21. #include "cmMidiPort.h"
  22. #include "dsp/cmDspValue.h"
  23. #include "cmMsgProtocol.h"
  24. #include "cmThread.h"
  25. #include "cmUdpPort.h"
  26. #include "cmUdpNet.h"
  27. #include "cmAudioSys.h"
  28. #include "cmProcObj.h"
  29. #include "dsp/cmDspCtx.h"
  30. #include "dsp/cmDspClass.h"
  31. #include "dsp/cmDspSys.h"
  32. #include "cmAudDsp.h"
  33. cmAdH_t cmAdNullHandle = cmSTATIC_NULL_HANDLE;
  34. typedef struct
  35. {
  36. cmDspSysH_t dsH;
  37. unsigned curPgmIdx;
  38. bool isLoadedFl;
  39. unsigned isSyncFl;
  40. } cmAdDsSubSys_t;
  41. typedef struct
  42. {
  43. const cmChar_t* label;
  44. cmAudioSysCfg_t cfg;
  45. } cmAdAsCfg_t;
  46. typedef struct
  47. {
  48. const cmChar_t* label;
  49. unsigned physDevCnt;
  50. unsigned* physDevIdxArray;
  51. } cmAdAggDev_t;
  52. typedef struct
  53. {
  54. const cmChar_t* label;
  55. double srate;
  56. unsigned iChCnt;
  57. unsigned oChCnt;
  58. unsigned cbPeriodMs;
  59. } cmAdNrtDev_t;
  60. typedef struct
  61. {
  62. const cmChar_t* label;
  63. const cmChar_t* inAudioFn;
  64. const cmChar_t* outAudioFn;
  65. unsigned oBits;
  66. unsigned oChCnt;
  67. } cmAdAfpDev_t;
  68. typedef struct
  69. {
  70. cmErr_t err;
  71. cmCtx_t ctx;
  72. cmMsgSendFuncPtr_t cbFunc;
  73. void* cbDataPtr;
  74. cmJsonH_t sysJsH;
  75. const cmChar_t* sysJsFn;
  76. cmUdpNetH_t netH;
  77. cmDspSysH_t dsH;
  78. cmAudioSysH_t asH;
  79. unsigned midiPortBufByteCnt;
  80. unsigned meterMs;
  81. unsigned msgsPerClientPoll;
  82. cmAdAggDev_t* aggDevArray;
  83. unsigned aggDevCnt;
  84. cmAdNrtDev_t* nrtDevArray;
  85. unsigned nrtDevCnt;
  86. cmAdAfpDev_t* afpDevArray;
  87. unsigned afpDevCnt;
  88. cmAdAsCfg_t* asCfgArray;
  89. unsigned asCfgCnt;
  90. unsigned curAsCfgIdx;
  91. unsigned dsSsCnt;
  92. cmAdDsSubSys_t* dsSsArray;
  93. bool syncFl; // all cmAdDsSubSys's are synced
  94. } cmAd_t;
  95. cmAd_t* _cmAdHandleToPtr( cmAdH_t h )
  96. {
  97. cmAd_t* p = (cmAd_t*)h.h;
  98. assert( p != NULL );
  99. return p;
  100. }
  101. // cmAudioSys DSP processing callback - this is the entry point
  102. // from the cmAudioSystem to the cmDspSystem. Note that it is called from the
  103. // the audio processing thread in cmAudioSys.c: _cmAsDeliverMsgsWithLock()
  104. cmRC_t _cmAudDspCallback( void *cbPtr, unsigned msgByteCnt, const void* msgDataPtr )
  105. {
  106. cmAudioSysCtx_t* ctx = (cmAudioSysCtx_t*)cbPtr;
  107. cmAdDsSubSys_t* p = (cmAdDsSubSys_t*)ctx->ss->cbDataPtr;
  108. if( p != NULL && p->isLoadedFl )
  109. return cmDspSysRcvMsg(p->dsH,ctx, msgDataPtr, msgByteCnt, ctx->srcNetNodeId );
  110. return cmOkRC;
  111. }
  112. // This function is called by cmAudioSysReceiveMsg() to transfer messages from the
  113. // cmAudioSys or cmDspSys to the client.
  114. cmRC_t _cmAudioSysToClientCallback(void* userCbPtr, unsigned msgByteCnt, const void* msgDataPtr )
  115. {
  116. cmAd_t* p = (cmAd_t*)userCbPtr;
  117. return p->cbFunc(p->cbDataPtr, msgByteCnt, msgDataPtr );
  118. }
  119. // This function is called by cmUdpNetReceive(), which is called in
  120. // cmAudioSys.c:_cmAsThreadCallback() just prior to executing the DSP process.
  121. void _cmAdUdpNetCallback( void* cbArg, cmUdpNetH_t h, const char* data, unsigned dataByteCnt, unsigned srcNetNodeId )
  122. {
  123. cmAd_t* p = (cmAd_t*)cbArg;
  124. // send the incoming message to the audio system for later delivery to the DSP system
  125. cmAudioSysDeliverMsg(p->asH, data, dataByteCnt, srcNetNodeId );
  126. }
  127. cmAdRC_t _cmAdParseMemberErr( cmAd_t* p, cmJsRC_t jsRC, const cmChar_t* errLabel, const cmChar_t* objectLabel )
  128. {
  129. if( jsRC == kNodeNotFoundJsRC && errLabel != NULL )
  130. return cmErrMsg(&p->err,kJsonFailAdRC,"The required field '%s'was not found in the audio DSP resource tree in the object '%s' in the file '%s'.",errLabel,cmStringNullGuard(objectLabel), cmStringNullGuard(p->sysJsFn));
  131. return cmErrMsg(&p->err,kJsonFailAdRC,"JSON parsing failed on the Audio DSP resource file '%s' in the resource object '%s'.",cmStringNullGuard(p->sysJsFn),cmStringNullGuard(objectLabel));
  132. }
  133. cmAdRC_t _cmAdParseSysJsonTree( cmAd_t* p )
  134. {
  135. cmAdRC_t rc = kOkAdRC;
  136. cmJsonNode_t* asCfgArrNodePtr = NULL;
  137. cmJsonNode_t* aggDevArrNodePtr = NULL;
  138. cmJsonNode_t* nrtDevArrNodePtr = NULL;
  139. cmJsonNode_t* afpDevArrNodePtr = NULL;
  140. cmJsonNode_t* audDspNodePtr = NULL;
  141. const cmChar_t* errLabelPtr = NULL;
  142. unsigned i;
  143. cmJsRC_t jsRC = kOkJsRC;
  144. // locate the aud_dsp container object
  145. if( cmJsonNodeMember( cmJsonRoot(p->sysJsH), "aud_dsp", &audDspNodePtr ) != kOkJsRC )
  146. {
  147. rc = cmErrMsg(&p->err,kJsonFailAdRC,"The audio DSP system resource file '%s' does not contain an 'aud_dsp' object.",cmStringNullGuard(p->sysJsFn));
  148. goto errLabel;
  149. }
  150. // locate the read the aud_dsp sub-elements
  151. if(( jsRC = cmJsonMemberValues( audDspNodePtr, &errLabelPtr,
  152. "midiPortBufByteCnt", kIntTId, &p->midiPortBufByteCnt,
  153. "meterMs", kIntTId, &p->meterMs,
  154. "msgsPerClientPoll", kIntTId, &p->msgsPerClientPoll,
  155. "audioSysCfgArray", kArrayTId, &asCfgArrNodePtr,
  156. "aggDevArray", kArrayTId | kOptArgJsFl, &aggDevArrNodePtr,
  157. "nrtDevArray", kArrayTId | kOptArgJsFl, &nrtDevArrNodePtr,
  158. "afpDevArray", kArrayTId | kOptArgJsFl, &afpDevArrNodePtr,
  159. NULL )) != kOkJsRC )
  160. {
  161. rc = _cmAdParseMemberErr(p, jsRC, errLabelPtr, "aud_dsp" );
  162. goto errLabel;
  163. }
  164. // parse the aggregate device specifications into p->aggDevArray[].
  165. if( aggDevArrNodePtr != NULL && (p->aggDevCnt = cmJsonChildCount(aggDevArrNodePtr)) > 0)
  166. {
  167. // alloc the aggregate spec. array
  168. p->aggDevArray = cmMemResizeZ( cmAdAggDev_t, p->aggDevArray, p->aggDevCnt );
  169. // for each agg. device spec. recd
  170. for(i=0; i<p->aggDevCnt; ++i)
  171. {
  172. const cmJsonNode_t* np = cmJsonArrayElementC(aggDevArrNodePtr,i);
  173. const cmJsonNode_t* devIdxArrNodePtr = NULL;
  174. unsigned j;
  175. // read aggDevArray record values
  176. if(( jsRC = cmJsonMemberValues( np, &errLabelPtr,
  177. "label", kStringTId, &p->aggDevArray[i].label,
  178. "physDevIdxArray", kArrayTId, &devIdxArrNodePtr,
  179. NULL )) != kOkJsRC )
  180. {
  181. rc = _cmAdParseMemberErr(p, jsRC, errLabelPtr, cmStringNullGuard(p->aggDevArray[i].label) );
  182. goto errLabel;
  183. }
  184. unsigned physDevCnt = cmJsonChildCount(devIdxArrNodePtr);
  185. // alloc the dev idx array for to hold the phys. dev indexes for this agg device
  186. p->aggDevArray[i].physDevIdxArray = cmMemResizeZ( unsigned, p->aggDevArray[i].physDevIdxArray, physDevCnt);
  187. p->aggDevArray[i].physDevCnt = physDevCnt;
  188. // store the phys. dev. idx's
  189. for(j=0; j<physDevCnt; ++j)
  190. if( cmJsonUIntValue( cmJsonArrayElementC(devIdxArrNodePtr,j), p->aggDevArray[i].physDevIdxArray + j ) != kOkJsRC )
  191. {
  192. rc = cmErrMsg(&p->err,kJsonFailAdRC,"Unable to retrieve a physical device index for the aggregate device '%s'.", cmStringNullGuard(p->aggDevArray[i].label));
  193. goto errLabel;
  194. }
  195. }
  196. }
  197. // parse the non-real-time device specifications into p->nrtDevArray[].
  198. if( nrtDevArrNodePtr != NULL && (p->nrtDevCnt = cmJsonChildCount(nrtDevArrNodePtr)) > 0)
  199. {
  200. // alloc the non-real-time spec. array
  201. p->nrtDevArray = cmMemResizeZ( cmAdNrtDev_t, p->nrtDevArray, p->nrtDevCnt );
  202. // for each nrt. device spec. recd
  203. for(i=0; i<p->nrtDevCnt; ++i)
  204. {
  205. const cmJsonNode_t* np = cmJsonArrayElementC(nrtDevArrNodePtr,i);
  206. // read nrtDevArray record values
  207. if(( jsRC = cmJsonMemberValues( np, &errLabelPtr,
  208. "label", kStringTId, &p->nrtDevArray[i].label,
  209. "srate", kRealTId, &p->nrtDevArray[i].srate,
  210. "iChCnt", kIntTId, &p->nrtDevArray[i].iChCnt,
  211. "oChCnt", kIntTId, &p->nrtDevArray[i].oChCnt,
  212. "cbPeriodMs", kIntTId, &p->nrtDevArray[i].cbPeriodMs,
  213. NULL )) != kOkJsRC )
  214. {
  215. rc = _cmAdParseMemberErr(p, jsRC, errLabelPtr, cmStringNullGuard(p->nrtDevArray[i].label) );
  216. goto errLabel;
  217. }
  218. }
  219. }
  220. // parse the audio file device specifications into p->afpDevArray[].
  221. if( afpDevArrNodePtr != NULL && (p->afpDevCnt = cmJsonChildCount(afpDevArrNodePtr)) > 0)
  222. {
  223. // alloc the non-real-time spec. array
  224. p->afpDevArray = cmMemResizeZ( cmAdAfpDev_t, p->afpDevArray, p->afpDevCnt );
  225. // for each afp. device spec. recd
  226. for(i=0; i<p->afpDevCnt; ++i)
  227. {
  228. const cmJsonNode_t* np = cmJsonArrayElementC(afpDevArrNodePtr,i);
  229. // read afpDevArray record values
  230. if(( jsRC = cmJsonMemberValues( np, &errLabelPtr,
  231. "label", kStringTId, &p->afpDevArray[i].label,
  232. "iAudioFn", kStringTId | kOptArgJsFl, &p->afpDevArray[i].inAudioFn,
  233. "oAudioFn", kStringTId | kOptArgJsFl, &p->afpDevArray[i].outAudioFn,
  234. "oBits", kIntTId | kOptArgJsFl, &p->afpDevArray[i].oBits,
  235. "oChCnt", kIntTId | kOptArgJsFl, &p->afpDevArray[i].oChCnt,
  236. NULL )) != kOkJsRC )
  237. {
  238. rc = _cmAdParseMemberErr(p, jsRC, errLabelPtr, cmStringNullGuard(p->afpDevArray[i].label) );
  239. goto errLabel;
  240. }
  241. }
  242. }
  243. if((p->asCfgCnt = cmJsonChildCount(asCfgArrNodePtr)) == 0 )
  244. goto errLabel;
  245. p->asCfgArray = cmMemResizeZ( cmAdAsCfg_t, p->asCfgArray, p->asCfgCnt);
  246. // for each cmAsAudioSysCfg record in audioSysCfgArray[]
  247. for(i=0; i<p->asCfgCnt; ++i)
  248. {
  249. unsigned j;
  250. const cmJsonNode_t* asCfgNodePtr = cmJsonArrayElementC(asCfgArrNodePtr,i);
  251. const cmJsonNode_t* ssArrayNodePtr = NULL;
  252. const char* cfgLabel = NULL;
  253. // read cmAsAudioSysCfg record values
  254. if(( jsRC = cmJsonMemberValues( asCfgNodePtr, &errLabelPtr,
  255. "label", kStringTId, &cfgLabel,
  256. "ssArray", kArrayTId, &ssArrayNodePtr,
  257. NULL )) != kOkJsRC )
  258. {
  259. rc = _cmAdParseMemberErr(p, jsRC, errLabelPtr, cmStringNullGuard(p->asCfgArray[i].label) );
  260. goto errLabel;
  261. }
  262. p->asCfgArray[i].label = cfgLabel;
  263. p->asCfgArray[i].cfg.ssCnt = cmJsonChildCount( ssArrayNodePtr );
  264. p->asCfgArray[i].cfg.ssArray = cmMemResizeZ( cmAudioSysSubSys_t, p->asCfgArray[i].cfg.ssArray, p->asCfgArray[i].cfg.ssCnt );
  265. p->asCfgArray[i].cfg.clientCbFunc = _cmAudioSysToClientCallback;
  266. p->asCfgArray[i].cfg.clientCbData = p;
  267. // for each audio system sub-subsystem
  268. for(j=0; j<p->asCfgArray[i].cfg.ssCnt; ++j)
  269. {
  270. cmAudioSysArgs_t* asap = &p->asCfgArray[i].cfg.ssArray[j].args;
  271. const cmJsonNode_t* argsNodePtr = cmJsonArrayElementC(ssArrayNodePtr,j);
  272. if((jsRC = cmJsonMemberValues( argsNodePtr, &errLabelPtr,
  273. "inDevIdx", kIntTId, &asap->inDevIdx,
  274. "outDevIdx", kIntTId, &asap->outDevIdx,
  275. "syncToInputFl", kTrueTId, &asap->syncInputFl,
  276. "msgQueueByteCnt", kIntTId, &asap->msgQueueByteCnt,
  277. "devFramesPerCycle", kIntTId, &asap->devFramesPerCycle,
  278. "dspFramesPerCycle", kIntTId, &asap->dspFramesPerCycle,
  279. "audioBufCnt", kIntTId, &asap->audioBufCnt,
  280. "srate", kRealTId, &asap->srate,
  281. NULL )) != kOkJsRC )
  282. {
  283. rc = _cmAdParseMemberErr(p, jsRC, errLabelPtr, cmStringNullGuard(p->asCfgArray[i].label));
  284. goto errLabel;
  285. }
  286. }
  287. }
  288. errLabel:
  289. return rc;
  290. }
  291. cmAdRC_t _cmAdSetup( cmAd_t* p )
  292. {
  293. unsigned i;
  294. cmAdRC_t rc = kOkAdRC;
  295. for(i=0; i<p->asCfgCnt; ++i)
  296. {
  297. unsigned j;
  298. p->asCfgArray[i].cfg.meterMs = p->meterMs;
  299. // BUG BUG BUG - each sub-system should have it's own network
  300. // manager, and socket port.
  301. p->asCfgArray[i].cfg.netH = p->netH;
  302. for(j=0; j<p->asCfgArray[i].cfg.ssCnt; ++j)
  303. {
  304. p->asCfgArray[i].cfg.ssArray[j].cbDataPtr = NULL;
  305. p->asCfgArray[i].cfg.ssArray[j].cbFunc = _cmAudDspCallback;
  306. p->asCfgArray[i].cfg.ssArray[j].args.rpt = p->err.rpt;
  307. }
  308. }
  309. return rc;
  310. }
  311. cmAdRC_t _cmAdCreateAggDevices( cmAd_t* p )
  312. {
  313. cmAdRC_t rc = kOkAdRC;
  314. unsigned i;
  315. if( cmApAggAllocate(p->err.rpt) != kOkAgRC )
  316. return cmErrMsg(&p->err,kAggDevSysFailAdRC,"The aggregate device system allocation failed.");
  317. for(i=0; i<p->aggDevCnt; ++i)
  318. {
  319. cmAdAggDev_t* adp = p->aggDevArray + i;
  320. if( cmApAggCreateDevice(adp->label,adp->physDevCnt,adp->physDevIdxArray,kInAggFl | kOutAggFl) != kOkAgRC )
  321. rc = cmErrMsg(&p->err,kAggDevCreateFailAdRC,"The aggregate device '%s' creation failed.",cmStringNullGuard(adp->label));
  322. }
  323. return rc;
  324. }
  325. cmAdRC_t _cmAdCreateNrtDevices( cmAd_t* p )
  326. {
  327. cmAdRC_t rc = kOkAdRC;
  328. unsigned i;
  329. if( cmApNrtAllocate(p->err.rpt) != kOkApRC )
  330. return cmErrMsg(&p->err,kNrtDevSysFailAdRC,"The non-real-time device system allocation failed.");
  331. for(i=0; i<p->nrtDevCnt; ++i)
  332. {
  333. cmAdNrtDev_t* adp = p->nrtDevArray + i;
  334. if( cmApNrtCreateDevice(adp->label,adp->srate,adp->iChCnt,adp->oChCnt,adp->cbPeriodMs) != kOkApRC )
  335. rc = cmErrMsg(&p->err,kNrtDevSysFailAdRC,"The non-real-time device '%s' creation failed.",cmStringNullGuard(adp->label));
  336. }
  337. return rc;
  338. }
  339. cmAdRC_t _cmAdCreateAfpDevices( cmAd_t* p )
  340. {
  341. cmAdRC_t rc = kOkAdRC;
  342. if( cmApFileAllocate(p->err.rpt) != kOkApRC )
  343. return cmErrMsg(&p->err,kAfpDevSysFailAdRC,"The audio file device system allocation failed.");
  344. unsigned i;
  345. // create the audio file devices
  346. for(i=0; i<p->afpDevCnt; ++i)
  347. {
  348. //const cmAudioSysFilePort_t* afp = cfg->afpArray + i;
  349. cmAdAfpDev_t* afp = p->afpDevArray + i;
  350. if( cmApFileDeviceCreate( afp->label, afp->inAudioFn, afp->outAudioFn, afp->oBits, afp->oChCnt ) != kOkApRC )
  351. rc = cmErrMsg(&p->err,kAfpDevSysFailAdRC,"The audio file device '%s' creation failed.",cmStringNullGuard(afp->label));
  352. }
  353. return rc;
  354. }
  355. cmAdRC_t _cmAdSendAudioSysCfgLabels( cmAd_t* p)
  356. {
  357. cmAdRC_t rc = kOkAdRC;
  358. unsigned i;
  359. for(i=0; i<p->asCfgCnt; ++i)
  360. {
  361. cmDspValue_t v;
  362. cmDsvSetStrcz(&v, p->asCfgArray[i].label);
  363. if( cmMsgSend( &p->err,cmInvalidIdx,kUiSelAsId,kAudioSysCfgDuiId,0,i,p->asCfgCnt,&v,p->cbFunc,p->cbDataPtr) != kOkMsgRC )
  364. {
  365. rc = cmErrMsg(&p->err,kSendMsgFailAdRC,"Error sending audio system cfg. label message to host.");
  366. break;
  367. }
  368. }
  369. return rc;
  370. }
  371. cmAdRC_t _cmAdSendDeviceLabels( cmAd_t* p )
  372. {
  373. cmAdRC_t rc = kOkAdRC;
  374. unsigned i,j;
  375. unsigned n = cmApDeviceCount();
  376. for(i=0; i<2; ++i)
  377. {
  378. bool inputFl = i==0;
  379. for(j=0; j<n; ++j)
  380. if( cmApDeviceChannelCount(j,inputFl) )
  381. {
  382. cmDspValue_t v;
  383. cmDsvSetStrcz(&v, cmApDeviceLabel(j));
  384. if( cmMsgSend( &p->err,cmInvalidIdx,kUiSelAsId,kDeviceDuiId,inputFl,j,n,&v,p->cbFunc,p->cbDataPtr) != kOkMsgRC )
  385. {
  386. rc = cmErrMsg(&p->err,kSendMsgFailAdRC,"Error sending device label message to host.");
  387. break;
  388. }
  389. }
  390. }
  391. return rc;
  392. }
  393. cmAdRC_t _cmAdSendProgramLabels( cmAd_t* p )
  394. {
  395. cmAdRC_t rc = kOkAdRC;
  396. unsigned pgmCnt = cmDspSysPgmCount(p->dsH);
  397. unsigned i;
  398. for(i=0; i<pgmCnt; ++i)
  399. {
  400. cmDspValue_t v;
  401. cmDsvSetStrcz(&v, cmDspPgmLabel(p->dsH,i));
  402. if( cmMsgSend( &p->err,cmInvalidIdx,kUiSelAsId,kProgramDuiId,0,i,pgmCnt,&v,p->cbFunc,p->cbDataPtr) != kOkMsgRC )
  403. {
  404. rc = cmErrMsg(&p->err,kSendMsgFailAdRC,"Error sending program label message to host.");
  405. break;
  406. }
  407. }
  408. return rc;
  409. }
  410. cmAdRC_t _cmAudDspFree( cmAd_t* p )
  411. {
  412. cmAdRC_t rc = kOkAdRC;
  413. if( cmAudioSysFree(&p->asH) != kOkAsRC )
  414. {
  415. rc = cmErrMsg(&p->err,kAudioSysFailAdRC,"The audio system release failed.");
  416. goto errLabel;
  417. }
  418. if( cmDspSysFinalize(&p->dsH) != kOkDspRC )
  419. {
  420. rc = cmErrMsg(&p->err,kDspSysFailAdRC,"DSP system finalization failed.");
  421. goto errLabel;
  422. }
  423. if( cmUdpNetFree(&p->netH) != kOkUnRC )
  424. {
  425. rc = cmErrMsg(&p->err,kNetSysFailAdRC,"UDP Network finalization failed.");
  426. goto errLabel;
  427. }
  428. if( cmMpIsInitialized() )
  429. if( cmMpFinalize() != kOkMpRC )
  430. {
  431. rc = cmErrMsg(&p->err,kMidiSysFailAdRC,"MIDI system finalization failed.");
  432. goto errLabel;
  433. }
  434. if( cmApFinalize() != kOkApRC )
  435. {
  436. rc = cmErrMsg(&p->err,kAudioPortFailAdRC,"Audio port finalization failed.");
  437. goto errLabel;
  438. }
  439. if( cmApBufFinalize() != kOkApRC )
  440. {
  441. rc = cmErrMsg(&p->err,kAudioPortFailAdRC,"Audio port buffer finalization failed.");
  442. goto errLabel;
  443. }
  444. if( cmApFileFree() != kOkApRC )
  445. {
  446. rc = cmErrMsg(&p->err,kAfpDevSysFailAdRC,"The audio file device system release failed.");
  447. goto errLabel;
  448. }
  449. if( cmApNrtFree() != kOkAgRC )
  450. {
  451. rc = cmErrMsg(&p->err,kNrtDevSysFailAdRC,"The non-real-time device system release failed.");
  452. goto errLabel;
  453. }
  454. if( cmApAggFree() != kOkAgRC )
  455. {
  456. rc = cmErrMsg(&p->err,kAggDevSysFailAdRC,"The aggregate device system release failed.");
  457. goto errLabel;
  458. }
  459. cmMemPtrFree(&p->nrtDevArray);
  460. unsigned i;
  461. for(i=0; i<p->aggDevCnt; ++i)
  462. cmMemPtrFree(&p->aggDevArray[i].physDevIdxArray);
  463. cmMemPtrFree(&p->aggDevArray);
  464. for(i=0; i<p->asCfgCnt; ++i)
  465. cmMemPtrFree(&p->asCfgArray[i].cfg.ssArray);
  466. cmMemPtrFree(&p->asCfgArray);
  467. cmMemPtrFree(&p->dsSsArray);
  468. if( cmJsonFinalize(&p->sysJsH) != kOkJsRC )
  469. {
  470. rc = cmErrMsg(&p->err,kJsonFailAdRC,"System JSON tree finalization failed.");
  471. goto errLabel;
  472. }
  473. if( p->sysJsFn != NULL )
  474. cmFsFreeFn(p->sysJsFn);
  475. cmMemFree(p);
  476. errLabel:
  477. return rc;
  478. }
  479. cmAdRC_t cmAudDspAlloc( cmCtx_t* ctx, cmAdH_t* hp, cmMsgSendFuncPtr_t cbFunc, void* cbDataPtr )
  480. {
  481. cmAdRC_t rc = kOkAdRC;
  482. cmAdRC_t rc0 = kOkAdRC;
  483. if((rc = cmAudDspFree(hp)) != kOkAdRC )
  484. return rc;
  485. cmAd_t* p = cmMemAllocZ(cmAd_t,1);
  486. cmErrSetup(&p->err,&ctx->rpt,"Audio DSP Engine");
  487. // form the audio dsp resource file name
  488. if((p->sysJsFn = cmFsMakeFn( cmFsPrefsDir(),cmAudDspSys_FILENAME,NULL,NULL)) == NULL )
  489. {
  490. rc = cmErrMsg(&p->err,kFileSysFailAdRC,"Unable to form the audio dsp system resource file name.");
  491. goto errLabel;
  492. }
  493. // open the audio dsp resource file
  494. if(cmJsonInitializeFromFile(&p->sysJsH,p->sysJsFn,ctx) != kOkJsRC )
  495. {
  496. rc = cmErrMsg(&p->err,kJsonFailAdRC,"Unable to open the audio dsp resource file: '%s'.",cmStringNullGuard(p->sysJsFn));
  497. goto errLabel;
  498. }
  499. // parse the JSON tree
  500. if((rc = _cmAdParseSysJsonTree(p)) != kOkAdRC )
  501. goto errLabel;
  502. // create the aggregate device
  503. if( _cmAdCreateAggDevices(p) != kOkAdRC )
  504. goto errLabel;
  505. // create the non-real-time devices
  506. if( _cmAdCreateNrtDevices(p) != kOkAdRC )
  507. goto errLabel;
  508. // create the audio file devices
  509. if( _cmAdCreateAfpDevices(p) != kOkAdRC )
  510. goto errLabel;
  511. // initialize the audio device system
  512. if( cmApInitialize(&ctx->rpt) != kOkApRC )
  513. {
  514. rc = cmErrMsg(&p->err,kAudioPortFailAdRC,"Audio port intialization failed.");
  515. goto errLabel;
  516. }
  517. // initialize the audio buffer
  518. if( cmApBufInitialize( cmApDeviceCount(), p->meterMs ) != kOkApRC )
  519. {
  520. rc = cmErrMsg(&p->err,kAudioPortFailAdRC,"Audio port buffer initialization failed.");
  521. goto errLabel;
  522. }
  523. // initialize the MIDI system
  524. if( cmMpInitialize(ctx,NULL,NULL,p->midiPortBufByteCnt,"app") != kOkMpRC )
  525. {
  526. rc = cmErrMsg(&p->err,kMidiSysFailAdRC,"The MIDI system initialization failed.");
  527. goto errLabel;
  528. }
  529. // initialize the UDP network - but do not go into 'listening' mode.
  530. if( cmUdpNetAllocJson(ctx,&p->netH,p->sysJsH,_cmAdUdpNetCallback,p,kNetOptionalUnFl) != kOkUnRC )
  531. {
  532. cmErrMsg(&p->err,kNetSysFailAdRC,"The UDP network initialization failed.");
  533. goto errLabel;
  534. }
  535. if((rc = _cmAdSetup(p)) != kOkAdRC )
  536. goto errLabel;
  537. // initialize the DSP system
  538. if( cmDspSysInitialize(ctx,&p->dsH,p->netH) )
  539. {
  540. rc = cmErrMsg(&p->err,kDspSysFailAdRC,"The DSP system initialization failed.");
  541. goto errLabel;
  542. }
  543. // allocate the audio system
  544. if( cmAudioSysAllocate(&p->asH, &ctx->rpt, NULL ) != kOkAsRC )
  545. {
  546. rc = cmErrMsg(&p->err,kAudioSysFailAdRC,"The audio system allocation failed.");
  547. goto errLabel;
  548. }
  549. p->cbFunc = cbFunc;
  550. p->cbDataPtr = cbDataPtr;
  551. p->curAsCfgIdx = cmInvalidIdx;
  552. p->ctx = *ctx;
  553. hp->h = p;
  554. errLabel:
  555. if( rc != kOkAdRC )
  556. rc0 = _cmAudDspFree(p);
  557. return rc == kOkAdRC ? rc0 : rc;
  558. }
  559. cmAdRC_t cmAudDspFree( cmAdH_t* hp )
  560. {
  561. cmAdRC_t rc = kOkAdRC;
  562. if( hp == NULL || cmAudDspIsValid(*hp)==false )
  563. return kOkAdRC;
  564. cmAd_t* p = _cmAdHandleToPtr(*hp);
  565. if((rc = _cmAudDspFree(p)) != kOkAdRC )
  566. return rc;
  567. hp->h = NULL;
  568. return rc;
  569. }
  570. cmAdRC_t cmAudDspSendSetup( cmAdH_t h )
  571. {
  572. cmAdRC_t rc = kOkAdRC;
  573. cmAd_t* p = _cmAdHandleToPtr( h );
  574. // notify the client of the available audio system configurations
  575. if((rc = _cmAdSendAudioSysCfgLabels(p)) != kOkAdRC )
  576. goto errLabel;
  577. // notify the client of the available devices
  578. if((rc = _cmAdSendDeviceLabels(p)) != kOkAdRC)
  579. goto errLabel;
  580. // notify the client of the available programs
  581. if((rc = _cmAdSendProgramLabels(p)) != kOkAdRC )
  582. goto errLabel;
  583. errLabel:
  584. return rc;
  585. }
  586. bool cmAudDspIsValid( cmAdH_t h )
  587. { return h.h != NULL; }
  588. cmAdRC_t _cmAudDspUnloadPgm( cmAd_t* p, unsigned asSubSysIdx )
  589. {
  590. cmAdRC_t rc = kOkAdRC;
  591. const cmAdAsCfg_t* cfgPtr = NULL;
  592. // Must disable audio thread callbacks to _cmAudDspCallback()
  593. // while changing DSP system data structures.
  594. if( cmAudioSysIsEnabled(p->asH) )
  595. if(cmAudioSysEnable(p->asH,false) != kOkAsRC )
  596. {
  597. rc = cmErrMsg(&p->err,kAudioSysFailAdRC,"The audio system could not be disabled.");
  598. goto errLabel;
  599. }
  600. // validate the sub-system index
  601. if( asSubSysIdx >= p->dsSsCnt )
  602. {
  603. rc = cmErrMsg(&p->err,kInvalidSubSysIdxAdRC,"The invalid sub-system index %i was encountered while unloading a program.",asSubSysIdx);
  604. goto errLabel;
  605. }
  606. // if a valid cfg recd exists
  607. if( p->curAsCfgIdx != cmInvalidIdx )
  608. {
  609. // pointer to audio system configuration
  610. cfgPtr = p->asCfgArray + p->curAsCfgIdx;
  611. // count of audio system sub-systems should be the same as the current cfg
  612. assert( p->dsSsCnt == cfgPtr->cfg.ssCnt );
  613. // mark the DSP program as unloaded and pre-sync
  614. p->dsSsArray[ asSubSysIdx ].isLoadedFl = false;
  615. p->dsSsArray[ asSubSysIdx ].isSyncFl = false;
  616. p->syncFl = false;
  617. }
  618. // unload the current program
  619. if( cmDspSysUnload(p->dsSsArray[asSubSysIdx].dsH) != kOkDspRC )
  620. {
  621. rc = cmErrMsg(&p->err,kDspSysFailAdRC,"Program unload failed.");
  622. goto errLabel;
  623. }
  624. errLabel:
  625. return rc;
  626. }
  627. cmAdRC_t _cmAudDspUnloadAudioSys( cmAd_t* p )
  628. {
  629. unsigned i;
  630. cmAdRC_t rc = kOkAdRC;
  631. p->syncFl = false;
  632. for(i=1; i<p->dsSsCnt; ++i)
  633. {
  634. if((rc = _cmAudDspUnloadPgm(p,i)) != kOkAdRC )
  635. goto errLabel;
  636. if( cmDspSysFinalize(&p->dsSsArray[i].dsH) != kOkDspRC )
  637. {
  638. rc = cmErrMsg(&p->err,kDspSysFailAdRC,"DSP system finalization failed.");
  639. goto errLabel;
  640. }
  641. }
  642. p->curAsCfgIdx = cmInvalidIdx;
  643. errLabel:
  644. return rc;
  645. }
  646. cmAdRC_t _cmAdSendIntMsgToHost( cmAd_t* p, unsigned asSubIdx, unsigned selId, unsigned flags, unsigned intValue )
  647. {
  648. cmAdRC_t rc = kOkAdRC;
  649. cmDspValue_t v;
  650. cmDsvSetUInt(&v,intValue);
  651. if( cmMsgSend( &p->err,asSubIdx,kUiSelAsId,selId,flags,cmInvalidId,cmInvalidId,&v,p->cbFunc,p->cbDataPtr) != kOkMsgRC )
  652. rc = cmErrMsg(&p->err,kSendMsgFailAdRC,"Error sending message to host.");
  653. return rc;
  654. }
  655. // verify that a valid audio cfg has been selected
  656. cmAdRC_t _cmAdIsAudioSysLoaded( cmAd_t* p )
  657. {
  658. cmAdRC_t rc = kOkAdRC;
  659. if( cmAudioSysHandleIsValid(p->asH) == false )
  660. {
  661. rc = cmErrMsg(&p->err,kAudioSysFailAdRC,"The audio system is not allocated.");
  662. goto errLabel;
  663. }
  664. if( p->curAsCfgIdx == cmInvalidIdx )
  665. return kInvalidCfgIdxAdRC;
  666. // verify that an audio system is loaded
  667. if( cmAudioSysIsInitialized(p->asH) && p->curAsCfgIdx == cmInvalidIdx )
  668. {
  669. rc = cmErrMsg(&p->err,kInvalidCfgIdxAdRC,"The audio system has not been configured.");
  670. goto errLabel;
  671. }
  672. // count of audio system sub-systems should be the same as the current cfg
  673. assert( p->dsSsCnt == p->asCfgArray[p->curAsCfgIdx].cfg.ssCnt );
  674. errLabel:
  675. return rc;
  676. }
  677. // verify that a valid audio cfg and DSP program has been selected
  678. cmAdRC_t _cmAdIsPgmLoaded( cmAd_t* p, bool verboseFl )
  679. {
  680. cmAdRC_t rc;
  681. // a program cannot be loaded if the audio system has not been configured
  682. if((rc = _cmAdIsAudioSysLoaded(p)) != kOkAdRC )
  683. return rc;
  684. unsigned i;
  685. // for each sub-system
  686. for(i=0; i<p->dsSsCnt; ++i)
  687. {
  688. // verify that the DSP system has been created
  689. if( cmDspSysIsValid(p->dsSsArray[i].dsH) == false )
  690. return cmErrMsg(&p->err,kDspSysFailAdRC,"The DSP sub-system at index %i is not initialized.",i);
  691. // verify that the DSP program was loaded
  692. if( p->dsSsArray[ i ].isLoadedFl == false )
  693. {
  694. if( verboseFl )
  695. cmErrMsg(&p->err,kNoPgmLoadedAdRC,"There is no program loaded.");
  696. return kNoPgmLoadedAdRC;
  697. }
  698. }
  699. return rc;
  700. }
  701. bool _cmAudDspIsPgmSynced( cmAd_t* p )
  702. {
  703. unsigned syncCnt = 0;
  704. unsigned i;
  705. if( p->syncFl )
  706. return true;
  707. // if the pgm is not loaded then it cannot be sync'd
  708. if(_cmAdIsPgmLoaded(p,false) != kOkAdRC )
  709. return false;
  710. // check each sub-system
  711. for(i=0; i<p->dsSsCnt; ++i)
  712. {
  713. unsigned syncState = cmDspSysSyncState(p->dsSsArray[i].dsH);
  714. // if the subsys is already synced
  715. if( p->dsSsArray[i].isSyncFl )
  716. ++syncCnt;
  717. else
  718. {
  719. switch( syncState )
  720. {
  721. // the sub-sys is pre or pending sync mode
  722. case kSyncPreDspId:
  723. case kSyncPendingDspId:
  724. break;
  725. // sync mode completed - w/ success or fail
  726. case kSyncSuccessDspId:
  727. case kSyncFailDspId:
  728. {
  729. // notify the client of the the sync state
  730. bool syncFl = syncState == kSyncSuccessDspId;
  731. _cmAdSendIntMsgToHost(p,cmInvalidIdx,kSyncDuiId,syncFl,cmInvalidIdx);
  732. p->dsSsArray[i].isSyncFl = syncFl;
  733. }
  734. break;
  735. }
  736. }
  737. }
  738. p->syncFl = syncCnt == p->dsSsCnt;
  739. return p->syncFl;
  740. }
  741. cmAdRC_t _cmAudDspLoadPgm( cmAd_t* p, unsigned asSubSysIdx, unsigned pgmIdx )
  742. {
  743. cmAdRC_t rc = kOkAdRC;
  744. unsigned i;
  745. p->syncFl = false;
  746. // the audio system must be configured before a program is loaded
  747. if((rc = _cmAdIsAudioSysLoaded(p)) != kOkAdRC )
  748. return cmErrMsg(&p->err,rc,"The audio system is not configured. Program load failed.");
  749. // validate the sub-system index arg.
  750. if( asSubSysIdx!=cmInvalidIdx && asSubSysIdx >= p->dsSsCnt )
  751. {
  752. rc = cmErrMsg(&p->err,kInvalidSubSysIdxAdRC,"The sub-system index %i is invalid. Program load failed.",asSubSysIdx);
  753. goto errLabel;
  754. }
  755. // for each sub-system
  756. for(i=0; i<p->dsSsCnt; ++i)
  757. if( asSubSysIdx==cmInvalidIdx || i==asSubSysIdx )
  758. {
  759. // unload any currently loaded program on this sub-system
  760. // (unloading a program automatically disables the audio system)
  761. if((rc = _cmAudDspUnloadPgm(p, i )) != kOkAdRC )
  762. goto errLabel;
  763. // load the program
  764. if( cmDspSysLoad(p->dsSsArray[ i ].dsH, cmAudioSysContext(p->asH,i), pgmIdx ) != kOkDspRC )
  765. {
  766. rc = cmErrMsg(&p->err,kDspSysFailAdRC,"The program load failed on audio sub-system %i.",i);
  767. goto errLabel;
  768. }
  769. // update the state of the DSP sub-system
  770. p->dsSsArray[i].curPgmIdx = pgmIdx;
  771. p->dsSsArray[i].isLoadedFl = true;
  772. p->dsSsArray[i].isSyncFl = false;
  773. p->syncFl = false;
  774. // notify the host of the new program
  775. _cmAdSendIntMsgToHost(p,i,kSetPgmDuiId,0,pgmIdx);
  776. }
  777. errLabel:
  778. return rc;
  779. }
  780. cmAdRC_t _cmAudDspPrintPgm( cmAd_t* p, unsigned asSubSysIdx, const cmChar_t* fn )
  781. {
  782. cmAdRC_t rc = kOkAdRC;
  783. unsigned i;
  784. // the audio system must be configured before a program is loaded
  785. if((rc = _cmAdIsAudioSysLoaded(p)) != kOkAdRC )
  786. return cmErrMsg(&p->err,rc,"The audio system is not configured. Program print failed.");
  787. // validate the sub-system index arg.
  788. if( asSubSysIdx!=cmInvalidIdx && asSubSysIdx >= p->dsSsCnt )
  789. {
  790. rc = cmErrMsg(&p->err,kInvalidSubSysIdxAdRC,"The sub-system index %i is invalid. Program print failed.",asSubSysIdx);
  791. goto errLabel;
  792. }
  793. // for each sub-system
  794. for(i=0; i<p->dsSsCnt; ++i)
  795. if( i==asSubSysIdx || asSubSysIdx==cmInvalidIdx )
  796. {
  797. if( cmDspSysPrintPgm(p->dsSsArray[i].dsH,fn) != kOkDspRC )
  798. rc = cmErrMsg(&p->err,kDspSysFailAdRC,"The program print failed.");
  799. break;
  800. }
  801. errLabel:
  802. return rc;
  803. }
  804. cmAdRC_t _cmAdReinitAudioSys( cmAd_t* p )
  805. {
  806. cmAdRC_t rc = kOkAdRC;
  807. p->syncFl = false;
  808. // pointer to the new audio system configuration
  809. cmAdAsCfg_t* cfgPtr = p->asCfgArray + p->curAsCfgIdx;
  810. // initialize the audio system
  811. if( cmAudioSysInitialize(p->asH, &cfgPtr->cfg ) != kOkAsRC )
  812. {
  813. rc = cmErrMsg(&p->err,kAudioSysFailAdRC,"The audio system initialization failed.");
  814. goto errLabel;
  815. }
  816. // reload any currently loaded programs
  817. unsigned i;
  818. for(i=0; i<p->dsSsCnt; ++i)
  819. {
  820. unsigned pgmIdx;
  821. if((pgmIdx = p->dsSsArray[i].curPgmIdx) != cmInvalidIdx )
  822. if((rc = _cmAudDspLoadPgm(p,i,pgmIdx)) != kOkAdRC )
  823. break;
  824. }
  825. errLabel:
  826. return rc;
  827. }
  828. cmAdRC_t _cmAudDspLoadAudioSys( cmAd_t* p, unsigned asCfgIdx )
  829. {
  830. cmAdRC_t rc = kOkAdRC;
  831. cmAdAsCfg_t* cfgPtr;
  832. unsigned i;
  833. // validate asCfgIdx
  834. if( asCfgIdx >= p->asCfgCnt )
  835. {
  836. cmErrMsg(&p->err,kInvalidCfgIdxAdRC,"The audio system index %i is invalid.",asCfgIdx);
  837. goto errLabel;
  838. }
  839. // clear the current audio system setup - this will automatically disable the audio system
  840. if((rc = _cmAudDspUnloadAudioSys(p)) != kOkAdRC )
  841. goto errLabel;
  842. // pointer to the new audio system configuration
  843. cfgPtr = p->asCfgArray + asCfgIdx;
  844. // get the count of audio system sub-systems
  845. p->dsSsCnt = cfgPtr->cfg.ssCnt;
  846. // store the index of the current audio system configuration
  847. p->curAsCfgIdx = asCfgIdx;
  848. if( p->dsSsCnt > 0 )
  849. {
  850. p->dsSsArray = cmMemResizeZ(cmAdDsSubSys_t, p->dsSsArray, p->dsSsCnt );
  851. for(i=0; i<p->dsSsCnt; ++i)
  852. {
  853. cmDspSysH_t dsH;
  854. // the first sub-system will always use the existing DSP system handle ...
  855. if( i==0 )
  856. dsH = p->dsH;
  857. else
  858. {
  859. // ... and allocate additional DSP systems when more than one sub-sys is
  860. // defined in the audio system configuration
  861. if( cmDspSysInitialize(&p->ctx,&dsH,p->netH) != kOkDspRC )
  862. {
  863. rc = cmErrMsg(&p->err,kDspSysFailAdRC,"Unable to initialize an additional DSP system.");
  864. goto errLabel;
  865. }
  866. }
  867. p->dsSsArray[i].dsH = dsH;
  868. p->dsSsArray[i].curPgmIdx = cmInvalidIdx;
  869. p->dsSsArray[i].isLoadedFl= false;
  870. // this cbDataPtr is picked up in _cmAudDspCallback().
  871. // It is used to connect the audio system to a DSP system handle.
  872. cfgPtr->cfg.ssArray[i].cbDataPtr = p->dsSsArray + i;
  873. }
  874. }
  875. // notify the client of the change of audio configuration
  876. _cmAdSendIntMsgToHost(p,cmInvalidIdx,kSetAudioCfgDuiId,0,asCfgIdx);
  877. // notify the client of the count of audio sub-systems
  878. _cmAdSendIntMsgToHost(p,cmInvalidIdx,kSubSysCntDuiId,0,p->dsSsCnt);
  879. // for each sub-system
  880. for(i=0; i<p->dsSsCnt; ++i)
  881. {
  882. // notify the client of the currently selected devices
  883. _cmAdSendIntMsgToHost(p,i,kSetAudioDevDuiId,true, cfgPtr->cfg.ssArray[i].args.inDevIdx);
  884. _cmAdSendIntMsgToHost(p,i,kSetAudioDevDuiId,false,cfgPtr->cfg.ssArray[i].args.outDevIdx);
  885. // notify the client of the sample rate
  886. _cmAdSendIntMsgToHost(p,i,kSetSampleRateDuiId,0,(unsigned)cfgPtr->cfg.ssArray[i].args.srate);
  887. _cmAdSendIntMsgToHost(p,i,kSetPgmDuiId,0,cmInvalidIdx);
  888. }
  889. // the audio system configuration changed so we need to initialize the audio system
  890. if((rc = _cmAdReinitAudioSys(p)) != kOkAdRC )
  891. goto errLabel;
  892. errLabel:
  893. if( rc != kOkAdRC )
  894. _cmAudDspUnloadAudioSys(p);
  895. return rc;
  896. }
  897. cmAdRC_t _cmAudDspEnableAudio( cmAd_t* p, bool enableFl )
  898. {
  899. cmAdRC_t rc = kOkAdRC;
  900. if( enableFl )
  901. {
  902. // verify an audio system cfg and DSP program has been selected
  903. if(( rc = _cmAdIsPgmLoaded(p,true)) != kOkAdRC )
  904. return cmErrMsg(&p->err,rc,"Audio enable failed.");
  905. // if the audio system is already enabled/disabled then do nothing
  906. if( cmAudioSysIsEnabled(p->asH) == enableFl )
  907. return kOkAdRC;
  908. // for each sub-system
  909. unsigned i;
  910. for(i=0; i<p->dsSsCnt; ++i)
  911. {
  912. if( cmDspSysReset(p->dsSsArray[i].dsH) != kOkDspRC )
  913. {
  914. rc = cmErrMsg(&p->err,kDspSysFailAdRC,"The DSP system reset failed.");
  915. goto errLabel;
  916. }
  917. }
  918. }
  919. // start/stop the audio sub-system
  920. if( cmAudioSysEnable(p->asH,enableFl) != kOkAsRC )
  921. {
  922. rc = cmErrMsg(&p->err,kAudioSysFailAdRC,"The audio system %s failed.", enableFl ? "enable" : "disable");
  923. goto errLabel;
  924. }
  925. // notify the host of the new enable state
  926. _cmAdSendIntMsgToHost(p,cmInvalidIdx,kEnableDuiId,enableFl,cmInvalidIdx);
  927. errLabel:
  928. return rc;
  929. }
  930. cmAdRC_t _cmAudDspSetDevice(cmAd_t* p,unsigned asSubIdx, bool inputFl, unsigned devIdx)
  931. {
  932. cmAdRC_t rc;
  933. // a device cannot be set if the audio system is not already configured
  934. if((rc = _cmAdIsAudioSysLoaded(p)) != kOkAdRC )
  935. return cmErrMsg(&p->err,rc,"Set audio device failed.");
  936. cmAdAsCfg_t* cfgPtr = p->asCfgArray + p->curAsCfgIdx;
  937. // validate the sub-system index
  938. if( asSubIdx >= p->dsSsCnt )
  939. {
  940. rc = cmErrMsg(&p->err,kInvalidSubSysIdxAdRC,"The sub-system index %i is invalid.",asSubIdx);
  941. goto errLabel;
  942. }
  943. // assign the new device index to the indicated audio system configuration recd
  944. if( inputFl )
  945. {
  946. if( cfgPtr->cfg.ssArray[ asSubIdx ].args.inDevIdx != devIdx )
  947. cfgPtr->cfg.ssArray[ asSubIdx ].args.inDevIdx = devIdx;
  948. }
  949. else
  950. {
  951. if( cfgPtr->cfg.ssArray[ asSubIdx ].args.outDevIdx != devIdx )
  952. cfgPtr->cfg.ssArray[ asSubIdx ].args.outDevIdx = devIdx;
  953. }
  954. // notify the host that the new device has been set
  955. _cmAdSendIntMsgToHost(p,asSubIdx,kSetAudioDevDuiId,inputFl, devIdx);
  956. // reinitialize the audio system
  957. rc = _cmAdReinitAudioSys(p);
  958. errLabel:
  959. return rc;
  960. }
  961. cmAdRC_t _cmAudDspSetSampleRate(cmAd_t* p, unsigned asSubIdx, double srate )
  962. {
  963. cmAdRC_t rc;
  964. if((rc = _cmAdIsAudioSysLoaded(p)) != kOkAdRC )
  965. return cmErrMsg(&p->err,rc,"Set audio device failed.");
  966. cmAdAsCfg_t* cfgPtr = p->asCfgArray + p->curAsCfgIdx;
  967. // validate the sub-system index
  968. if( asSubIdx != cmInvalidIdx && asSubIdx >= p->dsSsCnt )
  969. {
  970. rc = cmErrMsg(&p->err,kInvalidSubSysIdxAdRC,"The sub-system index %i is invalid.",asSubIdx);
  971. goto errLabel;
  972. }
  973. unsigned i;
  974. for(i=0; i<p->dsSsCnt; ++i)
  975. {
  976. // assign the new device index to the indicated audio system configuration recd
  977. if( asSubIdx==cmInvalidIdx || asSubIdx == i )
  978. {
  979. if( cfgPtr->cfg.ssArray[ i ].args.srate != srate )
  980. cfgPtr->cfg.ssArray[ i ].args.srate = srate;
  981. }
  982. }
  983. // notify the client of the new sample rate
  984. _cmAdSendIntMsgToHost(p,asSubIdx,kSetSampleRateDuiId,0,(unsigned)srate);
  985. // reinitialize the audio system
  986. rc = _cmAdReinitAudioSys(p);
  987. errLabel:
  988. return rc;
  989. }
  990. cmAdRC_t _cmAudDspClientMsgPoll( cmAd_t* p )
  991. {
  992. unsigned i = 0;
  993. // if the program is not synced then don't bother polling the audio system
  994. if( _cmAudDspIsPgmSynced(p) == false )
  995. return kOkAdRC;
  996. for(i=0; i<p->msgsPerClientPoll; ++i)
  997. {
  998. if( cmAudioSysIsMsgWaiting(p->asH) == 0 )
  999. break;
  1000. if(cmAudioSysReceiveMsg(p->asH,NULL,0) != kOkAsRC )
  1001. return cmErrMsg(&p->err,kAudioSysFailAdRC,"The delivery of an audio system msg for the client failed.");
  1002. }
  1003. return kOkAdRC;
  1004. }
  1005. cmAdRC_t cmAudDspReceiveClientMsg( cmAdH_t h, unsigned msgByteCnt, const void* msg )
  1006. {
  1007. cmAdRC_t rc = kOkAdRC;
  1008. cmAd_t* p = _cmAdHandleToPtr(h);
  1009. cmDspUiHdr_t* m = (cmDspUiHdr_t*)msg;
  1010. /*
  1011. if( m->uiId != kUiSelAsId )
  1012. {
  1013. rc = cmErrMsg(&p->err,kUnknownMsgTypeAdRC,"The message type %i is unknown.");
  1014. goto errLabel;
  1015. }
  1016. */
  1017. switch( m->selId )
  1018. {
  1019. case kDevReportDuiId:
  1020. cmRptPrintf(p->err.rpt,"\nAUDIO DEVICES\n");
  1021. cmApReport(p->err.rpt);
  1022. cmRptPrintf(p->err.rpt,"\nMIDI DEVICES\n");
  1023. cmMpReport(p->err.rpt);
  1024. break;
  1025. case kSetAudioCfgDuiId:
  1026. rc = _cmAudDspLoadAudioSys(p,cmDsvUInt(&m->value));
  1027. break;
  1028. case kSetPgmDuiId:
  1029. rc = _cmAudDspLoadPgm(p,m->asSubIdx,cmDsvUInt(&m->value));
  1030. break;
  1031. case kSetAudioDevDuiId:
  1032. rc = _cmAudDspSetDevice(p,m->asSubIdx,m->flags,cmDsvUInt(&m->value));
  1033. break;
  1034. case kSetSampleRateDuiId:
  1035. rc = _cmAudDspSetSampleRate(p,m->asSubIdx,cmDsvDouble(&m->value));
  1036. break;
  1037. case kEnableDuiId:
  1038. rc = _cmAudDspEnableAudio(p,m->flags);
  1039. break;
  1040. case kSetNotifyEnableDuiId:
  1041. cmAudioSysStatusNotifyEnable(p->asH, cmInvalidIdx, m->flags );
  1042. break;
  1043. case kClientMsgPollDuiId:
  1044. rc = _cmAudDspClientMsgPoll(p);
  1045. break;
  1046. case kPrintPgmDuiId:
  1047. _cmAudDspPrintPgm(p,m->asSubIdx,cmDsvStrcz(&m->value));
  1048. break;
  1049. default:
  1050. if( cmAudioSysDeliverMsg(p->asH,msg,msgByteCnt,cmInvalidId) != kOkAsRC )
  1051. rc = cmErrMsg(&p->err,kSendMsgFailAdRC,"Message delivery to the audio system failed.");
  1052. break;
  1053. }
  1054. // errLabel:
  1055. return rc;
  1056. }