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.

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, cmDspSampleRate(ctx), 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, cmDspSampleRate(ctx), 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. }