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

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