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.

cmDspKr.c 26KB

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