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.

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