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.

cmSdb.c 38KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554
  1. //| Copyright: (C) 2009-2020 Kevin Larke <contact AT larke DOT org>
  2. //| License: GNU GPL version 3.0 or above. See the accompanying LICENSE file.
  3. #include "cmGlobal.h"
  4. #include "cmFloatTypes.h"
  5. #include "cmRpt.h"
  6. #include "cmErr.h"
  7. #include "cmCtx.h"
  8. #include "cmMem.h"
  9. #include "cmMallocDebug.h"
  10. #include "cmLinkedHeap.h"
  11. #include "cmLex.h"
  12. #include "cmCsv.h"
  13. #include "cmSdb.h"
  14. #include "cmText.h"
  15. #include "cmMath.h"
  16. #include "cmTime.h"
  17. #include "cmMidi.h"
  18. #include "cmVectOpsTemplateMain.h"
  19. #include "cmAudioFile.h"
  20. #include "cmFileSys.h"
  21. typedef enum
  22. {
  23. kUuidColIdx,
  24. kBaseUuidColIdx,
  25. kChIdxColIdx,
  26. kObiColIdx,
  27. kIbiColIdx,
  28. kIeiColIdx,
  29. kOeiColIdx,
  30. kSrcColIdx,
  31. kMidiColIdx,
  32. kInstrColIdx,
  33. kSrateColIdx,
  34. kChCntColIdx,
  35. kNotesColIdx,
  36. kAfnColIdx,
  37. kInvalidColIdx
  38. } cmSdbColIdx_t;
  39. struct cmSdb_str;
  40. typedef struct cmSdbSeqBlk_str
  41. {
  42. cmSdbSeqEvent_t* eV;
  43. unsigned cnt;
  44. struct cmSdbSeqBlk_str* link;
  45. } cmSdbSeqBlk_t;
  46. typedef struct cmSdbSeq_str
  47. {
  48. struct cmSdb_str* p;
  49. cmSdbSeqBlk_t* blocks;
  50. cmSdbSeqBlk_t* ebp;
  51. unsigned cnt; // total count of events in all blocks
  52. unsigned chCnt; // max(chIdx)+1 of all events
  53. double minDurSec; // min dur of all events
  54. double maxDurSec; // max dur of all events
  55. struct cmSdbSeq_str* link;
  56. } cmSdbSeq_t;
  57. typedef struct cmSdbRspBlk_str
  58. {
  59. unsigned* indexV; // indexV[ cmSdb_t.blkIdxAllocCnt ]
  60. unsigned cnt; // count of indexes used
  61. struct cmSdbRspBlk_str* link; // cmSdbRsp_t.blocks link
  62. } cmSdbRspBlk_t;
  63. typedef struct cmSdbRsp_str
  64. {
  65. struct cmSdb_str* p; //
  66. cmSdbRspBlk_t* blocks; // first block ptr
  67. cmSdbRspBlk_t* ebp; // end block ptr
  68. unsigned cnt; // total count of indexes
  69. struct cmSdbRsp_str* link; // cmSdb_t.responses link
  70. } cmSdbRsp_t;
  71. typedef struct cmSdb_str
  72. {
  73. cmCtx_t ctx;
  74. cmLHeapH_t lhH;
  75. cmCsvH_t csvH;
  76. cmSdbEvent_t* eV;
  77. unsigned eN;
  78. cmChar_t* audioDir;
  79. unsigned blkIdxAllocCnt;
  80. unsigned blkEvtAllocCnt;
  81. cmSdbRsp_t* responses;
  82. cmSdbSeq_t* seqs;
  83. } cmSdb_t;
  84. cmSdbH_t cmSdbNullHandle = cmSTATIC_NULL_HANDLE;
  85. cmSdbResponseH_t cmSdbResponseNullHandle = cmSTATIC_NULL_HANDLE;
  86. cmSdbSeqH_t cmSdbSeqNullHandle = cmSTATIC_NULL_HANDLE;
  87. cmSdb_t* _cmSdbHandleToPtr( cmSdbH_t h )
  88. {
  89. cmSdb_t* p = (cmSdb_t*)h.h;
  90. assert( p != NULL );
  91. return p;
  92. }
  93. void _cmSdbRspFree( cmSdbRsp_t* );
  94. cmSdbRC_t _cmSdbSeqFree( cmSdbSeq_t* );
  95. cmSdbRC_t _cmSdbDestroy( cmSdb_t* p )
  96. {
  97. cmSdbRC_t rc = kOkSdbRC;
  98. if( cmCsvFinalize(&p->csvH) != kOkCsvRC )
  99. rc = cmErrMsg(&p->ctx.err,kCsvFailSdbRC,"CSV file finalize failed.");
  100. while( p->responses != NULL )
  101. _cmSdbRspFree(p->responses);
  102. while( p->seqs != NULL )
  103. _cmSdbSeqFree(p->seqs);
  104. cmLHeapDestroy(&p->lhH);
  105. cmMemFree(p);
  106. return rc;
  107. }
  108. cmSdbRC_t cmSdbCreate( cmCtx_t* ctx, cmSdbH_t* hp, const cmChar_t* csvFn, const cmChar_t* audioDir )
  109. {
  110. cmSdbRC_t rc;
  111. if((rc = cmSdbDestroy(hp)) != kOkSdbRC )
  112. return rc;
  113. cmSdb_t* p = cmMemAllocZ(cmSdb_t,1);
  114. p->ctx = *ctx;
  115. p->blkIdxAllocCnt = 1024;
  116. p->blkEvtAllocCnt = 1024;
  117. cmErrSetup(&p->ctx.err,&ctx->rpt,"sdb");
  118. if( cmLHeapIsValid( p->lhH = cmLHeapCreate(8192,ctx)) == false )
  119. {
  120. rc = cmErrMsg(&p->ctx.err,kLHeapFailSdbRC,"Linked heap mgr. allocation failed.");
  121. goto errLabel;
  122. }
  123. hp->h = p;
  124. if( csvFn != NULL )
  125. if((rc = cmSdbLoad(*hp,csvFn,audioDir)) != kOkSdbRC )
  126. goto errLabel;
  127. errLabel:
  128. if( rc != kOkSdbRC )
  129. _cmSdbDestroy(p);
  130. return rc;
  131. }
  132. cmSdbRC_t cmSdbDestroy( cmSdbH_t* hp )
  133. {
  134. cmSdbRC_t rc = kOkSdbRC;
  135. if( hp==NULL || cmSdbIsValid(*hp)==false )
  136. return rc;
  137. cmSdb_t* p = _cmSdbHandleToPtr(*hp);
  138. if((rc = _cmSdbDestroy(p)) != kOkSdbRC )
  139. return rc;
  140. hp->h = NULL;
  141. return rc;
  142. }
  143. bool cmSdbIsValid( cmSdbH_t h )
  144. { return h.h != NULL; }
  145. cmSdbRC_t _cmSdbSyntaxError(cmSdb_t* p, const cmChar_t* csvFn, unsigned rowIdx, unsigned colIdx, const cmChar_t* colLabel )
  146. {
  147. 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));
  148. }
  149. cmSdbRC_t cmSdbLoad( cmSdbH_t h, const cmChar_t* csvFn, const cmChar_t* audioDir )
  150. {
  151. cmSdbRC_t rc = kOkSdbRC;
  152. unsigned i;
  153. cmSdb_t* p = _cmSdbHandleToPtr(h);
  154. if( cmCsvInitializeFromFile(&p->csvH, csvFn, 0, &p->ctx ) != kOkCsvRC )
  155. {
  156. rc = cmErrMsg(&p->ctx.err,kCsvFailSdbRC,"CSV file load fail on '%s'.",cmStringNullGuard(csvFn));
  157. goto errLabel;
  158. }
  159. p->eN = cmCsvRowCount(p->csvH)-1;
  160. // release all the memory held by the linked heap
  161. cmLHeapClear(p->lhH,true);
  162. p->eV = cmLhAllocZ(p->lhH,cmSdbEvent_t,p->eN);
  163. for(i=0; rc==kOkSdbRC && i<p->eN; ++i)
  164. {
  165. unsigned rowIdx = i+1;
  166. if((p->eV[i].uuid = cmCsvCellUInt(p->csvH,rowIdx,kUuidColIdx)) == UINT_MAX )
  167. rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kUuidColIdx,"uuid");
  168. if((p->eV[i].baseUuid = cmCsvCellUInt(p->csvH,rowIdx,kBaseUuidColIdx)) == UINT_MAX )
  169. rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kBaseUuidColIdx,"baseUuid");
  170. if((p->eV[i].chIdx = cmCsvCellUInt(p->csvH,rowIdx,kChIdxColIdx)) == UINT_MAX )
  171. rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kChIdxColIdx,"chIdx");
  172. else
  173. p->eV[i].chIdx -= 1; // CSV channel index is 1 based
  174. if((p->eV[i].obi = cmCsvCellUInt(p->csvH,rowIdx,kObiColIdx)) == UINT_MAX )
  175. rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kObiColIdx,"obi");
  176. else
  177. p->eV[i].obi -= 1;
  178. if((p->eV[i].ibi = cmCsvCellUInt(p->csvH,rowIdx,kIbiColIdx)) == UINT_MAX )
  179. rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kIbiColIdx,"ibi");
  180. else
  181. p->eV[i].ibi -= 1;
  182. if((p->eV[i].iei = cmCsvCellUInt(p->csvH,rowIdx,kIeiColIdx)) == UINT_MAX )
  183. rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kIeiColIdx,"obi");
  184. else
  185. p->eV[i].iei -= 1;
  186. if((p->eV[i].oei = cmCsvCellUInt(p->csvH,rowIdx,kOeiColIdx)) == UINT_MAX )
  187. rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kOeiColIdx,"ibi");
  188. else
  189. p->eV[i].oei -= 1;
  190. if((p->eV[i].src = cmCsvCellText(p->csvH,rowIdx,kSrcColIdx)) == NULL )
  191. rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kSrcColIdx,"src");
  192. if((p->eV[i].midi = cmCsvCellInt(p->csvH,rowIdx,kMidiColIdx)) == INT_MAX )
  193. rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kMidiColIdx,"midi");
  194. if((p->eV[i].instr = cmCsvCellText(p->csvH,rowIdx,kInstrColIdx)) == NULL )
  195. rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kInstrColIdx,"instr");
  196. if((p->eV[i].srate = cmCsvCellUInt(p->csvH,rowIdx,kSrateColIdx)) == UINT_MAX )
  197. rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kSrateColIdx,"srate");
  198. if((p->eV[i].chCnt = cmCsvCellUInt(p->csvH,rowIdx,kChCntColIdx)) == UINT_MAX )
  199. rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kChCntColIdx,"chCnt");
  200. cmCsvCell_t* c;
  201. if((c = cmCsvCellPtr(p->csvH,rowIdx,kNotesColIdx)) == NULL )
  202. {
  203. rc = cmErrMsg(&p->ctx.err,kSyntaxErrSdbRC,"Syntax Error: No 'notes' or 'audio file name' field for row %i in '%s'.",rowIdx+1,cmStringNullGuard(csvFn));
  204. goto errLabel;
  205. }
  206. // count the number of 'notes'
  207. unsigned nn = 0;
  208. for(; c->rowPtr != NULL; c=c->rowPtr)
  209. ++nn;
  210. if( nn > 0 )
  211. {
  212. unsigned k = 0;
  213. // allocate the 'notes' ptr array - the last entry is set to NULL.
  214. p->eV[i].notesV = cmLhAllocZ(p->lhH,const cmChar_t*,nn+1);
  215. // read each note
  216. for(c=cmCsvCellPtr(p->csvH,rowIdx,kNotesColIdx); c!=NULL&&c->rowPtr!=NULL; c=c->rowPtr,++k)
  217. if(( p->eV[i].notesV[k] = cmCsvCellText(p->csvH,rowIdx,kNotesColIdx+k)) == NULL )
  218. rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kNotesColIdx+k,"notes");
  219. assert(k==nn);
  220. }
  221. // read the audio file name
  222. if((p->eV[i].afn = cmCsvCellText(p->csvH,rowIdx,kNotesColIdx+nn)) == NULL )
  223. rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kNotesColIdx+nn,"afn");
  224. }
  225. // store the audio directory
  226. if( cmTextLength(audioDir) )
  227. p->audioDir = cmLhAllocStr(p->lhH,audioDir);
  228. else
  229. {
  230. cmLhFree(p->lhH,&p->audioDir);
  231. p->audioDir = NULL;
  232. }
  233. errLabel:
  234. return rc;
  235. }
  236. cmSdbRC_t cmSdbSyncChPairs( cmSdbH_t h )
  237. {
  238. cmSdbRC_t rc = kOkSdbRC;
  239. cmSdb_t* p = _cmSdbHandleToPtr(h);
  240. unsigned i;
  241. // for each multi-channel event
  242. for(i=0; i<p->eN; ++i)
  243. if(p->eV[i].chCnt > 1 )
  244. {
  245. const cmSdbEvent_t* ep = p->eV + i;
  246. unsigned iV[ep->chCnt];
  247. unsigned j,k;
  248. // load iV[] with the event indexes of the channel pairs
  249. for(j=0,k=0; j<p->eN && k<ep->chCnt; ++j)
  250. if( p->eV[j].baseUuid == ep->baseUuid )
  251. {
  252. assert( p->eV[j].chIdx < ep->chCnt );
  253. iV[p->eV[j].chIdx] = j;
  254. ++k;
  255. }
  256. if( k != ep->chCnt )
  257. 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);
  258. else
  259. {
  260. unsigned mobi = ep->obi;
  261. unsigned mibi = ep->ibi;
  262. unsigned miei = ep->iei;
  263. unsigned moei = ep->oei;
  264. // get the min onsets and max offsets
  265. for(j=0; j<ep->chCnt; ++j)
  266. {
  267. mobi = cmMin(mobi,p->eV[ iV[j] ].obi);
  268. mibi = cmMin(mibi,p->eV[ iV[j] ].ibi);
  269. miei = cmMax(miei,p->eV[ iV[j] ].iei);
  270. moei = cmMax(moei,p->eV[ iV[j] ].oei);
  271. }
  272. // set the onsets to the min onset / offsets to max offsets
  273. for(j=0; j<ep->chCnt; ++j)
  274. {
  275. p->eV[ iV[j] ].obi = mobi;
  276. p->eV[ iV[j] ].ibi = mibi;
  277. p->eV[ iV[j] ].iei = miei;
  278. p->eV[ iV[j] ].oei = moei;
  279. }
  280. }
  281. }
  282. return rc;
  283. }
  284. const cmSdbEvent_t* _cmSdbEvent( cmSdb_t* p, unsigned uuid )
  285. {
  286. unsigned i;
  287. for(i=0; i<p->eN; ++i)
  288. if( p->eV[i].uuid == uuid )
  289. return p->eV + i;
  290. return NULL;
  291. }
  292. const cmSdbEvent_t* cmSdbEvent( cmSdbH_t h, unsigned uuid )
  293. {
  294. cmSdb_t* p = _cmSdbHandleToPtr(h);
  295. return _cmSdbEvent(p,uuid);
  296. }
  297. //================================================================================================================================
  298. cmSdbRsp_t* _cmSdbRspHandleToPtr( cmSdbResponseH_t h )
  299. {
  300. cmSdbRsp_t* p = (cmSdbRsp_t*)h.h;
  301. assert( p != NULL );
  302. return p;
  303. }
  304. void _cmSdbRspBlkFree( cmSdb_t* p, cmSdbRspBlk_t* bp )
  305. {
  306. cmLhFree(p->lhH, bp->indexV);
  307. cmLhFree(p->lhH, bp);
  308. }
  309. cmSdbRspBlk_t* _cmSdbRspBlkUnlink( cmSdbRsp_t* rp, cmSdbRspBlk_t* bp )
  310. {
  311. cmSdbRspBlk_t* dp = rp->blocks;
  312. cmSdbRspBlk_t* pp = NULL;
  313. for(; dp!=NULL; dp=dp->link)
  314. {
  315. if( dp == bp )
  316. {
  317. if( pp == NULL )
  318. rp->blocks = dp->link;
  319. else
  320. pp->link = dp->link;
  321. return bp;
  322. }
  323. pp = dp;
  324. }
  325. assert(0);
  326. return NULL;
  327. }
  328. void _cmSdbRspInsertIndex( cmSdb_t* p, cmSdbRsp_t* rp, unsigned evtIndex )
  329. {
  330. if( rp->ebp == NULL || rp->ebp->cnt == p->blkIdxAllocCnt )
  331. {
  332. cmSdbRspBlk_t* bp = cmLhAllocZ(p->lhH,cmSdbRspBlk_t,1);
  333. bp->indexV = cmLhAllocZ(p->lhH,unsigned,p->blkIdxAllocCnt);
  334. if( rp->ebp != NULL )
  335. rp->ebp->link = bp;
  336. if( rp->blocks == NULL )
  337. rp->blocks = bp;
  338. rp->ebp = bp;
  339. }
  340. assert( rp->ebp!=NULL && rp->ebp->cnt < p->blkIdxAllocCnt );
  341. rp->ebp->indexV[ rp->ebp->cnt++ ] = evtIndex;
  342. rp->cnt += 1;
  343. }
  344. cmSdbRsp_t* _cmSdbRspUnlink( cmSdbRsp_t* rp )
  345. {
  346. cmSdb_t* p = rp->p;
  347. cmSdbRsp_t* dp = p->responses;
  348. cmSdbRsp_t* pp = NULL;
  349. for(; dp!=NULL; dp=dp->link)
  350. {
  351. if( dp == rp )
  352. {
  353. if( pp == NULL )
  354. p->responses = dp->link;
  355. else
  356. pp->link = dp->link;
  357. return rp;
  358. }
  359. pp = dp;
  360. }
  361. assert( 0 );
  362. return NULL;
  363. }
  364. void _cmSdbRspFree( cmSdbRsp_t* rp )
  365. {
  366. _cmSdbRspUnlink(rp);
  367. while( rp->blocks != NULL )
  368. {
  369. cmSdbRspBlk_t* np = rp->blocks->link;
  370. cmSdbRspBlk_t* bp;
  371. if((bp = _cmSdbRspBlkUnlink(rp,rp->blocks)) != NULL )
  372. _cmSdbRspBlkFree(rp->p,bp);
  373. rp->blocks = np;
  374. }
  375. cmLhFree(rp->p->lhH,rp);
  376. }
  377. cmSdbRsp_t* _cmSdbRspAlloc( cmSdb_t* p )
  378. {
  379. cmSdbRsp_t* rp = cmLhAllocZ(p->lhH,cmSdbRsp_t,1);
  380. rp->p = p;
  381. rp->link = p->responses;
  382. p->responses = rp;
  383. return rp;
  384. }
  385. // Compare 'label' to every string in tV[i] and return true if any comparision is a match.
  386. // If 'subFlV[i]' is set then 'label' must only contain tV[i] as a substring to match.
  387. // If 'negFlV[i]' is set then return true if any comparision is a mismatch.
  388. bool _cmSdbSelectText( const cmSdbEvent_t* r, const cmChar_t** tV, const bool* subFlV, const bool* negFlV, const cmChar_t* label )
  389. {
  390. unsigned i;
  391. if( label == NULL )
  392. return false;
  393. if( tV == NULL )
  394. return true;
  395. for(i=0; tV[i]!=NULL; ++i)
  396. {
  397. bool matchFl = false;
  398. if( subFlV[i] )
  399. matchFl = strstr(label,tV[i]) != NULL;
  400. else
  401. matchFl = strcmp(tV[i],label)==0;
  402. if( negFlV[i] )
  403. matchFl = !matchFl;
  404. if(matchFl)
  405. return true;
  406. }
  407. return false;
  408. }
  409. unsigned _cmSdbStrVectCnt( const cmChar_t** v )
  410. {
  411. unsigned n = 0;
  412. unsigned i = 0;
  413. if( v == NULL )
  414. return 0;
  415. for(i=0; v[i]!=NULL; ++i)
  416. ++n;
  417. return n;
  418. }
  419. void _cmSdbStrVectFlags( const cmChar_t** v, bool* sV, bool* nV )
  420. {
  421. unsigned i = 0;
  422. if( v == NULL )
  423. return;
  424. for(i=0; v[i]!=NULL; ++i)
  425. {
  426. nV[i] = false;
  427. sV[i] = false;
  428. if( strncmp(v[i],"*!",2)==0 || strncmp(v[i],"!*",2)==0)
  429. {
  430. sV[i] = nV[i] = true;
  431. v[i] += 2;
  432. }
  433. else
  434. {
  435. if( strncmp(v[i],"!",1)==0 )
  436. {
  437. nV[i] = true;
  438. v[i] += 1;
  439. }
  440. if( strncmp(v[i],"*",1)==0 )
  441. {
  442. sV[i] = true;
  443. v[i] += 1;
  444. }
  445. }
  446. }
  447. }
  448. cmSdbRC_t cmSdbSelect(
  449. cmSdbH_t h,
  450. double srate,
  451. const cmChar_t** instrV,
  452. const cmChar_t** srcV,
  453. const cmChar_t** notesV,
  454. const unsigned* pitchV,
  455. double minDurSec,
  456. double maxDurSec,
  457. unsigned minChCnt,
  458. cmSdbResponseH_t* rhp )
  459. {
  460. cmSdbRC_t rc;
  461. if((rc = cmSdbResponseFree(rhp)) != kOkSdbRC )
  462. return rc;
  463. cmSdb_t* p = _cmSdbHandleToPtr(h);
  464. cmSdbRsp_t* rp = _cmSdbRspAlloc(p);
  465. unsigned i;
  466. // get the length of each string vector
  467. unsigned srcN = _cmSdbStrVectCnt(srcV);
  468. unsigned insN = _cmSdbStrVectCnt(instrV);
  469. unsigned notN = _cmSdbStrVectCnt(notesV);
  470. // allocate flag vectors
  471. bool srcSubFlV[ srcN ];
  472. bool srcNegFlV[ srcN ];
  473. bool insSubFlV[ insN ];
  474. bool insNegFlV[ insN ];
  475. bool notSubFlV[ notN ];
  476. bool notNegFlV[ notN ];
  477. // fill the flag vectors
  478. _cmSdbStrVectFlags(srcV, srcSubFlV,srcNegFlV);
  479. _cmSdbStrVectFlags(instrV,insSubFlV,insNegFlV);
  480. _cmSdbStrVectFlags(notesV,notSubFlV,notNegFlV);
  481. for(i=0; i<p->eN; ++i)
  482. {
  483. const cmSdbEvent_t* r = p->eV + i;
  484. double durSec = (double)r->srate * (r->oei - r->obi);
  485. unsigned j;
  486. if( srate!=0 && srate!=r->srate )
  487. continue;
  488. if( durSec < minDurSec || (maxDurSec!=0 && maxDurSec < durSec) )
  489. continue;
  490. if( minChCnt!=0 && r->chCnt > minChCnt )
  491. continue;
  492. if( !_cmSdbSelectText(r,srcV,srcSubFlV,srcNegFlV,r->src) )
  493. continue;
  494. if( !_cmSdbSelectText(r,instrV,insSubFlV,insNegFlV,r->instr) )
  495. continue;
  496. if( pitchV != NULL )
  497. {
  498. for(j=0; pitchV[j]!=kInvalidMidiPitch; ++j)
  499. if( pitchV[j] == r->midi )
  500. break;
  501. if( pitchV[j] != r->midi )
  502. continue;
  503. }
  504. if( r->notesV != NULL )
  505. {
  506. for(j=0; r->notesV[j]!=NULL; ++j)
  507. if( _cmSdbSelectText(r,notesV,notSubFlV,notNegFlV,r->notesV[j]) == true )
  508. break;
  509. if( r->notesV[j]==NULL )
  510. continue;
  511. }
  512. _cmSdbRspInsertIndex(p,rp,i);
  513. }
  514. rhp->h = rp;
  515. if(rc != kOkSdbRC )
  516. _cmSdbRspFree(rp);
  517. return rc;
  518. }
  519. cmSdbRC_t _cmSdbSelectChPairs( cmSdb_t* p, const cmSdbEvent_t* ep, cmSdbResponseH_t* rhp )
  520. {
  521. cmSdbRC_t rc;
  522. if((rc = cmSdbResponseFree(rhp)) != kOkSdbRC )
  523. return rc;
  524. cmSdbRsp_t* rp = _cmSdbRspAlloc(p);
  525. unsigned i;
  526. // for each channel of this event
  527. for(i=0; i<ep->chCnt; ++i)
  528. {
  529. // if i channel is not the known events channel
  530. if( ep->chIdx != i )
  531. {
  532. unsigned j;
  533. // examine each record
  534. for(j=0; j<p->eN; ++j)
  535. // if eV[j] shares a baseUuid but is on a different channel than *ep ...
  536. if( p->eV[j].baseUuid == ep->baseUuid && p->eV[j].chIdx==i )
  537. {
  538. // .. then a match has been found
  539. _cmSdbRspInsertIndex(p,rp,j);
  540. break;
  541. }
  542. if( j== p->eN )
  543. {
  544. 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);
  545. }
  546. }
  547. }
  548. rhp->h = rp;
  549. return rc;
  550. }
  551. cmSdbRC_t cmSdbSelectChPairs( cmSdbH_t h, const cmSdbEvent_t* ep, cmSdbResponseH_t* rhp )
  552. {
  553. cmSdb_t* p = _cmSdbHandleToPtr(h);
  554. return _cmSdbSelectChPairs( p, ep,rhp );
  555. }
  556. unsigned cmSdbResponseCount( cmSdbResponseH_t rh )
  557. {
  558. cmSdbRsp_t* rp = _cmSdbRspHandleToPtr(rh);
  559. return rp->cnt;
  560. }
  561. const cmSdbEvent_t* cmSdbResponseEvent( cmSdbResponseH_t rh, unsigned index )
  562. {
  563. cmSdbRsp_t* rp = _cmSdbRspHandleToPtr(rh);
  564. if( index >= rp->cnt )
  565. return NULL;
  566. cmSdbRspBlk_t* bp = rp->blocks;
  567. unsigned i;
  568. for(i=0; bp!=NULL; i+=bp->cnt,bp=bp->link)
  569. if( i <= index && index < (i + bp->cnt) )
  570. return rp->p->eV + bp->indexV[index-i];
  571. cmErrMsg(&rp->p->ctx.err,kInvalidRspIdxSdbRC,"Invalid query response index=%i.",index);
  572. return NULL;
  573. }
  574. bool cmSdbResponseIsValid( cmSdbResponseH_t rh )
  575. { return rh.h != NULL; }
  576. cmSdbRC_t cmSdbResponseFree( cmSdbResponseH_t* rhp )
  577. {
  578. cmSdbRC_t rc = kOkSdbRC;
  579. if( rhp == NULL || cmSdbResponseIsValid(*rhp)==false )
  580. return rc;
  581. cmSdbRsp_t* rp = _cmSdbRspHandleToPtr(*rhp);
  582. _cmSdbRspFree(rp);
  583. rhp->h = NULL;
  584. return rc;
  585. }
  586. void cmSdbResponsePrint( cmSdbResponseH_t rh, cmRpt_t* rpt )
  587. {
  588. unsigned n = cmSdbResponseCount(rh);
  589. unsigned i;
  590. for(i=0; i<n; ++i)
  591. {
  592. const cmSdbEvent_t* e = cmSdbResponseEvent(rh,i);
  593. if( e != NULL )
  594. cmRptPrintf(rpt,"%6i %6i %2i %12i %12i %12i %12i %2i %6i %2i %10s %15s\n",
  595. e->uuid,e->baseUuid,e->chIdx,e->obi,e->ibi,e->iei,e->oei,e->midi,e->srate,e->chCnt,
  596. cmStringNullGuard(e->src), cmStringNullGuard(e->instr) );
  597. }
  598. }
  599. //================================================================================================================================
  600. cmSdbSeq_t* _cmSdbSeqHandleToPtr( cmSdbSeqH_t sh )
  601. {
  602. cmSdbSeq_t* sp = (cmSdbSeq_t*)sh.h;
  603. assert(sp !=NULL );
  604. return sp;
  605. }
  606. void _cmSdbSeqInsertEvent( cmSdbSeq_t* sp, unsigned uuid, unsigned chIdx, double begSecs, double durSecs )
  607. {
  608. cmSdb_t* p = sp->p;
  609. // if no block has been allocated or the current block is full
  610. if( sp->ebp == NULL || sp->ebp->cnt >= p->blkEvtAllocCnt )
  611. {
  612. // allocate a new seq block recd
  613. cmSdbSeqBlk_t* bp = cmLhAllocZ(sp->p->lhH,cmSdbSeqBlk_t,1);
  614. // allocate a seq evt array
  615. bp->eV = cmLhAllocZ(sp->p->lhH,cmSdbSeqEvent_t,p->blkEvtAllocCnt);
  616. // link in the block recd
  617. if( sp->ebp != NULL )
  618. sp->ebp->link = bp;
  619. if( sp->blocks == NULL )
  620. {
  621. sp->blocks = bp;
  622. sp->minDurSec = durSecs;
  623. sp->maxDurSec = durSecs;
  624. }
  625. sp->ebp = bp;
  626. }
  627. assert( sp->ebp != NULL && sp->ebp->cnt < p->blkEvtAllocCnt );
  628. // get the next seq evt recd to fill
  629. cmSdbSeqEvent_t* ep = sp->ebp->eV + sp->ebp->cnt;
  630. // fill the seq evt recd
  631. ep->uuid = uuid;
  632. ep->begSec = begSecs;
  633. ep->durSec = durSecs;
  634. ep->outChIdx = chIdx;
  635. ep->gain = 1.0;
  636. // incr the seq evt cnt
  637. sp->ebp->cnt += 1;
  638. sp->cnt += 1;
  639. sp->chCnt = cmMax(sp->chCnt,chIdx+1);
  640. sp->minDurSec = cmMin(sp->minDurSec,durSecs);
  641. sp->maxDurSec = cmMax(sp->maxDurSec,durSecs);
  642. }
  643. // unlink a sequence record from p->seqs.
  644. cmSdbSeq_t* _cmSdbSeqUnlink( cmSdbSeq_t* sp )
  645. {
  646. cmSdb_t* p = sp->p;
  647. cmSdbSeq_t* cp = p->seqs;
  648. cmSdbSeq_t* pp = NULL;
  649. for(; cp!=NULL; cp=cp->link)
  650. {
  651. if( cp == sp )
  652. {
  653. if( pp == NULL )
  654. p->seqs = sp->link;
  655. else
  656. pp->link = sp->link;
  657. return sp;
  658. }
  659. pp = cp;
  660. }
  661. assert(0);
  662. return NULL;
  663. }
  664. // free a sequence record
  665. cmSdbRC_t _cmSdbSeqFree( cmSdbSeq_t* sp )
  666. {
  667. cmSdb_t* p = sp->p;
  668. // unlink this seq. record from p->seqs
  669. if( _cmSdbSeqUnlink(sp) == NULL )
  670. return cmErrMsg(&p->ctx.err,kAssertFailSdbRC,"Sequence unlink failed.");
  671. // release the seq blocks held by the sequence
  672. while( sp->blocks != NULL )
  673. {
  674. cmSdbSeqBlk_t* np = sp->blocks->link;
  675. cmLhFree(p->lhH,sp->blocks->eV);
  676. cmLhFree(p->lhH,sp->blocks);
  677. sp->blocks = np;
  678. }
  679. cmLhFree(p->lhH,sp);
  680. return kOkSdbRC;
  681. }
  682. // allocate a sequence record
  683. cmSdbSeq_t* _cmSdbSeqAlloc( cmSdb_t* p )
  684. {
  685. cmSdbSeq_t* sp = cmLhAllocZ(p->lhH,cmSdbSeq_t,1);
  686. sp->p = p;
  687. sp->link = p->seqs;
  688. p->seqs = sp;
  689. return sp;
  690. }
  691. cmSdbRC_t _cmSdbStoreSeqEvent(
  692. cmSdb_t* p,
  693. cmSdbSeq_t* sp,
  694. cmSdbResponseH_t rh,
  695. unsigned ri,
  696. unsigned seqChCnt,
  697. double begSecs,
  698. double limitEvtDurSecs,
  699. double* durSecsRef )
  700. {
  701. cmSdbRC_t rc = kOkSdbRC;
  702. double maxEvtDurSecs = 0;
  703. // retrieve the event record
  704. const cmSdbEvent_t* ep;
  705. if((ep = cmSdbResponseEvent(rh,ri)) == NULL )
  706. {
  707. rc = cmErrMsg(&p->ctx.err,kRspEvtNotFoundSdbRC,"A response event could not be found during random sequence generation.");
  708. goto errLabel;
  709. }
  710. cmSdbResponseH_t rh0 = cmSdbResponseNullHandle;
  711. unsigned rn0 = 0;
  712. unsigned ci = 0;
  713. // locate the channel pairs for 'ep'.
  714. if( seqChCnt>1 && ep->chCnt>1 )
  715. {
  716. if( _cmSdbSelectChPairs(p, ep, &rh0 ) != kOkSdbRC )
  717. {
  718. rc = cmErrMsg(&p->ctx.err,kChPairNotFoundSdbRC,"A response event could not find channel pairs during random sequence generation.");
  719. goto errLabel;
  720. }
  721. rn0 = cmSdbResponseCount(rh0);
  722. }
  723. while(1)
  724. {
  725. // calculate the event duration
  726. double durSecs = (double)(ep->oei - ep->obi)/ep->srate;
  727. // truncate the event if it is longer than limitEvtDurSecs
  728. if( limitEvtDurSecs!=0 && durSecs>limitEvtDurSecs )
  729. durSecs = cmMin(limitEvtDurSecs,durSecs);
  730. // track the longest event
  731. maxEvtDurSecs = cmMax(maxEvtDurSecs,durSecs);
  732. // store the sequence event
  733. _cmSdbSeqInsertEvent(sp,ep->uuid,ci,begSecs,durSecs);
  734. // incr the output ch index
  735. ++ci;
  736. // if all the out ch's are filled or the sample event has no more channels
  737. if( ci >= seqChCnt || ci-1 >= rn0 )
  738. break;
  739. // get the next channel pair
  740. if((ep = cmSdbResponseEvent(rh0,ci-1)) == NULL )
  741. {
  742. rc = cmErrMsg(&p->ctx.err,kRspEvtNotFoundSdbRC,"A channel pair response event could not be found during random sequence generation.");
  743. goto errLabel;
  744. }
  745. } // for each sample event pair
  746. errLabel:
  747. if( durSecsRef != NULL )
  748. *durSecsRef = maxEvtDurSecs;
  749. cmSdbResponseFree(&rh0);
  750. return rc;
  751. }
  752. cmSdbRC_t cmSdbSeqRand(
  753. cmSdbResponseH_t rh,
  754. unsigned seqDurSecs,
  755. unsigned seqChCnt,
  756. unsigned minEvtPerSec,
  757. unsigned maxEvtPerSec,
  758. cmSdbSeqH_t* shp )
  759. {
  760. cmSdbRC_t rc;
  761. if((rc = cmSdbSeqFree(shp)) != kOkSdbRC )
  762. return rc;
  763. cmSdbRsp_t* rp = _cmSdbRspHandleToPtr(rh);
  764. cmSdb_t* p = rp->p;
  765. cmSdbSeq_t* sp = _cmSdbSeqAlloc(p);
  766. if( seqChCnt < 1 )
  767. return cmErrMsg(&p->ctx.err,kInvalidArgSdbRC,"The random sequence generator channel count parameter must be non-zero.");
  768. if( seqDurSecs <= 0 )
  769. return cmErrMsg(&p->ctx.err,kInvalidArgSdbRC,"The random sequence generator signal duration must be greater than 0.");
  770. if( maxEvtPerSec < minEvtPerSec )
  771. return cmErrMsg(&p->ctx.err,kInvalidArgSdbRC,"The random sequence generator max. events per second must be greater or equal to the min. events per second.");
  772. if((rc = cmSdbSeqFree(shp)) != kOkSdbRC )
  773. return rc;
  774. unsigned rn = cmSdbResponseCount(rh);
  775. unsigned sec;
  776. for(sec=0; sec<seqDurSecs; sec+=1 )
  777. {
  778. // calcuate the number of events to initiate during this second
  779. unsigned en = cmRandUInt(minEvtPerSec,maxEvtPerSec);
  780. unsigned ei;
  781. for(ei=0; ei<en; ++ei)
  782. {
  783. // select an event index
  784. unsigned ri = cmRandUInt(0,rn-1);
  785. // double select a start time for this event
  786. double begSecs = sec + cmRandDouble(0.0,1.0);
  787. double maxEvtDurSecs = 0;
  788. if((rc = _cmSdbStoreSeqEvent(p,sp,rh,ri,seqChCnt,begSecs,maxEvtDurSecs,NULL)) != kOkSdbRC )
  789. goto errLabel;
  790. } // for each event init'd during this second
  791. } // for each second
  792. shp->h = sp;
  793. errLabel:
  794. if( rc != kOkSdbRC )
  795. _cmSdbSeqFree(sp);
  796. return rc;
  797. }
  798. cmSdbRC_t cmSdbSeqSerial(
  799. cmSdbResponseH_t rh,
  800. unsigned seqChCnt,
  801. double gapSec,
  802. double maxEvtDurSec,
  803. cmSdbSeqH_t* shp )
  804. {
  805. cmSdbRC_t rc;
  806. if((rc = cmSdbSeqFree(shp)) != kOkSdbRC )
  807. return rc;
  808. cmSdbRsp_t* rp = _cmSdbRspHandleToPtr(rh);
  809. cmSdb_t* p = rp->p;
  810. cmSdbSeq_t* sp = _cmSdbSeqAlloc(p);
  811. unsigned n = cmSdbResponseCount(rh);
  812. double begSecs = 0;
  813. unsigned ri;
  814. for(ri=0; ri<n; ++ri)
  815. {
  816. double durSecs = 0;
  817. if((rc = _cmSdbStoreSeqEvent(p,sp,rh,ri,seqChCnt,begSecs,maxEvtDurSec,&durSecs)) != kOkSdbRC )
  818. goto errLabel;
  819. // offset to next event
  820. begSecs += durSecs + gapSec;
  821. }
  822. shp->h = sp;
  823. errLabel:
  824. if(rc != kOkSdbRC )
  825. _cmSdbSeqFree(sp);
  826. return rc;
  827. }
  828. cmSdbRC_t cmSdbSeqChord(
  829. cmSdbResponseH_t* rhp,
  830. unsigned rn,
  831. unsigned seqChCnt,
  832. unsigned maxEvtDurSec,
  833. cmSdbSeqH_t* shp )
  834. {
  835. cmSdbRC_t rc = kOkSdbRC;
  836. assert( shp != NULL );
  837. if( rn == 0 )
  838. return rc;
  839. cmSdbResponseH_t rh = rhp[0];
  840. cmSdbRsp_t* rp = _cmSdbRspHandleToPtr(rh);
  841. cmSdb_t* p = rp->p;
  842. cmSdbSeq_t* sp = _cmSdbSeqAlloc(p);
  843. unsigned i;
  844. if((rc = cmSdbSeqFree(shp)) != kOkSdbRC )
  845. return rc;
  846. // for each chord note
  847. for(i=0; i<rn; ++i)
  848. {
  849. // get the query response handle for this note
  850. rh = rhp[i];
  851. rp = _cmSdbRspHandleToPtr(rh);
  852. // verify that all query responses were drawn from the same cmSdbH_t handle.
  853. if( rp->p != p )
  854. {
  855. rc = cmErrMsg(&p->ctx.err,kAssertFailSdbRC,"All chord query response handle must be derived from the same cmSdbH_t handle.");
  856. goto errLabel;
  857. }
  858. // pick one event at random from the response
  859. unsigned n = cmSdbResponseCount(rh);
  860. unsigned rei = cmRandUInt(0,n-1);
  861. // all notes start at time: 0.0.
  862. double begSecs = 0.0;
  863. // store the sequence event
  864. if((rc = _cmSdbStoreSeqEvent(p,sp,rh,rei,seqChCnt,begSecs,maxEvtDurSec,NULL)) != kOkSdbRC )
  865. goto errLabel;
  866. }
  867. shp->h = sp;
  868. errLabel:
  869. if(rc != kOkSdbRC )
  870. _cmSdbSeqFree(sp);
  871. return rc;
  872. }
  873. bool cmSdbSeqIsValid( cmSdbSeqH_t sh )
  874. { return sh.h != NULL; }
  875. cmSdbRC_t cmSdbSeqFree( cmSdbSeqH_t* shp )
  876. {
  877. cmSdbRC_t rc = kOkSdbRC;
  878. if( shp==NULL || cmSdbSeqIsValid(*shp)==false )
  879. return rc;
  880. cmSdbSeq_t* sp = _cmSdbSeqHandleToPtr(*shp);
  881. if((rc = _cmSdbSeqFree(sp)) != kOkSdbRC )
  882. return rc;
  883. shp->h = NULL;
  884. return rc;
  885. }
  886. unsigned cmSdbSeqCount( cmSdbSeqH_t sh )
  887. {
  888. if( cmSdbSeqIsValid(sh)==false )
  889. return 0;
  890. cmSdbSeq_t* sp = _cmSdbSeqHandleToPtr(sh);
  891. return sp->cnt;
  892. }
  893. const cmSdbSeqEvent_t* cmSdbSeqEvent( cmSdbSeqH_t sh, unsigned index )
  894. {
  895. cmSdbSeq_t* sp = _cmSdbSeqHandleToPtr(sh);
  896. if( index >= sp->cnt )
  897. return NULL;
  898. cmSdbSeqBlk_t* bp = sp->blocks;
  899. unsigned i;
  900. for(i=0; bp!=NULL; i+=bp->cnt,bp=bp->link)
  901. if( i <= index && index < (i + bp->cnt) )
  902. return bp->eV + index-i;
  903. cmErrMsg(&sp->p->ctx.err,kInvalidSeqIdxSdbRC,"Invalid sequence event index=%i.",index);
  904. return NULL;
  905. }
  906. const cmSdbEvent_t* cmSdbSeqSdbEvent( cmSdbSeqH_t sh, unsigned index )
  907. {
  908. const cmSdbSeqEvent_t* ep;
  909. if((ep = cmSdbSeqEvent(sh,index)) == NULL )
  910. return NULL;
  911. cmSdbSeq_t* sp = _cmSdbSeqHandleToPtr(sh);
  912. return _cmSdbEvent(sp->p,ep->uuid);
  913. }
  914. double cmSdbSeqDurSeconds( cmSdbSeqH_t sh )
  915. {
  916. cmSdbSeq_t* sp = _cmSdbSeqHandleToPtr(sh);
  917. cmSdbSeqBlk_t* bp = sp->blocks;
  918. while( bp!=NULL && bp->link!=NULL )
  919. bp=bp->link;
  920. if( bp == NULL )
  921. return 0;
  922. cmSdbSeqEvent_t* ep = bp->eV + bp->cnt - 1;
  923. return ep->begSec + ep->durSec;
  924. }
  925. double cmSdbSeqSampleRate( cmSdbSeqH_t sh )
  926. {
  927. unsigned n = cmSdbSeqCount(sh);
  928. unsigned i;
  929. const cmSdbEvent_t* ep;
  930. for(i=0; i<n; ++i)
  931. if((ep = cmSdbSeqSdbEvent(sh,i)) != NULL && ep->srate != 0 )
  932. return ep->srate;
  933. return 0;
  934. }
  935. cmSdbRC_t cmSdbSeqToAudio(
  936. cmSdbSeqH_t sh,
  937. unsigned decayMs,
  938. double noiseDb,
  939. double normFact,
  940. cmSample_t** signalRef,
  941. unsigned* sigSmpCntRef )
  942. {
  943. assert( signalRef!=NULL && sigSmpCntRef!=NULL);
  944. *signalRef = NULL;
  945. *sigSmpCntRef = 0;
  946. cmSdbRC_t rc = kOkSdbRC;
  947. cmSdbSeq_t* sp = _cmSdbSeqHandleToPtr(sh);
  948. cmSdb_t* p = sp->p;
  949. unsigned qN = cmSdbSeqCount(sh);
  950. double durSecs = cmSdbSeqDurSeconds(sh);
  951. double srate = cmSdbSeqSampleRate(sh);
  952. assert(sp->maxDurSec>=sp->minDurSec);
  953. // verify that sequence events exist
  954. if( qN==0 || durSecs==0 || sp->chCnt==0 || sp->maxDurSec==0)
  955. return rc;
  956. // validate the sample rate
  957. if( srate == 0 )
  958. return cmErrMsg(&p->ctx.err,kAssertFailSdbRC,"The sample rate of the sequence could not be determined.");
  959. unsigned sN = (unsigned)floor(srate * (durSecs + 0.25)); // output signal sample count + 1/4 second of silence
  960. unsigned dN = (unsigned)floor(srate * decayMs / 1000.0); // decay env. sample count
  961. unsigned tN = (unsigned)floor(srate * sp->maxDurSec); // length of longest audio event in samples
  962. cmSample_t* s = cmMemAllocZ(cmSample_t,sN*sp->chCnt); // allocate the outputsignal buffer
  963. cmSample_t* t = cmMemAllocZ(cmSample_t,tN*sp->chCnt); // audio event read buffer
  964. cmSample_t* d = NULL;
  965. cmSample_t* chBuf[ sp->chCnt ];
  966. unsigned i;
  967. // fill the channel buffers
  968. for(i=0; i<sp->chCnt; ++i)
  969. chBuf[i] = t + (i*tN);
  970. // if a decay rate was specified
  971. if( dN > 0 )
  972. {
  973. d = cmMemAllocZ(cmSample_t,dN); // allocate the decay env. buffer
  974. cmVOS_LinSpace(d,dN,1.0,0.0); // calc. a decay envelope
  975. cmVOS_PowVS(d,dN,4.0);
  976. }
  977. // if a noise floor was specified
  978. if( noiseDb != 0 )
  979. {
  980. // fill the signal with low level white noise
  981. cmVOS_Random(s,sN,-1.0,1.0);
  982. cmVOS_MultVS(s,sN,pow(10.0,-fabs(noiseDb)/20.0));
  983. }
  984. // for each sequence event
  985. for(i=0; rc==kOkSdbRC && i<qN; ++i)
  986. {
  987. const cmSdbSeqEvent_t* qep;
  988. const cmSdbEvent_t* ep;
  989. // get the sequence event record
  990. if((qep = cmSdbSeqEvent(sh,i)) == NULL )
  991. {
  992. rc = cmErrMsg(&p->ctx.err,kAssertFailSdbRC,"Unable to retrieve the sequence event at index %i.",i);
  993. goto errLabel;
  994. }
  995. // get the audio event record
  996. if((ep = _cmSdbEvent(p,qep->uuid)) == NULL)
  997. {
  998. rc = cmErrMsg(&p->ctx.err,kAssertFailSdbRC,"Unable to retrieve the sample event with uuid:%i.",qep->uuid);
  999. goto errLabel;
  1000. }
  1001. unsigned begFrmIdx = floor(srate * qep->begSec ); // dest. index into output signal
  1002. unsigned frmCnt = floor(srate * qep->durSec ); // seq. event dur in samples
  1003. const cmChar_t* afn = NULL; // audio event file name
  1004. unsigned actFrmCnt = 0; // actual count of samples read from the audio event file
  1005. cmAudioFileInfo_t afInfo; // audio file info. record
  1006. // form the audio event file name
  1007. if((afn = cmFsMakeFn(p->audioDir,ep->afn,NULL,NULL))==NULL)
  1008. {
  1009. rc = cmErrMsg(&p->ctx.err,kFileSysFailSdbRC,"Unable to form the file name for %s/%s.",cmStringNullGuard(p->audioDir),cmStringNullGuard(ep->afn));
  1010. goto errLabel;
  1011. }
  1012. assert(ep->oei-ep->obi>0 );
  1013. // read the audio event from the file into t[]
  1014. if( cmAudioFileGetSample(afn, ep->obi, cmMin(tN,cmMin(frmCnt,ep->oei-ep->obi)), 0, ep->chCnt, chBuf, &actFrmCnt, &afInfo, p->ctx.err.rpt ) != kOkAfRC )
  1015. {
  1016. rc = cmErrMsg(&p->ctx.err,kFileSysFailSdbRC,"Audio event read failed for event uuid:%i in '%s'.",qep->uuid,cmStringNullGuard(afn));
  1017. goto doneLabel;
  1018. }
  1019. // 'actFrmCnt' now holds the length of the event signal
  1020. // verify that the audio event sample rate matches the sequence srate
  1021. if( afInfo.srate != srate )
  1022. cmErrWarnMsg(&p->ctx.err,kAssertFailSdbRC,"The sample rate (%f) of audio event uuid:%i in '%s' does not match the sequence sample rate:%f.",afInfo.srate,qep->uuid,cmStringNullGuard(afn),srate);
  1023. // if a decay rate was specified
  1024. if( dN > 0 )
  1025. {
  1026. unsigned ti = 0; // start of decay in t[]
  1027. unsigned di = 0; // start of decay in d[]
  1028. if( actFrmCnt > dN )
  1029. ti = actFrmCnt - dN; // decay func is applied to end of audio event
  1030. else
  1031. di = dN - actFrmCnt; // decay func is longer than audio event (shorten it)
  1032. unsigned mn = dN - di; // decay function length
  1033. unsigned j;
  1034. // apply the decay function
  1035. for(j=0; j<sp->chCnt; ++j)
  1036. cmVOS_MultVV(t + (j*tN) +ti , mn, d+di);
  1037. }
  1038. // normalize the event signal
  1039. if( normFact != 0 )
  1040. cmVOS_NormToAbsMax(t,actFrmCnt,normFact);
  1041. // verify the the signal event falls inside the output signal
  1042. if( begFrmIdx >= sN )
  1043. rc = cmErrMsg(&p->ctx.err,kAssertFailSdbRC,"A sequence event start time falls after the end of the sequence signal. This should never happen.");
  1044. else
  1045. {
  1046. // if the event signal goes past the end of the signal - truncate the event
  1047. if( begFrmIdx + actFrmCnt > sN )
  1048. actFrmCnt = sN - begFrmIdx;
  1049. // sum the event signal into the output signal
  1050. cmVOS_AddVV(s + (qep->outChIdx*sN) + begFrmIdx,actFrmCnt,t);
  1051. }
  1052. doneLabel:
  1053. cmFsFreeFn(afn);
  1054. }
  1055. *signalRef = s;
  1056. *sigSmpCntRef = sN;
  1057. errLabel:
  1058. if( rc != kOkSdbRC )
  1059. cmMemFree(s);
  1060. cmMemFree(d);
  1061. cmMemFree(t);
  1062. return rc;
  1063. }
  1064. cmSdbRC_t cmSdbSeqToAudioFn(
  1065. cmSdbSeqH_t sh,
  1066. unsigned decayMs,
  1067. double noiseDb,
  1068. double evtNormFact,
  1069. double sigNormFact,
  1070. const cmChar_t* fn,
  1071. unsigned bitsPerSample
  1072. )
  1073. {
  1074. cmSdbRC_t rc = kOkSdbRC;
  1075. cmSample_t* s = NULL;
  1076. unsigned sN = 0;
  1077. cmSdbSeq_t* sp = _cmSdbSeqHandleToPtr(sh);
  1078. cmSdb_t* p = sp->p;
  1079. double srate = cmSdbSeqSampleRate(sh);
  1080. unsigned i;
  1081. // fill s[sN] with the sequence audio signal
  1082. if((rc = cmSdbSeqToAudio(sh,decayMs,noiseDb,evtNormFact,&s,&sN)) != kOkSdbRC )
  1083. return rc;
  1084. // if no audio signal was created there is nothing to do
  1085. if( sN == 0 )
  1086. return rc;
  1087. // the sample rate was already check by cmSdbSeqToAudio().
  1088. assert(srate != 0 && s != NULL);
  1089. // if requested normalize the signal
  1090. if( sigNormFact != 0 )
  1091. cmVOS_NormToAbsMax(s,sN*sp->chCnt,sigNormFact);
  1092. // fill the channel buffer
  1093. cmSample_t* chBuf[ sp->chCnt ];
  1094. for(i=0; i<sp->chCnt; ++i)
  1095. chBuf[i] = s + (i*sN);
  1096. // write the signal to an audio file
  1097. if((rc = cmAudioFileWriteFileFloat(fn, srate, bitsPerSample, sN, sp->chCnt, chBuf, p->ctx.err.rpt )) != kOkAfRC )
  1098. {
  1099. rc = cmErrMsg(&p->ctx.err,kAudioFileFailSdbRC,"The sequence audio file '%s' could not be created.",cmStringNullGuard(fn));
  1100. goto errLabel;
  1101. }
  1102. errLabel:
  1103. cmMemFree(s);
  1104. return rc;
  1105. }
  1106. void cmSdbSeqPrint( cmSdbSeqH_t sh, cmRpt_t* rpt )
  1107. {
  1108. unsigned i;
  1109. unsigned n = cmSdbSeqCount(sh);
  1110. cmSdbSeq_t* sp = _cmSdbSeqHandleToPtr(sh);
  1111. const cmSdbSeqEvent_t* ep;
  1112. cmRptPrintf(rpt,"evt cnt:%i ch cnt:%i dur min:%f max:%f \n",sp->cnt,sp->chCnt,sp->minDurSec,sp->maxDurSec);
  1113. cmRptPrintf(rpt," uuid ch beg dur gain \n");
  1114. cmRptPrintf(rpt,"------- --- ------- ------- -------\n");
  1115. for(i=0; i<n; ++i)
  1116. if((ep = cmSdbSeqEvent(sh,i)) != NULL )
  1117. cmRptPrintf(rpt,"%7i %3i %7.3f %7.3f %7.3f\n",ep->uuid,ep->outChIdx,ep->begSec,ep->durSec,ep->gain );
  1118. }
  1119. cmSdbRC_t cmSdbTest( cmCtx_t* ctx )
  1120. {
  1121. cmSdbRC_t rc = kOkSdbRC;
  1122. cmSdbH_t h = cmSdbNullHandle;
  1123. const cmChar_t* audioDir = "/home/kevin/media/audio";
  1124. const cmChar_t* csvFn = "/home/kevin/temp/sdb0/sdb_master.csv";
  1125. cmErr_t err;
  1126. cmErrSetup(&err,&ctx->rpt,"sdb test");
  1127. if((rc = cmSdbCreate(ctx, &h, csvFn, audioDir )) != kOkSdbRC )
  1128. {
  1129. rc = cmErrMsg(&err,rc,"sdb create failed.");
  1130. goto errLabel;
  1131. }
  1132. if((rc = cmSdbSyncChPairs(h)) != kOkSdbRC )
  1133. {
  1134. rc = cmErrMsg(&err,rc,"sdb sync-ch-pairs failed.");
  1135. goto errLabel;
  1136. }
  1137. if(1)
  1138. {
  1139. cmSdbResponseH_t rH = cmSdbResponseNullHandle;
  1140. cmSdbSeqH_t sH = cmSdbSeqNullHandle;
  1141. const cmChar_t* instrV[] = { "violin", NULL };
  1142. const cmChar_t* srcV[] = { "ui", NULL };
  1143. const cmChar_t* notesV[] = { "!vibrato", NULL };
  1144. if((rc = cmSdbSelect(h,0,instrV,srcV,notesV,NULL,0,0,0,&rH)) != kOkSdbRC )
  1145. {
  1146. rc = cmErrMsg(&err,rc,"sdb query failed.");
  1147. goto errLabel;
  1148. }
  1149. //cmSdbResponsePrint(rH,&ctx->rpt);
  1150. unsigned seqDurSecs = 15;
  1151. unsigned seqChCnt = 2;
  1152. unsigned sel = 2;
  1153. switch( sel )
  1154. {
  1155. case 0:
  1156. {
  1157. unsigned minEvtPerSec = 1;
  1158. unsigned maxEvtPerSec = 5;
  1159. if((rc = cmSdbSeqRand(rH,seqDurSecs,seqChCnt,minEvtPerSec,maxEvtPerSec,&sH)) != kOkSdbRC )
  1160. {
  1161. rc = cmErrMsg(&err,rc,"sdb random sequence generation failed.");
  1162. goto errLabel;
  1163. }
  1164. }
  1165. break;
  1166. case 1:
  1167. {
  1168. double gapSec = 0.1;
  1169. double maxEvtDurSec = 1.0;
  1170. if((rc = cmSdbSeqSerial(rH,seqChCnt,gapSec,maxEvtDurSec,&sH)) != kOkSdbRC )
  1171. {
  1172. rc = cmErrMsg(&err,rc,"sdb serial sequence generation failed.");
  1173. goto errLabel;
  1174. }
  1175. }
  1176. break;
  1177. case 2:
  1178. {
  1179. cmSdbResponseH_t rhV[] = { rH, rH, rH };
  1180. unsigned rN = sizeof(rhV)/sizeof(rhV[0]);
  1181. double maxEvtDurSec = 1.0;
  1182. if((rc = cmSdbSeqChord(rhV,rN,seqChCnt,maxEvtDurSec,&sH)) != kOkSdbRC )
  1183. {
  1184. rc = cmErrMsg(&err,rc,"sdb chord sequence generation failed.");
  1185. goto errLabel;
  1186. }
  1187. }
  1188. break;
  1189. }
  1190. cmSdbSeqPrint(sH,&ctx->rpt);
  1191. const cmChar_t* afn = "/home/kevin/temp/aaa.aif";
  1192. unsigned decayMs = 50;
  1193. double noiseDb = -70.0;
  1194. double evtNormFact = 0; //0.7;
  1195. double sigNormFact = 0.7; //0.7;
  1196. unsigned bitsPerSample = 16;
  1197. if((rc = cmSdbSeqToAudioFn(sH,decayMs,noiseDb,evtNormFact,sigNormFact,afn,bitsPerSample)) != kOkSdbRC )
  1198. {
  1199. rc = cmErrMsg(&err,rc,"sdb sequence audio file generation failed.");
  1200. goto errLabel;
  1201. }
  1202. cmSdbSeqFree(&sH);
  1203. cmSdbResponseFree(&rH);
  1204. }
  1205. errLabel:
  1206. if((rc = cmSdbDestroy(&h)) != kOkSdbRC )
  1207. rc = cmErrMsg(&err,rc,"sdb destroy failed.");
  1208. return rc;
  1209. }