libcm is a C development framework with an emphasis on audio signal processing applications.
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

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. }