libcm is a C development framework with an emphasis on audio signal processing applications.
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

cmDspKr.c 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842
  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. };
  411. cmDspClass_t _cmMidiFilePlayDC;
  412. typedef struct
  413. {
  414. cmDspInst_t inst;
  415. cmMidiFileH_t mfH;
  416. unsigned curMsgIdx; // current midi file msg index
  417. int csi; // current sample index
  418. int bsi; // starting sample index
  419. int esi; // ending sample index
  420. unsigned startSymId;
  421. unsigned stopSymId;
  422. unsigned contSymId;
  423. } cmDspMidiFilePlay_t;
  424. /*
  425. 'bsi' and 'esi' give the starting and ending sample for MIDI file playback.
  426. These indexes are relative to the start of the file.
  427. When the player recieves a 'start' msg it sets the current sample index
  428. 'si' to 'bsi' and begins scanning for the next note to play.
  429. On each call to the _cmDspMidiFilePlayExec() msgs that fall in the interval
  430. si:si+sPc-1 will be transmitted. (where sPc are the number of samples per DSP cycle).
  431. */
  432. cmDspInst_t* _cmDspMidiFilePlayAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  433. {
  434. cmDspVarArg_t args[] =
  435. {
  436. { "fn", kFnMfId, 0, 0, kInDsvFl | kStrzDsvFl, "File name"},
  437. { "sel", kSelMfId, 0, 0, kInDsvFl | kSymDsvFl, "start | stop | continue" },
  438. { "bsi", kBsiMfId, 0, 0, kInDsvFl | kIntDsvFl, "Starting sample." },
  439. { "esi", kEsiMfId, 0, 0, kInDsvFl | kIntDsvFl, "Ending sample."},
  440. { "status", kStatusMfId, 0, 0, kOutDsvFl | kIntDsvFl, "Status value output" },
  441. { "d0", kD0MfId, 0, 0, kOutDsvFl | kUIntDsvFl, "Data byte 0" },
  442. { "d1", kD1MfId, 0, 0, kOutDsvFl | kUIntDsvFl, "Data byte 1" },
  443. { NULL, 0, 0, 0, 0 }
  444. };
  445. cmDspMidiFilePlay_t* p = cmDspInstAlloc(cmDspMidiFilePlay_t,ctx,classPtr,args,instSymId,id,storeSymId,va_cnt,vl);
  446. p->startSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"start");
  447. p->stopSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"stop");
  448. p->contSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"continue");
  449. p->mfH = cmMidiFileNullHandle;
  450. cmDspSetDefaultStrcz( ctx, &p->inst, kFnMfId, NULL, "");
  451. cmDspSetDefaultSymbol(ctx, &p->inst, kSelMfId, p->stopSymId);
  452. cmDspSetDefaultInt( ctx, &p->inst, kBsiMfId, 0, 0);
  453. cmDspSetDefaultInt( ctx, &p->inst, kEsiMfId, 0, 0);
  454. cmDspSetDefaultUInt( ctx, &p->inst, kStatusMfId, 0, 0);
  455. cmDspSetDefaultUInt( ctx, &p->inst, kD0MfId, 0, 0);
  456. cmDspSetDefaultUInt( ctx, &p->inst, kD1MfId, 0, 0);
  457. return &p->inst;
  458. }
  459. cmDspRC_t _cmDspMidiFilePlayFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  460. {
  461. cmDspMidiFilePlay_t* p = (cmDspMidiFilePlay_t*)inst;
  462. if( cmMidiFileClose(&p->mfH) )
  463. return cmErrMsg(&inst->classPtr->err, kInstFinalFailDspRC, "MIDI file close failed.");
  464. return kOkDspRC;
  465. }
  466. // return the index of the msg following smpIdx
  467. unsigned _cmDspMidiFilePlaySeekMsgIdx( cmDspCtx_t* ctx, cmDspMidiFilePlay_t* p, unsigned smpIdx )
  468. {
  469. unsigned i;
  470. unsigned n = cmMidiFileMsgCount(p->mfH);
  471. const cmMidiTrackMsg_t** a = cmMidiFileMsgArray(p->mfH);
  472. for(i=0; i<n; ++i)
  473. if( a[i]->dtick > smpIdx )
  474. break;
  475. return i==n ? cmInvalidIdx : i;
  476. }
  477. cmDspRC_t _cmDspMidiFilePlayOpen(cmDspCtx_t* ctx, cmDspInst_t* inst )
  478. {
  479. cmDspRC_t rc = kOkDspRC;
  480. const cmChar_t* fn = cmDspStrcz(inst,kFnMfId);
  481. cmDspMidiFilePlay_t* p = (cmDspMidiFilePlay_t*)inst;
  482. if( fn==NULL || strlen(fn)==0 )
  483. return rc;
  484. if( cmMidiFileOpen( fn, &p->mfH, ctx->cmCtx ) != kOkFileRC )
  485. rc = cmErrMsg(&inst->classPtr->err, kInstResetFailDspRC, "MIDI file open failed.");
  486. else
  487. {
  488. p->curMsgIdx = 0;
  489. p->bsi = cmDspInt(inst,kBsiMfId);
  490. p->esi = cmDspInt(inst,kEsiMfId);
  491. p->csi = 0;
  492. // force the first msg to occurr one quarter note into the file
  493. cmMidiFileSetDelay(p->mfH, cmMidiFileTicksPerQN(p->mfH) );
  494. // convert midi msg times to absolute time in samples
  495. cmMidiFileTickToSamples(p->mfH,cmDspSampleRate(ctx),true);
  496. }
  497. return rc;
  498. }
  499. cmDspRC_t _cmDspMidiFilePlayReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  500. {
  501. cmDspApplyAllDefaults(ctx,inst);
  502. return _cmDspMidiFilePlayOpen(ctx,inst);
  503. }
  504. cmDspRC_t _cmDspMidiFilePlayExec(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  505. {
  506. cmDspRC_t rc = kOkDspRC;
  507. cmDspMidiFilePlay_t* p = (cmDspMidiFilePlay_t*)inst;
  508. unsigned sPc = cmDspSamplesPerCycle(ctx);
  509. if( cmDspSymbol(inst,kSelMfId) != p->stopSymId )
  510. {
  511. const cmMidiTrackMsg_t** mpp = cmMidiFileMsgArray(p->mfH);
  512. unsigned msgN = cmMidiFileMsgCount(p->mfH);
  513. for(; p->curMsgIdx < msgN && p->csi <= mpp[p->curMsgIdx]->dtick && mpp[p->curMsgIdx]->dtick < (p->csi + sPc); ++p->curMsgIdx )
  514. {
  515. const cmMidiTrackMsg_t* mp = mpp[p->curMsgIdx];
  516. switch( mp->status )
  517. {
  518. case kNoteOnMdId:
  519. case kCtlMdId:
  520. cmDspSetUInt(ctx,inst, kD1MfId, mp->u.chMsgPtr->d1);
  521. cmDspSetUInt(ctx,inst, kD0MfId, mp->u.chMsgPtr->d0);
  522. cmDspSetUInt(ctx,inst, kStatusMfId, mp->status);
  523. break;
  524. }
  525. }
  526. }
  527. p->csi += sPc;
  528. return rc;
  529. }
  530. cmDspRC_t _cmDspMidiFilePlayRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  531. {
  532. cmDspMidiFilePlay_t* p = (cmDspMidiFilePlay_t*)inst;
  533. cmDspSetEvent(ctx,inst,evt);
  534. switch(evt->dstVarId)
  535. {
  536. case kFnMfId:
  537. _cmDspMidiFilePlayOpen(ctx, inst );
  538. break;
  539. case kSelMfId:
  540. {
  541. if( cmDspSymbol(inst,kSelMfId)==p->startSymId )
  542. {
  543. p->csi = cmDspInt(inst,kBsiMfId);
  544. p->curMsgIdx = _cmDspMidiFilePlaySeekMsgIdx(ctx, p, p->csi );
  545. }
  546. break;
  547. }
  548. }
  549. return kOkDspRC;
  550. }
  551. struct cmDspClass_str* cmMidiFilePlayClassCons( cmDspCtx_t* ctx )
  552. {
  553. cmDspClassSetup(&_cmMidiFilePlayDC,ctx,"MidiFilePlay",
  554. NULL,
  555. _cmDspMidiFilePlayAlloc,
  556. _cmDspMidiFilePlayFree,
  557. _cmDspMidiFilePlayReset,
  558. _cmDspMidiFilePlayExec,
  559. _cmDspMidiFilePlayRecv,
  560. NULL,NULL,
  561. "Time tagged text file.");
  562. return &_cmMidiFilePlayDC;
  563. }
  564. //==========================================================================================================================================
  565. enum
  566. {
  567. kFnSfId,
  568. kBufCntSfId,
  569. kBufMsSfId,
  570. kIndexSfId,
  571. kStatusSfId,
  572. kD0SfId,
  573. kD1SfId,
  574. kOutSfId
  575. };
  576. cmDspClass_t _cmScFolDC;
  577. typedef struct
  578. {
  579. cmDspInst_t inst;
  580. cmScFol* sfp;
  581. cmScH_t scH;
  582. } cmDspScFol_t;
  583. cmDspInst_t* _cmDspScFolAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  584. {
  585. cmDspVarArg_t args[] =
  586. {
  587. { "fn", kFnSfId, 0, 0, kInDsvFl | kStrzDsvFl | kReqArgDsvFl, "Score file." },
  588. { "bufcnt",kBufCntSfId, 0, 0, kInDsvFl | kUIntDsvFl, "Event buffer element count." },
  589. { "bufms", kBufMsSfId, 0, 0, kInDsvFl | kUIntDsvFl, "Event buffer length milliseconds."},
  590. { "index", kIndexSfId, 0, 0, kInDsvFl | kUIntDsvFl, "Tracking start location."},
  591. { "status",kStatusSfId, 0, 0, kInDsvFl | kUIntDsvFl, "MIDI status byte"},
  592. { "d0", kD0SfId, 0, 0, kInDsvFl | kUIntDsvFl, "MIDI data byte 0"},
  593. { "d1", kD1SfId, 0, 0, kInDsvFl | kUIntDsvFl, "MIDI data byte 1"},
  594. { "out", kOutSfId, 0, 0, kOutDsvFl| kUIntDsvFl, "Current score index."},
  595. { NULL, 0, 0, 0, 0, NULL }
  596. };
  597. cmDspScFol_t* p;
  598. if((p = cmDspInstAlloc(cmDspScFol_t,ctx,classPtr,args,instSymId,id,storeSymId,va_cnt,vl)) == NULL )
  599. return NULL;
  600. p->sfp = cmScFolAlloc(ctx->cmProcCtx, NULL, 0, 0, 0, cmScNullHandle );
  601. cmDspSetDefaultUInt( ctx, &p->inst, kBufCntSfId, 0, 10);
  602. cmDspSetDefaultUInt( ctx, &p->inst, kBufMsSfId, 0, 5000);
  603. cmDspSetDefaultUInt( ctx, &p->inst, kIndexSfId, 0, 0);
  604. cmDspSetDefaultUInt( ctx, &p->inst, kOutSfId, 0, 0);
  605. return &p->inst;
  606. }
  607. cmDspRC_t _cmDspScFolFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  608. {
  609. cmDspScFol_t* p = (cmDspScFol_t*)inst;
  610. cmScFolFree(&p->sfp);
  611. cmScoreFinalize(&p->scH);
  612. return kOkDspRC;
  613. }
  614. cmDspRC_t _cmDspScFolOpenScore( cmDspCtx_t* ctx, cmDspInst_t* inst )
  615. {
  616. const cmChar_t* fn;
  617. cmDspScFol_t* p = (cmDspScFol_t*)inst;
  618. if((fn = cmDspStrcz(inst,kFnSfId)) == NULL || strlen(fn)==0 )
  619. return cmErrMsg(&inst->classPtr->err, kInvalidArgDspRC, "No score file name supplied.");
  620. if( cmScoreInitialize(ctx->cmCtx, &p->scH, fn, NULL, NULL ) != kOkScRC )
  621. return cmErrMsg(&inst->classPtr->err, kSubSysFailDspRC, "Unable to open the score '%s'.",fn);
  622. return kOkDspRC;
  623. }
  624. cmDspRC_t _cmDspScFolReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  625. {
  626. cmDspRC_t rc = kOkDspRC;
  627. cmDspScFol_t* p = (cmDspScFol_t*)inst;
  628. rc = cmDspApplyAllDefaults(ctx,inst);
  629. if((rc = _cmDspScFolOpenScore(ctx,inst)) != kOkDspRC )
  630. return rc;
  631. if( cmScoreIsValid(p->scH) )
  632. if( cmScFolInit(p->sfp, cmDspSampleRate(ctx), cmDspUInt(inst,kBufCntSfId), cmDspUInt(inst,kBufMsSfId), p->scH) != cmOkRC )
  633. rc = cmErrMsg(&inst->classPtr->err, kSubSysFailDspRC, "Internal score follower allocation failed.");
  634. return rc;
  635. }
  636. cmDspRC_t _cmDspScFolRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  637. {
  638. cmDspRC_t rc = kOkDspRC;
  639. cmDspScFol_t* p = (cmDspScFol_t*)inst;
  640. if((rc = cmDspSetEvent(ctx,inst,evt)) == kOkDspRC && p->sfp != NULL )
  641. {
  642. switch( evt->dstVarId )
  643. {
  644. case kIndexSfId:
  645. if( cmScoreIsValid(p->scH) )
  646. if( cmScFolReset( p->sfp, cmDspUInt(inst,kIndexSfId) ) != cmOkRC )
  647. cmErrMsg(&inst->classPtr->err, kSubSysFailDspRC, "Score follower reset to score index '%i' failed.");
  648. break;
  649. case kStatusSfId:
  650. if( cmScoreIsValid(p->scH))
  651. {
  652. unsigned idx = cmScFolExec(p->sfp, ctx->cycleCnt, cmDspUInt(inst,kStatusSfId), cmDspUInt(inst,kD0SfId), cmDspUInt(inst,kD1SfId));
  653. if( idx != cmInvalidIdx )
  654. cmDspSetUInt(ctx,inst,kOutSfId,idx);
  655. }
  656. break;
  657. case kFnSfId:
  658. _cmDspScFolOpenScore(ctx,inst);
  659. break;
  660. }
  661. }
  662. return rc;
  663. }
  664. struct cmDspClass_str* cmScFolClassCons( cmDspCtx_t* ctx )
  665. {
  666. cmDspClassSetup(&_cmScFolDC,ctx,"ScFol",
  667. NULL,
  668. _cmDspScFolAlloc,
  669. _cmDspScFolFree,
  670. _cmDspScFolReset,
  671. NULL,
  672. _cmDspScFolRecv,
  673. NULL,NULL,
  674. "Score Follower");
  675. return &_cmScFolDC;
  676. }