Browse Source

Initial DSP midi file play and merged cmTimeLine.h/c xxxAtTime() funcs.

master
kevin 11 years ago
parent
commit
0e06db1593
6 changed files with 310 additions and 4 deletions
  1. 81
    0
      app/cmTimeLine.c
  2. 6
    0
      app/cmTimeLine.h
  3. 1
    2
      dsp/cmDspBuiltIn.c
  4. 205
    1
      dsp/cmDspKr.c
  5. 1
    0
      dsp/cmDspKr.h
  6. 16
    1
      dsp/cmDspPgmKr.c

+ 81
- 0
app/cmTimeLine.c View File

@@ -1193,6 +1193,87 @@ cmTlMidiFile_t* cmTimeLineFindMidiFile( cmTlH_t h, const cmChar_t* fn )
1193 1193
   return NULL;
1194 1194
 }
1195 1195
 
1196
+_cmTlObj_t* _cmTimeLineObjAtTime( _cmTl_t* p, unsigned seqId, unsigned seqSmpIdx, unsigned typeId )
1197
+{
1198
+  assert( seqId < p->seqCnt );
1199
+  _cmTlObj_t* op      = p->seq[seqId].first;
1200
+  _cmTlObj_t* min_op  = NULL;
1201
+  unsigned    minDist = UINT_MAX;
1202
+
1203
+  for(; op!=NULL; op=op->next)
1204
+    if( typeId==cmInvalidId || op->obj->typeId == typeId )
1205
+    {
1206
+      // if seqSmpIdx is inside this object - then return it as the solution
1207
+      if((op->obj->seqSmpIdx <= seqSmpIdx && seqSmpIdx < (op->obj->seqSmpIdx + op->obj->durSmpCnt)))
1208
+        return op;
1209
+
1210
+      // measure the distance from seqSmpIdx to the begin and end of this object
1211
+      unsigned d0 =  op->obj->seqSmpIdx                    < seqSmpIdx ? seqSmpIdx - op->obj->seqSmpIdx                    : op->obj->seqSmpIdx - seqSmpIdx;
1212
+      unsigned d1 =  op->obj->seqSmpIdx+op->obj->durSmpCnt < seqSmpIdx ? seqSmpIdx - op->obj->seqSmpIdx+op->obj->durSmpCnt : op->obj->seqSmpIdx+op->obj->durSmpCnt - seqSmpIdx;
1213
+
1214
+      // d0 and d1 should decrease as the cur object approaches seqSmpIdx
1215
+      // If they do not then the search is over - return the closest point.
1216
+      if( d0>minDist && d1>minDist)
1217
+        break;
1218
+
1219
+      // track the min dist and the assoc'd obj
1220
+      if( d0 < minDist )
1221
+      {
1222
+        minDist = d0;
1223
+        min_op  = op;
1224
+      }
1225
+
1226
+      if( d1 < minDist )
1227
+      {
1228
+        minDist = d1;
1229
+        min_op  = op;
1230
+      }
1231
+        
1232
+    }
1233
+       
1234
+  return min_op;
1235
+}
1236
+
1237
+cmTlAudioFile_t* cmTimeLineAudioFileAtTime( cmTlH_t h, unsigned seqId, unsigned seqSmpIdx )
1238
+{ 
1239
+  _cmTl_t*   p = _cmTlHandleToPtr(h);
1240
+  _cmTlObj_t* op;
1241
+  if((op = _cmTimeLineObjAtTime(p,seqId,seqSmpIdx,kAudioFileTlId)) == NULL )
1242
+    return NULL;
1243
+
1244
+  return _cmTlAudioFileObjPtr(p,op->obj,false);  
1245
+}
1246
+
1247
+cmTlMidiFile_t*  cmTimeLineMidiFileAtTime(  cmTlH_t h, unsigned seqId, unsigned seqSmpIdx )
1248
+{
1249
+  _cmTl_t*   p = _cmTlHandleToPtr(h);
1250
+  _cmTlObj_t* op;
1251
+  if((op = _cmTimeLineObjAtTime(p,seqId,seqSmpIdx,kMidiFileTlId)) == NULL )
1252
+    return NULL;
1253
+
1254
+  return _cmTlMidiFileObjPtr(p,op->obj,false);  
1255
+}
1256
+
1257
+cmTlMidiEvt_t*   cmTimeLineMidiEvtAtTime(   cmTlH_t h, unsigned seqId, unsigned seqSmpIdx )
1258
+{
1259
+  _cmTl_t*   p = _cmTlHandleToPtr(h);
1260
+  _cmTlObj_t* op;
1261
+  if((op = _cmTimeLineObjAtTime(p,seqId,seqSmpIdx,kMidiEvtTlId)) == NULL )
1262
+    return NULL;
1263
+
1264
+  return _cmTlMidiEvtObjPtr(p,op->obj,false);  
1265
+}
1266
+
1267
+cmTlMarker_t*    cmTimeLineMarkerAtTime(    cmTlH_t h, unsigned seqId, unsigned seqSmpIdx )
1268
+{
1269
+  _cmTl_t*   p = _cmTlHandleToPtr(h);
1270
+  _cmTlObj_t* op;
1271
+  if((op = _cmTimeLineObjAtTime(p,seqId,seqSmpIdx,kMarkerTlId)) == NULL )
1272
+    return NULL;
1273
+
1274
+  return _cmTlMarkerObjPtr(p,op->obj,false);  
1275
+}
1276
+
1196 1277
 
1197 1278
 cmTlRC_t _cmTlParseErr( cmErr_t* err, const cmChar_t* errLabelPtr, unsigned idx, const cmChar_t* fn )
