libcm is a C development framework with an emphasis on audio signal processing applications.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

cmDevCfg.c 39KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542
  1. #include "cmGlobal.h"
  2. #include "cmFloatTypes.h"
  3. #include "cmRpt.h"
  4. #include "cmErr.h"
  5. #include "cmCtx.h"
  6. #include "cmMem.h"
  7. #include "cmMallocDebug.h"
  8. #include "cmLinkedHeap.h"
  9. #include "cmFileSys.h"
  10. #include "cmJson.h"
  11. #include "cmText.h"
  12. #include "cmThread.h"
  13. #include "cmMidi.h"
  14. #include "cmMidiPort.h"
  15. #include "cmAudioPort.h"
  16. #include "cmUdpPort.h"
  17. #include "cmUdpNet.h"
  18. #include "cmRtSysMsg.h"
  19. #include "cmRtSys.h"
  20. #include "cmDevCfg.h"
  21. cmDevCfgH_t cmDevCfgNullHandle = cmSTATIC_NULL_HANDLE;
  22. typedef struct cmDcmCfg_str
  23. {
  24. cmChar_t* dcLabelStr; // the cfg label
  25. unsigned cfgId; // unique among all cfg's assigned to a loc
  26. cmTypeDcmId_t typeId; // the cfg type id (e.g. midi, audio, net, ...)
  27. cmChar_t* descStr; // summary description string
  28. // NOTE: any fields added to this structure, type generic (above)
  29. // or type specific (below), must be explicitely duplicated in cmDevCfgLocStore().
  30. union
  31. {
  32. cmDcmMidi_t m;
  33. cmDcmAudio_t a;
  34. cmDcmNet_t n;
  35. } u;
  36. struct cmDcmCfg_str* next;
  37. struct cmDcmCfg_str* prev;
  38. } cmDcmCfg_t;
  39. typedef struct
  40. {
  41. cmTypeDcmId_t tid; // Type Id for this map or tInvalidDcmTId if the record is not active.
  42. unsigned cfgId; // cfgId of the cfg recd assoc'd with this map
  43. cmDcmCfg_t* cfg; // pointer to the cfg recd assoc'd with this map (cfg->cfgId == cmDcmMap_t.cfgId)
  44. } cmDcmMap_t;
  45. typedef struct
  46. {
  47. bool activeFl;
  48. cmDcmMap_t* map;
  49. unsigned mapCnt;
  50. } cmDcmApp_t;
  51. typedef struct cmDcmLoc_str
  52. {
  53. cmChar_t* labelStr;
  54. cmDcmApp_t* app;
  55. unsigned appCnt;
  56. cmDcmCfg_t* cfg;
  57. struct cmDcmLoc_str* next;
  58. struct cmDcmLoc_str* prev;
  59. } cmDcmLoc_t;
  60. typedef struct
  61. {
  62. cmErr_t err;
  63. cmCtx_t* ctx;
  64. cmDcmLoc_t* loc;
  65. cmDcmLoc_t* clp;
  66. cmChar_t* fn;
  67. } cmDcm_t;
  68. cmDcm_t* _cmDcmHandleToPtr( cmDevCfgH_t h )
  69. {
  70. cmDcm_t* p = (cmDcm_t*)h.h;
  71. assert( p!=NULL );
  72. return p;
  73. }
  74. const cmChar_t* _cmDcmTrimLabel( cmDcm_t*p, const cmChar_t* s, const cmChar_t* title )
  75. {
  76. if( s == NULL )
  77. {
  78. cmErrMsg(&p->err,kBlankLabelDcRC,"A blank '%s' label was encountered.",title);
  79. return NULL;
  80. }
  81. while( *s && isspace(*s) )
  82. ++s;
  83. if( strlen(s) == 0 )
  84. {
  85. cmErrMsg(&p->err,kBlankLabelDcRC,"An empty '%s' label was encountered.",title);
  86. return NULL;
  87. }
  88. return s;
  89. }
  90. void _cmDcmFreeMidi( cmDcmMidi_t* r )
  91. {
  92. cmMemFree(r->devLabelStr);
  93. cmMemFree(r->portLabelStr);
  94. }
  95. void _cmDcmDuplMidi( cmDcmMidi_t* d, const cmDcmMidi_t* s )
  96. {
  97. d->devLabelStr = cmMemAllocStr(s->devLabelStr);
  98. d->portLabelStr = cmMemAllocStr(s->portLabelStr);
  99. d->inputFl = s->inputFl;
  100. d->devIdx = s->devIdx;
  101. d->portIdx = s->portIdx;
  102. }
  103. void _cmDcmFreeAudio( cmDcmAudio_t* r )
  104. {
  105. cmMemFree(r->inDevLabelStr);
  106. cmMemFree(r->outDevLabelStr);
  107. }
  108. void _cmDcmDuplAudio( cmDcmAudio_t* d, const cmDcmAudio_t* s )
  109. {
  110. d->inDevLabelStr = cmMemAllocStr(s->inDevLabelStr);
  111. d->outDevLabelStr = cmMemAllocStr(s->outDevLabelStr);
  112. d->rtSysArgs = s->rtSysArgs;
  113. }
  114. void _cmDcmFreeNet( cmDcmNet_t* r )
  115. {
  116. cmMemFree(r->sockAddr);
  117. }
  118. void _cmDcmDuplNet( cmDcmNet_t* d, const cmDcmNet_t* s )
  119. {
  120. d->sockAddr = cmMemAllocStr(s->sockAddr);
  121. d->portNumber = s->portNumber;
  122. d->localFl = s->localFl;
  123. d->activeFl = s->activeFl;
  124. }
  125. void _cmDcmFreeCfg( cmDcm_t* p, cmDcmLoc_t* lp, cmDcmCfg_t* cp )
  126. {
  127. // unlink the cfg recd
  128. if( cp->prev == NULL )
  129. lp->cfg = cp->next;
  130. else
  131. cp->prev->next = cp->next;
  132. if( cp->next != NULL )
  133. cp->next->prev = cp->prev;
  134. cmMemFree(cp->dcLabelStr);
  135. cmMemFree(cp->descStr);
  136. switch( cp->typeId )
  137. {
  138. case kMidiDcmTId: _cmDcmFreeMidi(&cp->u.m); break;
  139. case kAudioDcmTId: _cmDcmFreeAudio(&cp->u.a); break;
  140. case kNetDcmTId: _cmDcmFreeNet(&cp->u.n); break;
  141. default:
  142. assert(0);
  143. break;
  144. }
  145. cmMemFree(cp);
  146. }
  147. void _cmDcmFreeLoc( cmDcm_t* p, cmDcmLoc_t* lp )
  148. {
  149. unsigned i;
  150. // unlink the loc recd
  151. if( lp->prev == NULL )
  152. p->loc = lp->next;
  153. else
  154. lp->prev->next = lp->next;
  155. if( lp->next != NULL )
  156. lp->next->prev = lp->prev;
  157. // free each app
  158. for(i=0; i<lp->appCnt; ++i)
  159. cmMemFree(lp->app[i].map);
  160. cmMemFree(lp->app);
  161. cmMemFree(lp->labelStr);
  162. while( lp->cfg != NULL )
  163. _cmDcmFreeCfg(p,lp,lp->cfg);
  164. cmMemFree(lp);
  165. }
  166. void _cmDcmFreeAllLocs( cmDcm_t* p )
  167. {
  168. while( p->loc != NULL )
  169. _cmDcmFreeLoc(p,p->loc);
  170. p->clp = NULL;
  171. }
  172. cmDcRC_t _cmDcmFree( cmDcm_t* p )
  173. {
  174. cmDcRC_t rc = kOkDcRC;
  175. _cmDcmFreeAllLocs(p);
  176. cmMemFree(p->fn);
  177. cmMemFree(p);
  178. return rc;
  179. }
  180. cmDcmLoc_t* _cmDcmFindLoc( cmDcm_t* p, const cmChar_t* labelStr )
  181. {
  182. cmDcmLoc_t* lp = p->loc;
  183. for(; lp!=NULL; lp=lp->next)
  184. if(strcmp(lp->labelStr,labelStr) == 0)
  185. return lp;
  186. return NULL;
  187. }
  188. cmDcRC_t _cmDcmNewLoc( cmDcm_t* p, const cmChar_t* labelStr, cmDcmLoc_t** locRef)
  189. {
  190. cmDcmLoc_t* lp;
  191. assert(locRef != NULL);
  192. *locRef = NULL;
  193. // verify and condition the label
  194. if((labelStr = _cmDcmTrimLabel(p,labelStr,"location")) == NULL )
  195. return cmErrLastRC(&p->err);
  196. // verify that the label is not already in use
  197. if((lp = _cmDcmFindLoc(p,labelStr)) != NULL )
  198. return cmErrMsg(&p->err,kDuplLabelDcRC,"The location label '%s' is already in use.",labelStr);
  199. // create a new loc recd
  200. lp = cmMemAllocZ(cmDcmLoc_t,1);
  201. lp->labelStr = cmMemAllocStr(labelStr);
  202. // if the cur loc is not current set - then prepend loc
  203. if( p->clp == NULL )
  204. {
  205. lp->prev = NULL;
  206. lp->next = p->loc;
  207. if( p->loc == NULL )
  208. p->loc = lp;
  209. else
  210. p->loc->prev = lp;
  211. }
  212. else // otherwise insert loc after the cur loc
  213. {
  214. lp->prev = p->clp;
  215. lp->next = p->clp->next;
  216. if( p->clp->next != NULL )
  217. p->clp->next->prev = lp;
  218. p->clp->next = lp;
  219. }
  220. // make the new loc the current loc
  221. p->clp = lp;
  222. *locRef = lp;
  223. return kOkDcRC;
  224. }
  225. cmDcRC_t _cmDevCfgRead( cmDcm_t* p, cmJsonH_t jsH, const cmJsonNode_t* rootObjPtr );
  226. cmDcRC_t _cmDevCfgReadFile( cmDcm_t* p, const cmChar_t* fn )
  227. {
  228. cmDcRC_t rc = kOkDcRC;
  229. cmJsonH_t jsH = cmJsonNullHandle;
  230. // initialize the JSON tree from the preferences file
  231. if( cmJsonInitializeFromFile( &jsH, fn, p->ctx ) != kOkJsRC )
  232. {
  233. rc = cmErrMsg(&p->err,kJsonFailDcRC,"JSON initialization from '%s' failed.",cmStringNullGuard(fn));
  234. goto errLabel;
  235. }
  236. if((rc = _cmDevCfgRead(p, jsH, cmJsonRoot(jsH))) != kOkJsRC )
  237. goto errLabel;
  238. errLabel:
  239. if( cmJsonFinalize(&jsH) != kOkJsRC )
  240. cmErrMsg(&p->err,kJsonFailDcRC,"JSON finalization failed following dev cfg read.");
  241. return rc;
  242. }
  243. cmDcRC_t cmDevCfgAlloc( cmCtx_t* c, cmDevCfgH_t* hp, const cmChar_t* fn )
  244. {
  245. cmDcRC_t rc;
  246. cmDcmLoc_t* lp;
  247. if((rc = cmDevCfgFree(hp)) != kOkDcRC )
  248. return rc;
  249. cmDcm_t* p = cmMemAllocZ(cmDcm_t,1);
  250. cmErrSetup(&p->err,&c->rpt,"cmDevCfg");
  251. p->ctx = c;
  252. if( fn != NULL )
  253. {
  254. p->fn = cmMemAllocStr(fn);
  255. if( cmFsIsFile(fn) )
  256. {
  257. // if the file read fails then reset and go with the default empty setup.
  258. if(_cmDevCfgReadFile(p,fn) != kOkDcRC )
  259. _cmDcmFreeAllLocs(p);
  260. }
  261. }
  262. // if the location array is empty then create a default location
  263. if( p->loc == NULL )
  264. {
  265. if((rc = _cmDcmNewLoc(p,"Default", &lp)) != kOkDcRC )
  266. goto errLabel;
  267. }
  268. hp->h = p;
  269. errLabel:
  270. if( rc != kOkDcRC )
  271. _cmDcmFree(p);
  272. return rc;
  273. }
  274. cmDcRC_t cmDevCfgFree( cmDevCfgH_t* hp )
  275. {
  276. cmDcRC_t rc = kOkDcRC;
  277. if( hp == NULL || cmDevCfgIsValid(*hp) == false )
  278. return rc;
  279. cmDcm_t* p = _cmDcmHandleToPtr(*hp);
  280. if((rc = _cmDcmFree(p)) != kOkDcRC )
  281. return rc;
  282. hp->h = NULL;
  283. return rc;
  284. }
  285. bool cmDevCfgIsValid( cmDevCfgH_t h )
  286. { return h.h != NULL; }
  287. unsigned cmDevCfgCount( cmDevCfgH_t h, cmTypeDcmId_t typeId )
  288. {
  289. unsigned n = 0;
  290. cmDcm_t* p = _cmDcmHandleToPtr(h);
  291. assert( p->clp != NULL);
  292. const cmDcmCfg_t* cp = p->clp->cfg;
  293. for(; cp!= NULL; cp=cp->next)
  294. if( cp->typeId == typeId )
  295. ++n;
  296. return n;
  297. }
  298. cmDcmCfg_t* _cmDevCfgIndexToPtr( cmDcm_t* p, cmTypeDcmId_t typeId, unsigned index, bool errFl )
  299. {
  300. unsigned n = 0;
  301. assert( p->clp != NULL);
  302. cmDcmCfg_t* cp = p->clp->cfg;
  303. for(; cp!= NULL; cp=cp->next)
  304. if( cp->typeId == typeId )
  305. {
  306. if( n == index )
  307. return cp;
  308. ++n;
  309. }
  310. if( errFl )
  311. cmErrMsg(&p->err,kInvalidCfgIdxDcRC,"The cfg index %i is not valid in location '%s'.",cmStringNullGuard(p->clp->labelStr));
  312. return NULL;
  313. }
  314. const cmChar_t* cmDevCfgLabel( cmDevCfgH_t h, cmTypeDcmId_t typeId, unsigned index )
  315. {
  316. cmDcm_t* p = _cmDcmHandleToPtr(h);
  317. cmDcmCfg_t* cp;
  318. if((cp = _cmDevCfgIndexToPtr(p,typeId,index,false)) == NULL )
  319. return NULL;
  320. return cp->dcLabelStr;
  321. }
  322. const cmChar_t* cmDevCfgDesc( cmDevCfgH_t h, cmTypeDcmId_t typeId, unsigned index )
  323. {
  324. cmDcm_t* p = _cmDcmHandleToPtr(h);
  325. cmDcmCfg_t* cp;
  326. if((cp = _cmDevCfgIndexToPtr(p,typeId,index,false)) == NULL )
  327. return NULL;
  328. return cp->descStr;
  329. }
  330. cmDcmCfg_t* _cmDcmCfgLabelToPtr( cmDcm_t* p, cmTypeDcmId_t typeId, const cmChar_t* label, bool errFl )
  331. {
  332. assert( p->clp != NULL);
  333. cmDcmCfg_t* cp = p->clp->cfg;
  334. for(; cp!= NULL; cp=cp->next)
  335. if( cp->typeId == typeId )
  336. {
  337. if( strcmp(cp->dcLabelStr,label) == 0 )
  338. return cp;
  339. }
  340. if( errFl )
  341. cmErrMsg(&p->err,kLabelNotFoundDcRC, "The cfg label '%s' was not found.",cmStringNullGuard(label));
  342. return NULL;
  343. }
  344. unsigned cmDevCfgLabelToIndex( cmDevCfgH_t h, cmTypeDcmId_t typeId, const cmChar_t* label )
  345. {
  346. unsigned n = 0;
  347. cmDcm_t* p = _cmDcmHandleToPtr(h);
  348. assert( p->clp != NULL);
  349. const cmDcmCfg_t* cp = p->clp->cfg;
  350. for(; cp!= NULL; cp=cp->next)
  351. if( cp->typeId == typeId )
  352. {
  353. if( strcmp(cp->dcLabelStr,label) == 0 )
  354. return n;
  355. ++n;
  356. }
  357. return cmInvalidIdx;
  358. }
  359. cmDcmCfg_t* _cmDcmFindOrCreateCfg( cmDcm_t* p, cmTypeDcmId_t typeId, const cmChar_t* dcLabelStr )
  360. {
  361. assert( p->clp != NULL );
  362. cmDcmCfg_t* cp;
  363. // validate the label
  364. if( (dcLabelStr=_cmDcmTrimLabel(p,dcLabelStr,"cfg")) == NULL )
  365. return NULL;
  366. // if the cfg recd already exists then return it
  367. if((cp = _cmDcmCfgLabelToPtr(p, typeId, dcLabelStr, false )) != NULL )
  368. return cp;
  369. unsigned newCfgId = 0;
  370. // use ep to track the end of the list
  371. cmDcmCfg_t* ep = NULL;
  372. // find the max cfgId used by this loc
  373. cp = p->clp->cfg;
  374. for(; cp!=NULL; cp=cp->next)
  375. {
  376. if( cp->cfgId > newCfgId )
  377. newCfgId = cp->cfgId;
  378. ep = cp;
  379. }
  380. // add one to the max cfgId to create a unique cfgId
  381. newCfgId += 1;
  382. // allocate a new cfg recd
  383. cp = cmMemAllocZ(cmDcmCfg_t,1);
  384. cp->dcLabelStr = cmMemAllocStr(dcLabelStr);
  385. cp->cfgId = newCfgId;
  386. cp->typeId = typeId;
  387. // link to the end of the loc's cfg list
  388. if( ep == NULL )
  389. p->clp->cfg = cp;
  390. else
  391. {
  392. ep->next = cp;
  393. cp->prev = ep;
  394. }
  395. return cp;
  396. }
  397. void _cmDcmDisconnectMap( cmDcmMap_t* mp )
  398. {
  399. mp->tid = kInvalidDcmTId;
  400. mp->cfgId = cmInvalidId;
  401. mp->cfg = NULL;
  402. }
  403. cmDcRC_t cmDevCfgDeleteCfg( cmDevCfgH_t h, cmTypeDcmId_t typeId, const cmChar_t* dcLabelStr )
  404. {
  405. cmDcmCfg_t* cp;
  406. cmDcm_t* p = _cmDcmHandleToPtr(h);
  407. unsigned i,j;
  408. // locate the cfg to delete
  409. if((cp = _cmDcmCfgLabelToPtr(p,typeId,dcLabelStr,true)) == NULL )
  410. return cmErrLastRC(&p->err);
  411. // for every app in the current location ...
  412. for(i=0; i<p->clp->appCnt; ++i)
  413. {
  414. cmDcmApp_t* ap = p->clp->app + i;
  415. // ... disconnect any maps to this cfg
  416. if( ap->activeFl && ap->map != NULL )
  417. for(j=0; j<ap->mapCnt; ++j)
  418. if( ap->map[j].cfgId == cp->cfgId )
  419. _cmDcmDisconnectMap(ap->map + j );
  420. }
  421. // unlink and release the cfg recd
  422. _cmDcmFreeCfg(p,p->clp,cp);
  423. return kOkDcRC;
  424. }
  425. cmDcRC_t cmDevCfgCreateMap( cmDevCfgH_t h, cmTypeDcmId_t typeId, const cmChar_t* dcLabelStr, unsigned usrAppId, unsigned usrMapId )
  426. {
  427. cmDcRC_t rc = kOkDcRC;
  428. cmDcm_t* p = _cmDcmHandleToPtr(h);
  429. cmDcmCfg_t* cp;
  430. // locate the cfg to map to
  431. if((cp = _cmDcmCfgLabelToPtr(p,typeId,dcLabelStr,true)) == NULL )
  432. return cmErrLastRC(&p->err);
  433. // if usrAppId references a new app
  434. if( usrAppId >= p->clp->appCnt )
  435. {
  436. p->clp->appCnt = usrAppId + 1;
  437. p->clp->app = cmMemResizePZ(cmDcmApp_t,p->clp->app,p->clp->appCnt);
  438. }
  439. cmDcmApp_t* ap = p->clp->app + usrAppId;
  440. // if usrMapId ref's a new map
  441. if( usrMapId >= ap->mapCnt )
  442. {
  443. ap->mapCnt = usrMapId+1;
  444. ap->map = cmMemResizePZ(cmDcmMap_t,ap->map,ap->mapCnt);
  445. }
  446. cmDcmMap_t* mp = ap->map + usrMapId;
  447. mp->tid = typeId;
  448. mp->cfgId = cp->cfgId;
  449. mp->cfg = cp;
  450. return rc;
  451. }
  452. cmDcmMap_t* _cmDcmFindMap( cmDcm_t* p, cmTypeDcmId_t typeId, unsigned usrAppId, unsigned usrMapId, bool activeFl )
  453. {
  454. if( usrAppId >= p->clp->appCnt )
  455. {
  456. cmErrMsg(&p->err,kInvalidUserAppIdRC,"The user app. id %i is out of range %i in location '%s'.",usrAppId,p->clp->appCnt,cmStringNullGuard(p->clp->labelStr));
  457. goto errLabel;
  458. }
  459. cmDcmApp_t* ap = p->clp->app + usrAppId;
  460. if( usrMapId >= ap->mapCnt )
  461. {
  462. cmErrMsg(&p->err,kInvalidUserMapIdRC,"The user map id %i is out of range %i in location '%s'.",usrMapId,ap->mapCnt,cmStringNullGuard(p->clp->labelStr));
  463. goto errLabel;
  464. }
  465. if( activeFl && (ap->map[usrMapId].tid == kInvalidDcmTId || ap->map[usrMapId].cfg == NULL))
  466. {
  467. cmErrMsg(&p->err,kInvalidUserMapIdRC,"The user map id %i inactive in location '%s'.",usrMapId,cmStringNullGuard(p->clp->labelStr));
  468. goto errLabel;
  469. }
  470. return ap->map + usrMapId;
  471. errLabel:
  472. return NULL;
  473. }
  474. cmDcRC_t cmDevCfgDeleteMap( cmDevCfgH_t h, cmTypeDcmId_t typeId, unsigned usrAppId, unsigned usrMapId )
  475. {
  476. cmDcm_t* p = _cmDcmHandleToPtr(h);
  477. cmDcmMap_t* mp;
  478. if((mp = _cmDcmFindMap(p,typeId,usrAppId,usrMapId,false)) == NULL )
  479. return cmErrLastRC(&p->err);
  480. _cmDcmDisconnectMap( mp );
  481. return kOkDcRC;
  482. }
  483. cmDcRC_t cmDevCfgNameMidiPort(
  484. cmDevCfgH_t h,
  485. const cmChar_t* dcLabelStr,
  486. const cmChar_t* devLabelStr,
  487. const cmChar_t* portLabelStr,
  488. bool inputFl )
  489. {
  490. cmDcm_t* p = _cmDcmHandleToPtr(h);
  491. cmDcmCfg_t* cp;
  492. unsigned midiDevIdx;
  493. unsigned midiPortIdx;
  494. // validate the label
  495. if((dcLabelStr = _cmDcmTrimLabel(p,dcLabelStr,"MIDI cfg")) == NULL)
  496. return cmErrLastRC(&p->err);
  497. // verify that the device label is valid
  498. if((midiDevIdx = cmMpDeviceNameToIndex( devLabelStr )) == cmInvalidIdx )
  499. return cmErrMsg(&p->err, kInvalidArgDcRC,"The MIDI device name '%s' is not valid.",devLabelStr);
  500. // verify that the port label is valid
  501. if((midiPortIdx = cmMpDevicePortNameToIndex( midiDevIdx, inputFl ? kInMpFl : kOutMpFl, portLabelStr )) == cmInvalidIdx )
  502. return cmErrMsg(&p->err, kInvalidArgDcRC,"The MIDI port name '%s' is not valid on the device '%s'.",portLabelStr,devLabelStr);
  503. // if dcLabelStr is already in use for this location and type then update
  504. // the assoc'd recd otherwise create a new one.
  505. if((cp = _cmDcmFindOrCreateCfg(p,kMidiDcmTId, dcLabelStr)) == NULL )
  506. return cmErrLastRC(&p->err);
  507. cp->u.m.label = cp->dcLabelStr;
  508. cp->u.m.devLabelStr = cmMemResizeStr(cp->u.m.devLabelStr,devLabelStr);
  509. cp->u.m.portLabelStr = cmMemResizeStr(cp->u.m.portLabelStr,portLabelStr);
  510. cp->u.m.inputFl = inputFl;
  511. cp->u.m.devIdx = midiDevIdx;
  512. cp->u.m.portIdx = midiPortIdx;
  513. cp->descStr = cmTsPrintfP(cp->descStr,"%s %s %s",inputFl?"Input":"Output",devLabelStr,portLabelStr);
  514. return kOkDcRC;
  515. }
  516. const cmDcmMidi_t* cmDevCfgMidiCfg( cmDevCfgH_t h, unsigned cfgIdx )
  517. {
  518. cmDcm_t* p = _cmDcmHandleToPtr(h);
  519. cmDcmCfg_t* cp;
  520. if((cp = _cmDevCfgIndexToPtr(p, kMidiDcmTId, cfgIdx, true )) == NULL )
  521. return NULL;
  522. return &cp->u.m;
  523. }
  524. const cmDcmMidi_t* cmDevCfgMidiDevMap( cmDevCfgH_t h, unsigned usrAppId, unsigned usrMapId )
  525. {
  526. cmDcm_t* p = _cmDcmHandleToPtr(h);
  527. cmDcmMap_t* mp;
  528. if((mp =_cmDcmFindMap(p,kMidiDcmTId, usrAppId, usrMapId, true )) == NULL )
  529. return NULL;
  530. return &mp->cfg->u.m;
  531. }
  532. const cmDcmMidi_t* cmDevCfgMidiCfgFromLabel( cmDevCfgH_t h, const cmChar_t* cfgLabel )
  533. {
  534. cmDcm_t* p = _cmDcmHandleToPtr(h);
  535. const cmDcmMidi_t* c;
  536. unsigned idx;
  537. if((idx = cmDevCfgLabelToIndex(h, kMidiDcmTId, cfgLabel )) == cmInvalidIdx )
  538. {
  539. cmErrMsg(&p->err,kLabelNotFoundDcRC,"The MIDI cfg. '%s' was not found.",cmStringNullGuard(cfgLabel));
  540. return NULL;
  541. }
  542. if((c = cmDevCfgMidiCfg(h,idx)) == NULL )
  543. {
  544. cmErrMsg(&p->err,kInvalidCfgIdxDcRC,"The MIDI cfg. index %i is invalid.",idx);
  545. return NULL;
  546. }
  547. return c;
  548. }
  549. cmDcRC_t cmDevCfgNameAudioPort(
  550. cmDevCfgH_t h,
  551. const cmChar_t* dcLabelStr,
  552. const cmChar_t* inDevNameStr,
  553. const cmChar_t* outDevNameStr,
  554. bool syncInputFl,
  555. unsigned msgQueueByteCnt,
  556. unsigned devFramesPerCycle,
  557. unsigned dspFramesPerCycle,
  558. unsigned audioBufCnt,
  559. double srate,
  560. bool activeFl )
  561. {
  562. cmDcm_t* p = _cmDcmHandleToPtr(h);
  563. cmDcmCfg_t* cp;
  564. unsigned inDevIdx = cmInvalidIdx;
  565. unsigned outDevIdx = cmInvalidIdx;
  566. // validate the label
  567. if((dcLabelStr = _cmDcmTrimLabel(p,dcLabelStr,"Audio cfg")) == NULL)
  568. return cmErrLastRC(&p->err);
  569. // validate the input device
  570. if( inDevNameStr != NULL )
  571. if(( inDevIdx = cmApDeviceLabelToIndex(inDevNameStr)) == cmInvalidIdx )
  572. return cmErrMsg(&p->err, kInvalidArgDcRC,"The input audio device name '%s' is not valid.",cmStringNullGuard(inDevNameStr));
  573. // validate the output device
  574. if( outDevNameStr != NULL )
  575. if(( outDevIdx = cmApDeviceLabelToIndex(outDevNameStr)) == cmInvalidIdx )
  576. return cmErrMsg(&p->err, kInvalidArgDcRC,"The output audio device name '%s' is not valid.",cmStringNullGuard(outDevNameStr));
  577. // validate the msg byte cnt
  578. if( msgQueueByteCnt == 0 )
  579. return cmErrMsg(&p->err, kInvalidArgDcRC,"The 'message queue size' must be greater than zero.");
  580. // validate the dev. frames per cycle
  581. if( devFramesPerCycle == 0 )
  582. return cmErrMsg(&p->err, kInvalidArgDcRC,"The 'device frames per cycle' must be greater than zero.");
  583. // validate the dsp frames per cycle
  584. if( dspFramesPerCycle == 0 || ((devFramesPerCycle/dspFramesPerCycle) * dspFramesPerCycle != devFramesPerCycle) )
  585. return cmErrMsg(&p->err, kInvalidArgDcRC,"The 'DSP frames per cycle' must be greater than zero and an integer factor of 'Device frames per cycle.'.");
  586. // validate the sample rate
  587. if( srate == 0 )
  588. return cmErrMsg(&p->err, kInvalidArgDcRC,"The audio sample rate must be greater than zero.");
  589. // if dcLabelStr is already in use for this location and type then update
  590. // the assoc'd recd otherwise create a new one.
  591. if((cp = _cmDcmFindOrCreateCfg(p,kAudioDcmTId, dcLabelStr)) == NULL )
  592. return cmErrLastRC(&p->err);
  593. unsigned inChCnt = cmApDeviceChannelCount( inDevIdx, true );
  594. unsigned outChCnt = cmApDeviceChannelCount( outDevIdx, false );
  595. cp->u.a.label = cp->dcLabelStr;
  596. cp->u.a.inDevLabelStr = cmMemAllocStr(inDevNameStr==NULL?"":inDevNameStr);
  597. cp->u.a.outDevLabelStr = cmMemAllocStr(outDevNameStr==NULL?"":outDevNameStr);
  598. cp->u.a.activeFl = activeFl;
  599. cp->u.a.rtSysArgs.rpt = p->err.rpt;
  600. cp->u.a.rtSysArgs.inDevIdx = inDevIdx;
  601. cp->u.a.rtSysArgs.outDevIdx = outDevIdx;
  602. cp->u.a.rtSysArgs.syncInputFl = syncInputFl;
  603. cp->u.a.rtSysArgs.msgQueueByteCnt = msgQueueByteCnt;
  604. cp->u.a.rtSysArgs.devFramesPerCycle = devFramesPerCycle;
  605. cp->u.a.rtSysArgs.dspFramesPerCycle = dspFramesPerCycle;
  606. cp->u.a.rtSysArgs.audioBufCnt = audioBufCnt;
  607. cp->u.a.rtSysArgs.srate = srate;
  608. cp->descStr = cmTsPrintfP(cp->descStr,"%sIn: Chs:%i %s\nOut: Chs:%i %s",activeFl?"":"INACTIVE ",inChCnt,cp->u.a.inDevLabelStr,outChCnt,cp->u.a.outDevLabelStr);
  609. return kOkDcRC;
  610. }
  611. cmDcRC_t cmDevCfgAudioSetDefaultCfgIndex( cmDevCfgH_t h, unsigned cfgIdx )
  612. {
  613. cmDcm_t* p = _cmDcmHandleToPtr(h);
  614. assert( p->clp != NULL );
  615. cmDcmCfg_t* cp = p->clp->cfg;
  616. unsigned i;
  617. for(i=0; cp!=NULL; cp=cp->next)
  618. if( cp->typeId == kAudioDcmTId )
  619. {
  620. if( i == cfgIdx )
  621. cp->u.a.dfltFl = true;
  622. else
  623. {
  624. if( cp->u.a.dfltFl )
  625. cp->u.a.dfltFl = false;
  626. }
  627. ++i;
  628. }
  629. return kOkDcRC;
  630. }
  631. unsigned cmDevCfgAudioGetDefaultCfgIndex( cmDevCfgH_t h )
  632. {
  633. cmDcm_t* p = _cmDcmHandleToPtr(h);
  634. assert( p->clp != NULL );
  635. cmDcmCfg_t* cp = p->clp->cfg;
  636. unsigned i;
  637. for(i=0; cp!=NULL; cp=cp->next)
  638. if( cp->typeId == kAudioDcmTId )
  639. {
  640. if( cp->u.a.dfltFl )
  641. return i;
  642. ++i;
  643. }
  644. return cmInvalidIdx;
  645. }
  646. bool cmDevCfgAudioIsDeviceActive( cmDevCfgH_t h, const cmChar_t* devNameStr, bool inputFl )
  647. {
  648. cmDcm_t* p = _cmDcmHandleToPtr(h);
  649. assert( p->clp != NULL );
  650. cmDcmCfg_t* cp = p->clp->cfg;
  651. unsigned i;
  652. for(i=0; cp!=NULL; cp=cp->next)
  653. if( cp->typeId == kAudioDcmTId )
  654. {
  655. bool fl;
  656. if( inputFl )
  657. fl = strcmp(devNameStr,cp->u.a.inDevLabelStr)==0;
  658. else
  659. fl = strcmp(devNameStr,cp->u.a.outDevLabelStr)==0;
  660. if( fl )
  661. return cp->u.a.activeFl;
  662. ++i;
  663. }
  664. return false;
  665. }
  666. unsigned cmDevCfgAudioActiveCount( cmDevCfgH_t h )
  667. {
  668. cmDcm_t* p = _cmDcmHandleToPtr(h);
  669. assert( p->clp != NULL );
  670. cmDcmCfg_t* cp = p->clp->cfg;
  671. unsigned n;
  672. for(n=0; cp!=NULL; cp=cp->next)
  673. if( cp->typeId == kAudioDcmTId && cp->u.a.activeFl )
  674. ++n;
  675. return n;
  676. }
  677. const cmChar_t* cmDevCfgAudioActiveLabel( cmDevCfgH_t h, unsigned idx )
  678. {
  679. cmDcm_t* p = _cmDcmHandleToPtr(h);
  680. assert( p->clp != NULL );
  681. cmDcmCfg_t* cp = p->clp->cfg;
  682. unsigned i;
  683. for(i=0; cp!=NULL; cp=cp->next)
  684. if( cp->typeId == kAudioDcmTId && cp->u.a.activeFl )
  685. {
  686. if( i == idx )
  687. return cp->dcLabelStr;
  688. ++i;
  689. }
  690. assert(0);
  691. return NULL;
  692. }
  693. const cmDcmAudio_t* cmDevCfgAudioActiveCfg( cmDevCfgH_t h, unsigned idx )
  694. {
  695. cmDcm_t* p = _cmDcmHandleToPtr(h);
  696. assert( p->clp != NULL );
  697. cmDcmCfg_t* cp = p->clp->cfg;
  698. unsigned i;
  699. for(i=0; cp!=NULL; cp=cp->next)
  700. if( cp->typeId == kAudioDcmTId && cp->u.a.activeFl )
  701. {
  702. if( i == idx )
  703. return &cp->u.a;
  704. ++i;
  705. }
  706. assert(0);
  707. return NULL;
  708. }
  709. unsigned cmDevCfgAudioActiveIndex( cmDevCfgH_t h, const cmChar_t* cfgLabel )
  710. {
  711. cmDcm_t* p = _cmDcmHandleToPtr(h);
  712. if( cfgLabel == NULL )
  713. return cmInvalidIdx;
  714. assert( p->clp != NULL );
  715. cmDcmCfg_t* cp = p->clp->cfg;
  716. unsigned i;
  717. for(i=0; cp!=NULL; cp=cp->next)
  718. if( cp->typeId == kAudioDcmTId && cp->u.a.activeFl)
  719. {
  720. if( cp->dcLabelStr!=NULL && strcmp(cp->dcLabelStr,cfgLabel) == 0 )
  721. return i;
  722. ++i;
  723. }
  724. return cmInvalidIdx;
  725. }
  726. const cmDcmAudio_t* cmDevCfgAudioCfg( cmDevCfgH_t h, unsigned cfgIdx )
  727. {
  728. cmDcm_t* p = _cmDcmHandleToPtr(h);
  729. cmDcmCfg_t* cp;
  730. if((cp = _cmDevCfgIndexToPtr(p, kAudioDcmTId, cfgIdx, true )) == NULL )
  731. return NULL;
  732. return &cp->u.a;
  733. }
  734. const cmDcmAudio_t* cmDevCfgAudioDevMap( cmDevCfgH_t h, unsigned usrAppId, unsigned usrMapId )
  735. {
  736. cmDcm_t* p = _cmDcmHandleToPtr(h);
  737. cmDcmMap_t* mp;
  738. if((mp =_cmDcmFindMap(p,kAudioDcmTId, usrAppId, usrMapId, true )) == NULL )
  739. return NULL;
  740. return &mp->cfg->u.a;
  741. }
  742. cmDcRC_t cmDevCfgNameNetPort(
  743. cmDevCfgH_t h,
  744. const cmChar_t* dcLabelStr,
  745. const cmChar_t* sockAddr,
  746. unsigned portNumber,
  747. bool localFl,
  748. bool activeFl)
  749. {
  750. cmDcm_t* p = _cmDcmHandleToPtr(h);
  751. cmDcmCfg_t* cp;
  752. if( portNumber > 0xffff )
  753. return cmErrMsg(&p->err,kInvalidArgDcRC,"The network port number %i is invalid. The valid IP port number range is:0-0xffff.");
  754. // validate the label
  755. if((dcLabelStr = _cmDcmTrimLabel(p,dcLabelStr,"Net cfg")) == NULL)
  756. return cmErrLastRC(&p->err);
  757. // if dcLabelStr is already in use for this location and type then update
  758. // the assoc'd recd otherwise create a new one.
  759. if((cp = _cmDcmFindOrCreateCfg(p,kNetDcmTId, dcLabelStr)) == NULL )
  760. return cmErrLastRC(&p->err);
  761. cp->u.n.label = cp->dcLabelStr;
  762. cp->u.n.sockAddr = cmMemAllocStr(sockAddr);
  763. cp->u.n.portNumber = portNumber;
  764. cp->u.n.localFl = localFl;
  765. cp->u.n.activeFl = activeFl;
  766. cp->descStr = cmTsPrintfP(cp->descStr,"%s %s %s:%i",activeFl?"":"INACTIVE",localFl?"local":"remote",sockAddr,portNumber);
  767. return kOkDcRC;
  768. }
  769. unsigned cmDevCfgNetActiveCount( cmDevCfgH_t h )
  770. {
  771. cmDcm_t* p = _cmDcmHandleToPtr(h);
  772. assert( p->clp != NULL );
  773. cmDcmCfg_t* cp = p->clp->cfg;
  774. unsigned n;
  775. for(n=0; cp!=NULL; cp=cp->next)
  776. if( cp->typeId == kNetDcmTId && cp->u.a.activeFl )
  777. ++n;
  778. return n;
  779. }
  780. const cmDcmNet_t* cmDevCfgNetActiveCfg( cmDevCfgH_t h, unsigned idx )
  781. {
  782. cmDcm_t* p = _cmDcmHandleToPtr(h);
  783. assert( p->clp != NULL );
  784. cmDcmCfg_t* cp = p->clp->cfg;
  785. unsigned i;
  786. for(i=0; cp!=NULL; cp=cp->next)
  787. if( cp->typeId == kNetDcmTId && cp->u.a.activeFl )
  788. {
  789. if( i == idx )
  790. return &cp->u.n;
  791. ++i;
  792. }
  793. assert(0);
  794. return NULL;
  795. }
  796. const cmDcmNet_t* cmDevCfgNetCfg( cmDevCfgH_t h, unsigned cfgIdx )
  797. {
  798. cmDcm_t* p = _cmDcmHandleToPtr(h);
  799. cmDcmCfg_t* cp;
  800. if((cp = _cmDevCfgIndexToPtr(p, kNetDcmTId, cfgIdx, true )) == NULL )
  801. return NULL;
  802. return &cp->u.n;
  803. }
  804. const cmDcmNet_t* cmDevCfgNetDevMap( cmDevCfgH_t h, unsigned usrAppId, unsigned usrMapId )
  805. {
  806. cmDcm_t* p = _cmDcmHandleToPtr(h);
  807. cmDcmMap_t* mp;
  808. if((mp =_cmDcmFindMap(p,kNetDcmTId, usrAppId, usrMapId, true )) == NULL )
  809. return NULL;
  810. return &mp->cfg->u.n;
  811. }
  812. unsigned cmDevCfgLocCount( cmDevCfgH_t h )
  813. {
  814. unsigned n = 0;
  815. cmDcm_t* p = _cmDcmHandleToPtr(h);
  816. const cmDcmLoc_t* lp = p->loc;
  817. for(; lp!=NULL; lp=lp->next)
  818. ++n;
  819. return n;
  820. }
  821. const cmChar_t* cmDevCfgLocLabel( cmDevCfgH_t h, unsigned locIdx )
  822. {
  823. cmDcm_t* p = _cmDcmHandleToPtr(h);
  824. const cmDcmLoc_t* lp = p->loc;
  825. unsigned i;
  826. for(i=0; lp!=NULL; lp=lp->next,++i)
  827. if( i == locIdx )
  828. return lp->labelStr;
  829. assert(0);
  830. return NULL;
  831. }
  832. cmDcmLoc_t* _cmDcmLocLabelToPtr( cmDcm_t* p, const cmChar_t* locLabelStr, bool errFl)
  833. {
  834. if((locLabelStr = _cmDcmTrimLabel(p,locLabelStr,"location")) == NULL )
  835. return NULL;
  836. cmDcmLoc_t* lp = p->loc;
  837. for(; lp!=NULL; lp=lp->next)
  838. if( strcmp(lp->labelStr,locLabelStr) == 0 )
  839. return lp;
  840. if( errFl )
  841. cmErrMsg(&p->err,kLabelNotFoundDcRC,"The location label '%s' was not found.",locLabelStr);
  842. return NULL;
  843. }
  844. cmDcRC_t cmDevCfgLocStore( cmDevCfgH_t h, const cmChar_t* locLabelStr )
  845. {
  846. cmDcRC_t rc = kOkDcRC;
  847. cmDcm_t* p = _cmDcmHandleToPtr(h);
  848. unsigned i,j;
  849. // if this location label is already in use then it has already been stored.
  850. if( _cmDcmLocLabelToPtr(p,locLabelStr,false) != NULL )
  851. return kOkDcRC;
  852. // store the current loc ptr
  853. cmDcmLoc_t* olp = p->clp;
  854. cmDcmLoc_t* nlp;
  855. // create a new location recd and make it current
  856. if((rc = _cmDcmNewLoc(p,locLabelStr,&nlp)) != kOkDcRC )
  857. return kOkDcRC;
  858. // duplicate the cfg's
  859. cmDcmCfg_t* ocp = olp->cfg;
  860. for(; ocp!=NULL; ocp=ocp->next)
  861. {
  862. cmDcmCfg_t* ncp;
  863. // this will always create (never find) a new cfg recd
  864. if((ncp = _cmDcmFindOrCreateCfg(p,ocp->typeId, ocp->dcLabelStr)) == NULL )
  865. {
  866. rc = cmErrLastRC(&p->err);
  867. goto errLabel;
  868. }
  869. // duplicate the desc. string
  870. ncp->descStr = cmMemAllocStr(ocp->descStr);
  871. switch( ncp->typeId )
  872. {
  873. case kMidiDcmTId: _cmDcmDuplMidi(&ncp->u.m,&ocp->u.m); break;
  874. case kAudioDcmTId: _cmDcmDuplAudio(&ncp->u.a,&ocp->u.a); break;
  875. case kNetDcmTId: _cmDcmDuplNet( &ncp->u.n,&ocp->u.n); break;
  876. default:
  877. assert(0);
  878. break;
  879. }
  880. }
  881. // duplicate the app array
  882. nlp->appCnt = olp->appCnt;
  883. nlp->app = cmMemAllocZ(cmDcmApp_t,nlp->appCnt);
  884. for(i=0; i<nlp->appCnt; ++i)
  885. {
  886. cmDcmApp_t* nap = nlp->app + i;
  887. cmDcmApp_t* oap = olp->app + i;
  888. //nap->usrAppId = oap->usrAppId;
  889. nap->activeFl = oap->activeFl;
  890. nap->mapCnt = oap->mapCnt;
  891. nap->map = cmMemAllocZ(cmDcmMap_t,nap->mapCnt);
  892. for(j=0; j<nap->mapCnt; ++j)
  893. {
  894. cmDcmMap_t* nmp = nap->map + j;
  895. cmDcmMap_t* omp = oap->map + j;
  896. nmp->tid = omp->tid;
  897. nmp->cfgId = omp->cfgId;
  898. if( omp->tid != kInvalidDcmTId && omp->cfg->dcLabelStr != NULL )
  899. nmp->cfg = _cmDcmCfgLabelToPtr(p,nmp->tid,omp->cfg->dcLabelStr,true);
  900. }
  901. }
  902. errLabel:
  903. if( rc != kOkDcRC )
  904. _cmDcmFreeLoc(p,nlp);
  905. return rc;
  906. }
  907. cmDcRC_t cmDevCfgLocRecall( cmDevCfgH_t h, const cmChar_t* locLabelStr )
  908. {
  909. cmDcm_t* p = _cmDcmHandleToPtr(h);
  910. cmDcmLoc_t* lp;
  911. if((lp = _cmDcmLocLabelToPtr(p,locLabelStr,true)) == NULL)
  912. return cmErrLastRC(&p->err);
  913. p->clp = lp;
  914. return kOkDcRC;
  915. }
  916. cmDcRC_t cmDevCfgLocDelete( cmDevCfgH_t h, const cmChar_t* locLabelStr )
  917. {
  918. cmDcm_t* p = _cmDcmHandleToPtr(h);
  919. cmDcmLoc_t* lp;
  920. if((lp = _cmDcmLocLabelToPtr(p,locLabelStr,true)) == NULL )
  921. return cmErrLastRC(&p->err);
  922. _cmDcmFreeLoc(p,lp);
  923. return kOkDcRC;
  924. }
  925. unsigned cmDevCfgLocCurIndex( cmDevCfgH_t h )
  926. {
  927. unsigned i;
  928. cmDcm_t* p = _cmDcmHandleToPtr(h);
  929. cmDcmLoc_t* lp = p->loc;
  930. for(i=0; lp!=NULL; lp=lp->next,++i)
  931. if( lp == p->clp )
  932. return i;
  933. assert(0);
  934. return cmInvalidIdx;
  935. }
  936. cmDcRC_t _cmDcmJsonNotFound( cmDcm_t* p, const cmChar_t* tagStr )
  937. { return cmErrMsg(&p->err,kJsonFailDcRC,"JSON element '%s' not found.",tagStr); }
  938. cmDcRC_t _cmDcmJsonSyntaxErr( cmDcm_t* p, const cmChar_t* tagStr )
  939. { return cmErrMsg(&p->err,kJsonFailDcRC,"JSON syntax error '%s' not found.",tagStr); }
  940. cmDcRC_t _cmDevCfgRead( cmDcm_t* p, cmJsonH_t jsH, const cmJsonNode_t* rootObjPtr )
  941. {
  942. cmDcRC_t rc = kOkDcRC;
  943. const cmChar_t* errLabelPtr = NULL;
  944. cmJsonNode_t* cfgNp, *locArrNp;
  945. unsigned i,j;
  946. cmDevCfgH_t h;
  947. h.h = p;
  948. // clear the all locations
  949. _cmDcmFreeAllLocs(p);
  950. if((cfgNp = cmJsonFindValue(jsH, "cfg", rootObjPtr, kObjectTId )) == NULL )
  951. return _cmDcmJsonNotFound(p,"cfg");
  952. // get loc array
  953. if((locArrNp = cmJsonFindValue(jsH,"loc",cfgNp, kArrayTId )) == NULL )
  954. return _cmDcmJsonNotFound(p,"loc");
  955. // for each loc object
  956. for(i=0; i<cmJsonChildCount(locArrNp); ++i)
  957. {
  958. cmJsonNode_t* locObjNp, *cfgArrNp;
  959. const cmChar_t* locLabelStr = NULL;
  960. // get the loc object
  961. if((locObjNp = cmJsonArrayElement(locArrNp,i)) == NULL || cmJsonIsObject(locObjNp)==false )
  962. return _cmDcmJsonSyntaxErr(p,"loc object");
  963. // read the loc object fields
  964. if( cmJsonMemberValues(locObjNp, &errLabelPtr,
  965. "label", kStringTId, &locLabelStr,
  966. "cfg", kArrayTId, &cfgArrNp,
  967. NULL ) != kOkJsRC )
  968. { return _cmDcmJsonNotFound(p,errLabelPtr); }
  969. // create a new location recd
  970. cmDcmLoc_t* locPtr = NULL;
  971. if((rc = _cmDcmNewLoc(p,locLabelStr,&locPtr)) != kOkDcRC )
  972. return cmErrMsg(&p->err,kJsonFailDcRC,"Location '%s' create failed.",cmStringNullGuard(locLabelStr));
  973. /*
  974. // read each app object
  975. for(j=0; j<cmJsonChildCount(appArrNp); ++j)
  976. {
  977. cmJsonNode_t* appObjNp;
  978. // get the app object
  979. if((appObjNp = cmJsonArrayElement(appArrNp,j)) == NULL || cmJsonIsObject(appObjNp)==false )
  980. return _cmDcmJsonSyntaxErr(p,"loc object");
  981. // locate the map array
  982. cmJsonNode_t* mapArrNp;
  983. if((mapArrNp = cmJsonFindValue(jsH,"map",appObjNp,kArrayTId)) == NULL )
  984. return _cmDcmJsonNotFound(p,"map");
  985. // for each map array
  986. for(k=0; k<cmJsonChildCount(mapArrNp); ++k)
  987. {
  988. unsigned tid,cfgId;
  989. cmJsonNode_t* mapObjNp;
  990. if((mapObjNp = cmJsonArrayElement(mapArrNp,j)) == NULL || cmJsonIsObject(mapObjNp)==false)
  991. return _cmDcmJsonSyntaxErr(p,"cfg object");
  992. if( cmJsonMemberValues( mapObjNp, &errLabelPtr,
  993. "tid", kIntTId, &tid,
  994. "cfgId", kIntTId, &cfgId,
  995. NULL ) != kOkDcRC )
  996. { return _cmDcmJsonSyntaxErr(p,errLabelPtr); }
  997. }
  998. }
  999. */
  1000. // read each cfg object
  1001. for(j=0; j<cmJsonChildCount(cfgArrNp); ++j)
  1002. {
  1003. cmJsonNode_t* cfgObjNp;
  1004. const cmChar_t* dcLabelStr;
  1005. const cmChar_t* descStr;
  1006. unsigned cfgId, typeId;
  1007. if((cfgObjNp = cmJsonArrayElement(cfgArrNp,j)) == NULL || cmJsonIsObject(cfgObjNp)==false)
  1008. return _cmDcmJsonSyntaxErr(p,"cfg object");
  1009. if( cmJsonMemberValues( cfgObjNp, &errLabelPtr,
  1010. "label", kStringTId, &dcLabelStr,
  1011. "cfgId", kIntTId, &cfgId,
  1012. "typeId", kIntTId, &typeId,
  1013. "desc", kStringTId, &descStr,
  1014. NULL ) != kOkJsRC )
  1015. { _cmDcmJsonSyntaxErr(p,errLabelPtr); }
  1016. cmDcmMidi_t m;
  1017. cmDcmAudio_t a;
  1018. cmDcmNet_t n;
  1019. switch( typeId )
  1020. {
  1021. case kMidiDcmTId:
  1022. if( cmJsonMemberValues( cfgObjNp, &errLabelPtr,
  1023. "devLabelStr", kStringTId, &m.devLabelStr,
  1024. "portLabelStr",kStringTId, &m.portLabelStr,
  1025. "inputFl", kBoolTId, &m.inputFl,
  1026. NULL) != kOkJsRC )
  1027. {
  1028. rc = _cmDcmJsonSyntaxErr(p,errLabelPtr);
  1029. goto errLabel;
  1030. }
  1031. if((rc = cmDevCfgNameMidiPort(h,dcLabelStr,m.devLabelStr,m.portLabelStr,m.inputFl)) != kOkDcRC )
  1032. goto errLabel;
  1033. break;
  1034. case kAudioDcmTId:
  1035. if( cmJsonMemberValues( cfgObjNp, &errLabelPtr,
  1036. "inDevLabelStr", kStringTId, &a.inDevLabelStr,
  1037. "outDevLabelStr", kStringTId, &a.outDevLabelStr,
  1038. "syncInputFl", kBoolTId, &a.rtSysArgs.syncInputFl,
  1039. "msgQueueByteCnt", kIntTId, &a.rtSysArgs.msgQueueByteCnt,
  1040. "devFramesPerCycle", kIntTId, &a.rtSysArgs.devFramesPerCycle,
  1041. "dspFramesPerCycle", kIntTId, &a.rtSysArgs.dspFramesPerCycle,
  1042. "audioBufCnt", kIntTId, &a.rtSysArgs.audioBufCnt,
  1043. "srate", kRealTId, &a.rtSysArgs.srate,
  1044. "active", kBoolTId, &a.activeFl,
  1045. NULL ) != kOkJsRC )
  1046. {
  1047. rc = _cmDcmJsonSyntaxErr(p,errLabelPtr);
  1048. goto errLabel;
  1049. }
  1050. if((rc = cmDevCfgNameAudioPort(h,dcLabelStr,a.inDevLabelStr,a.outDevLabelStr,
  1051. a.rtSysArgs.syncInputFl,
  1052. a.rtSysArgs.msgQueueByteCnt,
  1053. a.rtSysArgs.devFramesPerCycle,
  1054. a.rtSysArgs.dspFramesPerCycle,
  1055. a.rtSysArgs.audioBufCnt,
  1056. a.rtSysArgs.srate,
  1057. a.activeFl)) != kOkDcRC )
  1058. {
  1059. goto errLabel;
  1060. }
  1061. break;
  1062. case kNetDcmTId:
  1063. if( cmJsonMemberValues( cfgObjNp, &errLabelPtr,
  1064. "sockAddr", kStringTId, &n.sockAddr,
  1065. "portNumber", kIntTId, &n.portNumber,
  1066. "localFl", kBoolTId, &n.localFl,
  1067. "activeFl", kBoolTId, &n.activeFl,
  1068. NULL ) != kOkJsRC )
  1069. {
  1070. rc = _cmDcmJsonSyntaxErr(p,errLabelPtr);
  1071. goto errLabel;
  1072. }
  1073. if((rc = cmDevCfgNameNetPort(h,dcLabelStr,n.sockAddr,n.portNumber,n.localFl,n.activeFl)) != kOkDcRC )
  1074. goto errLabel;
  1075. break;
  1076. default:
  1077. assert(0);
  1078. break;
  1079. }
  1080. }
  1081. }
  1082. errLabel:
  1083. return kOkDcRC;
  1084. }
  1085. cmDcRC_t _cmDevCfgWrite( cmDcm_t* p, cmJsonH_t jsH, cmJsonNode_t* rootObjPtr )
  1086. {
  1087. cmDcRC_t rc = kOkDcRC;
  1088. const cmDcmLoc_t* lp = p->loc;
  1089. cmJsonNode_t* cfgNp = cmJsonInsertPairObject(jsH, rootObjPtr, "cfg" );
  1090. // create the loc array
  1091. cmJsonNode_t* locArrNp = cmJsonInsertPairArray( jsH, cfgNp, "loc" );
  1092. for(; lp!=NULL; lp=lp->next)
  1093. {
  1094. // create the 'loc' object
  1095. cmJsonNode_t* locObjNp = cmJsonCreateObject(jsH,locArrNp);
  1096. // set the loc label
  1097. cmJsonInsertPairString(jsH, locObjNp, "label", lp->labelStr );
  1098. /*
  1099. // create the 'loc.app[]' array
  1100. cmJsonNode_t* appArrNp = cmJsonInsertPairArray(jsH,locObjNp,"app");
  1101. // for each app recd
  1102. for(i=0; i<lp->appCnt; ++i)
  1103. if( lp->app[i].activeFl )
  1104. {
  1105. // create the app recd
  1106. cmJsonNode_t* appNp = cmJsonCreateObject(jsH,appArrNp );
  1107. // create the map array
  1108. cmJsonNode_t* mapArrNp = cmJsonInsertPairArray(jsH, appNp, "map" );
  1109. // for each map recd
  1110. for(j=0; j<lp->app[i].mapCnt; ++j)
  1111. {
  1112. cmJsonNode_t* mapNp = cmJsonCreateObject(jsH,mapArrNp);
  1113. cmJsonInsertPairs(jsH, mapNp,
  1114. "tid", kIntTId, lp->app[i].map[j].tid,
  1115. "cfgId", kIntTId, lp->app[i].map[j].cfgId,
  1116. NULL );
  1117. }
  1118. }
  1119. */
  1120. // create the 'loc.cfg[]' array
  1121. cmJsonNode_t* cfgArrNp = cmJsonInsertPairArray(jsH,locObjNp,"cfg");
  1122. // for each cfg recd
  1123. cmDcmCfg_t* cp = lp->cfg;
  1124. for(; cp!=NULL; cp=cp->next)
  1125. {
  1126. // create the cfg recd
  1127. cmJsonNode_t* cfgObjNp = cmJsonCreateObject(jsH,cfgArrNp);
  1128. // fill the cfg recd
  1129. cmJsonInsertPairs(jsH, cfgObjNp,
  1130. "label", kStringTId, cp->dcLabelStr,
  1131. "cfgId", kIntTId, cp->cfgId,
  1132. "typeId", kIntTId, cp->typeId,
  1133. "desc", kStringTId, cp->descStr,
  1134. NULL );
  1135. switch( cp->typeId )
  1136. {
  1137. case kMidiDcmTId:
  1138. cmJsonInsertPairs(jsH, cfgObjNp,
  1139. "devLabelStr", kStringTId, cp->u.m.devLabelStr,
  1140. "portLabelStr",kStringTId, cp->u.m.portLabelStr,
  1141. "inputFl", kBoolTId, cp->u.m.inputFl,
  1142. NULL );
  1143. break;
  1144. case kAudioDcmTId:
  1145. cmJsonInsertPairs(jsH, cfgObjNp,
  1146. "inDevLabelStr", kStringTId, cp->u.a.inDevLabelStr,
  1147. "outDevLabelStr", kStringTId, cp->u.a.outDevLabelStr,
  1148. "syncInputFl", kBoolTId, cp->u.a.rtSysArgs.syncInputFl,
  1149. "msgQueueByteCnt", kIntTId, cp->u.a.rtSysArgs.msgQueueByteCnt,
  1150. "devFramesPerCycle", kIntTId, cp->u.a.rtSysArgs.devFramesPerCycle,
  1151. "dspFramesPerCycle", kIntTId, cp->u.a.rtSysArgs.dspFramesPerCycle,
  1152. "audioBufCnt", kIntTId, cp->u.a.rtSysArgs.audioBufCnt,
  1153. "srate", kRealTId, cp->u.a.rtSysArgs.srate,
  1154. "active", kBoolTId, cp->u.a.activeFl,
  1155. NULL );
  1156. break;
  1157. case kNetDcmTId:
  1158. cmJsonInsertPairs(jsH, cfgObjNp,
  1159. "sockAddr", kStringTId, cp->u.n.sockAddr,
  1160. "portNumber",kIntTId, cp->u.n.portNumber,
  1161. "localFl", kBoolTId, cp->u.n.localFl,
  1162. "activeFl", kBoolTId, cp->u.n.activeFl,
  1163. NULL );
  1164. break;
  1165. default:
  1166. assert(0);
  1167. break;
  1168. }
  1169. }
  1170. }
  1171. return rc;
  1172. }
  1173. cmDcRC_t cmDevCfgWrite( cmDevCfgH_t h, const cmChar_t* fn )
  1174. {
  1175. cmDcRC_t rc = kOkDcRC;
  1176. cmDcm_t* p = _cmDcmHandleToPtr(h);
  1177. cmJsonH_t jsH = cmJsonNullHandle;
  1178. if( fn == NULL )
  1179. fn = p->fn;
  1180. // validate the filename
  1181. if( fn == NULL || strlen(fn)==0 )
  1182. return cmErrMsg(&p->err,kInvalidFnDcRC,"No output file name was provided.");
  1183. // create a json object
  1184. if( cmJsonInitialize( &jsH, p->ctx ) != kOkJsRC )
  1185. {
  1186. rc = cmErrMsg(&p->err,kJsonFailDcRC,"An empty JSON tree could not be created.");
  1187. goto errLabel;
  1188. }
  1189. // insert a wrapper object as the root
  1190. if( cmJsonCreateObject( jsH, NULL ) == NULL )
  1191. {
  1192. rc = cmErrMsg(&p->err,kJsonFailDcRC,"The JSON root object could not be created.");
  1193. goto errLabel;
  1194. }
  1195. // fill the JSON tree
  1196. if((rc = _cmDevCfgWrite(p,jsH,cmJsonRoot(jsH))) != kOkDcRC )
  1197. goto errLabel;
  1198. // write the output file
  1199. if( cmJsonWrite(jsH, cmJsonRoot(jsH), fn ) != kOkJsRC )
  1200. {
  1201. rc = cmErrMsg(&p->err,kJsonFailDcRC,"The JSON file write failed on '%s'.",cmStringNullGuard(fn));
  1202. goto errLabel;
  1203. }
  1204. errLabel:
  1205. if( cmJsonFinalize(&jsH) != kOkJsRC )
  1206. cmErrMsg(&p->err,kJsonFailDcRC,"JSON tree finalization failed.");
  1207. return rc;
  1208. }