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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607
  1. #include "cmGlobal.h"
  2. #include "cmRpt.h"
  3. #include "cmErr.h"
  4. #include "cmCtx.h"
  5. #include "cmMem.h"
  6. #include "cmMallocDebug.h"
  7. #include "cmJson.h"
  8. #include "cmMidi.h"
  9. #include "cmMidiPort.h"
  10. #include "cmDevCfg.h"
  11. cmDevCfgH_t cmDevCfgNullHandle = cmSTATIC_NULL_HANDLE;
  12. typedef struct
  13. {
  14. cmChar_t* dcLabelStr; // Name of this cfg recd or NULL if the recd is inactive.
  15. cmChar_t* devLabelStr; // Midi device label.
  16. cmChar_t* portLabelStr; // Midi device port label.
  17. bool inputFl; // 'True' if this is an input port.
  18. unsigned devIdx; // Midi device index.
  19. unsigned portIdx; // Midi port index.
  20. } cmDcmMidi_t;
  21. typedef struct
  22. {
  23. cmChar_t* dcLabelStr; // Name of this cfg record or NULL if the recd is inactive.
  24. cmChar_t* inDevLabelStr; // Input audio device label.
  25. cmChar_t* outDevLabelStr; // Output audio device label.
  26. bool syncToInputFl; // 'True' if the audio system should sync to the input port.
  27. unsigned msgQueueByteCnt; // Audio system msg queue in bytes.
  28. unsigned devFramesPerCycle; // Audio system sample frames per device callback.
  29. unsigned dspFramesPerCycle; // DSP system samples per block.
  30. unsigned audioBufCnt; // Count of audio buffers (of size devFramesPerCycle)
  31. double srate; // Audio system sample rate.
  32. } cmDcmAudio_t;
  33. typedef struct
  34. {
  35. cmChar_t* dcLabelStr; // Name of this cfg recd or NULL if the recd is inactive
  36. cmChar_t* sockAddr; // Remote socket address.
  37. unsigned portNumber; // Remote socket port number
  38. unsigned netNodeId; // Network node id associated with sockAddr and portNumber.
  39. } cmDcmNet_t;
  40. typedef struct
  41. {
  42. cmTypeDcmId_t tid; // Type Id for this map or tInvalidDcmTId if the record is not active.
  43. unsigned usrDevId; // Same as index into p->map[] for this recd.
  44. unsigned cfgIndex; // Index into p->midi[],p->audio[], or p->net[].
  45. } cmDcmMap_t;
  46. typedef struct
  47. {
  48. unsigned usrAppId;
  49. bool activeFl;
  50. cmDcmMap_t* map;
  51. unsigned mapCnt;
  52. } cmDcmApp_t;
  53. typedef struct
  54. {
  55. cmErr_t err;
  56. cmDcmApp_t* app;
  57. unsigned appCnt;
  58. cmDcmMidi_t* midi;
  59. unsigned midiCnt;
  60. cmDcmAudio_t* audio;
  61. unsigned audioCnt;
  62. cmDcmNet_t* net;
  63. unsigned netCnt;
  64. } cmDcm_t;
  65. cmDcm_t* _cmDcmHandleToPtr( cmDevCfgH_t h )
  66. {
  67. cmDcm_t* p = (cmDcm_t*)h.h;
  68. assert( p!=NULL );
  69. return p;
  70. }
  71. void _cmDcmMidiFree( cmDcmMidi_t* r )
  72. {
  73. cmMemPtrFree(&r->dcLabelStr);
  74. cmMemPtrFree(&r->devLabelStr);
  75. cmMemPtrFree(&r->portLabelStr);
  76. }
  77. void _cmDcmAudioFree( cmDcmAudio_t* r )
  78. {
  79. cmMemPtrFree(&r->dcLabelStr);
  80. cmMemPtrFree(&r->inDevLabelStr);
  81. cmMemPtrFree(&r->outDevLabelStr);
  82. }
  83. void _cmDcmNetFree( cmDcmNet_t* r )
  84. {
  85. cmMemPtrFree(&r->dcLabelStr);
  86. cmMemPtrFree(&r->sockAddr);
  87. }
  88. void _cmDcmAppFree( cmDcmApp_t* r )
  89. {
  90. cmMemPtrFree(&r->map);
  91. }
  92. cmDcRC_t _cmDcmFree( cmDcm_t* p )
  93. {
  94. unsigned i;
  95. for(i=0; p->midi!=NULL && i<p->midiCnt; ++i)
  96. _cmDcmMidiFree(p->midi + i );
  97. cmMemPtrFree(&p->midi);
  98. for(i=0; p->audio!=NULL && i<p->audioCnt; ++i)
  99. _cmDcmAudioFree(p->audio + i );
  100. cmMemPtrFree(&p->audio);
  101. for(i=0; p->net!=NULL && i<p->netCnt; ++i)
  102. _cmDcmNetFree(p->net + i );
  103. cmMemPtrFree(&p->net);
  104. for(i=0; p->app!=NULL && i<p->appCnt; ++i)
  105. _cmDcmAppFree(p->app + i );
  106. cmMemPtrFree(&p->app);
  107. return kOkDcRC;
  108. }
  109. cmDcmMidi_t* _cmDcmMidiFind( cmDcm_t* p, const cmChar_t* dcLabelStr, bool errFl )
  110. {
  111. assert( dcLabelStr != NULL );
  112. unsigned i;
  113. for(i=0; i<p->midiCnt; ++i)
  114. if(p->midi[i].dcLabelStr!=NULL && strcmp(p->midi[i].dcLabelStr,dcLabelStr)==0)
  115. return p->midi + i;
  116. if( errFl )
  117. cmErrMsg(&p->err,cmLabelNotFoundDcRC,"The MIDI cfg. record '%s' not found.",dcLabelStr);
  118. return NULL;
  119. }
  120. cmDcmAudio_t* _cmDcmAudioFind( cmDcm_t* p, const cmChar_t* dcLabelStr, bool errFl )
  121. {
  122. assert( dcLabelStr != NULL );
  123. unsigned i;
  124. for(i=0; i<p->audioCnt; ++i)
  125. if(p->audio[i].dcLabelStr!=NULL && strcmp(p->audio[i].dcLabelStr,dcLabelStr)==0)
  126. return p->audio + i;
  127. if( errFl )
  128. cmErrMsg(&p->err,cmLabelNotFoundDcRC,"The audio cfg. record '%s' not found.",dcLabelStr);
  129. return NULL;
  130. }
  131. cmDcmNet_t* _cmDcmNetFind( cmDcm_t* p, const cmChar_t* dcLabelStr, bool errFl )
  132. {
  133. assert( dcLabelStr != NULL );
  134. unsigned i;
  135. for(i=0; i<p->netCnt; ++i)
  136. if(p->net[i].dcLabelStr!=NULL && strcmp(p->net[i].dcLabelStr,dcLabelStr)==0)
  137. return p->net + i;
  138. if( errFl )
  139. cmErrMsg(&p->err,cmLabelNotFoundDcRC,"The net cfg. record '%s' not found.",dcLabelStr);
  140. return NULL;
  141. }
  142. cmDcmApp_t* _cmDcmFindOrCreateApp(cmDcm_t* p, unsigned usrAppId )
  143. {
  144. cmDcmApp_t* a;
  145. if( usrAppId < p->appCnt )
  146. a = p->app + usrAppId;
  147. else
  148. {
  149. p->appCnt = usrAppId + 1;
  150. p->app = cmMemResizePZ(cmDcmApp_t,p->app,p->appCnt);
  151. a = p->app + usrAppId;
  152. a->usrAppId = usrAppId;
  153. a->activeFl = true;
  154. }
  155. return a;
  156. }
  157. cmDcmMap_t* _cmDcmFindOrCreateMap(cmDcm_t* p, cmDcmApp_t* a, unsigned usrDevId )
  158. {
  159. cmDcmMap_t* m;
  160. if( usrDevId < a->mapCnt )
  161. m = a->map + usrDevId;
  162. else
  163. {
  164. a->mapCnt = usrDevId + 1;
  165. a->map = cmMemResizePZ(cmDcmMap_t,a->map,a->mapCnt);
  166. m = a->map + usrDevId;
  167. m->usrDevId = usrDevId;
  168. }
  169. return m;
  170. }
  171. cmDcRC_t _cmDcmLookupApp(cmDcm_t* p, unsigned usrAppId, cmDcmApp_t** appRef)
  172. {
  173. // validate the usrAppId
  174. if( usrAppId >= p->appCnt )
  175. return cmErrMsg(&p->err,kInvalidDevArgDcRC,"Invalid user app. id:%i\n",usrAppId);
  176. // check that the app recd is active
  177. if( p->app[usrAppId].activeFl == false )
  178. return cmErrMsg(&p->err,kInvalidDevArgDcRC,"The user app. with id:%i is not active.",usrAppId);
  179. *appRef = p->app + usrAppId;
  180. return kOkDcRC;
  181. }
  182. cmDcRC_t _cmDcmLookupMap(cmDcm_t* p, cmDcmApp_t* a, unsigned usrDevId, cmDcmMap_t** mapRef )
  183. {
  184. // validate the usrDevId
  185. if( usrDevId >= a->mapCnt )
  186. return cmErrMsg(&p->err,kInvalidDevArgDcRC,"Invalid user device id:%i on app:%i\n",usrDevId,a->usrAppId);
  187. // check that the map recd is active
  188. if( a->map[ usrDevId ].tid == kInvalidDcmTId )
  189. return cmErrMsg(&p->err,kInvalidDevArgDcRC,"The user device id:%i on app:%i is not active.",usrDevId,a->usrAppId);
  190. *mapRef = a->map + usrDevId;
  191. return kOkDcRC;
  192. }
  193. cmDcRC_t _cmDcmLookupAppMap(cmDcm_t* p, unsigned usrAppId, unsigned usrDevId, cmDcmMap_t** mapRef )
  194. {
  195. cmDcRC_t rc;
  196. cmDcmApp_t* a;
  197. if((rc = _cmDcmLookupApp(p,usrAppId,&a)) == kOkDcRC )
  198. return rc;
  199. return _cmDcmLookupMap(p,a,usrDevId,mapRef );
  200. }
  201. // Delete all maps in all apps which reference a particular cfg recd.
  202. void _cmDevCfgDeleteCfgMaps( cmDcm_t* p, cmTypeDcmId_t tid, unsigned cfgIndex )
  203. {
  204. unsigned i,j;
  205. for(i=0; i<p->appCnt; ++i)
  206. if( p->app[i].activeFl )
  207. for(j=0; j<p->app[i].mapCnt; ++j)
  208. if( p->app[i].map[j].tid == tid && p->app[i].map[j].cfgIndex == cfgIndex )
  209. {
  210. p->app[i].map[j].tid = kInvalidDcmTId;
  211. break;
  212. }
  213. }
  214. cmDcRC_t cmDevCfgMgrAlloc( cmCtx_t* ctx, cmDevCfgH_t* hp, cmJsonH_t jsH )
  215. {
  216. cmDcRC_t rc;
  217. if((rc = cmDevCfgMgrFree(hp)) != kOkDcRC )
  218. return rc;
  219. cmDcm_t* p = cmMemAllocZ(cmDcm_t,1);
  220. cmErrSetup(&p->err,&ctx->rpt,"DevCfgMgr");
  221. hp->h = p;
  222. if( rc != kOkDcRC )
  223. _cmDcmFree(p);
  224. return rc;
  225. }
  226. cmDcRC_t cmDevCfgMgrFree( cmDevCfgH_t* hp )
  227. {
  228. cmDcRC_t rc = kOkDcRC;
  229. if(hp!=NULL || cmDevCfgIsValid(*hp))
  230. return rc;
  231. cmDcm_t* p = _cmDcmHandleToPtr(*hp);
  232. if((rc = _cmDcmFree(p)) != kOkDcRC )
  233. return rc;
  234. cmMemFree(p);
  235. hp->h = NULL;
  236. return rc;
  237. }
  238. cmDcRC_t cmDevCfgIsValid( cmDevCfgH_t h )
  239. { return h.h != NULL; }
  240. cmDcRC_t _cmDcmFindCfgIndex( cmDcm_t* p, cmTypeDcmId_t tid, const cmChar_t* dcLabelStr, unsigned* cfgIndexRef )
  241. {
  242. cmDcRC_t rc = kOkDcRC;
  243. *cfgIndexRef = cmInvalidIdx;
  244. switch( tid )
  245. {
  246. case kMidiDcmTId:
  247. {
  248. const cmDcmMidi_t* r;
  249. if((r = _cmDcmMidiFind(p,dcLabelStr,true)) == NULL )
  250. rc = cmErrLastRC(&p->err);
  251. else
  252. *cfgIndexRef = r - p->midi;
  253. }
  254. break;
  255. case kAudioDcmTId:
  256. {
  257. const cmDcmAudio_t* r;
  258. if((r = _cmDcmAudioFind(p,dcLabelStr,true)) == NULL )
  259. rc = cmErrLastRC(&p->err);
  260. else
  261. *cfgIndexRef = r - p->audio;
  262. }
  263. break;
  264. case kNetDcmTId:
  265. {
  266. const cmDcmNet_t* r;
  267. if((r = _cmDcmNetFind(p,dcLabelStr,true)) == NULL )
  268. rc = cmErrLastRC(&p->err);
  269. else
  270. *cfgIndexRef = r - p->net;
  271. }
  272. break;
  273. default:
  274. assert(0);
  275. break;
  276. }
  277. return rc;
  278. }
  279. cmDcRC_t _cmDevCfgDeleteCfg( cmDcm_t* p, cmTypeDcmId_t tid, unsigned cfgIndex )
  280. {
  281. // release any resources held by this cfg record and mark
  282. // the record as inactive by setting the dcLabelStr field to NULL.
  283. switch( tid )
  284. {
  285. case kMidiDcmTId:
  286. _cmDcmMidiFree( p->midi + cfgIndex );
  287. break;
  288. case kAudioDcmTId:
  289. _cmDcmAudioFree( p->audio + cfgIndex );
  290. break;
  291. case kNetDcmTId:
  292. _cmDcmNetFree( p->net + cfgIndex );
  293. break;
  294. default:
  295. assert(0);
  296. break;
  297. }
  298. // delete all maps which reference this cfg recd
  299. if( cfgIndex != cmInvalidIdx )
  300. _cmDevCfgDeleteCfgMaps(p, tid, cfgIndex );
  301. return kOkDcRC;
  302. }
  303. cmDcRC_t cmDevCfgDeleteCfg( cmDevCfgH_t h, cmTypeDcmId_t tid, const cmChar_t* dcLabelStr )
  304. {
  305. cmDcRC_t rc;
  306. cmDcm_t* p = _cmDcmHandleToPtr(h);
  307. unsigned cfgIndex = cmInvalidIdx;
  308. // locate the cfg record index
  309. if((rc = _cmDcmFindCfgIndex(p,tid,dcLabelStr,&cfgIndex)) == kOkDcRC )
  310. return rc;
  311. return _cmDevCfgDeleteCfg( p, tid, cfgIndex );
  312. }
  313. cmDcRC_t cmDevCfgCreateMap( cmDevCfgH_t h, cmTypeDcmId_t tid, const cmChar_t* dcLabelStr, unsigned usrAppId, unsigned usrDevId )
  314. {
  315. cmDcRC_t rc = kOkDcRC;
  316. cmDcm_t* p = _cmDcmHandleToPtr(h);
  317. unsigned cfgIndex = cmInvalidIdx;
  318. if((rc = _cmDcmFindCfgIndex(p,tid,dcLabelStr,&cfgIndex)) == kOkDcRC )
  319. return rc;
  320. if( cfgIndex != cmInvalidIdx )
  321. {
  322. cmDcmApp_t* a;
  323. cmDcmMap_t* m;
  324. // locate or create the requested app recrod
  325. if((a = _cmDcmFindOrCreateApp(p,usrAppId)) == NULL )
  326. {
  327. rc = cmErrLastRC(&p->err);
  328. goto errLabel;
  329. }
  330. // locate or create the requested map record
  331. if((m = _cmDcmFindOrCreateMap(p,a,usrDevId)) == NULL )
  332. {
  333. rc = cmErrLastRC(&p->err);
  334. goto errLabel;
  335. }
  336. m->usrDevId = usrDevId;
  337. m->tid = tid;
  338. m->cfgIndex = cfgIndex;
  339. }
  340. errLabel:
  341. return rc;
  342. }
  343. cmDcRC_t cmDevCfgDeleteMap( cmDevCfgH_t h, cmTypeDcmId_t typeId, unsigned usrAppId, unsigned usrDevId )
  344. {
  345. cmDcRC_t rc = kOkDcRC;
  346. cmDcm_t* p = _cmDcmHandleToPtr(h);
  347. cmDcmMap_t* m;
  348. if((rc = _cmDcmLookupAppMap(p,usrAppId,usrDevId,&m)) != kOkDcRC )
  349. return rc;
  350. m->usrDevId = cmInvalidId;
  351. m->tid = kInvalidDcmTId;
  352. m->cfgIndex = cmInvalidIdx;
  353. return rc;
  354. }
  355. cmDcRC_t cmDevCfgNameMidiPort(
  356. cmDevCfgH_t h,
  357. const cmChar_t* dcLabelStr,
  358. const cmChar_t* devNameStr,
  359. const cmChar_t* portNameStr,
  360. bool inputFl )
  361. {
  362. cmDcRC_t rc = kOkDcRC;
  363. cmDcm_t* p = _cmDcmHandleToPtr(h);
  364. cmDcmMidi_t* r = _cmDcmMidiFind(p,dcLabelStr,false);
  365. unsigned i;
  366. // if 'dcLabelStr' was not already used then look for an empty MIDI record.
  367. if( r == NULL )
  368. for(i=0; i<p->midiCnt; ++i)
  369. if( p->midi[i].dcLabelStr == NULL )
  370. {
  371. r = p->midi + i;
  372. break;
  373. }
  374. // if no available cfg record exists then create one
  375. if( r == NULL )
  376. {
  377. p->midi = cmMemResizePZ(cmDcmMidi_t,p->midi,p->midiCnt+1);
  378. r = p->midi + p->midiCnt;
  379. p->midiCnt += 1;
  380. }
  381. assert( r != NULL );
  382. // verify that the device label is valid
  383. if((r->devIdx = cmMpDeviceNameToIndex( r->devLabelStr )) == cmInvalidIdx )
  384. {
  385. rc = cmErrMsg(&p->err, kInvalidDevArgDcRC,"The MIDI device name '%s' is not valid.",r->devLabelStr);
  386. goto errLabel;
  387. }
  388. // verify that the port label is valid
  389. if((r->portIdx = cmMpDevicePortNameToIndex( r->devIdx, r->inputFl ? kInMpFl : kOutMpFl, r->portLabelStr )) == cmInvalidIdx )
  390. {
  391. rc = cmErrMsg(&p->err, kInvalidDevArgDcRC,"The MIDI port name '%s' is not valid on the device '%s'.",r->portLabelStr,r->devLabelStr);
  392. goto errLabel;
  393. }
  394. // if this cfg recd was not previously active then assign a cfg label
  395. if( r->dcLabelStr == NULL )
  396. r->dcLabelStr = cmMemAllocStr(dcLabelStr);
  397. // fill in the cfg recd
  398. r->devLabelStr = cmMemResizeStr(r->devLabelStr,devNameStr);
  399. r->portLabelStr = cmMemResizeStr(r->portLabelStr,portNameStr);
  400. r->inputFl = inputFl;
  401. errLabel:
  402. // on error delete the cfg record and any maps depending on it
  403. if( rc != kOkDcRC && r != NULL )
  404. _cmDevCfgDeleteCfg( p, kMidiDcmTId, r - p->midi );
  405. return rc;
  406. }
  407. cmDcRC_t cmDevCfgMidiDevIdx( cmDevCfgH_t h, unsigned usrAppId, unsigned usrDevId, unsigned* midiDevIdxRef, unsigned* midiPortIdxRef )
  408. {
  409. cmDcRC_t rc = kOkDcRC;
  410. cmDcm_t* p = _cmDcmHandleToPtr(h);
  411. cmDcmMap_t* m;
  412. if((rc = _cmDcmLookupAppMap(p,usrAppId,usrDevId,&m)) != kOkDcRC )
  413. return rc;
  414. cmDcmMidi_t* r = p->midi + m->cfgIndex;
  415. assert(r->dcLabelStr != NULL );
  416. *midiDevIdxRef = r->devIdx;
  417. *midiPortIdxRef = r->portIdx;
  418. return rc;
  419. }
  420. cmDcRC_t cmDevCfgNameAudioPort(
  421. cmDevCfgH_t h,
  422. const cmChar_t* dcLabelStr,
  423. const cmChar_t* inDevNameStr,
  424. const cmChar_t* outDevNameStr,
  425. bool syncInputFl,
  426. unsigned msgQueueByteCnt,
  427. unsigned devFramesPerCycle,
  428. unsigned dspFramesPerCycle,
  429. unsigned audioBufCnt,
  430. double srate )
  431. {
  432. return kOkDcRC;
  433. }
  434. const struct cmAudioSysArgs_str* cmDevCfgAudioSysArgs( cmDevCfgH_t h, unsigned usrAppId, unsigned usrDevId )
  435. {
  436. return NULL;
  437. }
  438. cmDcRC_t cmDevCfgNetPort(
  439. cmDevCfgH_t h,
  440. const cmChar_t* dcLabelStr,
  441. const cmChar_t* sockAddr,
  442. unsigned portNumber )
  443. {
  444. return kOkDcRC;
  445. }
  446. unsigned cmDevCfgNetNodeId( cmDevCfgH_t h, unsigned usrAppId, unsigned usrDevId )
  447. {
  448. return cmInvalidId;
  449. }
  450. // Preset Management Functions:
  451. unsigned cmDevCfgPresetCount( cmDevCfgH_t h )
  452. {
  453. return 0;
  454. }
  455. const cmChar_t* cmDevCfgPresetLabel( cmDevCfgH_t h, unsigned presetIdx )
  456. {
  457. return NULL;
  458. }
  459. cmDcRC_t cmDevCfgStore( cmDevCfgH_t h, const cmChar_t* presetLabelStr )
  460. {
  461. return kOkDcRC;
  462. }
  463. cmDcRC_t cmDevCfgRecall( cmDevCfgH_t h, const cmChar_t* presetLabelStr )
  464. {
  465. return kOkDcRC;
  466. }
  467. cmDcRC_t cmDevCfgDelete( cmDevCfgH_t h, const cmChar_t* presetLabelStr )
  468. {
  469. return kOkDcRC;
  470. }
  471. cmDcRC_t cmDevCfgWrite( cmDevCfgH_t h )
  472. {
  473. return kOkDcRC;
  474. }