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

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