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 33KB

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