libcm is a C development framework with an emphasis on audio signal processing applications.
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

cmDspKr.c 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726
  1. #include "cmPrefix.h"
  2. #include "cmGlobal.h"
  3. #include "cmFloatTypes.h"
  4. #include "cmComplexTypes.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 "cmFile.h"
  12. #include "cmSymTbl.h"
  13. #include "cmJson.h"
  14. #include "cmPrefs.h"
  15. #include "cmDspValue.h"
  16. #include "cmMsgProtocol.h"
  17. #include "cmThread.h"
  18. #include "cmUdpPort.h"
  19. #include "cmUdpNet.h"
  20. #include "cmAudioSys.h"
  21. #include "cmDspCtx.h"
  22. #include "cmDspClass.h"
  23. #include "cmDspUi.h"
  24. #include "cmOp.h"
  25. #include "cmMath.h"
  26. #include "cmAudioFile.h"
  27. #include "cmFileSys.h"
  28. #include "cmProcObj.h"
  29. #include "cmProcTemplateMain.h"
  30. #include "cmProc.h"
  31. #include "cmMidi.h"
  32. #include "cmProc2.h"
  33. #include "cmVectOpsTemplateMain.h"
  34. #include "cmAudioFile.h"
  35. #include "cmMidiFile.h"
  36. #include "cmTimeLine.h"
  37. #include "cmScore.h"
  38. #include "cmProc4.h"
  39. enum
  40. {
  41. kWndSmpCntKrId,
  42. kHopFactKrId,
  43. kModeKrId,
  44. kThreshKrId,
  45. kLwrSlopeKrId,
  46. kUprSlopeKrId,
  47. kOffsetKrId,
  48. kInvertKrId,
  49. kAudioInKrId,
  50. kAudioOutKrId
  51. };
  52. typedef struct
  53. {
  54. cmDspInst_t inst;
  55. cmCtx* ctx;
  56. cmSpecDist_t* sdp;
  57. } cmDspKr_t;
  58. cmDspClass_t _cmKrDC;
  59. //==========================================================================================================================================
  60. cmDspInst_t* _cmDspKrAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  61. {
  62. cmDspVarArg_t args[] =
  63. {
  64. { "wndn", kWndSmpCntKrId, 0, 0, kInDsvFl | kUIntDsvFl | kReqArgDsvFl, "Window sample count" },
  65. { "hopf", kHopFactKrId, 0, 0, kInDsvFl | kUIntDsvFl | kOptArgDsvFl, "Hop factor" },
  66. { "mode", kModeKrId, 0, 0, kInDsvFl | kUIntDsvFl | kOptArgDsvFl, "Mode 0=bypass 1=basic 2=spec cnt 3=amp env" },
  67. { "thrh", kThreshKrId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Threshold" },
  68. { "lwrs", kLwrSlopeKrId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Lower Slope"},
  69. { "uprs", kUprSlopeKrId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Upper Slope"},
  70. { "offs", kOffsetKrId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Offset"},
  71. { "invt", kInvertKrId, 0, 0, kInDsvFl | kUIntDsvFl | kOptArgDsvFl, "Invert"},
  72. { "in", kAudioInKrId, 0, 0, kInDsvFl | kAudioBufDsvFl, "Audio Input" },
  73. { "out", kAudioOutKrId, 0, 1, kOutDsvFl | kAudioBufDsvFl, "Audio Output" },
  74. { NULL, 0, 0, 0, 0 }
  75. };
  76. cmDspKr_t* p = cmDspInstAlloc(cmDspKr_t,ctx,classPtr,args,instSymId,id,storeSymId,va_cnt,vl);
  77. unsigned defWndSmpCnt = cmDspDefaultUInt(&p->inst,kWndSmpCntKrId);
  78. unsigned wndSmpCnt = cmNextPowerOfTwo( defWndSmpCnt );
  79. cmDspSetDefaultUInt( ctx,&p->inst, kWndSmpCntKrId, defWndSmpCnt, wndSmpCnt );
  80. cmDspSetDefaultUInt( ctx,&p->inst, kHopFactKrId, 0, 4 );
  81. cmDspSetDefaultUInt( ctx,&p->inst, kModeKrId, 0, kBasicModeSdId );
  82. cmDspSetDefaultDouble( ctx,&p->inst, kThreshKrId, 0, 60.0 );
  83. cmDspSetDefaultDouble( ctx,&p->inst, kLwrSlopeKrId, 0, 2.0 );
  84. cmDspSetDefaultDouble( ctx,&p->inst, kUprSlopeKrId, 0, 0.0 );
  85. cmDspSetDefaultDouble( ctx,&p->inst, kOffsetKrId, 0, 30.0);
  86. cmDspSetDefaultUInt( ctx,&p->inst, kInvertKrId, 0, 0 );
  87. //_cmDspKrCmInit(ctx,p); // initialize the cm library
  88. p->ctx = cmCtxAlloc(NULL,ctx->rpt,ctx->lhH,ctx->stH);
  89. return &p->inst;
  90. }
  91. cmDspRC_t _cmDspKrFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  92. {
  93. cmDspRC_t rc = kOkDspRC;
  94. cmDspKr_t* p = (cmDspKr_t*)inst;
  95. cmSpecDistFree(&p->sdp);
  96. cmCtxFree(&p->ctx);
  97. //_cmDspKrCmFinal(ctx,p); // finalize the cm library
  98. return rc;
  99. }
  100. cmDspRC_t _cmDspKrSetup(cmDspCtx_t* ctx, cmDspKr_t* p )
  101. {
  102. cmDspRC_t rc = kOkDspRC;
  103. unsigned wndSmpCnt = cmDspUInt(&p->inst,kWndSmpCntKrId);
  104. unsigned hopFact = cmDspUInt(&p->inst,kHopFactKrId);
  105. unsigned olaWndTypeId = kHannWndId;
  106. cmSpecDistFree(&p->sdp);
  107. p->sdp = cmSpecDistAlloc(p->ctx, NULL, cmDspSamplesPerCycle(ctx), cmDspSampleRate(ctx), wndSmpCnt, hopFact, olaWndTypeId);
  108. assert(p->sdp != NULL );
  109. if((rc = cmDspZeroAudioBuf(ctx,&p->inst,kAudioOutKrId)) != kOkDspRC )
  110. return rc;
  111. return rc;
  112. }
  113. cmDspRC_t _cmDspKrReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  114. {
  115. cmDspKr_t* p = (cmDspKr_t*)inst;
  116. cmDspRC_t rc;
  117. if((rc = cmDspApplyAllDefaults(ctx,inst)) != kOkDspRC )
  118. return rc;
  119. return _cmDspKrSetup(ctx,p);
  120. }
  121. cmDspRC_t _cmDspKrExec(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  122. {
  123. cmDspKr_t* p = (cmDspKr_t*)inst;
  124. cmDspRC_t rc = kOkDspRC;
  125. unsigned iChIdx = 0;
  126. const cmSample_t* ip = cmDspAudioBuf(ctx,inst,kAudioInKrId,iChIdx);
  127. unsigned iSmpCnt = cmDspVarRows(inst,kAudioInKrId);
  128. unsigned oChIdx = 0;
  129. cmSample_t* op = cmDspAudioBuf(ctx,inst,kAudioOutKrId,oChIdx);
  130. unsigned oSmpCnt = cmDspVarRows(inst,kAudioOutKrId);
  131. const cmSample_t* sp;
  132. cmSpecDistExec(p->sdp,ip,iSmpCnt);
  133. if((sp = cmSpecDistOut(p->sdp)) != NULL )
  134. vs_Copy(op,sp,oSmpCnt);
  135. return rc;
  136. }
  137. cmDspRC_t _cmDspKrRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  138. {
  139. cmDspKr_t* p = (cmDspKr_t*)inst;
  140. cmDspRC_t rc = kOkDspRC;
  141. cmDspSetEvent(ctx,inst,evt);
  142. switch( evt->dstVarId )
  143. {
  144. case kWndSmpCntKrId:
  145. case kHopFactKrId:
  146. _cmDspKrSetup(ctx,p);
  147. printf("wsn:%i hsn:%i\n",p->sdp->wndSmpCnt,p->sdp->hopSmpCnt);
  148. break;
  149. case kModeKrId:
  150. p->sdp->mode = cmDspUInt(inst,kModeKrId);
  151. printf("mode:%i\n",p->sdp->mode);
  152. break;
  153. case kThreshKrId:
  154. p->sdp->thresh = cmDspDouble(inst,kThreshKrId);
  155. break;
  156. case kUprSlopeKrId:
  157. p->sdp->uprSlope = cmDspDouble(inst,kUprSlopeKrId);
  158. printf("upr slope:%f\n",p->sdp->uprSlope);
  159. break;
  160. case kLwrSlopeKrId:
  161. p->sdp->lwrSlope = cmDspDouble(inst,kLwrSlopeKrId);
  162. printf("upr slope:%f\n",p->sdp->lwrSlope);
  163. break;
  164. case kOffsetKrId:
  165. p->sdp->offset = cmDspDouble(inst,kOffsetKrId);
  166. break;
  167. case kInvertKrId:
  168. p->sdp->invertFl = cmDspUInt(inst,kInvertKrId)!=0;
  169. break;
  170. default:
  171. { assert(0); }
  172. }
  173. return rc;
  174. }
  175. struct cmDspClass_str* cmKrClassCons( cmDspCtx_t* ctx )
  176. {
  177. cmDspClassSetup(&_cmKrDC,ctx,"Kr",
  178. NULL,
  179. _cmDspKrAlloc,
  180. _cmDspKrFree,
  181. _cmDspKrReset,
  182. _cmDspKrExec,
  183. _cmDspKrRecv,
  184. NULL,NULL,
  185. "Fourier based non-linear transformer.");
  186. return &_cmKrDC;
  187. }
  188. //==========================================================================================================================================
  189. // Time Line UI Object
  190. enum
  191. {
  192. kTlFileTlId,
  193. kAudPathTlId,
  194. kSelTlId,
  195. kAudFnTlId,
  196. kMidiFnTlId,
  197. kBegAudSmpIdxTlId,
  198. kEndAudSmpIdxTlId,
  199. kBegMidiSmpIdxTlId,
  200. kEndMidiSmpIdxTlId
  201. };
  202. cmDspClass_t _cmTimeLineDC;
  203. typedef struct
  204. {
  205. cmDspInst_t inst;
  206. cmTlH_t tlH;
  207. } cmDspTimeLine_t;
  208. cmDspInst_t* _cmDspTimeLineAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  209. {
  210. cmDspVarArg_t args[] =
  211. {
  212. { "tlfile", kTlFileTlId, 0, 0, kInDsvFl | kStrzDsvFl | kReqArgDsvFl, "Time line file." },
  213. { "path", kAudPathTlId, 0, 0, kInDsvFl | kStrzDsvFl | kReqArgDsvFl, "Audio path" },
  214. { "sel", kSelTlId, 0, 0, kInDsvFl | kInDsvFl | kOutDsvFl | kUIntDsvFl, "Selected marker id."},
  215. { "afn", kAudFnTlId, 0, 0, kOutDsvFl | kStrzDsvFl, "Selected Audio file." },
  216. { "mfn", kMidiFnTlId, 0, 0, kOutDsvFl | kStrzDsvFl, "Selected MIDI file." },
  217. { "absi", kBegAudSmpIdxTlId, 0, 0, kOutDsvFl | kIntDsvFl, "Begin audio sample index."},
  218. { "aesi", kEndAudSmpIdxTlId, 0, 0, kOutDsvFl | kIntDsvFl, "End audio sample index."},
  219. { "mbsi", kBegMidiSmpIdxTlId, 0, 0, kOutDsvFl | kIntDsvFl, "Begin MIDI sample index."},
  220. { "mesi", kEndMidiSmpIdxTlId, 0, 0, kOutDsvFl | kIntDsvFl, "End MIDI sample index."},
  221. { NULL, 0, 0, 0, 0 }
  222. };
  223. cmDspTimeLine_t* p = cmDspInstAlloc(cmDspTimeLine_t,ctx,classPtr,args,instSymId,id,storeSymId,va_cnt,vl);
  224. cmDspSetDefaultUInt( ctx, &p->inst, kSelTlId, 0, cmInvalidId);
  225. cmDspSetDefaultStrcz(ctx, &p->inst, kAudFnTlId, NULL, "");
  226. cmDspSetDefaultStrcz(ctx, &p->inst, kMidiFnTlId, NULL, "");
  227. cmDspSetDefaultInt( ctx, &p->inst, kBegAudSmpIdxTlId, 0, cmInvalidIdx);
  228. cmDspSetDefaultInt( ctx, &p->inst, kEndAudSmpIdxTlId, 0, cmInvalidIdx);
  229. cmDspSetDefaultInt( ctx, &p->inst, kBegMidiSmpIdxTlId, 0, cmInvalidIdx);
  230. cmDspSetDefaultInt( ctx, &p->inst, kEndMidiSmpIdxTlId, 0, cmInvalidIdx);
  231. // create the UI control
  232. cmDspUiTimeLineCreate(ctx,&p->inst,kTlFileTlId,kAudPathTlId,kSelTlId);
  233. p->tlH = cmTimeLineNullHandle;
  234. return &p->inst;
  235. }
  236. cmDspRC_t _cmDspTimeLineFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  237. {
  238. cmDspRC_t rc = kOkDspRC;
  239. cmDspTimeLine_t* p = (cmDspTimeLine_t*)inst;
  240. if( cmTimeLineFinalize(&p->tlH) != kOkTlRC )
  241. return cmErrMsg(&inst->classPtr->err, kInstFinalFailDspRC, "Time-line finalize failed.");
  242. return rc;
  243. }
  244. cmDspRC_t _cmDspTimeLineReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  245. {
  246. cmDspRC_t rc = kOkDspRC;
  247. cmDspTimeLine_t* p = (cmDspTimeLine_t*)inst;
  248. cmDspApplyAllDefaults(ctx,inst);
  249. const cmChar_t* tlFn;
  250. if((tlFn = cmDspStrcz(inst, kTlFileTlId )) != NULL )
  251. if( cmTimeLineInitializeFromFile(ctx->cmCtx, &p->tlH, NULL, NULL, tlFn ) != kOkTlRC )
  252. rc = cmErrMsg(&inst->classPtr->err, kInstResetFailDspRC, "Time-line file open failed.");
  253. return rc;
  254. }
  255. cmDspRC_t _cmDspTimeLineRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  256. {
  257. cmDspTimeLine_t* p = (cmDspTimeLine_t*)inst;
  258. switch( evt->dstVarId )
  259. {
  260. case kSelTlId:
  261. {
  262. unsigned markerId;
  263. cmDspSetEvent(ctx,inst,evt);
  264. // get the id of the selected marker
  265. if((markerId = cmDspUInt(inst,kSelTlId)) != cmInvalidId )
  266. {
  267. // get the marker object
  268. cmTlObj_t* op;
  269. if((op = cmTimeLineIdToObj(p->tlH, cmInvalidId, markerId )) != NULL )
  270. {
  271. assert(op->typeId == kMarkerTlId);
  272. cmDspSetInt(ctx, inst, kBegAudSmpIdxTlId, op->begSmpIdx );
  273. cmDspSetInt(ctx, inst, kEndAudSmpIdxTlId, op->begSmpIdx + op->durSmpCnt );
  274. // locate the audio file assoc'd with the marker
  275. cmTlAudioFile_t* afp;
  276. if((afp = cmTimeLineAudioFileAtTime(p->tlH,op->seqId,op->seqSmpIdx)) != NULL)
  277. cmDspSetStrcz(ctx, inst, kAudFnTlId, afp->fn );
  278. // locate the midi file assoc'd with the marker
  279. cmTlMidiFile_t* mfp;
  280. if((mfp = cmTimeLineMidiFileAtTime(p->tlH,op->seqId,op->seqSmpIdx)) != NULL )
  281. {
  282. cmDspSetInt(ctx, inst, kBegMidiSmpIdxTlId, op->seqSmpIdx - mfp->obj.seqSmpIdx );
  283. cmDspSetInt(ctx, inst, kEndMidiSmpIdxTlId, op->seqSmpIdx + op->durSmpCnt - mfp->obj.seqSmpIdx );
  284. cmDspSetStrcz(ctx, inst, kMidiFnTlId, mfp->fn );
  285. }
  286. }
  287. }
  288. }
  289. break;
  290. default:
  291. {assert(0);}
  292. }
  293. return kOkDspRC;
  294. }
  295. struct cmDspClass_str* cmTimeLineClassCons( cmDspCtx_t* ctx )
  296. {
  297. cmDspClassSetup(&_cmTimeLineDC,ctx,"TimeLine",
  298. NULL,
  299. _cmDspTimeLineAlloc,
  300. _cmDspTimeLineFree,
  301. _cmDspTimeLineReset,
  302. NULL,
  303. _cmDspTimeLineRecv,
  304. NULL,NULL,
  305. "Time Line control.");
  306. return &_cmTimeLineDC;
  307. }
  308. //==========================================================================================================================================
  309. // MIDI File Player
  310. enum
  311. {
  312. kFnMfId,
  313. kSelMfId,
  314. kBsiMfId,
  315. kEsiMfId,
  316. kStatusMfId,
  317. kD0MfId,
  318. kD1MfId
  319. };
  320. cmDspClass_t _cmMidiFilePlayDC;
  321. typedef struct
  322. {
  323. cmDspInst_t inst;
  324. cmMidiFileH_t mfH;
  325. unsigned curMsgIdx; // current midi file msg index
  326. int csi; // current sample index
  327. int bsi; // starting sample index
  328. int esi; // ending sample index
  329. unsigned startSymId;
  330. unsigned stopSymId;
  331. unsigned contSymId;
  332. } cmDspMidiFilePlay_t;
  333. /*
  334. 'bsi' and 'esi' give the starting and ending sample for MIDI file playback.
  335. These indexes are relative to the start of the file.
  336. When the player recieves a 'start' msg it sets the current sample index
  337. 'si' to 'bsi' and begins scanning for the next note to play.
  338. On each call to the _cmDspMidiFilePlayExec() msgs that fall in the interval
  339. si:si+sPc-1 will be transmitted. (where sPc are the number of samples per DSP cycle).
  340. */
  341. cmDspInst_t* _cmDspMidiFilePlayAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  342. {
  343. cmDspVarArg_t args[] =
  344. {
  345. { "fn", kFnMfId, 0, 0, kInDsvFl | kStrzDsvFl, "File name"},
  346. { "sel", kSelMfId, 0, 0, kInDsvFl | kSymDsvFl, "start | stop | continue" },
  347. { "bsi", kBsiMfId, 0, 0, kInDsvFl | kIntDsvFl, "Starting sample." },
  348. { "esi", kEsiMfId, 0, 0, kInDsvFl | kIntDsvFl, "Ending sample."},
  349. { "status", kStatusMfId, 0, 0, kOutDsvFl | kIntDsvFl, "Status value output" },
  350. { "d0", kD0MfId, 0, 0, kOutDsvFl | kUIntDsvFl, "Data byte 0" },
  351. { "d1", kD1MfId, 0, 0, kOutDsvFl | kUIntDsvFl, "Data byte 1" },
  352. { NULL, 0, 0, 0, 0 }
  353. };
  354. cmDspMidiFilePlay_t* p = cmDspInstAlloc(cmDspMidiFilePlay_t,ctx,classPtr,args,instSymId,id,storeSymId,va_cnt,vl);
  355. p->startSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"start");
  356. p->stopSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"stop");
  357. p->contSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"continue");
  358. p->mfH = cmMidiFileNullHandle;
  359. cmDspSetDefaultStrcz( ctx, &p->inst, kFnMfId, NULL, "");
  360. cmDspSetDefaultSymbol(ctx, &p->inst, kSelMfId, p->stopSymId);
  361. cmDspSetDefaultInt( ctx, &p->inst, kBsiMfId, 0, 0);
  362. cmDspSetDefaultInt( ctx, &p->inst, kEsiMfId, 0, 0);
  363. cmDspSetDefaultUInt( ctx, &p->inst, kStatusMfId, 0, 0);
  364. cmDspSetDefaultUInt( ctx, &p->inst, kD0MfId, 0, 0);
  365. cmDspSetDefaultUInt( ctx, &p->inst, kD1MfId, 0, 0);
  366. return &p->inst;
  367. }
  368. cmDspRC_t _cmDspMidiFilePlayFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  369. {
  370. cmDspMidiFilePlay_t* p = (cmDspMidiFilePlay_t*)inst;
  371. if( cmMidiFileClose(&p->mfH) )
  372. return cmErrMsg(&inst->classPtr->err, kInstFinalFailDspRC, "MIDI file close failed.");
  373. return kOkDspRC;
  374. }
  375. // return the index of the msg following smpIdx
  376. unsigned _cmDspMidiFilePlaySeekMsgIdx( cmDspCtx_t* ctx, cmDspMidiFilePlay_t* p, unsigned smpIdx )
  377. {
  378. unsigned i;
  379. unsigned n = cmMidiFileMsgCount(p->mfH);
  380. const cmMidiTrackMsg_t** a = cmMidiFileMsgArray(p->mfH);
  381. for(i=0; i<n; ++i)
  382. if( a[i]->dtick > smpIdx )
  383. break;
  384. return i==n ? cmInvalidIdx : i;
  385. }
  386. cmDspRC_t _cmDspMidiFilePlayOpen(cmDspCtx_t* ctx, cmDspInst_t* inst )
  387. {
  388. cmDspRC_t rc = kOkDspRC;
  389. const cmChar_t* fn = cmDspStrcz(inst,kFnMfId);
  390. cmDspMidiFilePlay_t* p = (cmDspMidiFilePlay_t*)inst;
  391. if( fn==NULL || strlen(fn)==0 )
  392. return rc;
  393. if( cmMidiFileOpen( fn, &p->mfH, ctx->cmCtx ) != kOkFileRC )
  394. rc = cmErrMsg(&inst->classPtr->err, kInstResetFailDspRC, "MIDI file open failed.");
  395. else
  396. {
  397. p->curMsgIdx = 0;
  398. p->bsi = cmDspInt(inst,kBsiMfId);
  399. p->esi = cmDspInt(inst,kEsiMfId);
  400. p->csi = 0;
  401. // force the first msg to occurr one quarter note into the file
  402. cmMidiFileSetDelay(p->mfH, cmMidiFileTicksPerQN(p->mfH) );
  403. // convert midi msg times to absolute time in samples
  404. cmMidiFileTickToSamples(p->mfH,cmDspSampleRate(ctx),true);
  405. }
  406. return rc;
  407. }
  408. cmDspRC_t _cmDspMidiFilePlayReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  409. {
  410. cmDspApplyAllDefaults(ctx,inst);
  411. return _cmDspMidiFilePlayOpen(ctx,inst);
  412. }
  413. cmDspRC_t _cmDspMidiFilePlayExec(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  414. {
  415. cmDspRC_t rc = kOkDspRC;
  416. cmDspMidiFilePlay_t* p = (cmDspMidiFilePlay_t*)inst;
  417. unsigned sPc = cmDspSamplesPerCycle(ctx);
  418. if( cmDspSymbol(inst,kSelMfId) != p->stopSymId )
  419. {
  420. const cmMidiTrackMsg_t** mpp = cmMidiFileMsgArray(p->mfH);
  421. unsigned msgN = cmMidiFileMsgCount(p->mfH);
  422. for(; p->curMsgIdx < msgN && p->csi <= mpp[p->curMsgIdx]->dtick && mpp[p->curMsgIdx]->dtick < (p->csi + sPc); ++p->curMsgIdx )
  423. {
  424. const cmMidiTrackMsg_t* mp = mpp[p->curMsgIdx];
  425. switch( mp->status )
  426. {
  427. case kNoteOnMdId:
  428. case kCtlMdId:
  429. cmDspSetUInt(ctx,inst, kD1MfId, mp->u.chMsgPtr->d1);
  430. cmDspSetUInt(ctx,inst, kD0MfId, mp->u.chMsgPtr->d0);
  431. cmDspSetUInt(ctx,inst, kStatusMfId, mp->status);
  432. break;
  433. }
  434. }
  435. }
  436. p->csi += sPc;
  437. return rc;
  438. }
  439. cmDspRC_t _cmDspMidiFilePlayRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  440. {
  441. cmDspMidiFilePlay_t* p = (cmDspMidiFilePlay_t*)inst;
  442. cmDspSetEvent(ctx,inst,evt);
  443. switch(evt->dstVarId)
  444. {
  445. case kFnMfId:
  446. _cmDspMidiFilePlayOpen(ctx, inst );
  447. break;
  448. case kSelMfId:
  449. {
  450. if( cmDspSymbol(inst,kSelMfId)==p->startSymId )
  451. {
  452. p->csi = cmDspInt(inst,kBsiMfId);
  453. p->curMsgIdx = _cmDspMidiFilePlaySeekMsgIdx(ctx, p, p->csi );
  454. }
  455. break;
  456. }
  457. }
  458. return kOkDspRC;
  459. }
  460. struct cmDspClass_str* cmMidiFilePlayClassCons( cmDspCtx_t* ctx )
  461. {
  462. cmDspClassSetup(&_cmMidiFilePlayDC,ctx,"MidiFilePlay",
  463. NULL,
  464. _cmDspMidiFilePlayAlloc,
  465. _cmDspMidiFilePlayFree,
  466. _cmDspMidiFilePlayReset,
  467. _cmDspMidiFilePlayExec,
  468. _cmDspMidiFilePlayRecv,
  469. NULL,NULL,
  470. "Time tagged text file.");
  471. return &_cmMidiFilePlayDC;
  472. }
  473. //==========================================================================================================================================
  474. enum
  475. {
  476. kFnSfId,
  477. kWndCntSfId,
  478. kWndMsSfId,
  479. kIndexSfId,
  480. kStatusSfId,
  481. kD0SfId,
  482. kD1SfId,
  483. kOutSfId
  484. };
  485. cmDspClass_t _cmScFolDC;
  486. typedef struct
  487. {
  488. cmDspInst_t inst;
  489. cmScFol* sfp;
  490. cmScH_t scH;
  491. } cmDspScFol_t;
  492. cmDspInst_t* _cmDspScFolAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  493. {
  494. cmDspVarArg_t args[] =
  495. {
  496. { "fn", kFnSfId, 0, 0, kInDsvFl | kStrzDsvFl | kReqArgDsvFl, "Score file." },
  497. { "wndcnt",kWndCntSfId, 0, 0, kInDsvFl | kUIntDsvFl, "Event window element count." },
  498. { "wndms", kWndMsSfId, 0, 0, kInDsvFl | kUIntDsvFl, "Event window length milliseconds."},
  499. { "index", kIndexSfId, 0, 0, kInDsvFl | kUIntDsvFl, "Tracking start location."},
  500. { "status",kStatusSfId, 0, 0, kInDsvFl | kUIntDsvFl, "MIDI status byte"},
  501. { "d0", kD0SfId, 0, 0, kInDsvFl | kUIntDsvFl, "MIDI data byte 0"},
  502. { "d1", kD1SfId, 0, 0, kInDsvFl | kUIntDsvFl, "MIDI data byte 1"},
  503. { "out", kOutSfId, 0, 0, kOutDsvFl| kUIntDsvFl, "Current score index."},
  504. { NULL, 0, 0, 0, 0, NULL }
  505. };
  506. cmDspScFol_t* p;
  507. if((p = cmDspInstAlloc(cmDspScFol_t,ctx,classPtr,args,instSymId,id,storeSymId,va_cnt,vl)) == NULL )
  508. return NULL;
  509. p->sfp = cmScFolAlloc(ctx->cmProcCtx, NULL, 0, 0, 0, cmScNullHandle );
  510. cmDspSetDefaultUInt( ctx, &p->inst, kWndCntSfId, 0, 10);
  511. cmDspSetDefaultUInt( ctx, &p->inst, kWndMsSfId, 0, 5000);
  512. cmDspSetDefaultUInt( ctx, &p->inst, kIndexSfId, 0, 0);
  513. cmDspSetDefaultUInt( ctx, &p->inst, kOutSfId, 0, 0);
  514. return &p->inst;
  515. }
  516. cmDspRC_t _cmDspScFolFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  517. {
  518. cmDspScFol_t* p = (cmDspScFol_t*)inst;
  519. cmScFolFree(&p->sfp);
  520. cmScoreFinalize(&p->scH);
  521. return kOkDspRC;
  522. }
  523. cmDspRC_t _cmDspScFolOpenScore( cmDspCtx_t* ctx, cmDspInst_t* inst )
  524. {
  525. const cmChar_t* fn;
  526. cmDspScFol_t* p = (cmDspScFol_t*)inst;
  527. if((fn = cmDspStrcz(inst,kFnSfId)) == NULL || strlen(fn)==0 )
  528. return cmErrMsg(&inst->classPtr->err, kInvalidArgDspRC, "No score file name supplied.");
  529. if( cmScoreInitialize(ctx->cmCtx, &p->scH, fn, NULL, NULL ) != kOkScRC )
  530. return cmErrMsg(&inst->classPtr->err, kSubSysFailDspRC, "Unable to open the score '%s'.",fn);
  531. return kOkDspRC;
  532. }
  533. cmDspRC_t _cmDspScFolReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  534. {
  535. cmDspRC_t rc = kOkDspRC;
  536. cmDspScFol_t* p = (cmDspScFol_t*)inst;
  537. rc = cmDspApplyAllDefaults(ctx,inst);
  538. if((rc = _cmDspScFolOpenScore(ctx,inst)) != kOkDspRC )
  539. return rc;
  540. if( cmScoreIsValid(p->scH) )
  541. if( cmScFolInit(p->sfp, cmDspSampleRate(ctx), cmDspUInt(inst,kWndCntSfId), cmDspUInt(inst,kWndMsSfId), p->scH) != cmOkRC )
  542. rc = cmErrMsg(&inst->classPtr->err, kSubSysFailDspRC, "Internal score follower allocation failed.");
  543. return rc;
  544. }
  545. cmDspRC_t _cmDspScFolRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  546. {
  547. cmDspRC_t rc = kOkDspRC;
  548. cmDspScFol_t* p = (cmDspScFol_t*)inst;
  549. if((rc = cmDspSetEvent(ctx,inst,evt)) == kOkDspRC && p->sfp != NULL )
  550. {
  551. switch( evt->dstVarId )
  552. {
  553. case kIndexSfId:
  554. if( cmScoreIsValid(p->scH) )
  555. if( cmScFolReset( p->sfp, cmDspUInt(inst,kIndexSfId) ) != cmOkRC )
  556. cmErrMsg(&inst->classPtr->err, kSubSysFailDspRC, "Score follower reset to score index '%i' failed.");
  557. break;
  558. case kStatusSfId:
  559. if( cmScoreIsValid(p->scH))
  560. {
  561. unsigned idx = cmScFolExec(p->sfp, ctx->cycleCnt, cmDspUInt(inst,kStatusSfId), cmDspUInt(inst,kD0SfId), cmDspUInt(inst,kD1SfId));
  562. if( idx != cmInvalidIdx )
  563. cmDspSetUInt(ctx,inst,kOutSfId,idx);
  564. }
  565. break;
  566. case kFnSfId:
  567. _cmDspScFolOpenScore(ctx,inst);
  568. break;
  569. }
  570. }
  571. return rc;
  572. }
  573. struct cmDspClass_str* cmScFolClassCons( cmDspCtx_t* ctx )
  574. {
  575. cmDspClassSetup(&_cmScFolDC,ctx,"ScFol",
  576. NULL,
  577. _cmDspScFolAlloc,
  578. _cmDspScFolFree,
  579. _cmDspScFolReset,
  580. NULL,
  581. _cmDspScFolRecv,
  582. NULL,NULL,
  583. "Score Follower");
  584. return &_cmScFolDC;
  585. }