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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976
  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 "cmDspSys.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. cmVOS_Copy(op,oSmpCnt,sp);
  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. kCursTlId,
  196. kResetTlId,
  197. kAudFnTlId,
  198. kMidiFnTlId,
  199. kBegAudSmpIdxTlId,
  200. kEndAudSmpIdxTlId,
  201. kBegMidiSmpIdxTlId,
  202. kEndMidiSmpIdxTlId
  203. };
  204. cmDspClass_t _cmTimeLineDC;
  205. typedef struct
  206. {
  207. cmDspInst_t inst;
  208. cmTlH_t tlH;
  209. unsigned afIdx;
  210. } cmDspTimeLine_t;
  211. cmDspInst_t* _cmDspTimeLineAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  212. {
  213. cmDspVarArg_t args[] =
  214. {
  215. { "tlfile", kTlFileTlId, 0, 0, kInDsvFl | kStrzDsvFl | kReqArgDsvFl, "Time line file." },
  216. { "path", kAudPathTlId, 0, 0, kInDsvFl | kStrzDsvFl | kReqArgDsvFl, "Audio path" },
  217. { "sel", kSelTlId, 0, 0, kInDsvFl | kOutDsvFl | kUIntDsvFl, "Selected marker id."},
  218. { "curs", kCursTlId, 0, 0, kInDsvFl | kUIntDsvFl, "Current audio file index."},
  219. { "reset", kResetTlId, 0, 0, kInDsvFl | kSymDsvFl, "Resend all outputs." },
  220. { "afn", kAudFnTlId, 0, 0, kOutDsvFl | kStrzDsvFl, "Selected Audio file." },
  221. { "mfn", kMidiFnTlId, 0, 0, kOutDsvFl | kStrzDsvFl, "Selected MIDI file." },
  222. { "absi", kBegAudSmpIdxTlId, 0, 0, kOutDsvFl | kIntDsvFl, "Begin audio sample index."},
  223. { "aesi", kEndAudSmpIdxTlId, 0, 0, kOutDsvFl | kIntDsvFl, "End audio sample index."},
  224. { "mbsi", kBegMidiSmpIdxTlId, 0, 0, kOutDsvFl | kIntDsvFl, "Begin MIDI sample index."},
  225. { "mesi", kEndMidiSmpIdxTlId, 0, 0, kOutDsvFl | kIntDsvFl, "End MIDI sample index."},
  226. { NULL, 0, 0, 0, 0 }
  227. };
  228. cmDspTimeLine_t* p = cmDspInstAlloc(cmDspTimeLine_t,ctx,classPtr,args,instSymId,id,storeSymId,va_cnt,vl);
  229. cmDspSetDefaultUInt( ctx, &p->inst, kSelTlId, 0, cmInvalidId);
  230. cmDspSetDefaultUInt( ctx, &p->inst, kCursTlId, 0, 0);
  231. cmDspSetDefaultStrcz(ctx, &p->inst, kAudFnTlId, NULL, "");
  232. cmDspSetDefaultStrcz(ctx, &p->inst, kMidiFnTlId, NULL, "");
  233. cmDspSetDefaultInt( ctx, &p->inst, kBegAudSmpIdxTlId, 0, cmInvalidIdx);
  234. cmDspSetDefaultInt( ctx, &p->inst, kEndAudSmpIdxTlId, 0, cmInvalidIdx);
  235. cmDspSetDefaultInt( ctx, &p->inst, kBegMidiSmpIdxTlId, 0, cmInvalidIdx);
  236. cmDspSetDefaultInt( ctx, &p->inst, kEndMidiSmpIdxTlId, 0, cmInvalidIdx);
  237. // create the UI control
  238. cmDspUiTimeLineCreate(ctx,&p->inst,kTlFileTlId,kAudPathTlId,kSelTlId,kCursTlId);
  239. p->tlH = cmTimeLineNullHandle;
  240. return &p->inst;
  241. }
  242. cmDspRC_t _cmDspTimeLineFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  243. {
  244. cmDspRC_t rc = kOkDspRC;
  245. cmDspTimeLine_t* p = (cmDspTimeLine_t*)inst;
  246. if( cmTimeLineFinalize(&p->tlH) != kOkTlRC )
  247. return cmErrMsg(&inst->classPtr->err, kInstFinalFailDspRC, "Time-line finalize failed.");
  248. return rc;
  249. }
  250. cmDspRC_t _cmDspTimeLineReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  251. {
  252. cmDspRC_t rc = kOkDspRC;
  253. cmDspTimeLine_t* p = (cmDspTimeLine_t*)inst;
  254. cmDspApplyAllDefaults(ctx,inst);
  255. const cmChar_t* tlFn;
  256. if((tlFn = cmDspStrcz(inst, kTlFileTlId )) != NULL )
  257. if( cmTimeLineInitializeFromFile(ctx->cmCtx, &p->tlH, NULL, NULL, tlFn ) != kOkTlRC )
  258. rc = cmErrMsg(&inst->classPtr->err, kInstResetFailDspRC, "Time-line file open failed.");
  259. return rc;
  260. }
  261. cmDspRC_t _cmDspTimeLineRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  262. {
  263. cmDspTimeLine_t* p = (cmDspTimeLine_t*)inst;
  264. switch( evt->dstVarId )
  265. {
  266. case kCursTlId:
  267. cmDspSetEvent(ctx,inst,evt);
  268. break;
  269. case kResetTlId:
  270. case kSelTlId:
  271. {
  272. unsigned markerId;
  273. cmDspSetEvent(ctx,inst,evt);
  274. // get the id of the selected marker
  275. if((markerId = cmDspUInt(inst,kSelTlId)) != cmInvalidId )
  276. {
  277. // get the marker object
  278. cmTlObj_t* op;
  279. if((op = cmTimeLineIdToObj(p->tlH, cmInvalidId, markerId )) != NULL )
  280. {
  281. assert(op->typeId == kMarkerTlId);
  282. p->afIdx = op->begSmpIdx;
  283. cmDspSetInt(ctx, inst, kBegAudSmpIdxTlId, op->begSmpIdx );
  284. cmDspSetInt(ctx, inst, kEndAudSmpIdxTlId, op->begSmpIdx + op->durSmpCnt );
  285. // locate the audio file assoc'd with the marker
  286. cmTlAudioFile_t* afp;
  287. if((afp = cmTimeLineAudioFileAtTime(p->tlH,op->seqId,op->seqSmpIdx)) != NULL)
  288. cmDspSetStrcz(ctx, inst, kAudFnTlId, afp->fn );
  289. // locate the midi file assoc'd with the marker
  290. cmTlMidiFile_t* mfp;
  291. if((mfp = cmTimeLineMidiFileAtTime(p->tlH,op->seqId,op->seqSmpIdx)) != NULL )
  292. {
  293. cmDspSetInt(ctx, inst, kBegMidiSmpIdxTlId, op->seqSmpIdx - mfp->obj.seqSmpIdx );
  294. cmDspSetInt(ctx, inst, kEndMidiSmpIdxTlId, op->seqSmpIdx + op->durSmpCnt - mfp->obj.seqSmpIdx );
  295. cmDspSetStrcz(ctx, inst, kMidiFnTlId, mfp->fn );
  296. }
  297. }
  298. }
  299. }
  300. break;
  301. default:
  302. {assert(0);}
  303. }
  304. return kOkDspRC;
  305. }
  306. struct cmDspClass_str* cmTimeLineClassCons( cmDspCtx_t* ctx )
  307. {
  308. cmDspClassSetup(&_cmTimeLineDC,ctx,"TimeLine",
  309. NULL,
  310. _cmDspTimeLineAlloc,
  311. _cmDspTimeLineFree,
  312. _cmDspTimeLineReset,
  313. NULL,
  314. _cmDspTimeLineRecv,
  315. NULL,NULL,
  316. "Time Line control.");
  317. return &_cmTimeLineDC;
  318. }
  319. //==========================================================================================================================================
  320. // Score UI Object
  321. enum
  322. {
  323. kFnScId,
  324. kSelScId,
  325. kSendScId,
  326. kStatusScId,
  327. kD0ScId,
  328. kD1ScId,
  329. kSmpIdxScId,
  330. kLocIdxScId,
  331. kEvtIdxScId,
  332. kDynScId,
  333. kValTypeScId,
  334. kValueScId
  335. };
  336. cmDspClass_t _cmScoreDC;
  337. typedef struct
  338. {
  339. cmDspInst_t inst;
  340. cmScH_t scH;
  341. cmDspCtx_t* ctx; // temporary ctx ptr used during cmScore callback in _cmDspScoreRecv()
  342. } cmDspScore_t;
  343. cmDspInst_t* _cmDspScoreAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  344. {
  345. cmDspVarArg_t args[] =
  346. {
  347. { "fn", kFnScId, 0, 0, kInDsvFl | kStrzDsvFl | kReqArgDsvFl, "Score file." },
  348. { "sel", kSelScId, 0, 0, kInDsvFl | kOutDsvFl | kUIntDsvFl, "Selected score element index input."},
  349. { "send", kSendScId, 0, 0, kInDsvFl | kTypeDsvMask, "Resend last selected score element."},
  350. { "status", kStatusScId, 0, 0, kInDsvFl | kIntDsvFl, "Performed MIDI status value output" },
  351. { "d0", kD0ScId, 0, 0, kInDsvFl | kUIntDsvFl, "Performed MIDI msg data byte 0" },
  352. { "d1", kD1ScId, 0, 0, kInDsvFl | kUIntDsvFl, "Performed MIDI msg data byte 1" },
  353. { "smpidx", kSmpIdxScId, 0, 0, kInDsvFl | kUIntDsvFl, "Performed MIDi msg time tag as a sample index." },
  354. { "loc", kLocIdxScId, 0, 0, kInDsvFl | kUIntDsvFl, "Performance score location."},
  355. { "evtidx", kEvtIdxScId, 0, 0, kOutDsvFl | kUIntDsvFl, "Performed event index of following dynamcis level."},
  356. { "dyn", kDynScId, 0, 0, kOutDsvFl | kUIntDsvFl, "Dynamic level of previous event index."},
  357. { "type", kValTypeScId,0, 0, kOutDsvFl | kUIntDsvFl, "Output variable type."},
  358. { "value", kValueScId, 0, 0, kOutDsvFl | kDoubleDsvFl, "Output variable value."},
  359. { NULL, 0, 0, 0, 0 }
  360. };
  361. cmDspScore_t* p = cmDspInstAlloc(cmDspScore_t,ctx,classPtr,args,instSymId,id,storeSymId,va_cnt,vl);
  362. cmDspSetDefaultUInt( ctx, &p->inst, kSelScId, 0, cmInvalidId);
  363. // create the UI control
  364. cmDspUiScoreCreate(ctx,&p->inst,kFnScId,kSelScId,kSmpIdxScId,kD0ScId,kD1ScId,kLocIdxScId,kEvtIdxScId,kDynScId,kValTypeScId,kValueScId);
  365. p->scH = cmScNullHandle;
  366. return &p->inst;
  367. }
  368. cmDspRC_t _cmDspScoreFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  369. {
  370. cmDspRC_t rc = kOkDspRC;
  371. cmDspScore_t* p = (cmDspScore_t*)inst;
  372. if( cmScoreFinalize(&p->scH) != kOkTlRC )
  373. return cmErrMsg(&inst->classPtr->err, kInstFinalFailDspRC, "Score finalize failed.");
  374. return rc;
  375. }
  376. // Callback from cmScore triggered from _cmDspScoreRecv() during call to cmScoreSetPerfEvent().
  377. void _cmDspScoreCb( void* arg, const void* data, unsigned byteCnt )
  378. {
  379. cmDspInst_t* inst = (cmDspInst_t*)arg;
  380. cmDspScore_t* p = (cmDspScore_t*)inst;
  381. cmScMsg_t m;
  382. if( cmScoreDecode(data,byteCnt,&m) == kOkScRC )
  383. {
  384. switch( m.typeId )
  385. {
  386. case kDynMsgScId:
  387. cmDspSetUInt( p->ctx,inst, kEvtIdxScId, m.u.dyn.evtIdx );
  388. cmDspSetUInt( p->ctx,inst, kDynScId, m.u.dyn.dynLvl );
  389. break;
  390. case kVarMsgScId:
  391. cmDspSetUInt( p->ctx,inst, kValTypeScId, m.u.meas.varId);
  392. cmDspSetDouble(p->ctx,inst, kValueScId, m.u.meas.value);
  393. break;
  394. default:
  395. { assert(0); }
  396. }
  397. }
  398. }
  399. cmDspRC_t _cmDspScoreReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  400. {
  401. cmDspRC_t rc = kOkDspRC;
  402. cmDspScore_t* p = (cmDspScore_t*)inst;
  403. const cmChar_t* tlFn = NULL;
  404. unsigned* dynRefArray = NULL;
  405. unsigned dynRefCnt = 0;
  406. cmDspApplyAllDefaults(ctx,inst);
  407. if( cmDspRsrcUIntArray(ctx->dspH, &dynRefCnt, &dynRefArray, "dynRef", NULL ) != kOkDspRC )
  408. {
  409. rc = cmErrMsg(&inst->classPtr->err, kRsrcNotFoundDspRC, "The dynamics reference array resource was not found.");
  410. goto errLabel;
  411. }
  412. if((tlFn = cmDspStrcz(inst, kFnScId )) != NULL )
  413. if( cmScoreInitialize(ctx->cmCtx, &p->scH, tlFn, dynRefArray, dynRefCnt, _cmDspScoreCb, p ) != kOkTlRC )
  414. rc = cmErrMsg(&inst->classPtr->err, kInstResetFailDspRC, "Score file open failed.");
  415. errLabel:
  416. return rc;
  417. }
  418. cmDspRC_t _cmDspScoreRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  419. {
  420. cmDspScore_t* p = (cmDspScore_t*)inst;
  421. if( evt->dstVarId == kSendScId )
  422. {
  423. unsigned selIdx;
  424. if((selIdx = cmDspUInt(inst,kSelScId)) != cmInvalidIdx )
  425. {
  426. cmDspSetUInt(ctx,inst,kSelScId, selIdx );
  427. cmScoreClearPerfInfo(p->scH);
  428. }
  429. return kOkDspRC;
  430. }
  431. cmDspSetEvent(ctx,inst,evt);
  432. switch( evt->dstVarId )
  433. {
  434. case kSelScId:
  435. cmScoreClearPerfInfo(p->scH);
  436. break;
  437. case kStatusScId:
  438. //printf("st:%x\n",cmDspUInt(inst,kStatusScId));
  439. break;
  440. case kLocIdxScId:
  441. {
  442. assert( cmDspUInt(inst,kStatusScId ) == kNoteOnMdId );
  443. p->ctx = ctx; // setup p->ctx for use in _cmDspScoreCb()
  444. // this call may result in callbacks to _cmDspScoreCb()
  445. cmScoreExecPerfEvent(p->scH, cmDspUInt(inst,kLocIdxScId), cmDspUInt(inst,kSmpIdxScId), cmDspUInt(inst,kD0ScId), cmDspUInt(inst,kD1ScId) );
  446. }
  447. break;
  448. }
  449. return kOkDspRC;
  450. }
  451. struct cmDspClass_str* cmScoreClassCons( cmDspCtx_t* ctx )
  452. {
  453. cmDspClassSetup(&_cmScoreDC,ctx,"Score",
  454. NULL,
  455. _cmDspScoreAlloc,
  456. _cmDspScoreFree,
  457. _cmDspScoreReset,
  458. NULL,
  459. _cmDspScoreRecv,
  460. NULL,NULL,
  461. "Score control.");
  462. return &_cmScoreDC;
  463. }
  464. //==========================================================================================================================================
  465. // MIDI File Player
  466. enum
  467. {
  468. kFnMfId,
  469. kSelMfId,
  470. kBsiMfId,
  471. kEsiMfId,
  472. kStatusMfId,
  473. kD0MfId,
  474. kD1MfId,
  475. kSmpIdxMfId
  476. };
  477. cmDspClass_t _cmMidiFilePlayDC;
  478. typedef struct
  479. {
  480. cmDspInst_t inst;
  481. cmMidiFileH_t mfH;
  482. unsigned curMsgIdx; // current midi file msg index
  483. int csi; // current sample index
  484. int bsi; // starting sample index
  485. int esi; // ending sample index
  486. unsigned startSymId;
  487. unsigned stopSymId;
  488. unsigned contSymId;
  489. bool errFl;
  490. } cmDspMidiFilePlay_t;
  491. /*
  492. 'bsi' and 'esi' give the starting and ending sample for MIDI file playback.
  493. These indexes are relative to the start of the file.
  494. When the player recieves a 'start' msg it sets the current sample index
  495. 'si' to 'bsi' and begins scanning for the next note to play.
  496. On each call to the _cmDspMidiFilePlayExec() msgs that fall in the interval
  497. si:si+sPc-1 will be transmitted. (where sPc are the number of samples per DSP cycle).
  498. */
  499. cmDspInst_t* _cmDspMidiFilePlayAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  500. {
  501. cmDspVarArg_t args[] =
  502. {
  503. { "fn", kFnMfId, 0, 0, kInDsvFl | kStrzDsvFl, "File name"},
  504. { "sel", kSelMfId, 0, 0, kInDsvFl | kSymDsvFl, "start | stop | continue" },
  505. { "bsi", kBsiMfId, 0, 0, kInDsvFl | kIntDsvFl, "Starting sample." },
  506. { "esi", kEsiMfId, 0, 0, kInDsvFl | kIntDsvFl, "Ending sample."},
  507. { "status", kStatusMfId, 0, 0, kOutDsvFl | kIntDsvFl, "Status value output" },
  508. { "d0", kD0MfId, 0, 0, kOutDsvFl | kUIntDsvFl, "Data byte 0" },
  509. { "d1", kD1MfId, 0, 0, kOutDsvFl | kUIntDsvFl, "Data byte 1" },
  510. { "smpidx", kSmpIdxMfId, 0, 0, kOutDsvFl | kUIntDsvFl, "Msg time tag as a sample index." },
  511. { NULL, 0, 0, 0, 0 }
  512. };
  513. cmDspMidiFilePlay_t* p = cmDspInstAlloc(cmDspMidiFilePlay_t,ctx,classPtr,args,instSymId,id,storeSymId,va_cnt,vl);
  514. p->startSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"start");
  515. p->stopSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"stop");
  516. p->contSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"continue");
  517. p->mfH = cmMidiFileNullHandle;
  518. cmDspSetDefaultStrcz( ctx, &p->inst, kFnMfId, NULL, "");
  519. cmDspSetDefaultSymbol(ctx, &p->inst, kSelMfId, p->stopSymId);
  520. cmDspSetDefaultInt( ctx, &p->inst, kBsiMfId, 0, 0);
  521. cmDspSetDefaultInt( ctx, &p->inst, kEsiMfId, 0, 0);
  522. cmDspSetDefaultUInt( ctx, &p->inst, kStatusMfId, 0, 0);
  523. cmDspSetDefaultUInt( ctx, &p->inst, kD0MfId, 0, 0);
  524. cmDspSetDefaultUInt( ctx, &p->inst, kD1MfId, 0, 0);
  525. return &p->inst;
  526. }
  527. cmDspRC_t _cmDspMidiFilePlayFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  528. {
  529. cmDspMidiFilePlay_t* p = (cmDspMidiFilePlay_t*)inst;
  530. if( cmMidiFileClose(&p->mfH) )
  531. return cmErrMsg(&inst->classPtr->err, kInstFinalFailDspRC, "MIDI file close failed.");
  532. return kOkDspRC;
  533. }
  534. // return the index of the msg following smpIdx
  535. unsigned _cmDspMidiFilePlaySeekMsgIdx( cmDspCtx_t* ctx, cmDspInst_t* inst, unsigned smpIdx )
  536. {
  537. cmDspMidiFilePlay_t* p = (cmDspMidiFilePlay_t*)inst;
  538. if( cmMidiFileIsValid(p->mfH) == false )
  539. {
  540. cmErrMsg(&inst->classPtr->err, kInvalidStateDspRC,"The MIDI file player has not been given a valid MIDI file.");
  541. return cmInvalidIdx;
  542. }
  543. unsigned i;
  544. unsigned n = cmMidiFileMsgCount(p->mfH);
  545. const cmMidiTrackMsg_t** a = cmMidiFileMsgArray(p->mfH);
  546. for(i=0; i<n; ++i)
  547. if( a[i]->dtick > smpIdx )
  548. break;
  549. return i==n ? cmInvalidIdx : i;
  550. }
  551. cmDspRC_t _cmDspMidiFilePlayOpen(cmDspCtx_t* ctx, cmDspInst_t* inst )
  552. {
  553. cmDspRC_t rc = kOkDspRC;
  554. const cmChar_t* fn = cmDspStrcz(inst,kFnMfId);
  555. cmDspMidiFilePlay_t* p = (cmDspMidiFilePlay_t*)inst;
  556. p->errFl = false;
  557. if( fn==NULL || strlen(fn)==0 )
  558. return rc;
  559. if( cmMidiFileOpen( fn, &p->mfH, ctx->cmCtx ) != kOkFileRC )
  560. rc = cmErrMsg(&inst->classPtr->err, kInstResetFailDspRC, "MIDI file open failed.");
  561. else
  562. {
  563. p->curMsgIdx = 0;
  564. p->bsi = cmDspInt(inst,kBsiMfId);
  565. p->esi = cmDspInt(inst,kEsiMfId);
  566. p->csi = 0;
  567. // force the first msg to occurr one quarter note into the file
  568. cmMidiFileSetDelay(p->mfH, cmMidiFileTicksPerQN(p->mfH) );
  569. // convert midi msg times to absolute time in samples
  570. cmMidiFileTickToSamples(p->mfH,cmDspSampleRate(ctx),true);
  571. }
  572. return rc;
  573. }
  574. cmDspRC_t _cmDspMidiFilePlayReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  575. {
  576. cmDspApplyAllDefaults(ctx,inst);
  577. return _cmDspMidiFilePlayOpen(ctx,inst);
  578. }
  579. cmDspRC_t _cmDspMidiFilePlayExec(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  580. {
  581. cmDspRC_t rc = kOkDspRC;
  582. cmDspMidiFilePlay_t* p = (cmDspMidiFilePlay_t*)inst;
  583. unsigned sPc = cmDspSamplesPerCycle(ctx);
  584. if( cmDspSymbol(inst,kSelMfId) != p->stopSymId )
  585. {
  586. if( cmMidiFileIsValid(p->mfH) == false )
  587. {
  588. if( p->errFl==false )
  589. {
  590. rc = cmErrMsg(&inst->classPtr->err, kInvalidStateDspRC,"The MIDI file player has not been given a valid MIDI file.");
  591. p->errFl = true;
  592. }
  593. return rc;
  594. }
  595. const cmMidiTrackMsg_t** mpp = cmMidiFileMsgArray(p->mfH);
  596. unsigned msgN = cmMidiFileMsgCount(p->mfH);
  597. for(; p->curMsgIdx < msgN && p->csi <= mpp[p->curMsgIdx]->dtick && mpp[p->curMsgIdx]->dtick < (p->csi + sPc); ++p->curMsgIdx )
  598. {
  599. const cmMidiTrackMsg_t* mp = mpp[p->curMsgIdx];
  600. switch( mp->status )
  601. {
  602. case kNoteOnMdId:
  603. case kCtlMdId:
  604. cmDspSetUInt(ctx,inst, kSmpIdxMfId, mp->dtick);
  605. cmDspSetUInt(ctx,inst, kD1MfId, mp->u.chMsgPtr->d1);
  606. cmDspSetUInt(ctx,inst, kD0MfId, mp->u.chMsgPtr->d0);
  607. cmDspSetUInt(ctx,inst, kStatusMfId, mp->status);
  608. break;
  609. }
  610. }
  611. }
  612. p->csi += sPc;
  613. return rc;
  614. }
  615. cmDspRC_t _cmDspMidiFilePlayRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  616. {
  617. cmDspMidiFilePlay_t* p = (cmDspMidiFilePlay_t*)inst;
  618. cmDspSetEvent(ctx,inst,evt);
  619. switch(evt->dstVarId)
  620. {
  621. case kFnMfId:
  622. _cmDspMidiFilePlayOpen(ctx, inst );
  623. break;
  624. case kSelMfId:
  625. {
  626. if( cmDspSymbol(inst,kSelMfId)==p->startSymId )
  627. {
  628. p->csi = cmDspInt(inst,kBsiMfId);
  629. p->curMsgIdx = _cmDspMidiFilePlaySeekMsgIdx(ctx, inst, p->csi );
  630. }
  631. break;
  632. }
  633. }
  634. return kOkDspRC;
  635. }
  636. struct cmDspClass_str* cmMidiFilePlayClassCons( cmDspCtx_t* ctx )
  637. {
  638. cmDspClassSetup(&_cmMidiFilePlayDC,ctx,"MidiFilePlay",
  639. NULL,
  640. _cmDspMidiFilePlayAlloc,
  641. _cmDspMidiFilePlayFree,
  642. _cmDspMidiFilePlayReset,
  643. _cmDspMidiFilePlayExec,
  644. _cmDspMidiFilePlayRecv,
  645. NULL,NULL,
  646. "Time tagged text file.");
  647. return &_cmMidiFilePlayDC;
  648. }
  649. //==========================================================================================================================================
  650. enum
  651. {
  652. kFnSfId,
  653. kBufCntSfId,
  654. kMinLkAhdSfId,
  655. kMaxWndCntSfId,
  656. kMinVelSfId,
  657. kIndexSfId,
  658. kStatusSfId,
  659. kD0SfId,
  660. kD1SfId,
  661. kSmpIdxSfId,
  662. kCmdSfId,
  663. kOutSfId
  664. };
  665. cmDspClass_t _cmScFolDC;
  666. typedef struct
  667. {
  668. cmDspInst_t inst;
  669. cmScTrk* sfp;
  670. cmScH_t scH;
  671. unsigned printSymId;
  672. unsigned quietSymId;
  673. } cmDspScFol_t;
  674. cmDspInst_t* _cmDspScFolAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  675. {
  676. cmDspVarArg_t args[] =
  677. {
  678. { "fn", kFnSfId, 0, 0, kInDsvFl | kStrzDsvFl | kReqArgDsvFl, "Score file." },
  679. { "bufcnt",kBufCntSfId, 0, 0, kInDsvFl | kUIntDsvFl, "Event buffer element count." },
  680. { "lkahd", kMinLkAhdSfId, 0, 0, kInDsvFl | kUIntDsvFl, "Minimum window look-ahead."},
  681. { "wndcnt",kMaxWndCntSfId,0, 0, kInDsvFl | kUIntDsvFl, "Maximum window length."},
  682. { "minvel",kMinVelSfId, 0, 0, kInDsvFl | kUIntDsvFl, "Minimum velocity."},
  683. { "index", kIndexSfId, 0, 0, kInDsvFl | kUIntDsvFl, "Tracking start location."},
  684. { "status",kStatusSfId, 0, 0, kInDsvFl | kUIntDsvFl, "MIDI status byte"},
  685. { "d0", kD0SfId, 0, 0, kInDsvFl | kUIntDsvFl, "MIDI data byte 0"},
  686. { "d1", kD1SfId, 0, 0, kInDsvFl | kUIntDsvFl, "MIDI data byte 1"},
  687. { "smpidx",kSmpIdxSfId, 0, 0, kInDsvFl | kUIntDsvFl, "MIDI time tag as a sample index"},
  688. { "cmd", kCmdSfId, 0, 0, kInDsvFl | kSymDsvFl, "Command input: print | quiet"},
  689. { "out", kOutSfId, 0, 0, kOutDsvFl| kUIntDsvFl, "Current score index."},
  690. { NULL, 0, 0, 0, 0, NULL }
  691. };
  692. cmDspScFol_t* p;
  693. if((p = cmDspInstAlloc(cmDspScFol_t,ctx,classPtr,args,instSymId,id,storeSymId,va_cnt,vl)) == NULL )
  694. return NULL;
  695. p->sfp = cmScTrkAlloc(ctx->cmProcCtx, NULL, 0, cmScNullHandle, 0, 0, 0, 0 );
  696. p->printSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"print");
  697. p->quietSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"quiet");
  698. cmDspSetDefaultUInt( ctx, &p->inst, kBufCntSfId, 0, 7);
  699. cmDspSetDefaultUInt( ctx, &p->inst, kMinLkAhdSfId, 0, 10);
  700. cmDspSetDefaultUInt( ctx, &p->inst, kMaxWndCntSfId, 0, 25);
  701. cmDspSetDefaultUInt( ctx, &p->inst, kMinVelSfId, 0, 5);
  702. cmDspSetDefaultUInt( ctx, &p->inst, kIndexSfId, 0, 0);
  703. cmDspSetDefaultUInt( ctx, &p->inst, kOutSfId, 0, 0);
  704. cmDspSetDefaultSymbol(ctx,&p->inst, kCmdSfId, p->quietSymId );
  705. return &p->inst;
  706. }
  707. cmDspRC_t _cmDspScFolFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  708. {
  709. cmDspScFol_t* p = (cmDspScFol_t*)inst;
  710. cmScTrkFree(&p->sfp);
  711. cmScoreFinalize(&p->scH);
  712. return kOkDspRC;
  713. }
  714. cmDspRC_t _cmDspScFolOpenScore( cmDspCtx_t* ctx, cmDspInst_t* inst )
  715. {
  716. cmDspRC_t rc = kOkDspRC;
  717. cmDspScFol_t* p = (cmDspScFol_t*)inst;
  718. unsigned* dynRefArray = NULL;
  719. unsigned dynRefCnt = 0;
  720. const cmChar_t* fn;
  721. if((fn = cmDspStrcz(inst,kFnSfId)) == NULL || strlen(fn)==0 )
  722. return cmErrMsg(&inst->classPtr->err, kInvalidArgDspRC, "No score file name supplied.");
  723. if( cmDspRsrcUIntArray(ctx->dspH, &dynRefCnt, &dynRefArray, "dynRef", NULL ) != kOkDspRC )
  724. {
  725. rc = cmErrMsg(&inst->classPtr->err, kRsrcNotFoundDspRC, "The dynamics reference array resource was not found.");
  726. goto errLabel;
  727. }
  728. if( cmScoreInitialize(ctx->cmCtx, &p->scH, fn, NULL, 0, NULL, NULL ) != kOkScRC )
  729. return cmErrMsg(&inst->classPtr->err, kSubSysFailDspRC, "Unable to open the score '%s'.",fn);
  730. errLabel:
  731. return rc;
  732. }
  733. cmDspRC_t _cmDspScFolReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  734. {
  735. cmDspRC_t rc = kOkDspRC;
  736. cmDspScFol_t* p = (cmDspScFol_t*)inst;
  737. rc = cmDspApplyAllDefaults(ctx,inst);
  738. if((rc = _cmDspScFolOpenScore(ctx,inst)) != kOkDspRC )
  739. return rc;
  740. if( cmScoreIsValid(p->scH) )
  741. if( cmScTrkInit(p->sfp, cmDspSampleRate(ctx), p->scH, cmDspUInt(inst,kBufCntSfId), cmDspUInt(inst,kMinLkAhdSfId), cmDspUInt(inst,kMaxWndCntSfId), cmDspUInt(inst,kMinVelSfId) ) != cmOkRC )
  742. rc = cmErrMsg(&inst->classPtr->err, kSubSysFailDspRC, "Internal score follower allocation failed.");
  743. return rc;
  744. }
  745. cmDspRC_t _cmDspScFolRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  746. {
  747. cmDspRC_t rc = kOkDspRC;
  748. cmDspScFol_t* p = (cmDspScFol_t*)inst;
  749. if((rc = cmDspSetEvent(ctx,inst,evt)) == kOkDspRC && p->sfp != NULL )
  750. {
  751. switch( evt->dstVarId )
  752. {
  753. case kIndexSfId:
  754. if( cmScoreIsValid(p->scH) )
  755. if( cmScTrkReset( p->sfp, cmDspUInt(inst,kIndexSfId) ) != cmOkRC )
  756. cmErrMsg(&inst->classPtr->err, kSubSysFailDspRC, "Score follower reset to score index '%i' failed.");
  757. break;
  758. case kStatusSfId:
  759. if( cmScoreIsValid(p->scH))
  760. {
  761. unsigned idx = cmScTrkExec(p->sfp, ctx->cycleCnt, cmDspUInt(inst,kStatusSfId), cmDspUInt(inst,kD0SfId), cmDspUInt(inst,kD1SfId));
  762. if( idx != cmInvalidIdx )
  763. cmDspSetUInt(ctx,inst,kOutSfId,idx);
  764. }
  765. break;
  766. case kFnSfId:
  767. _cmDspScFolOpenScore(ctx,inst);
  768. break;
  769. case kCmdSfId:
  770. if( cmDspSymbol(inst,kCmdSfId) == p->printSymId )
  771. p->sfp->printFl = true;
  772. else
  773. if( cmDspSymbol(inst,kCmdSfId) == p->quietSymId )
  774. p->sfp->printFl = false;
  775. break;
  776. }
  777. }
  778. return rc;
  779. }
  780. struct cmDspClass_str* cmScFolClassCons( cmDspCtx_t* ctx )
  781. {
  782. cmDspClassSetup(&_cmScFolDC,ctx,"ScFol",
  783. NULL,
  784. _cmDspScFolAlloc,
  785. _cmDspScFolFree,
  786. _cmDspScFolReset,
  787. NULL,
  788. _cmDspScFolRecv,
  789. NULL,NULL,
  790. "Score Follower");
  791. return &_cmScFolDC;
  792. }