|
@@ -238,6 +238,7 @@ enum
|
238
|
238
|
kAudPathTlId,
|
239
|
239
|
kSelTlId,
|
240
|
240
|
kAudFnTlId,
|
|
241
|
+ kMidiFnTlId,
|
241
|
242
|
kBegSmpIdxTlId,
|
242
|
243
|
kEndSmpIdxTlId
|
243
|
244
|
};
|
|
@@ -258,6 +259,7 @@ cmDspInst_t* _cmDspTimeLineAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsig
|
258
|
259
|
{ "path", kAudPathTlId, 0, 0, kInDsvFl | kStrzDsvFl | kReqArgDsvFl, "Audio path" },
|
259
|
260
|
{ "sel", kSelTlId, 0, 0, kInDsvFl | kInDsvFl | kOutDsvFl | kUIntDsvFl, "Selected marker id."},
|
260
|
261
|
{ "afn", kAudFnTlId, 0, 0, kOutDsvFl | kStrzDsvFl, "Selected Audio file." },
|
|
262
|
+ { "mfn", kMidiFnTlId, 0, 0, kOutDsvFl | kStrzDsvFl, "Selected MIDI file." },
|
261
|
263
|
{ "bsi", kBegSmpIdxTlId, 0, 0, kOutDsvFl | kUIntDsvFl, "Begin audio sample index."},
|
262
|
264
|
{ "esi", kEndSmpIdxTlId, 0, 0, kOutDsvFl | kUIntDsvFl, "End audio sample index."},
|
263
|
265
|
{ NULL, 0, 0, 0, 0 }
|
|
@@ -267,6 +269,7 @@ cmDspInst_t* _cmDspTimeLineAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsig
|
267
|
269
|
|
268
|
270
|
cmDspSetDefaultUInt( ctx, &p->inst, kSelTlId, 0, cmInvalidId);
|
269
|
271
|
cmDspSetDefaultStrcz( ctx, &p->inst, kAudFnTlId, NULL, "");
|
|
272
|
+ cmDspSetDefaultStrcz( ctx, &p->inst, kMidiFnTlId, NULL, "");
|
270
|
273
|
cmDspSetDefaultUInt( ctx, &p->inst, kBegSmpIdxTlId, 0, cmInvalidIdx);
|
271
|
274
|
cmDspSetDefaultUInt( ctx, &p->inst, kEndSmpIdxTlId, 0, cmInvalidIdx);
|
272
|
275
|
|
|
@@ -307,11 +310,41 @@ cmDspRC_t _cmDspTimeLineReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt
|
307
|
310
|
|
308
|
311
|
cmDspRC_t _cmDspTimeLineRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
|
309
|
312
|
{
|
|
313
|
+ cmDspTimeLine_t* p = (cmDspTimeLine_t*)inst;
|
310
|
314
|
|
311
|
315
|
switch( evt->dstVarId )
|
312
|
316
|
{
|
313
|
317
|
case kSelTlId:
|
314
|
|
- cmDspSetEvent(ctx,inst,evt);
|
|
318
|
+ {
|
|
319
|
+ unsigned markerId;
|
|
320
|
+ cmDspSetEvent(ctx,inst,evt);
|
|
321
|
+
|
|
322
|
+ // get the id of the selected marker
|
|
323
|
+ if((markerId = cmDspUInt(inst,kSelTlId)) != cmInvalidId )
|
|
324
|
+ {
|
|
325
|
+ // get the marker object
|
|
326
|
+ cmTlObj_t* op;
|
|
327
|
+ if((op = cmTimeLineIdToObj(p->tlH, cmInvalidId, markerId )) != NULL )
|
|
328
|
+ {
|
|
329
|
+ assert(op->typeId == kMarkerTlId);
|
|
330
|
+
|
|
331
|
+ cmDspSetUInt(ctx, inst, kBegSmpIdxTlId, op->begSmpIdx );
|
|
332
|
+ cmDspSetUInt(ctx, inst, kEndSmpIdxTlId, op->begSmpIdx + op->durSmpCnt );
|
|
333
|
+
|
|
334
|
+ // locate the audio file assoc'd with the marker
|
|
335
|
+ cmTlAudioFile_t* afp;
|
|
336
|
+ if((afp = cmTimeLineAudioFileAtTime(p->tlH,op->seqId,op->seqSmpIdx)) != NULL)
|
|
337
|
+ cmDspSetStrcz(ctx, inst, kAudFnTlId, afp->fn );
|
|
338
|
+
|
|
339
|
+ // locate the midi file assoc'd with the marker
|
|
340
|
+ cmTlMidiFile_t* mfp;
|
|
341
|
+ if((mfp = cmTimeLineMidiFileAtTime(p->tlH,op->seqId,op->seqSmpIdx)) != NULL )
|
|
342
|
+ cmDspSetStrcz(ctx, inst, kMidiFnTlId, mfp->fn );
|
|
343
|
+ }
|
|
344
|
+
|
|
345
|
+ }
|
|
346
|
+
|
|
347
|
+ }
|
315
|
348
|
|
316
|
349
|
break;
|
317
|
350
|
|
|
@@ -337,3 +370,174 @@ struct cmDspClass_str* cmTimeLineClassCons( cmDspCtx_t* ctx )
|
337
|
370
|
return &_cmTimeLineDC;
|
338
|
371
|
}
|
339
|
372
|
|
|
373
|
+//==========================================================================================================================================
|
|
374
|
+
|
|
375
|
+//
|
|
376
|
+//
|
|
377
|
+// Read files created by this object with the Octave function cmTextFile().
|
|
378
|
+//
|
|
379
|
+//
|
|
380
|
+
|
|
381
|
+enum
|
|
382
|
+{
|
|
383
|
+ kFnMfId,
|
|
384
|
+ kSelMfId,
|
|
385
|
+ kBsiMfId,
|
|
386
|
+ kEsiMfId,
|
|
387
|
+ kStatusMfId,
|
|
388
|
+ kD0MfId,
|
|
389
|
+ kD1MfId
|
|
390
|
+};
|
|
391
|
+
|
|
392
|
+cmDspClass_t _cmMidiFilePlayDC;
|
|
393
|
+
|
|
394
|
+typedef struct
|
|
395
|
+{
|
|
396
|
+ cmDspInst_t inst;
|
|
397
|
+ cmMidiFileH_t mfH;
|
|
398
|
+ unsigned msgIdx; // current midi file msg index
|
|
399
|
+ unsigned bsi;
|
|
400
|
+ unsigned esi;
|
|
401
|
+ unsigned startSymId;
|
|
402
|
+ unsigned stopSymId;
|
|
403
|
+ unsigned contSymId;
|
|
404
|
+} cmDspMidiFilePlay_t;
|
|
405
|
+
|
|
406
|
+/*
|
|
407
|
+ 'bsi' and 'esi' give the starting and ending sample for MIDI file playback.
|
|
408
|
+ These indexes are relative to the start of the file.
|
|
409
|
+ When the player recieves a 'start' msg it sets the current sample index
|
|
410
|
+ 'si' to 'bsi' and begins scanning for the next note to play.
|
|
411
|
+ On each call to the _cmDspMidiFilePlayExec() msgs that fall in the interval
|
|
412
|
+ si:si+sPc-1 will be transmitted. (where sPc are the number of samples per DSP cycle).
|
|
413
|
+ */
|
|
414
|
+
|
|
415
|
+cmDspInst_t* _cmDspMidiFilePlayAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
|
|
416
|
+{
|
|
417
|
+ cmDspVarArg_t args[] =
|
|
418
|
+ {
|
|
419
|
+ { "fn", kFnMfId, 0, 0, kInDsvFl | kStrzDsvFl | kReqArgDsvFl, "File name"},
|
|
420
|
+ { "sel", kSelMfId, 0, 0, kInDsvFl | kSymDsvFl, "start | stop | continue" },
|
|
421
|
+ { "bsi", kBsiMfId, 0, 0, kInDsvFl | kUIntDsvFl, "Starting sample." },
|
|
422
|
+ { "esi", kEsiMfId, 0, 0, kInDsvFl | kUIntDsvFl, "Ending sample."},
|
|
423
|
+ { "status", kStatusMfId, 0, 0, kOutDsvFl | kUIntDsvFl, "Status value output" },
|
|
424
|
+ { "d0", kD0MfId, 0, 0, kOutDsvFl | kUIntDsvFl, "Data byte 0" },
|
|
425
|
+ { "d1", kD1MfId, 0, 0, kOutDsvFl | kUIntDsvFl, "Data byte 1" },
|
|
426
|
+ { NULL, 0, 0, 0, 0 }
|
|
427
|
+ };
|
|
428
|
+
|
|
429
|
+ cmDspMidiFilePlay_t* p = cmDspInstAlloc(cmDspMidiFilePlay_t,ctx,classPtr,args,instSymId,id,storeSymId,va_cnt,vl);
|
|
430
|
+
|
|
431
|
+ cmDspSetDefaultUInt( ctx, &p->inst, kStatusMfId, 0, 0);
|
|
432
|
+ cmDspSetDefaultUInt( ctx, &p->inst, kD0MfId, 0, 0);
|
|
433
|
+ cmDspSetDefaultUInt( ctx, &p->inst, kD1MfId, 0, 0);
|
|
434
|
+
|
|
435
|
+ p->startSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"start");
|
|
436
|
+ p->stopSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"stop");
|
|
437
|
+ p->contSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"continue");
|
|
438
|
+ p->mfH = cmMidiFileNullHandle;
|
|
439
|
+ return &p->inst;
|
|
440
|
+}
|
|
441
|
+
|
|
442
|
+cmDspRC_t _cmDspMidiFilePlayFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
|
|
443
|
+{
|
|
444
|
+ cmDspMidiFilePlay_t* p = (cmDspMidiFilePlay_t*)inst;
|
|
445
|
+ if( cmMidiFileClose(&p->mfH) )
|
|
446
|
+ return cmErrMsg(&inst->classPtr->err, kInstFinalFailDspRC, "MIDI file close failed.");
|
|
447
|
+ return kOkDspRC;
|
|
448
|
+}
|
|
449
|
+
|
|
450
|
+// return the index of the msg following smpIdx
|
|
451
|
+unsigned _cmDspMidiFilePlaySeekMsgIdx( cmDspCtx_t* ctx, cmDspMidiFilePlay_t* p, unsigned smpIdx )
|
|
452
|
+{
|
|
453
|
+ unsigned i;
|
|
454
|
+ unsigned n = cmMidiFileMsgCount(p->mfH);
|
|
455
|
+ const cmMidiTrackMsg_t** a = cmMidiFileMsgArray(p->mfH);
|
|
456
|
+ double srate = cmDspSampleRate(ctx);
|
|
457
|
+
|
|
458
|
+ for(i=0; i<n; ++i)
|
|
459
|
+ if( floor(a[i]->dtick*srate) > smpIdx )
|
|
460
|
+ break;
|
|
461
|
+
|
|
462
|
+ return i==n ? cmInvalidIdx : i;
|
|
463
|
+}
|
|
464
|
+
|
|
465
|
+cmDspRC_t _cmDspMidiFilePlayOpen(cmDspCtx_t* ctx, cmDspInst_t* inst )
|
|
466
|
+{
|
|
467
|
+ cmDspRC_t rc = kOkDspRC;
|
|
468
|
+ const cmChar_t* fn = cmDspStrcz(inst,kFnMfId);
|
|
469
|
+ cmDspMidiFilePlay_t* p = (cmDspMidiFilePlay_t*)inst;
|
|
470
|
+
|
|
471
|
+ if( cmMidiFileOpen( fn, &p->mfH, ctx->cmCtx ) != kOkFileRC )
|
|
472
|
+ rc = cmErrMsg(&inst->classPtr->err, kInstResetFailDspRC, "MIDI file open failed.");
|
|
473
|
+ else
|
|
474
|
+ {
|
|
475
|
+ p->msgIdx = 0;
|
|
476
|
+ p->bsi = cmDspUInt(inst,kBsiMfId);
|
|
477
|
+ p->esi = cmDspUInt(inst,kEsiMfId);
|
|
478
|
+ cmMidiFileTickToMicros(p->mfH);
|
|
479
|
+ }
|
|
480
|
+ return rc;
|
|
481
|
+}
|
|
482
|
+
|
|
483
|
+cmDspRC_t _cmDspMidiFilePlayReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
|
|
484
|
+{
|
|
485
|
+ cmDspApplyAllDefaults(ctx,inst);
|
|
486
|
+
|
|
487
|
+ return _cmDspMidiFilePlayOpen(ctx,inst);
|
|
488
|
+}
|
|
489
|
+
|
|
490
|
+cmDspRC_t _cmDspMidiFilePlayExec(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
|
|
491
|
+{
|
|
492
|
+ cmDspRC_t rc = kOkDspRC;
|
|
493
|
+ cmDspMidiFilePlay_t* p = (cmDspMidiFilePlay_t*)inst;
|
|
494
|
+
|
|
495
|
+ double srate = cmDspSampleRate(ctx);
|
|
496
|
+ unsigned sPc = cmDspSamplesPerCycle(ctx);
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+ return rc;
|
|
503
|
+}
|
|
504
|
+
|
|
505
|
+cmDspRC_t _cmDspMidiFilePlayRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
|
|
506
|
+{
|
|
507
|
+ cmDspMidiFilePlay_t* p = (cmDspMidiFilePlay_t*)inst;
|
|
508
|
+
|
|
509
|
+ cmDspSetEvent(ctx,inst,evt);
|
|
510
|
+
|
|
511
|
+ switch(evt->dstVarId)
|
|
512
|
+ {
|
|
513
|
+ case kFnMfId:
|
|
514
|
+ _cmDspMidiFilePlayOpen(ctx, inst );
|
|
515
|
+ break;
|
|
516
|
+
|
|
517
|
+ case kSelMfId:
|
|
518
|
+ {
|
|
519
|
+ if( cmDspSymbol(inst,kSelMfId)==p->startSymId )
|
|
520
|
+ {
|
|
521
|
+ _cmDspMidiFilePlaySeekMsgIdx(ctx, p, cmDspUInt(inst,kBsiMfId) );
|
|
522
|
+ }
|
|
523
|
+ break;
|
|
524
|
+ }
|
|
525
|
+ }
|
|
526
|
+
|
|
527
|
+ return kOkDspRC;
|
|
528
|
+}
|
|
529
|
+
|
|
530
|
+struct cmDspClass_str* cmMidiFilePlayClassCons( cmDspCtx_t* ctx )
|
|
531
|
+{
|
|
532
|
+ cmDspClassSetup(&_cmMidiFilePlayDC,ctx,"MidiFilePlay",
|
|
533
|
+ NULL,
|
|
534
|
+ _cmDspMidiFilePlayAlloc,
|
|
535
|
+ _cmDspMidiFilePlayFree,
|
|
536
|
+ _cmDspMidiFilePlayReset,
|
|
537
|
+ _cmDspMidiFilePlayExec,
|
|
538
|
+ _cmDspMidiFilePlayRecv,
|
|
539
|
+ NULL,NULL,
|
|
540
|
+ "Time tagged text file.");
|
|
541
|
+
|
|
542
|
+ return &_cmMidiFilePlayDC;
|
|
543
|
+}
|