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

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214
  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 "cmText.h"
  15. #include "cmPrefs.h"
  16. #include "cmDspValue.h"
  17. #include "cmMsgProtocol.h"
  18. #include "cmThread.h"
  19. #include "cmUdpPort.h"
  20. #include "cmUdpNet.h"
  21. #include "cmAudioSys.h"
  22. #include "cmDspCtx.h"
  23. #include "cmDspClass.h"
  24. #include "cmDspUi.h"
  25. #include "cmDspSys.h"
  26. #include "cmMath.h"
  27. #include "cmAudioFile.h"
  28. #include "cmFileSys.h"
  29. #include "cmProcObj.h"
  30. #include "cmProcTemplateMain.h"
  31. #include "cmProc.h"
  32. #include "cmMidi.h"
  33. #include "cmProc2.h"
  34. #include "cmVectOpsTemplateMain.h"
  35. #include "cmAudioFile.h"
  36. #include "cmMidiFile.h"
  37. #include "cmTimeLine.h"
  38. #include "cmScore.h"
  39. #include "cmProc4.h"
  40. enum
  41. {
  42. kWndSmpCntKrId,
  43. kHopFactKrId,
  44. kModeKrId,
  45. kThreshKrId,
  46. kLwrSlopeKrId,
  47. kUprSlopeKrId,
  48. kOffsetKrId,
  49. kInvertKrId,
  50. kAudioInKrId,
  51. kAudioOutKrId
  52. };
  53. typedef struct
  54. {
  55. cmDspInst_t inst;
  56. cmCtx* ctx;
  57. cmSpecDist_t* sdp;
  58. } cmDspKr_t;
  59. cmDspClass_t _cmKrDC;
  60. //==========================================================================================================================================
  61. cmDspInst_t* _cmDspKrAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  62. {
  63. cmDspVarArg_t args[] =
  64. {
  65. { "wndn", kWndSmpCntKrId, 0, 0, kInDsvFl | kUIntDsvFl | kReqArgDsvFl, "Window sample count" },
  66. { "hopf", kHopFactKrId, 0, 0, kInDsvFl | kUIntDsvFl | kOptArgDsvFl, "Hop factor" },
  67. { "mode", kModeKrId, 0, 0, kInDsvFl | kUIntDsvFl | kOptArgDsvFl, "Mode 0=bypass 1=basic 2=spec cnt 3=amp env" },
  68. { "thrh", kThreshKrId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Threshold" },
  69. { "lwrs", kLwrSlopeKrId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Lower Slope"},
  70. { "uprs", kUprSlopeKrId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Upper Slope"},
  71. { "offs", kOffsetKrId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Offset"},
  72. { "invt", kInvertKrId, 0, 0, kInDsvFl | kUIntDsvFl | kOptArgDsvFl, "Invert"},
  73. { "in", kAudioInKrId, 0, 0, kInDsvFl | kAudioBufDsvFl, "Audio Input" },
  74. { "out", kAudioOutKrId, 0, 1, kOutDsvFl | kAudioBufDsvFl, "Audio Output" },
  75. { NULL, 0, 0, 0, 0 }
  76. };
  77. cmDspKr_t* p = cmDspInstAlloc(cmDspKr_t,ctx,classPtr,args,instSymId,id,storeSymId,va_cnt,vl);
  78. unsigned defWndSmpCnt = cmDspDefaultUInt(&p->inst,kWndSmpCntKrId);
  79. unsigned wndSmpCnt = cmNextPowerOfTwo( defWndSmpCnt );
  80. cmDspSetDefaultUInt( ctx,&p->inst, kWndSmpCntKrId, defWndSmpCnt, wndSmpCnt );
  81. cmDspSetDefaultUInt( ctx,&p->inst, kHopFactKrId, 0, 4 );
  82. cmDspSetDefaultUInt( ctx,&p->inst, kModeKrId, 0, kBasicModeSdId );
  83. cmDspSetDefaultDouble( ctx,&p->inst, kThreshKrId, 0, 60.0 );
  84. cmDspSetDefaultDouble( ctx,&p->inst, kLwrSlopeKrId, 0, 2.0 );
  85. cmDspSetDefaultDouble( ctx,&p->inst, kUprSlopeKrId, 0, 0.0 );
  86. cmDspSetDefaultDouble( ctx,&p->inst, kOffsetKrId, 0, 30.0);
  87. cmDspSetDefaultUInt( ctx,&p->inst, kInvertKrId, 0, 0 );
  88. //_cmDspKrCmInit(ctx,p); // initialize the cm library
  89. p->ctx = cmCtxAlloc(NULL,ctx->rpt,ctx->lhH,ctx->stH);
  90. return &p->inst;
  91. }
  92. cmDspRC_t _cmDspKrFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  93. {
  94. cmDspRC_t rc = kOkDspRC;
  95. cmDspKr_t* p = (cmDspKr_t*)inst;
  96. cmSpecDistFree(&p->sdp);
  97. cmCtxFree(&p->ctx);
  98. //_cmDspKrCmFinal(ctx,p); // finalize the cm library
  99. return rc;
  100. }
  101. cmDspRC_t _cmDspKrSetup(cmDspCtx_t* ctx, cmDspKr_t* p )
  102. {
  103. cmDspRC_t rc = kOkDspRC;
  104. unsigned wndSmpCnt = cmDspUInt(&p->inst,kWndSmpCntKrId);
  105. unsigned hopFact = cmDspUInt(&p->inst,kHopFactKrId);
  106. unsigned olaWndTypeId = kHannWndId;
  107. cmSpecDistFree(&p->sdp);
  108. p->sdp = cmSpecDistAlloc(p->ctx, NULL, cmDspSamplesPerCycle(ctx), cmDspSampleRate(ctx), wndSmpCnt, hopFact, olaWndTypeId);
  109. assert(p->sdp != NULL );
  110. if((rc = cmDspZeroAudioBuf(ctx,&p->inst,kAudioOutKrId)) != kOkDspRC )
  111. return rc;
  112. return rc;
  113. }
  114. cmDspRC_t _cmDspKrReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  115. {
  116. cmDspKr_t* p = (cmDspKr_t*)inst;
  117. cmDspRC_t rc;
  118. if((rc = cmDspApplyAllDefaults(ctx,inst)) != kOkDspRC )
  119. return rc;
  120. return _cmDspKrSetup(ctx,p);
  121. }
  122. cmDspRC_t _cmDspKrExec(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  123. {
  124. cmDspKr_t* p = (cmDspKr_t*)inst;
  125. cmDspRC_t rc = kOkDspRC;
  126. unsigned iChIdx = 0;
  127. const cmSample_t* ip = cmDspAudioBuf(ctx,inst,kAudioInKrId,iChIdx);
  128. unsigned iSmpCnt = cmDspVarRows(inst,kAudioInKrId);
  129. // if no connected
  130. if( iSmpCnt == 0 )
  131. return rc;
  132. unsigned oChIdx = 0;
  133. cmSample_t* op = cmDspAudioBuf(ctx,inst,kAudioOutKrId,oChIdx);
  134. unsigned oSmpCnt = cmDspVarRows(inst,kAudioOutKrId);
  135. const cmSample_t* sp;
  136. cmSpecDistExec(p->sdp,ip,iSmpCnt);
  137. if((sp = cmSpecDistOut(p->sdp)) != NULL )
  138. cmVOS_Copy(op,oSmpCnt,sp);
  139. return rc;
  140. }
  141. cmDspRC_t _cmDspKrRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  142. {
  143. cmDspKr_t* p = (cmDspKr_t*)inst;
  144. cmDspRC_t rc = kOkDspRC;
  145. cmDspSetEvent(ctx,inst,evt);
  146. switch( evt->dstVarId )
  147. {
  148. case kWndSmpCntKrId:
  149. case kHopFactKrId:
  150. _cmDspKrSetup(ctx,p);
  151. printf("wsn:%i hsn:%i\n",p->sdp->wndSmpCnt,p->sdp->hopSmpCnt);
  152. break;
  153. case kModeKrId:
  154. p->sdp->mode = cmDspUInt(inst,kModeKrId);
  155. printf("mode:%i\n",p->sdp->mode);
  156. break;
  157. case kThreshKrId:
  158. p->sdp->thresh = cmDspDouble(inst,kThreshKrId);
  159. break;
  160. case kUprSlopeKrId:
  161. p->sdp->uprSlope = cmDspDouble(inst,kUprSlopeKrId);
  162. printf("upr slope:%f\n",p->sdp->uprSlope);
  163. break;
  164. case kLwrSlopeKrId:
  165. p->sdp->lwrSlope = cmDspDouble(inst,kLwrSlopeKrId);
  166. printf("upr slope:%f\n",p->sdp->lwrSlope);
  167. break;
  168. case kOffsetKrId:
  169. p->sdp->offset = cmDspDouble(inst,kOffsetKrId);
  170. break;
  171. case kInvertKrId:
  172. p->sdp->invertFl = cmDspUInt(inst,kInvertKrId)!=0;
  173. break;
  174. default:
  175. { assert(0); }
  176. }
  177. return rc;
  178. }
  179. struct cmDspClass_str* cmKrClassCons( cmDspCtx_t* ctx )
  180. {
  181. cmDspClassSetup(&_cmKrDC,ctx,"Kr",
  182. NULL,
  183. _cmDspKrAlloc,
  184. _cmDspKrFree,
  185. _cmDspKrReset,
  186. _cmDspKrExec,
  187. _cmDspKrRecv,
  188. NULL,NULL,
  189. "Fourier based non-linear transformer.");
  190. return &_cmKrDC;
  191. }
  192. //==========================================================================================================================================
  193. // Time Line UI Object
  194. enum
  195. {
  196. kTlFileTlId,
  197. kAudPathTlId,
  198. kSelTlId,
  199. kCursTlId,
  200. kResetTlId,
  201. kAudFnTlId,
  202. kMidiFnTlId,
  203. kBegAudSmpIdxTlId,
  204. kEndAudSmpIdxTlId,
  205. kBegMidiSmpIdxTlId,
  206. kEndMidiSmpIdxTlId
  207. };
  208. cmDspClass_t _cmTimeLineDC;
  209. typedef struct
  210. {
  211. cmDspInst_t inst;
  212. cmTlH_t tlH;
  213. unsigned afIdx;
  214. } cmDspTimeLine_t;
  215. cmDspInst_t* _cmDspTimeLineAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  216. {
  217. cmDspVarArg_t args[] =
  218. {
  219. { "tlfile", kTlFileTlId, 0, 0, kInDsvFl | kStrzDsvFl | kReqArgDsvFl, "Time line file." },
  220. { "path", kAudPathTlId, 0, 0, kInDsvFl | kStrzDsvFl | kReqArgDsvFl, "Audio path" },
  221. { "sel", kSelTlId, 0, 0, kInDsvFl | kOutDsvFl | kUIntDsvFl, "Selected marker id."},
  222. { "curs", kCursTlId, 0, 0, kInDsvFl | kUIntDsvFl, "Current audio file index."},
  223. { "reset", kResetTlId, 0, 0, kInDsvFl | kSymDsvFl, "Resend all outputs." },
  224. { "afn", kAudFnTlId, 0, 0, kOutDsvFl | kStrzDsvFl, "Selected Audio file." },
  225. { "mfn", kMidiFnTlId, 0, 0, kOutDsvFl | kStrzDsvFl, "Selected MIDI file." },
  226. { "absi", kBegAudSmpIdxTlId, 0, 0, kOutDsvFl | kIntDsvFl, "Begin audio sample index."},
  227. { "aesi", kEndAudSmpIdxTlId, 0, 0, kOutDsvFl | kIntDsvFl, "End audio sample index."},
  228. { "mbsi", kBegMidiSmpIdxTlId, 0, 0, kOutDsvFl | kIntDsvFl, "Begin MIDI sample index."},
  229. { "mesi", kEndMidiSmpIdxTlId, 0, 0, kOutDsvFl | kIntDsvFl, "End MIDI sample index."},
  230. { NULL, 0, 0, 0, 0 }
  231. };
  232. cmDspTimeLine_t* p = cmDspInstAlloc(cmDspTimeLine_t,ctx,classPtr,args,instSymId,id,storeSymId,va_cnt,vl);
  233. cmDspSetDefaultUInt( ctx, &p->inst, kSelTlId, 0, cmInvalidId);
  234. cmDspSetDefaultUInt( ctx, &p->inst, kCursTlId, 0, 0);
  235. cmDspSetDefaultStrcz(ctx, &p->inst, kAudFnTlId, NULL, "");
  236. cmDspSetDefaultStrcz(ctx, &p->inst, kMidiFnTlId, NULL, "");
  237. cmDspSetDefaultInt( ctx, &p->inst, kBegAudSmpIdxTlId, 0, cmInvalidIdx);
  238. cmDspSetDefaultInt( ctx, &p->inst, kEndAudSmpIdxTlId, 0, cmInvalidIdx);
  239. cmDspSetDefaultInt( ctx, &p->inst, kBegMidiSmpIdxTlId, 0, cmInvalidIdx);
  240. cmDspSetDefaultInt( ctx, &p->inst, kEndMidiSmpIdxTlId, 0, cmInvalidIdx);
  241. // create the UI control
  242. cmDspUiTimeLineCreate(ctx,&p->inst,kTlFileTlId,kAudPathTlId,kSelTlId,kCursTlId);
  243. p->tlH = cmTimeLineNullHandle;
  244. return &p->inst;
  245. }
  246. cmDspRC_t _cmDspTimeLineFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  247. {
  248. cmDspRC_t rc = kOkDspRC;
  249. cmDspTimeLine_t* p = (cmDspTimeLine_t*)inst;
  250. if( cmTimeLineFinalize(&p->tlH) != kOkTlRC )
  251. return cmErrMsg(&inst->classPtr->err, kInstFinalFailDspRC, "Time-line finalize failed.");
  252. return rc;
  253. }
  254. cmDspRC_t _cmDspTimeLineReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  255. {
  256. cmDspRC_t rc = kOkDspRC;
  257. cmDspTimeLine_t* p = (cmDspTimeLine_t*)inst;
  258. cmDspApplyAllDefaults(ctx,inst);
  259. const cmChar_t* tlFn;
  260. if((tlFn = cmDspStrcz(inst, kTlFileTlId )) != NULL )
  261. if( cmTimeLineInitializeFromFile(ctx->cmCtx, &p->tlH, NULL, NULL, tlFn ) != kOkTlRC )
  262. rc = cmErrMsg(&inst->classPtr->err, kInstResetFailDspRC, "Time-line file open failed.");
  263. return rc;
  264. }
  265. cmDspRC_t _cmDspTimeLineRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  266. {
  267. cmDspTimeLine_t* p = (cmDspTimeLine_t*)inst;
  268. switch( evt->dstVarId )
  269. {
  270. case kCursTlId:
  271. cmDspSetEvent(ctx,inst,evt);
  272. break;
  273. case kResetTlId:
  274. case kSelTlId:
  275. {
  276. unsigned markerId;
  277. cmDspSetEvent(ctx,inst,evt);
  278. // get the id of the selected marker
  279. if((markerId = cmDspUInt(inst,kSelTlId)) != cmInvalidId )
  280. {
  281. // get the marker object
  282. cmTlObj_t* op;
  283. if((op = cmTimeLineIdToObj(p->tlH, cmInvalidId, markerId )) != NULL )
  284. {
  285. assert(op->typeId == kMarkerTlId);
  286. p->afIdx = op->begSmpIdx;
  287. cmDspSetInt(ctx, inst, kBegAudSmpIdxTlId, op->begSmpIdx );
  288. cmDspSetInt(ctx, inst, kEndAudSmpIdxTlId, op->begSmpIdx + op->durSmpCnt );
  289. // locate the audio file assoc'd with the marker
  290. cmTlAudioFile_t* afp;
  291. if((afp = cmTimeLineAudioFileAtTime(p->tlH,op->seqId,op->seqSmpIdx)) != NULL)
  292. cmDspSetStrcz(ctx, inst, kAudFnTlId, afp->fn );
  293. // locate the midi file assoc'd with the marker
  294. cmTlMidiFile_t* mfp;
  295. if((mfp = cmTimeLineMidiFileAtTime(p->tlH,op->seqId,op->seqSmpIdx)) != NULL )
  296. {
  297. cmDspSetInt(ctx, inst, kBegMidiSmpIdxTlId, op->seqSmpIdx - mfp->obj.seqSmpIdx );
  298. cmDspSetInt(ctx, inst, kEndMidiSmpIdxTlId, op->seqSmpIdx + op->durSmpCnt - mfp->obj.seqSmpIdx );
  299. cmDspSetStrcz(ctx, inst, kMidiFnTlId, mfp->fn );
  300. }
  301. }
  302. }
  303. }
  304. break;
  305. default:
  306. {assert(0);}
  307. }
  308. return kOkDspRC;
  309. }
  310. struct cmDspClass_str* cmTimeLineClassCons( cmDspCtx_t* ctx )
  311. {
  312. cmDspClassSetup(&_cmTimeLineDC,ctx,"TimeLine",
  313. NULL,
  314. _cmDspTimeLineAlloc,
  315. _cmDspTimeLineFree,
  316. _cmDspTimeLineReset,
  317. NULL,
  318. _cmDspTimeLineRecv,
  319. NULL,NULL,
  320. "Time Line control.");
  321. return &_cmTimeLineDC;
  322. }
  323. //==========================================================================================================================================
  324. // Score UI Object
  325. enum
  326. {
  327. kFnScId,
  328. kSelScId,
  329. kSendScId,
  330. kStatusScId,
  331. kD0ScId,
  332. kD1ScId,
  333. kSmpIdxScId,
  334. kLocIdxScId,
  335. kEvtIdxScId,
  336. kDynScId,
  337. kValTypeScId,
  338. kValueScId
  339. };
  340. cmDspClass_t _cmScoreDC;
  341. typedef struct
  342. {
  343. cmDspInst_t inst;
  344. cmScH_t scH;
  345. cmDspCtx_t* ctx; // temporary ctx ptr used during cmScore callback in _cmDspScoreRecv()
  346. } cmDspScore_t;
  347. cmDspInst_t* _cmDspScoreAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  348. {
  349. cmDspVarArg_t args[] =
  350. {
  351. { "fn", kFnScId, 0, 0, kInDsvFl | kStrzDsvFl | kReqArgDsvFl, "Score file." },
  352. { "sel", kSelScId, 0, 0, kInDsvFl | kOutDsvFl | kUIntDsvFl, "Selected score element index input."},
  353. { "send", kSendScId, 0, 0, kInDsvFl | kTypeDsvMask, "Resend last selected score element."},
  354. { "status", kStatusScId, 0, 0, kInDsvFl | kIntDsvFl, "Performed MIDI status value output" },
  355. { "d0", kD0ScId, 0, 0, kInDsvFl | kUIntDsvFl, "Performed MIDI msg data byte 0" },
  356. { "d1", kD1ScId, 0, 0, kInDsvFl | kUIntDsvFl, "Performed MIDI msg data byte 1" },
  357. { "smpidx", kSmpIdxScId, 0, 0, kInDsvFl | kUIntDsvFl, "Performed MIDi msg time tag as a sample index." },
  358. { "loc", kLocIdxScId, 0, 0, kInDsvFl | kUIntDsvFl, "Performance score location."},
  359. { "evtidx", kEvtIdxScId, 0, 0, kOutDsvFl | kUIntDsvFl, "Performed event index of following dynamcis level."},
  360. { "dyn", kDynScId, 0, 0, kOutDsvFl | kUIntDsvFl, "Dynamic level of previous event index."},
  361. { "type", kValTypeScId,0, 0, kOutDsvFl | kUIntDsvFl, "Output variable type."},
  362. { "value", kValueScId, 0, 0, kOutDsvFl | kDoubleDsvFl, "Output variable value."},
  363. { NULL, 0, 0, 0, 0 }
  364. };
  365. cmDspScore_t* p = cmDspInstAlloc(cmDspScore_t,ctx,classPtr,args,instSymId,id,storeSymId,va_cnt,vl);
  366. cmDspSetDefaultUInt( ctx, &p->inst, kSelScId, 0, cmInvalidId);
  367. // create the UI control
  368. cmDspUiScoreCreate(ctx,&p->inst,kFnScId,kSelScId,kSmpIdxScId,kD0ScId,kD1ScId,kLocIdxScId,kEvtIdxScId,kDynScId,kValTypeScId,kValueScId);
  369. p->scH = cmScNullHandle;
  370. return &p->inst;
  371. }
  372. cmDspRC_t _cmDspScoreFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  373. {
  374. cmDspRC_t rc = kOkDspRC;
  375. cmDspScore_t* p = (cmDspScore_t*)inst;
  376. if( cmScoreFinalize(&p->scH) != kOkTlRC )
  377. return cmErrMsg(&inst->classPtr->err, kInstFinalFailDspRC, "Score finalize failed.");
  378. return rc;
  379. }
  380. // Callback from cmScore triggered from _cmDspScoreRecv() during call to cmScoreSetPerfEvent().
  381. void _cmDspScoreCb( void* arg, const void* data, unsigned byteCnt )
  382. {
  383. cmDspInst_t* inst = (cmDspInst_t*)arg;
  384. cmDspScore_t* p = (cmDspScore_t*)inst;
  385. cmScMsg_t m;
  386. if( cmScoreDecode(data,byteCnt,&m) == kOkScRC )
  387. {
  388. switch( m.typeId )
  389. {
  390. case kDynMsgScId:
  391. cmDspSetUInt( p->ctx,inst, kEvtIdxScId, m.u.dyn.evtIdx );
  392. cmDspSetUInt( p->ctx,inst, kDynScId, m.u.dyn.dynLvl );
  393. break;
  394. case kVarMsgScId:
  395. cmDspSetUInt( p->ctx,inst, kValTypeScId, m.u.meas.varId);
  396. cmDspSetDouble(p->ctx,inst, kValueScId, m.u.meas.value);
  397. break;
  398. default:
  399. { assert(0); }
  400. }
  401. }
  402. }
  403. cmDspRC_t _cmDspScoreReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  404. {
  405. cmDspRC_t rc = kOkDspRC;
  406. cmDspScore_t* p = (cmDspScore_t*)inst;
  407. const cmChar_t* tlFn = NULL;
  408. unsigned* dynRefArray = NULL;
  409. unsigned dynRefCnt = 0;
  410. cmDspApplyAllDefaults(ctx,inst);
  411. if( cmDspRsrcUIntArray(ctx->dspH, &dynRefCnt, &dynRefArray, "dynRef", NULL ) != kOkDspRC )
  412. {
  413. rc = cmErrMsg(&inst->classPtr->err, kRsrcNotFoundDspRC, "The dynamics reference array resource was not found.");
  414. goto errLabel;
  415. }
  416. if((tlFn = cmDspStrcz(inst, kFnScId )) != NULL )
  417. if( cmScoreInitialize(ctx->cmCtx, &p->scH, tlFn, cmDspSampleRate(ctx), dynRefArray, dynRefCnt, _cmDspScoreCb, p ) != kOkTlRC )
  418. rc = cmErrMsg(&inst->classPtr->err, kInstResetFailDspRC, "Score file open failed.");
  419. errLabel:
  420. return rc;
  421. }
  422. cmDspRC_t _cmDspScoreRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  423. {
  424. cmDspScore_t* p = (cmDspScore_t*)inst;
  425. if( evt->dstVarId == kSendScId )
  426. {
  427. unsigned selIdx;
  428. if((selIdx = cmDspUInt(inst,kSelScId)) != cmInvalidIdx )
  429. {
  430. cmDspSetUInt(ctx,inst,kSelScId, selIdx );
  431. cmScoreClearPerfInfo(p->scH);
  432. }
  433. return kOkDspRC;
  434. }
  435. cmDspSetEvent(ctx,inst,evt);
  436. switch( evt->dstVarId )
  437. {
  438. case kSelScId:
  439. cmScoreClearPerfInfo(p->scH);
  440. break;
  441. case kStatusScId:
  442. //printf("st:%x\n",cmDspUInt(inst,kStatusScId));
  443. break;
  444. case kLocIdxScId:
  445. {
  446. assert( cmDspUInt(inst,kStatusScId ) == kNoteOnMdId );
  447. p->ctx = ctx; // setup p->ctx for use in _cmDspScoreCb()
  448. // this call may result in callbacks to _cmDspScoreCb()
  449. cmScoreExecPerfEvent(p->scH, cmDspUInt(inst,kLocIdxScId), cmDspUInt(inst,kSmpIdxScId), cmDspUInt(inst,kD0ScId), cmDspUInt(inst,kD1ScId) );
  450. }
  451. break;
  452. }
  453. return kOkDspRC;
  454. }
  455. struct cmDspClass_str* cmScoreClassCons( cmDspCtx_t* ctx )
  456. {
  457. cmDspClassSetup(&_cmScoreDC,ctx,"Score",
  458. NULL,
  459. _cmDspScoreAlloc,
  460. _cmDspScoreFree,
  461. _cmDspScoreReset,
  462. NULL,
  463. _cmDspScoreRecv,
  464. NULL,NULL,
  465. "Score control.");
  466. return &_cmScoreDC;
  467. }
  468. //==========================================================================================================================================
  469. // MIDI File Player
  470. enum
  471. {
  472. kFnMfId,
  473. kSelMfId,
  474. kBsiMfId,
  475. kEsiMfId,
  476. kStatusMfId,
  477. kD0MfId,
  478. kD1MfId,
  479. kSmpIdxMfId
  480. };
  481. cmDspClass_t _cmMidiFilePlayDC;
  482. typedef struct
  483. {
  484. cmDspInst_t inst;
  485. cmMidiFileH_t mfH;
  486. unsigned curMsgIdx; // current midi file msg index
  487. int csi; // current sample index
  488. int bsi; // starting sample index
  489. int esi; // ending sample index
  490. unsigned startSymId;
  491. unsigned stopSymId;
  492. unsigned contSymId;
  493. bool errFl;
  494. } cmDspMidiFilePlay_t;
  495. /*
  496. 'bsi' and 'esi' give the starting and ending sample for MIDI file playback.
  497. These indexes are relative to the start of the file.
  498. When the player recieves a 'start' msg it sets the current sample index
  499. 'si' to 'bsi' and begins scanning for the next note to play.
  500. On each call to the _cmDspMidiFilePlayExec() msgs that fall in the interval
  501. si:si+sPc-1 will be transmitted. (where sPc are the number of samples per DSP cycle).
  502. */
  503. cmDspInst_t* _cmDspMidiFilePlayAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  504. {
  505. cmDspVarArg_t args[] =
  506. {
  507. { "fn", kFnMfId, 0, 0, kInDsvFl | kStrzDsvFl, "File name"},
  508. { "sel", kSelMfId, 0, 0, kInDsvFl | kSymDsvFl, "start | stop | continue" },
  509. { "bsi", kBsiMfId, 0, 0, kInDsvFl | kIntDsvFl, "Starting sample." },
  510. { "esi", kEsiMfId, 0, 0, kInDsvFl | kIntDsvFl, "Ending sample."},
  511. { "status", kStatusMfId, 0, 0, kOutDsvFl | kIntDsvFl, "Status value output" },
  512. { "d0", kD0MfId, 0, 0, kOutDsvFl | kUIntDsvFl, "Data byte 0" },
  513. { "d1", kD1MfId, 0, 0, kOutDsvFl | kUIntDsvFl, "Data byte 1" },
  514. { "smpidx", kSmpIdxMfId, 0, 0, kOutDsvFl | kUIntDsvFl, "Msg time tag as a sample index." },
  515. { NULL, 0, 0, 0, 0 }
  516. };
  517. cmDspMidiFilePlay_t* p = cmDspInstAlloc(cmDspMidiFilePlay_t,ctx,classPtr,args,instSymId,id,storeSymId,va_cnt,vl);
  518. p->startSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"start");
  519. p->stopSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"stop");
  520. p->contSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"continue");
  521. p->mfH = cmMidiFileNullHandle;
  522. cmDspSetDefaultStrcz( ctx, &p->inst, kFnMfId, NULL, "");
  523. cmDspSetDefaultSymbol(ctx, &p->inst, kSelMfId, p->stopSymId);
  524. cmDspSetDefaultInt( ctx, &p->inst, kBsiMfId, 0, 0);
  525. cmDspSetDefaultInt( ctx, &p->inst, kEsiMfId, 0, 0);
  526. cmDspSetDefaultUInt( ctx, &p->inst, kStatusMfId, 0, 0);
  527. cmDspSetDefaultUInt( ctx, &p->inst, kD0MfId, 0, 0);
  528. cmDspSetDefaultUInt( ctx, &p->inst, kD1MfId, 0, 0);
  529. return &p->inst;
  530. }
  531. cmDspRC_t _cmDspMidiFilePlayFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  532. {
  533. cmDspMidiFilePlay_t* p = (cmDspMidiFilePlay_t*)inst;
  534. if( cmMidiFileClose(&p->mfH) )
  535. return cmErrMsg(&inst->classPtr->err, kInstFinalFailDspRC, "MIDI file close failed.");
  536. return kOkDspRC;
  537. }
  538. // return the index of the msg following smpIdx
  539. unsigned _cmDspMidiFilePlaySeekMsgIdx( cmDspCtx_t* ctx, cmDspInst_t* inst, unsigned smpIdx )
  540. {
  541. cmDspMidiFilePlay_t* p = (cmDspMidiFilePlay_t*)inst;
  542. if( cmMidiFileIsValid(p->mfH) == false )
  543. {
  544. cmErrMsg(&inst->classPtr->err, kInvalidStateDspRC,"The MIDI file player has not been given a valid MIDI file.");
  545. return cmInvalidIdx;
  546. }
  547. unsigned i;
  548. unsigned n = cmMidiFileMsgCount(p->mfH);
  549. const cmMidiTrackMsg_t** a = cmMidiFileMsgArray(p->mfH);
  550. for(i=0; i<n; ++i)
  551. if( a[i]->dtick > smpIdx )
  552. break;
  553. return i==n ? cmInvalidIdx : i;
  554. }
  555. cmDspRC_t _cmDspMidiFilePlayOpen(cmDspCtx_t* ctx, cmDspInst_t* inst )
  556. {
  557. cmDspRC_t rc = kOkDspRC;
  558. const cmChar_t* fn = cmDspStrcz(inst,kFnMfId);
  559. cmDspMidiFilePlay_t* p = (cmDspMidiFilePlay_t*)inst;
  560. p->errFl = false;
  561. if( fn==NULL || strlen(fn)==0 )
  562. return rc;
  563. if( cmMidiFileOpen( fn, &p->mfH, ctx->cmCtx ) != kOkFileRC )
  564. rc = cmErrMsg(&inst->classPtr->err, kInstResetFailDspRC, "MIDI file open failed.");
  565. else
  566. {
  567. p->curMsgIdx = 0;
  568. p->bsi = cmDspInt(inst,kBsiMfId);
  569. p->esi = cmDspInt(inst,kEsiMfId);
  570. p->csi = 0;
  571. // force the first msg to occurr one quarter note into the file
  572. cmMidiFileSetDelay(p->mfH, cmMidiFileTicksPerQN(p->mfH) );
  573. // convert midi msg times to absolute time in samples
  574. cmMidiFileTickToSamples(p->mfH,cmDspSampleRate(ctx),true);
  575. }
  576. return rc;
  577. }
  578. cmDspRC_t _cmDspMidiFilePlayReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  579. {
  580. cmDspApplyAllDefaults(ctx,inst);
  581. return _cmDspMidiFilePlayOpen(ctx,inst);
  582. }
  583. cmDspRC_t _cmDspMidiFilePlayExec(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  584. {
  585. cmDspRC_t rc = kOkDspRC;
  586. cmDspMidiFilePlay_t* p = (cmDspMidiFilePlay_t*)inst;
  587. unsigned sPc = cmDspSamplesPerCycle(ctx);
  588. if( cmDspSymbol(inst,kSelMfId) != p->stopSymId )
  589. {
  590. if( cmMidiFileIsValid(p->mfH) == false )
  591. {
  592. if( p->errFl==false )
  593. {
  594. rc = cmErrMsg(&inst->classPtr->err, kInvalidStateDspRC,"The MIDI file player has not been given a valid MIDI file.");
  595. p->errFl = true;
  596. }
  597. return rc;
  598. }
  599. const cmMidiTrackMsg_t** mpp = cmMidiFileMsgArray(p->mfH);
  600. unsigned msgN = cmMidiFileMsgCount(p->mfH);
  601. for(; p->curMsgIdx < msgN && p->csi <= mpp[p->curMsgIdx]->dtick && mpp[p->curMsgIdx]->dtick < (p->csi + sPc); ++p->curMsgIdx )
  602. {
  603. const cmMidiTrackMsg_t* mp = mpp[p->curMsgIdx];
  604. switch( mp->status )
  605. {
  606. case kNoteOnMdId:
  607. case kCtlMdId:
  608. cmDspSetUInt(ctx,inst, kSmpIdxMfId, mp->dtick);
  609. cmDspSetUInt(ctx,inst, kD1MfId, mp->u.chMsgPtr->d1);
  610. cmDspSetUInt(ctx,inst, kD0MfId, mp->u.chMsgPtr->d0);
  611. cmDspSetUInt(ctx,inst, kStatusMfId, mp->status);
  612. break;
  613. }
  614. }
  615. }
  616. p->csi += sPc;
  617. return rc;
  618. }
  619. cmDspRC_t _cmDspMidiFilePlayRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  620. {
  621. cmDspMidiFilePlay_t* p = (cmDspMidiFilePlay_t*)inst;
  622. cmDspSetEvent(ctx,inst,evt);
  623. switch(evt->dstVarId)
  624. {
  625. case kFnMfId:
  626. _cmDspMidiFilePlayOpen(ctx, inst );
  627. break;
  628. case kSelMfId:
  629. {
  630. if( cmDspSymbol(inst,kSelMfId)==p->startSymId )
  631. {
  632. p->csi = cmDspInt(inst,kBsiMfId);
  633. p->curMsgIdx = _cmDspMidiFilePlaySeekMsgIdx(ctx, inst, p->csi );
  634. }
  635. break;
  636. }
  637. }
  638. return kOkDspRC;
  639. }
  640. struct cmDspClass_str* cmMidiFilePlayClassCons( cmDspCtx_t* ctx )
  641. {
  642. cmDspClassSetup(&_cmMidiFilePlayDC,ctx,"MidiFilePlay",
  643. NULL,
  644. _cmDspMidiFilePlayAlloc,
  645. _cmDspMidiFilePlayFree,
  646. _cmDspMidiFilePlayReset,
  647. _cmDspMidiFilePlayExec,
  648. _cmDspMidiFilePlayRecv,
  649. NULL,NULL,
  650. "Time tagged text file.");
  651. return &_cmMidiFilePlayDC;
  652. }
  653. //==========================================================================================================================================
  654. enum
  655. {
  656. kFnSfId,
  657. kBufCntSfId,
  658. kMinLkAhdSfId,
  659. kMaxWndCntSfId,
  660. kMinVelSfId,
  661. kIndexSfId,
  662. kStatusSfId,
  663. kD0SfId,
  664. kD1SfId,
  665. kSmpIdxSfId,
  666. kCmdSfId,
  667. kOutSfId,
  668. kDynSfId,
  669. kEvenSfId,
  670. kTempoSfId
  671. };
  672. cmDspClass_t _cmScFolDC;
  673. struct cmDspScFol_str;
  674. typedef struct
  675. {
  676. cmDspCtx_t* ctx;
  677. struct cmDspScFol_str* sfp;
  678. } cmDspScFolCbArg_t;
  679. typedef struct cmDspScFol_str
  680. {
  681. cmDspInst_t inst;
  682. cmScMatcher* sfp;
  683. cmScMeas* smp;
  684. cmScH_t scH;
  685. cmDspScFolCbArg_t arg;
  686. unsigned printSymId;
  687. unsigned quietSymId;
  688. } cmDspScFol_t;
  689. cmDspInst_t* _cmDspScFolAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  690. {
  691. cmDspVarArg_t args[] =
  692. {
  693. { "fn", kFnSfId, 0, 0, kInDsvFl | kStrzDsvFl | kReqArgDsvFl, "Score file." },
  694. { "bufcnt",kBufCntSfId, 0, 0, kInDsvFl | kUIntDsvFl, "Event buffer element count." },
  695. { "lkahd", kMinLkAhdSfId, 0, 0, kInDsvFl | kUIntDsvFl, "Minimum window look-ahead."},
  696. { "wndcnt",kMaxWndCntSfId,0, 0, kInDsvFl | kUIntDsvFl, "Maximum window length."},
  697. { "minvel",kMinVelSfId, 0, 0, kInDsvFl | kUIntDsvFl, "Minimum velocity."},
  698. { "index", kIndexSfId, 0, 0, kInDsvFl | kUIntDsvFl, "Tracking start location."},
  699. { "status",kStatusSfId, 0, 0, kInDsvFl | kUIntDsvFl, "MIDI status byte"},
  700. { "d0", kD0SfId, 0, 0, kInDsvFl | kUIntDsvFl, "MIDI data byte 0"},
  701. { "d1", kD1SfId, 0, 0, kInDsvFl | kUIntDsvFl, "MIDI data byte 1"},
  702. { "smpidx",kSmpIdxSfId, 0, 0, kInDsvFl | kUIntDsvFl, "MIDI time tag as a sample index"},
  703. { "cmd", kCmdSfId, 0, 0, kInDsvFl | kSymDsvFl, "Command input: print | quiet"},
  704. { "out", kOutSfId, 0, 0, kOutDsvFl| kUIntDsvFl, "Current score index."},
  705. { "dyn", kDynSfId, 0, 0, kOutDsvFl| kDoubleDsvFl, "Dynamic value."},
  706. { "even", kEvenSfId, 0, 0, kOutDsvFl| kDoubleDsvFl, "Evenness value."},
  707. { "tempo", kTempoSfId, 0, 0, kOutDsvFl| kDoubleDsvFl, "Tempo value."},
  708. { NULL, 0, 0, 0, 0, NULL }
  709. };
  710. cmDspScFol_t* p;
  711. if((p = cmDspInstAlloc(cmDspScFol_t,ctx,classPtr,args,instSymId,id,storeSymId,va_cnt,vl)) == NULL )
  712. return NULL;
  713. p->sfp = cmScMatcherAlloc(ctx->cmProcCtx, NULL, 0, cmScNullHandle, 0, 0, NULL, NULL );
  714. p->smp = cmScMeasAlloc( ctx->cmProcCtx, NULL, cmScNullHandle, 0, NULL, 0 );
  715. p->printSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"print");
  716. p->quietSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"quiet");
  717. cmDspSetDefaultUInt( ctx, &p->inst, kBufCntSfId, 0, 7);
  718. cmDspSetDefaultUInt( ctx, &p->inst, kMaxWndCntSfId, 0, 10);
  719. cmDspSetDefaultUInt( ctx, &p->inst, kMinLkAhdSfId, 0, 3);
  720. cmDspSetDefaultUInt( ctx, &p->inst, kMinVelSfId, 0, 5);
  721. cmDspSetDefaultUInt( ctx, &p->inst, kIndexSfId, 0, 0);
  722. cmDspSetDefaultUInt( ctx, &p->inst, kOutSfId, 0, 0);
  723. cmDspSetDefaultDouble( ctx, &p->inst, kDynSfId, 0, 0);
  724. cmDspSetDefaultDouble( ctx, &p->inst, kEvenSfId, 0, 0);
  725. cmDspSetDefaultDouble( ctx, &p->inst, kTempoSfId, 0, 0);
  726. cmDspSetDefaultSymbol(ctx,&p->inst, kCmdSfId, p->quietSymId );
  727. return &p->inst;
  728. }
  729. cmDspRC_t _cmDspScFolFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  730. {
  731. cmDspScFol_t* p = (cmDspScFol_t*)inst;
  732. cmScMatcherFree(&p->sfp);
  733. cmScMeasFree(&p->smp);
  734. cmScoreFinalize(&p->scH);
  735. return kOkDspRC;
  736. }
  737. // This is a callback function from cmScMatcherExec() which is called when
  738. // this cmDspFol object receives a new score location index.
  739. void _cmScFolMatcherCb( cmScMatcher* p, void* arg, cmScMatcherResult_t* rp )
  740. {
  741. cmDspScFolCbArg_t* ap = (cmDspScFolCbArg_t*)arg;
  742. if( cmScMeasExec(ap->sfp->smp, rp->mni, rp->locIdx, rp->scEvtIdx, rp->flags, rp->smpIdx, rp->pitch, rp->vel ) == cmOkRC )
  743. {
  744. cmDspInst_t* inst = &(ap->sfp->inst);
  745. // send 'set' values that were calculated on the previous call to cmScMeasExec()
  746. unsigned i;
  747. for(i=ap->sfp->smp->vsi; i<ap->sfp->smp->nsi; ++i)
  748. {
  749. switch( ap->sfp->smp->set[i].sp->varId )
  750. {
  751. case kEvenVarScId:
  752. cmDspSetDouble(ap->ctx,inst,kEvenSfId,ap->sfp->smp->set[i].value);
  753. break;
  754. case kDynVarScId:
  755. cmDspSetDouble(ap->ctx,inst,kDynSfId,ap->sfp->smp->set[i].value);
  756. break;
  757. case kTempoVarScId:
  758. cmDspSetDouble(ap->ctx,inst,kTempoSfId,ap->sfp->smp->set[i].value);
  759. break;
  760. default:
  761. { assert(0); }
  762. }
  763. }
  764. /*
  765. // trigger 'section' starts
  766. for(i=ap->sfp->smp->vsli; i<ap->sfp->smp->nsli; ++i)
  767. {
  768. const cmScoreLoc_t* locPtr = cmScoreLoc(ap->sfp->smp->mp->scH,i);
  769. if( locPtr->begSectPtr != NULL )
  770. cmDspSetUInt(ap->ctx,inst,kSectIndexSfId,locPtr->begSectPtr->index);
  771. }
  772. */
  773. }
  774. }
  775. cmDspRC_t _cmDspScFolOpenScore( cmDspCtx_t* ctx, cmDspInst_t* inst )
  776. {
  777. cmDspRC_t rc = kOkDspRC;
  778. cmDspScFol_t* p = (cmDspScFol_t*)inst;
  779. const cmChar_t* fn;
  780. if((fn = cmDspStrcz(inst,kFnSfId)) == NULL || strlen(fn)==0 )
  781. return cmErrMsg(&inst->classPtr->err, kInvalidArgDspRC, "No score file name supplied.");
  782. if( cmScoreInitialize(ctx->cmCtx, &p->scH, fn, cmDspSampleRate(ctx), NULL, 0, NULL, NULL ) != kOkScRC )
  783. return cmErrMsg(&inst->classPtr->err, kSubSysFailDspRC, "Unable to open the score '%s'.",fn);
  784. if( cmScoreIsValid(p->scH) )
  785. {
  786. unsigned* dynRefArray = NULL;
  787. unsigned dynRefCnt = 0;
  788. // initialize the cmScMatcher
  789. if( cmScMatcherInit(p->sfp, cmDspSampleRate(ctx), p->scH, cmDspUInt(inst,kMaxWndCntSfId), cmDspUInt(inst,kBufCntSfId), _cmScFolMatcherCb, p->smp ) != cmOkRC )
  790. rc = cmErrMsg(&inst->classPtr->err, kSubSysFailDspRC, "Internal score follower allocation failed.");
  791. // read the dynamics reference array
  792. if( cmDspRsrcUIntArray(ctx->dspH, &dynRefCnt, &dynRefArray, "dynRef", NULL ) != kOkDspRC )
  793. {
  794. rc = cmErrMsg(&inst->classPtr->err, kRsrcNotFoundDspRC, "The dynamics reference array resource was not found.");
  795. goto errLabel;
  796. }
  797. // initialize the cmScMeas object.
  798. if( cmScMeasInit(p->smp, p->scH, cmDspSampleRate(ctx), dynRefArray, dynRefCnt ) != cmOkRC )
  799. rc = cmErrMsg(&inst->classPtr->err, kSubSysFailDspRC, "Internal scMeas object initialization failed.");
  800. }
  801. errLabel:
  802. return rc;
  803. }
  804. cmDspRC_t _cmDspScFolReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  805. {
  806. cmDspRC_t rc;
  807. if((rc = cmDspApplyAllDefaults(ctx,inst)) != kOkDspRC )
  808. return rc;
  809. return _cmDspScFolOpenScore(ctx,inst);
  810. }
  811. cmDspRC_t _cmDspScFolRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  812. {
  813. cmDspRC_t rc = kOkDspRC;
  814. cmDspScFol_t* p = (cmDspScFol_t*)inst;
  815. if((rc = cmDspSetEvent(ctx,inst,evt)) == kOkDspRC && p->sfp != NULL )
  816. {
  817. switch( evt->dstVarId )
  818. {
  819. case kIndexSfId:
  820. if( cmScoreIsValid(p->scH) )
  821. {
  822. if( cmScMeasReset( p->smp ) != cmOkRC )
  823. cmErrMsg(&inst->classPtr->err, kSubSysFailDspRC, "Score measure unit reset to score index '%i' failed.");
  824. if( cmScMatcherReset( p->sfp, cmDspUInt(inst,kIndexSfId) ) != cmOkRC )
  825. cmErrMsg(&inst->classPtr->err, kSubSysFailDspRC, "Score follower reset to score index '%i' failed.");
  826. }
  827. break;
  828. case kStatusSfId:
  829. if( cmScoreIsValid(p->scH))
  830. {
  831. unsigned scLocIdx = cmInvalidIdx;
  832. // setup the cmScMeas() callback arg.
  833. p->arg.ctx = ctx;
  834. p->arg.sfp = p;
  835. p->sfp->cbArg = &p->arg;
  836. // this call may result in a callback to _cmScFolMatcherCb()
  837. if( cmScMatcherExec(p->sfp, cmDspUInt(inst,kSmpIdxSfId), cmDspUInt(inst,kStatusSfId), cmDspUInt(inst,kD0SfId), cmDspUInt(inst,kD1SfId), &scLocIdx) == cmOkRC )
  838. if( scLocIdx != cmInvalidIdx )
  839. cmDspSetUInt(ctx,inst,kOutSfId,scLocIdx);
  840. }
  841. break;
  842. case kFnSfId:
  843. _cmDspScFolOpenScore(ctx,inst);
  844. break;
  845. case kCmdSfId:
  846. if( cmDspSymbol(inst,kCmdSfId) == p->printSymId )
  847. p->sfp->printFl = true;
  848. else
  849. if( cmDspSymbol(inst,kCmdSfId) == p->quietSymId )
  850. p->sfp->printFl = false;
  851. break;
  852. }
  853. }
  854. return rc;
  855. }
  856. struct cmDspClass_str* cmScFolClassCons( cmDspCtx_t* ctx )
  857. {
  858. cmDspClassSetup(&_cmScFolDC,ctx,"ScFol",
  859. NULL,
  860. _cmDspScFolAlloc,
  861. _cmDspScFolFree,
  862. _cmDspScFolReset,
  863. NULL,
  864. _cmDspScFolRecv,
  865. NULL,NULL,
  866. "Score Follower");
  867. return &_cmScFolDC;
  868. }
  869. //==========================================================================================================================================
  870. enum
  871. {
  872. kScLocIdxMdId
  873. };
  874. cmDspClass_t _cmModulatorDC;
  875. typedef struct
  876. {
  877. cmDspInst_t inst;
  878. cmScModulator* mp;
  879. cmDspCtx_t* tmp_ctx; // used to temporarily hold the current cmDspCtx during callback
  880. } cmDspScMod_t;
  881. void _cmDspScModCb( void* arg, unsigned varSymId, double value )
  882. {
  883. cmDspScMod_t* p = (cmDspScMod_t*)arg;
  884. cmDspVar_t* varPtr;
  885. if((varPtr = cmDspVarSymbolToPtr( p->tmp_ctx, &p->inst, varSymId, 0 )) == NULL )
  886. return;
  887. cmDspSetDouble(p->tmp_ctx,&p->inst,varPtr->constId,value);
  888. }
  889. cmDspInst_t* _cmDspScModAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  890. {
  891. va_list vl1;
  892. va_copy(vl1,vl);
  893. cmDspVarArg_t args[] =
  894. {
  895. { "index", kScLocIdxMdId,0,0, kInDsvFl | kUIntDsvFl, "Score follower index input."},
  896. { NULL, 0, 0, 0, 0 }
  897. };
  898. // validate the argument count
  899. if( va_cnt != 2 )
  900. {
  901. cmDspClassErr(ctx,classPtr,kInvalidArgDspRC,"The Modulator requires at least two arguments.");
  902. return NULL;
  903. }
  904. // read the modulator file and label strings
  905. const cmChar_t* fn = va_arg(vl1,const cmChar_t*);
  906. const cmChar_t* modLabel = va_arg(vl1,const cmChar_t*);
  907. // validate the file
  908. if( fn==NULL || cmFsIsFile(fn)==false )
  909. {
  910. cmDspClassErr(ctx,classPtr,kInvalidArgDspRC,"The Modulator file '%s' is not valid.",cmStringNullGuard(fn));
  911. return NULL;
  912. }
  913. // allocate the internal modulator object
  914. cmScModulator* mp = cmScModulatorAlloc(ctx->cmProcCtx, NULL, ctx->cmCtx, ctx->stH, cmDspSampleRate(ctx), cmDspSamplesPerCycle(ctx), fn, modLabel, _cmDspScModCb, NULL );
  915. if(mp == NULL )
  916. {
  917. cmDspClassErr(ctx,classPtr,kInvalidArgDspRC,"The internal modulator object initialization failed.");
  918. return NULL;
  919. }
  920. unsigned fixArgCnt = 1;
  921. unsigned argCnt = fixArgCnt + cmScModulatorVarCount(mp);
  922. cmDspVarArg_t a[ argCnt+1 ];
  923. unsigned i;
  924. cmDspArgCopy( a, argCnt, 0, args, fixArgCnt );
  925. for(i=fixArgCnt; i<argCnt; ++i)
  926. {
  927. unsigned varIdx = i - fixArgCnt;
  928. const cmScModVar_t* vp = cmScModulatorVar(mp,varIdx);
  929. const cmChar_t* label = cmSymTblLabel( ctx->stH, vp->varSymId );
  930. const cmChar_t* docStr = cmTsPrintfS("Variable output for %s",label);
  931. cmDspArgSetup(ctx, a + i, label, cmInvalidId, i, 0, 0, kOutDsvFl | kDoubleDsvFl, docStr );
  932. }
  933. cmDspArgSetupNull(a+argCnt); // set terminating arg. flags
  934. cmDspScMod_t* p = cmDspInstAlloc(cmDspScMod_t,ctx,classPtr,a,instSymId,id,storeSymId,0,vl);
  935. p->mp = mp;
  936. mp->cbArg = p; // set the modulator callback arg
  937. cmDspSetDefaultUInt(ctx,&p->inst,kScLocIdxMdId,0,0);
  938. return &p->inst;
  939. }
  940. cmDspRC_t _cmDspScModFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  941. {
  942. cmDspRC_t rc = kOkDspRC;
  943. cmDspScMod_t* p = (cmDspScMod_t*)inst;
  944. if( cmScModulatorFree(&p->mp) != kOkTlRC )
  945. return cmErrMsg(&inst->classPtr->err, kInstFinalFailDspRC, "Modulator release failed.");
  946. return rc;
  947. }
  948. cmDspRC_t _cmDspScModReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  949. {
  950. cmDspRC_t rc = kOkDspRC;
  951. cmDspApplyAllDefaults(ctx,inst);
  952. return rc;
  953. }
  954. cmDspRC_t _cmDspScModRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  955. {
  956. cmDspSetEvent(ctx,inst,evt);
  957. return kOkDspRC;
  958. }
  959. cmDspRC_t _cmDspScModExec(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  960. {
  961. cmDspRC_t rc = kOkDspRC;
  962. cmDspScMod_t* p = (cmDspScMod_t*)inst;
  963. p->tmp_ctx = ctx;
  964. cmScModulatorExec(p->mp,cmDspUInt(inst,kScLocIdxMdId));
  965. return rc;
  966. }
  967. struct cmDspClass_str* cmScModClassCons( cmDspCtx_t* ctx )
  968. {
  969. cmDspClassSetup(&_cmModulatorDC,ctx,"ScMod",
  970. NULL,
  971. _cmDspScModAlloc,
  972. _cmDspScModFree,
  973. _cmDspScModReset,
  974. _cmDspScModExec,
  975. _cmDspScModRecv,
  976. NULL,NULL,
  977. "Score Driven Variable Modulator.");
  978. return &_cmModulatorDC;
  979. }