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

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