libcm is a C development framework with an emphasis on audio signal processing applications.
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

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. }