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.

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