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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724
  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 "cmLinkedHeap.h"
  8. #include "cmLex.h"
  9. #include "cmCsv.h"
  10. #include "cmSdb.h"
  11. #include "cmText.h"
  12. typedef enum
  13. {
  14. kUuidColIdx,
  15. kBaseUuidColIdx,
  16. kChIdxColIdx,
  17. kObiColIdx,
  18. kIbiColIdx,
  19. kIeiColIdx,
  20. kOeiColIdx,
  21. kSrcColIdx,
  22. kMidiColIdx,
  23. kInstrColIdx,
  24. kSrateColIdx,
  25. kChCntColIdx,
  26. kNotesColIdx,
  27. kAfnColIdx,
  28. kInvalidColIdx
  29. } cmSdbColIdx_t;
  30. struct cmSdb_str;
  31. typedef struct cmSdbRspBlk_str
  32. {
  33. unsigned* indexV; // indexV[ cmSdb_t.blkIdxAllocCnt ]
  34. unsigned cnt; // count of indexes used
  35. struct cmSdbRspBlk_str* link; // cmSdbRsp_t.blocks link
  36. } cmSdbRspBlk_t;
  37. typedef struct cmSdbRsp_str
  38. {
  39. struct cmSdb_str* p; //
  40. cmSdbRspBlk_t* blocks; // first block ptr
  41. cmSdbRspBlk_t* ebp; // end block ptr
  42. unsigned cnt; // total count of indexes
  43. struct cmSdbRsp_str* link; // cmSdb_t.responses link
  44. } cmSdbRsp_t;
  45. typedef struct cmSdb_str
  46. {
  47. cmCtx_t ctx;
  48. cmLHeapH_t lhH;
  49. cmCsvH_t csvH;
  50. cmSdbEvent_t* eV;
  51. unsigned eN;
  52. unsigned blkIdxAllocCnt;
  53. struct cmSdbRsp_str* responses;
  54. } cmSdb_t;
  55. cmSdbH_t cmSdbNullHandle = cmSTATIC_NULL_HANDLE;
  56. cmSdbResponseH_t cmSdbResponseNullHandle = cmSTATIC_NULL_HANDLE;
  57. cmSdb_t* _cmSdbHandleToPtr( cmSdbH_t h )
  58. {
  59. cmSdb_t* p = (cmSdb_t*)h.h;
  60. assert( p != NULL );
  61. return p;
  62. }
  63. cmSdbRsp_t* _cmSdbRspHandleToPtr( cmSdbResponseH_t h )
  64. {
  65. cmSdbRsp_t* p = (cmSdbRsp_t*)h.h;
  66. assert( p != NULL );
  67. return p;
  68. }
  69. void _cmSdbRspBlkFree( cmSdb_t* p, cmSdbRspBlk_t* bp )
  70. {
  71. cmLhFree(p->lhH, bp->indexV);
  72. cmLhFree(p->lhH, bp);
  73. }
  74. cmSdbRspBlk_t* _cmSdbRspBlkUnlink( cmSdbRsp_t* rp, cmSdbRspBlk_t* bp )
  75. {
  76. cmSdbRspBlk_t* dp = rp->blocks;
  77. cmSdbRspBlk_t* pp = NULL;
  78. for(; dp!=NULL; dp=dp->link)
  79. {
  80. if( dp == bp )
  81. {
  82. if( pp == NULL )
  83. rp->blocks = dp->link;
  84. else
  85. pp->link = dp->link;
  86. return bp;
  87. }
  88. pp = dp;
  89. }
  90. assert(0);
  91. return NULL;
  92. }
  93. void _cmSdbRspInsertIndex( cmSdb_t* p, cmSdbRsp_t* rp, unsigned evtIndex )
  94. {
  95. if( rp->ebp == NULL || rp->ebp->cnt == p->blkIdxAllocCnt )
  96. {
  97. cmSdbRspBlk_t* bp = cmLhAllocZ(p->lhH,cmSdbRspBlk_t,1);
  98. bp->indexV = cmLhAllocZ(p->lhH,unsigned,p->blkIdxAllocCnt);
  99. if( rp->ebp != NULL )
  100. rp->ebp->link = bp;
  101. if( rp->blocks == NULL )
  102. rp->blocks = bp;
  103. rp->ebp = bp;
  104. }
  105. assert( rp->ebp!=NULL && rp->ebp->cnt < p->blkIdxAllocCnt );
  106. rp->ebp->indexV[ rp->ebp->cnt++ ] = evtIndex;
  107. rp->cnt += 1;
  108. }
  109. void _cmSdbRspRelease( cmSdbRsp_t* rp )
  110. {
  111. while( rp->blocks != NULL )
  112. {
  113. cmSdbRspBlk_t* np = rp->blocks->link;
  114. cmSdbRspBlk_t* bp;
  115. if((bp = _cmSdbRspBlkUnlink(rp,rp->blocks)) != NULL )
  116. _cmSdbRspBlkFree(rp->p,bp);
  117. rp->blocks = np;
  118. }
  119. cmLhFree(rp->p->lhH,rp);
  120. }
  121. cmSdbRsp_t* _cmSdbRspUnlink( cmSdbRsp_t* rp )
  122. {
  123. cmSdb_t* p = rp->p;
  124. cmSdbRsp_t* dp = p->responses;
  125. cmSdbRsp_t* pp = NULL;
  126. for(; dp!=NULL; dp=dp->link)
  127. {
  128. if( dp == rp )
  129. {
  130. if( pp == NULL )
  131. p->responses = dp->link;
  132. else
  133. pp->link = dp->link;
  134. return rp;
  135. }
  136. pp = dp;
  137. }
  138. assert( 0 );
  139. return NULL;
  140. }
  141. void _cmSdbRspFree( cmSdbRsp_t* rp )
  142. {
  143. _cmSdbRspUnlink(rp);
  144. _cmSdbRspRelease(rp);
  145. }
  146. cmSdbRsp_t* _cmSdbRspAlloc( cmSdb_t* p, cmSdbResponseH_t* rhp )
  147. {
  148. if( cmSdbResponseFree(rhp) != kOkSdbRC )
  149. return NULL;
  150. cmSdbRsp_t* rp = cmLhAllocZ(p->lhH,cmSdbRsp_t,1);
  151. rp->p = p;
  152. rp->link = p->responses;
  153. p->responses = rp;
  154. rhp->h = rp;
  155. return rp;
  156. }
  157. cmSdbRC_t _cmSdbDestroy( cmSdb_t* p )
  158. {
  159. cmSdbRC_t rc = kOkSdbRC;
  160. if( cmCsvFinalize(&p->csvH) != kOkCsvRC )
  161. rc = cmErrMsg(&p->ctx.err,kCsvFailSdbRC,"CSV file finalize failed.");
  162. while( p->responses != NULL )
  163. _cmSdbRspRelease(p->responses);
  164. cmLHeapDestroy(&p->lhH);
  165. cmMemFree(p);
  166. return rc;
  167. }
  168. cmSdbRC_t cmSdbCreate( cmCtx_t* ctx, cmSdbH_t* hp, const cmChar_t* audioDir, const cmChar_t* csvFn )
  169. {
  170. cmSdbRC_t rc;
  171. if((rc = cmSdbDestroy(hp)) != kOkSdbRC )
  172. return rc;
  173. cmSdb_t* p = cmMemAllocZ(cmSdb_t,1);
  174. p->ctx = *ctx;
  175. p->blkIdxAllocCnt = 1024;
  176. cmErrSetup(&p->ctx.err,&ctx->rpt,"sdb");
  177. if( cmLHeapIsValid( p->lhH = cmLHeapCreate(8192,ctx)) == false )
  178. {
  179. rc = cmErrMsg(&p->ctx.err,kLHeapFailSdbRC,"Linked heap mgr. allocation failed.");
  180. goto errLabel;
  181. }
  182. hp->h = p;
  183. if( csvFn != NULL )
  184. if((rc = cmSdbLoad(*hp,csvFn)) != kOkSdbRC )
  185. goto errLabel;
  186. errLabel:
  187. if( rc != kOkSdbRC )
  188. _cmSdbDestroy(p);
  189. return rc;
  190. }
  191. cmSdbRC_t cmSdbDestroy( cmSdbH_t* hp )
  192. {
  193. cmSdbRC_t rc = kOkSdbRC;
  194. if( hp==NULL || cmSdbIsValid(*hp)==false )
  195. return rc;
  196. cmSdb_t* p = _cmSdbHandleToPtr(*hp);
  197. if((rc = _cmSdbDestroy(p)) != kOkSdbRC )
  198. return rc;
  199. hp->h = NULL;
  200. return rc;
  201. }
  202. bool cmSdbIsValid( cmSdbH_t h )
  203. { return h.h != NULL; }
  204. cmSdbRC_t _cmSdbSyntaxError(cmSdb_t* p, const cmChar_t* csvFn, unsigned rowIdx, unsigned colIdx, const cmChar_t* colLabel )
  205. {
  206. return cmErrMsg(&p->ctx.err,kSyntaxErrSdbRC,"A syntax error was found at row %i col %i (label:%s) in '%s'.",rowIdx+1,colIdx+1,cmStringNullGuard(colLabel),cmStringNullGuard(csvFn));
  207. }
  208. cmSdbRC_t cmSdbLoad( cmSdbH_t h, const cmChar_t* csvFn )
  209. {
  210. cmSdbRC_t rc = kOkSdbRC;
  211. unsigned i;
  212. cmSdb_t* p = _cmSdbHandleToPtr(h);
  213. if( cmCsvInitializeFromFile(&p->csvH, csvFn, 0, &p->ctx ) != kOkCsvRC )
  214. {
  215. rc = cmErrMsg(&p->ctx.err,kCsvFailSdbRC,"CSV file load fail on '%s'.",cmStringNullGuard(csvFn));
  216. goto errLabel;
  217. }
  218. p->eN = cmCsvRowCount(p->csvH)-1;
  219. // release all the memory held by the linked heap
  220. cmLHeapClear(p->lhH,true);
  221. p->eV = cmLhAllocZ(p->lhH,cmSdbEvent_t,p->eN);
  222. for(i=0; rc==kOkSdbRC && i<p->eN; ++i)
  223. {
  224. unsigned rowIdx = i+1;
  225. if((p->eV[i].uuid = cmCsvCellUInt(p->csvH,rowIdx,kUuidColIdx)) == UINT_MAX )
  226. rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kUuidColIdx,"uuid");
  227. if((p->eV[i].baseUuid = cmCsvCellUInt(p->csvH,rowIdx,kBaseUuidColIdx)) == UINT_MAX )
  228. rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kBaseUuidColIdx,"baseUuid");
  229. if((p->eV[i].chIdx = cmCsvCellUInt(p->csvH,rowIdx,kChIdxColIdx)) == UINT_MAX )
  230. rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kChIdxColIdx,"chIdx");
  231. else
  232. p->eV[i].chIdx -= 1; // CSV channel index is 1 based
  233. if((p->eV[i].obi = cmCsvCellUInt(p->csvH,rowIdx,kObiColIdx)) == UINT_MAX )
  234. rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kObiColIdx,"obi");
  235. else
  236. p->eV[i].obi -= 1;
  237. if((p->eV[i].ibi = cmCsvCellUInt(p->csvH,rowIdx,kIbiColIdx)) == UINT_MAX )
  238. rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kIbiColIdx,"ibi");
  239. else
  240. p->eV[i].ibi -= 1;
  241. if((p->eV[i].iei = cmCsvCellUInt(p->csvH,rowIdx,kIeiColIdx)) == UINT_MAX )
  242. rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kIeiColIdx,"obi");
  243. else
  244. p->eV[i].iei -= 1;
  245. if((p->eV[i].oei = cmCsvCellUInt(p->csvH,rowIdx,kOeiColIdx)) == UINT_MAX )
  246. rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kOeiColIdx,"ibi");
  247. else
  248. p->eV[i].oei -= 1;
  249. if((p->eV[i].src = cmCsvCellText(p->csvH,rowIdx,kSrcColIdx)) == NULL )
  250. rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kSrcColIdx,"src");
  251. if((p->eV[i].midi = cmCsvCellInt(p->csvH,rowIdx,kMidiColIdx)) == INT_MAX )
  252. rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kMidiColIdx,"midi");
  253. if((p->eV[i].instr = cmCsvCellText(p->csvH,rowIdx,kInstrColIdx)) == NULL )
  254. rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kInstrColIdx,"instr");
  255. if((p->eV[i].srate = cmCsvCellUInt(p->csvH,rowIdx,kSrateColIdx)) == UINT_MAX )
  256. rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kSrateColIdx,"srate");
  257. if((p->eV[i].chCnt = cmCsvCellUInt(p->csvH,rowIdx,kChCntColIdx)) == UINT_MAX )
  258. rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kChCntColIdx,"chCnt");
  259. cmCsvCell_t* c;
  260. if((c = cmCsvCellPtr(p->csvH,rowIdx,kNotesColIdx)) == NULL )
  261. {
  262. rc = cmErrMsg(&p->ctx.err,kSyntaxErrSdbRC,"Syntax Error: No 'notes' or 'audio file name' field for row %i in '%s'.",rowIdx+1,cmStringNullGuard(csvFn));
  263. goto errLabel;
  264. }
  265. // count the number of 'notes'
  266. unsigned nn = 0;
  267. for(; c->rowPtr != NULL; c=c->rowPtr)
  268. ++nn;
  269. if( nn > 0 )
  270. {
  271. unsigned k = 0;
  272. // allocate the 'notes' ptr array - the last entry is set to NULL.
  273. p->eV[i].notesV = cmLhAllocZ(p->lhH,const cmChar_t*,nn+1);
  274. // read each note
  275. for(c=cmCsvCellPtr(p->csvH,rowIdx,kNotesColIdx); c!=NULL&&c->rowPtr!=NULL; c=c->rowPtr,++k)
  276. if(( p->eV[i].notesV[k] = cmCsvCellText(p->csvH,rowIdx,kNotesColIdx+k)) == NULL )
  277. rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kNotesColIdx+k,"notes");
  278. assert(k==nn);
  279. }
  280. // read the audio file name
  281. if((p->eV[i].afn = cmCsvCellText(p->csvH,rowIdx,kNotesColIdx+nn)) == NULL )
  282. rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kNotesColIdx+nn,"afn");
  283. }
  284. errLabel:
  285. return rc;
  286. }
  287. // Compare 'label' to every string in tV[i] and return true if any comparision is a match.
  288. // If 'subFlV[i]' is set then 'label' must only contain tV[i] as a substring to match.
  289. // If 'negFlV[i]' is set then return true if any comparision is a mismatch.
  290. bool _cmSdbSelectText( const cmSdbEvent_t* r, const cmChar_t** tV, const bool* subFlV, const bool* negFlV, const cmChar_t* label )
  291. {
  292. unsigned i;
  293. if( label == NULL )
  294. return false;
  295. if( tV == NULL )
  296. return true;
  297. for(i=0; tV[i]!=NULL; ++i)
  298. {
  299. bool matchFl = false;
  300. if( subFlV[i] )
  301. matchFl = strstr(label,tV[i]) != NULL;
  302. else
  303. matchFl = strcmp(tV[i],label)==0;
  304. if( negFlV[i] )
  305. matchFl = !matchFl;
  306. if(matchFl)
  307. return true;
  308. }
  309. return false;
  310. }
  311. unsigned _cmSdbStrVectCnt( const cmChar_t** v )
  312. {
  313. unsigned n = 0;
  314. unsigned i = 0;
  315. if( v == NULL )
  316. return 0;
  317. for(i=0; v[i]!=NULL; ++i)
  318. ++n;
  319. return n;
  320. }
  321. void _cmSdbStrVectFlags( const cmChar_t** v, bool* sV, bool* nV )
  322. {
  323. unsigned i = 0;
  324. if( v == NULL )
  325. return;
  326. for(i=0; v[i]!=NULL; ++i)
  327. {
  328. nV[i] = false;
  329. sV[i] = false;
  330. if( strncmp(v[i],"*!",2)==0 || strncmp(v[i],"!*",2)==0)
  331. {
  332. sV[i] = nV[i] = true;
  333. v[i] += 2;
  334. }
  335. else
  336. {
  337. if( strncmp(v[i],"!",1)==0 )
  338. {
  339. nV[i] = true;
  340. v[i] += 1;
  341. }
  342. if( strncmp(v[i],"*",1)==0 )
  343. {
  344. sV[i] = true;
  345. v[i] += 1;
  346. }
  347. }
  348. }
  349. }
  350. cmSdbRC_t cmSdbSelect(
  351. cmSdbH_t h,
  352. double srate,
  353. const cmChar_t** instrV,
  354. const cmChar_t** srcV,
  355. const cmChar_t** notesV,
  356. double minDurSec,
  357. double maxDurSec,
  358. unsigned minChCnt,
  359. cmSdbResponseH_t* rhp )
  360. {
  361. cmSdbRC_t rc = kOkSdbRC;
  362. cmSdb_t* p = _cmSdbHandleToPtr(h);
  363. unsigned i;
  364. cmSdbRsp_t* rp = _cmSdbRspAlloc(p,rhp);
  365. // get the length of each string vector
  366. unsigned srcN = _cmSdbStrVectCnt(srcV);
  367. unsigned insN = _cmSdbStrVectCnt(instrV);
  368. unsigned notN = _cmSdbStrVectCnt(notesV);
  369. // allocate flag vectors
  370. bool srcSubFlV[ srcN ];
  371. bool srcNegFlV[ srcN ];
  372. bool insSubFlV[ insN ];
  373. bool insNegFlV[ insN ];
  374. bool notSubFlV[ notN ];
  375. bool notNegFlV[ notN ];
  376. // fill the flag vectors
  377. _cmSdbStrVectFlags(srcV, srcSubFlV,srcNegFlV);
  378. _cmSdbStrVectFlags(instrV,insSubFlV,insNegFlV);
  379. _cmSdbStrVectFlags(notesV,notSubFlV,notNegFlV);
  380. for(i=0; i<p->eN; ++i)
  381. {
  382. const cmSdbEvent_t* r = p->eV + i;
  383. double durSec = (double)r->srate * (r->oei - r->obi);
  384. unsigned j;
  385. if( srate!=0 && srate!=r->srate )
  386. continue;
  387. if( durSec < minDurSec || (maxDurSec!=0 && maxDurSec < durSec) )
  388. continue;
  389. if( minChCnt!=0 && r->chCnt > minChCnt )
  390. continue;
  391. if( !_cmSdbSelectText(r,srcV,srcSubFlV,srcNegFlV,r->src) )
  392. continue;
  393. if( !_cmSdbSelectText(r,instrV,insSubFlV,insNegFlV,r->instr) )
  394. continue;
  395. if( r->notesV != NULL )
  396. for(j=0; r->notesV[j]!=NULL; ++j)
  397. if( _cmSdbSelectText(r,notesV,notSubFlV,notNegFlV,r->notesV[j]) == true )
  398. break;
  399. if( r->notesV[j]==NULL )
  400. continue;
  401. _cmSdbRspInsertIndex(p,rp,i);
  402. }
  403. return rc;
  404. }
  405. cmSdbRC_t cmSdbSelectChPairs( cmSdbH_t h, const cmSdbEvent_t* ep, cmSdbResponseH_t* rhp )
  406. {
  407. cmSdbRC_t rc = kOkSdbRC;
  408. cmSdb_t* p = _cmSdbHandleToPtr(h);
  409. cmSdbRsp_t* rp = _cmSdbRspAlloc(p,rhp);
  410. unsigned i;
  411. // for each channel of this event
  412. for(i=0; i<ep->chCnt; ++i)
  413. {
  414. // if i channel is not the known events channel
  415. if( ep->chIdx != i )
  416. {
  417. unsigned j;
  418. // examine each record
  419. for(j=0; j<p->eN; ++j)
  420. // if eV[j] shares a baseUuid but is on a different channel than *ep ...
  421. if( p->eV[j].baseUuid == ep->baseUuid && p->eV[j].chIdx==i )
  422. {
  423. // .. then a match has been found
  424. _cmSdbRspInsertIndex(p,rp,j);
  425. break;
  426. }
  427. if( j== p->eN )
  428. {
  429. rc = cmErrMsg(&p->ctx.err,kChPairNotFoundSdbRC,"The channel pair associated with 'id:%i instr:%s src:%s ch index:%i could not be found.",ep->uuid,cmStringNullGuard(ep->instr),cmStringNullGuard(ep->src),ep->chIdx);
  430. }
  431. }
  432. }
  433. return rc;
  434. }
  435. unsigned cmSdbResponseCount( cmSdbResponseH_t rh )
  436. {
  437. cmSdbRsp_t* rp = _cmSdbRspHandleToPtr(rh);
  438. return rp->cnt;
  439. }
  440. const cmSdbEvent_t* cmSdbResponseEvent( cmSdbResponseH_t rh, unsigned index )
  441. {
  442. cmSdbRsp_t* rp = _cmSdbRspHandleToPtr(rh);
  443. if( index >= rp->cnt )
  444. return NULL;
  445. cmSdbRspBlk_t* bp = rp->blocks;
  446. unsigned i;
  447. for(i=0; bp!=NULL; i+=bp->cnt,bp=bp->link)
  448. if( i <= index && index < (i + bp->cnt) )
  449. return rp->p->eV + bp->indexV[index-i];
  450. cmErrMsg(&rp->p->ctx.err,kInvalidRspIdxSdbRC,"Invalid query response index=%i.",index);
  451. return NULL;
  452. }
  453. bool cmSdbResponseIsValid( cmSdbResponseH_t rh )
  454. { return rh.h != NULL; }
  455. cmSdbRC_t cmSdbResponseFree( cmSdbResponseH_t* rhp )
  456. {
  457. cmSdbRC_t rc = kOkSdbRC;
  458. if( rhp == NULL || cmSdbResponseIsValid(*rhp)==false )
  459. return rc;
  460. cmSdbRsp_t* rp = _cmSdbRspHandleToPtr(*rhp);
  461. _cmSdbRspFree(rp);
  462. rhp->h = NULL;
  463. return rc;
  464. }
  465. void cmSdbResponsePrint( cmSdbResponseH_t rh, cmRpt_t* rpt )
  466. {
  467. unsigned n = cmSdbResponseCount(rh);
  468. unsigned i;
  469. for(i=0; i<n; ++i)
  470. {
  471. const cmSdbEvent_t* e = cmSdbResponseEvent(rh,i);
  472. if( e != NULL )
  473. cmRptPrintf(rpt,"%6i %6i %2i %12i %12i %12i %12i %2i %6i %2i %10s %15s\n",
  474. e->uuid,e->baseUuid,e->chIdx,e->obi,e->ibi,e->iei,e->oei,e->midi,e->srate,e->chCnt,
  475. cmStringNullGuard(e->src), cmStringNullGuard(e->instr) );
  476. }
  477. }
  478. cmSdbRC_t cmSdbSyncChPairs( cmSdbH_t h )
  479. {
  480. cmSdbRC_t rc = kOkSdbRC;
  481. cmSdb_t* p = _cmSdbHandleToPtr(h);
  482. unsigned i;
  483. // for each multi-channel event
  484. for(i=0; i<p->eN; ++i)
  485. if(p->eV[i].chCnt > 1 )
  486. {
  487. const cmSdbEvent_t* ep = p->eV + i;
  488. unsigned iV[ep->chCnt];
  489. unsigned j,k;
  490. // load iV[] with the event indexes of the channel pairs
  491. for(j=0,k=0; j<p->eN && k<ep->chCnt; ++j)
  492. if( p->eV[j].baseUuid == ep->baseUuid )
  493. {
  494. assert( p->eV[j].chIdx < ep->chCnt );
  495. iV[p->eV[j].chIdx] = j;
  496. ++k;
  497. }
  498. if( k != ep->chCnt )
  499. rc = cmErrMsg(&p->ctx.err,kChPairNotFoundSdbRC,"The channel pair associated with 'id:%i instr:%s src:%s ch index:%i could not be found.",ep->uuid,cmStringNullGuard(ep->instr),cmStringNullGuard(ep->src),ep->chIdx);
  500. else
  501. {
  502. unsigned mobi = ep->obi;
  503. unsigned mibi = ep->ibi;
  504. unsigned miei = ep->iei;
  505. unsigned moei = ep->oei;
  506. // get the min onsets and max offsets
  507. for(j=0; j<ep->chCnt; ++j)
  508. {
  509. mobi = cmMin(mobi,p->eV[ iV[j] ].obi);
  510. mibi = cmMin(mibi,p->eV[ iV[j] ].ibi);
  511. miei = cmMax(miei,p->eV[ iV[j] ].iei);
  512. moei = cmMax(moei,p->eV[ iV[j] ].oei);
  513. }
  514. // set the onsets to the min onset / offsets to max offsets
  515. for(j=0; j<ep->chCnt; ++j)
  516. {
  517. p->eV[ iV[j] ].obi = mobi;
  518. p->eV[ iV[j] ].ibi = mibi;
  519. p->eV[ iV[j] ].iei = miei;
  520. p->eV[ iV[j] ].oei = moei;
  521. }
  522. }
  523. }
  524. return rc;
  525. }
  526. cmSdbRC_t cmSdbTest( cmCtx_t* ctx )
  527. {
  528. cmSdbRC_t rc = kOkSdbRC;
  529. cmSdbH_t h = cmSdbNullHandle;
  530. const cmChar_t* audioDir = "/home/kevin/media/audio";
  531. const cmChar_t* csvFn = "/home/kevin/temp/sdb0/sdb_master.csv";
  532. cmErr_t err;
  533. cmErrSetup(&err,&ctx->rpt,"sdb test");
  534. if((rc = cmSdbCreate(ctx, &h, audioDir, csvFn )) != kOkSdbRC )
  535. {
  536. rc = cmErrMsg(&err,rc,"sdb create failed.");
  537. goto errLabel;
  538. }
  539. if((rc = cmSdbSyncChPairs(h)) != kOkSdbRC )
  540. {
  541. rc = cmErrMsg(&err,rc,"sdb sync-ch-pairs failed.");
  542. goto errLabel;
  543. }
  544. if(0)
  545. {
  546. cmSdbResponseH_t rH = cmSdbResponseNullHandle;
  547. const cmChar_t* instrV[] = { "*viol", NULL };
  548. if((rc = cmSdbSelect(h,0,instrV,NULL,NULL,0,0,0,&rH)) != kOkSdbRC )
  549. {
  550. rc = cmErrMsg(&err,rc,"sdb query failed.");
  551. goto errLabel;
  552. }
  553. cmSdbResponsePrint(rH,&ctx->rpt);
  554. cmSdbResponseFree(&rH);
  555. }
  556. errLabel:
  557. if((rc = cmSdbDestroy(&h)) != kOkSdbRC )
  558. rc = cmErrMsg(&err,rc,"sdb destroy failed.");
  559. return rc;
  560. }