1198 1279
 {

+ 6
- 0
app/cmTimeLine.h View File

@@ -151,6 +151,12 @@ extern "C" {
151 151
   cmTlAudioFile_t* cmTimeLineFindAudioFile( cmTlH_t h, const cmChar_t* fn );
152 152
   cmTlMidiFile_t*  cmTimeLineFindMidiFile( cmTlH_t h, const cmChar_t* fn );
153 153
 
154
+
155
+  cmTlAudioFile_t* cmTimeLineAudioFileAtTime( cmTlH_t h, unsigned seqId, unsigned seqSmpIdx );
156
+  cmTlMidiFile_t*  cmTimeLineMidiFileAtTime(  cmTlH_t h, unsigned seqId, unsigned seqSmpIdx );
157
+  cmTlMidiEvt_t*   cmTimeLineMidiEvtAtTime(   cmTlH_t h, unsigned seqId, unsigned seqSmpIdx );
158
+  cmTlMarker_t*    cmTimeLineMarkerAtTime(    cmTlH_t h, unsigned seqId, unsigned seqSmpIdx );
159
+
154 160
   // 'typeId' = kAudioFileTlId, kMidiFileTId, kMarkerTlId.
155 161
   // 'nameStr' and 'refObjNameStr' may be NULL.
156 162
   cmTlRC_t cmTimeLineInsert( 

+ 1
- 2
dsp/cmDspBuiltIn.c View File

@@ -1534,8 +1534,6 @@ cmDspInst_t*  _cmDspTextAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned
1534 1534
 
1535 1535
   cmDspText_t* p = cmDspInstAlloc(cmDspText_t,ctx,classPtr,args,instSymId,id,storeSymId,va_cnt,vl);
1536 1536
 
1537
-  
1538
-
1539 1537
   // create the UI control
1540 1538
   cmDspUiTextCreate(ctx,&p->inst,kValTxId,kLblTxId);
1541 1539
 
@@ -4993,6 +4991,7 @@ cmDspClassConsFunc_t _cmDspClassBuiltInArray[] =
4993 4991
   cmSegLineClassCons,
4994 4992
   
4995 4993
   cmTimeLineClassCons,
4994
+  cmMidiFilePlayClassCons,
4996 4995
   
4997 4996
   NULL,
4998 4997
 };

+ 205
- 1
dsp/cmDspKr.c View File

@@ -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
+}

+ 1
- 0
dsp/cmDspKr.h View File

@@ -7,6 +7,7 @@ extern "C" {
7 7
 
8 8
   struct cmDspClass_str* cmKrClassCons( cmDspCtx_t* ctx );
9 9
   struct cmDspClass_str* cmTimeLineClassCons( cmDspCtx_t* ctx );
10
+  struct cmDspClass_str* cmMidiFilePlayClassCons( cmDspCtx_t* ctx );
10 11
 
11 12
 #ifdef __cplusplus
12 13
 }

+ 16
- 1
dsp/cmDspPgmKr.c View File

@@ -40,14 +40,29 @@ cmDspRC_t _cmDspSysPgm_TimeLine(cmDspSysH_t h, void** userPtrPtr )
40 40
   const cmChar_t* tlFn    = "/home/kevin/src/cmgv/src/gv/data/tl7.js";
41 41
   const cmChar_t* audPath = "/home/kevin/media/audio/20110723-Kriesberg/Audio Files";
42 42
 
43
-  cmDspInst_t* tlp = cmDspSysAllocInst(h,"TimeLine",   "tl",  2, tlFn, audPath );
43
+  cmDspInst_t* tlp  = cmDspSysAllocInst(h,"TimeLine",   "tl",  2, tlFn, audPath );
44
+  cmDspInst_t* php  = cmDspSysAllocInst(h,"Phasor",   NULL,  0 );
45
+  cmDspInst_t* wtp  = cmDspSysAllocInst(h,"WaveTable",NULL,  2, cmDspSysSampleRate(h), 0 );
46
+  cmDspInst_t* ao0p = cmDspSysAllocInst(h,"AudioOut",NULL,   1, 0 );
47
+  cmDspInst_t* ao1p = cmDspSysAllocInst(h,"AudioOut",NULL,   1, 1 );
48
+
49
+
44 50
   cmDspInst_t* prp = cmDspSysAllocInst(h,"Printer", NULL,   1, ">" );
45 51
   
46 52
   if((rc = cmDspSysLastRC(h)) != kOkDspRC )
47 53
     return rc;
48 54
 
55
+  cmDspSysConnectAudio(h, php, "out", wtp,  "phs" );   // phs -> wt
56
+  cmDspSysConnectAudio(h, wtp, "out", ao0p, "in"  );   // wt  -> aout0
57
+  cmDspSysConnectAudio(h, wtp, "out", ao1p, "in" );    // wt  -> aout1
58
+
49 59
   
50 60
   cmDspSysInstallCb(h, tlp, "afn", prp, "in", NULL );
61
+  cmDspSysInstallCb(h, tlp, "afn", wtp, "fn", NULL );
62
+  cmDspSysInstallCb(h, tlp, "bsi", wtp, "beg", NULL );
63
+  cmDspSysInstallCb(h, tlp, "esi", wtp, "end", NULL );
64
+
65
+  cmDspSysInstallCb(h, tlp, "mfn", prp, "in", NULL );
51 66
   cmDspSysInstallCb(h, tlp, "sel", prp, "in", NULL );
52 67
 
53 68
   return rc;

Loading…
Cancel
Save