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

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