Browse Source

cmMidiFile.h/c : Rewrote the way absolute time is calculated. Added _cmMidiFileSetAccumlateTick() and _cmMidiFileSetAbsoluteTime().

master
kevin 8 years ago
parent
commit
7c4290579d
2 changed files with 141 additions and 19 deletions
  1. 139
    17
      cmMidiFile.c
  2. 2
    2
      cmMidiFile.h

+ 139
- 17
cmMidiFile.c View File

@@ -422,6 +422,99 @@ int _cmMidiFileSortFunc( const void *p0, const void* p1 )
422 422
   return (*(cmMidiTrackMsg_t**)p0)->atick < (*(cmMidiTrackMsg_t**)p1)->atick ? -1 : 1;  
423 423
 }
424 424
 
425
+// Set the absolute accumulated ticks (atick) value of each track message.
426
+// The absolute accumulated ticks gives a global time ordering for all
427
+// messages in the file.
428
+void _cmMidiFileSetAccumulateTicks( _cmMidiFile_t* p )
429
+{
430
+  cmMidiTrackMsg_t* nextTrkMsg[ p->trkN ]; // next msg in each track
431
+  unsigned          atick = 0;
432
+  unsigned          i;
433
+  
434
+  // iniitalize nextTrkTick[] and nextTrkMsg[].
435
+  for(i=0; i<p->trkN; ++i)
436
+    if((nextTrkMsg[i]  =  p->trkV[i].base) != NULL )
437
+      nextTrkMsg[i]->atick = nextTrkMsg[i]->dtick;
438
+
439
+  while(1)
440
+  {
441
+    unsigned k = cmInvalidIdx;
442
+
443
+    // find the trk which has the next msg (min atick time)
444
+    for(i=0; i<p->trkN; ++i)
445
+      if( nextTrkMsg[i]!=NULL && (k==cmInvalidIdx || nextTrkMsg[i]->atick < nextTrkMsg[k]->atick) )
446
+        k = i;
447
+
448
+    // no next msg was found - we're done
449
+    if( k == cmInvalidIdx )
450
+      break;
451
+
452
+    // store the current atick
453
+    atick = nextTrkMsg[k]->atick;
454
+
455
+    // advance the selected track to it's next message
456
+    nextTrkMsg[k] = nextTrkMsg[k]->link;
457
+
458
+    // set the selected tracks next atick time 
459
+    if( nextTrkMsg[k] != NULL )
460
+      nextTrkMsg[k]->atick = atick + nextTrkMsg[k]->dtick;      
461
+  }  
462
+}
463
+
464
+void _cmMidiFileSetAbsoluteTime( _cmMidiFile_t* mfp )
465
+{
466
+  double   microsPerQN   = 60000000/120; // default tempo;
467
+  double   amicro        = 0;
468
+  double   microsPerTick = microsPerQN / mfp->ticksPerQN;
469
+  double   maxDMicro     = 60000000;
470
+  bool     fl            = true;
471
+  unsigned i;
472
+
473
+  for(i=0; i<mfp->msgN; ++i)
474
+  {
475
+    cmMidiTrackMsg_t* mp    = mfp->msgV[i];
476
+    unsigned          dtick = 0;
477
+    
478
+    if( i > 0 )
479
+    {
480
+      // atick must have already been set and sorted
481
+      assert( mp->atick >= mfp->msgV[i-1]->atick );
482
+      dtick = mp->atick -  mfp->msgV[i-1]->atick;
483
+    }
484
+
485
+    // if this is the first msg with a dtick greater than zero
486
+    if( fl && mfp->msgV[i]->dtick > 0  )
487
+    {
488
+      fl = false;
489
+
490
+      // if this mesg has a large offset
491
+      if( microsPerTick * dtick > maxDMicro )
492
+      {
493
+        cmErrWarnMsg(&mfp->err,kLargeDeltaTickMfRC,"A message delta time of %f seconds was decreased to %f seconds.",(double)microsPerTick * dtick/1000000.0,(double)maxDMicro/1000000.0);        
494
+
495
+        // change the dtick to 1 (so it will still be the first msg w/ a non-zero dtick)
496
+        mfp->msgV[i]->dtick = 1; 
497
+
498
+        // dtick changed so the aticks need to be recalculated
499
+        _cmMidiFileSetAccumulateTicks(mfp);
500
+    
501
+        // call this function recursively
502
+        return _cmMidiFileSetAbsoluteTime(mfp);
503
+
504
+      }
505
+    }
506
+    
507
+    amicro     += microsPerTick * dtick;
508
+    mp->amicro  = round(amicro);
509
+    
510
+    
511
+    // track tempo changes
512
+    if( mp->status == kMetaStId && mp->metaId == kTempoMdId )
513
+      microsPerTick = mp->u.iVal / mfp->ticksPerQN;
514
+  }
515
+  
516
+}
517
+
425 518
 cmMfRC_t _cmMidiFileClose( _cmMidiFile_t* mfp )
426 519
 {
427 520
   cmMfRC_t rc = kOkMfRC;
@@ -451,6 +544,7 @@ cmMfRC_t cmMidiFileOpen( cmCtx_t* ctx, cmMidiFileH_t* hPtr, const char* fn )
451 544
   _cmMidiFile_t* mfp    = NULL;
452 545
   unsigned short trkIdx = 0;
453 546
   cmErr_t        err;
547
+  unsigned i,j;
454 548
 
455 549
   if( cmMidiFileIsValid(*hPtr) )
456 550
     if((rc = _cmMidiFileClose(_cmMidiFileHandleToPtr(*hPtr))) != kOkMfRC )
@@ -521,17 +615,32 @@ cmMfRC_t cmMidiFileOpen( cmCtx_t* ctx, cmMidiFileH_t* hPtr, const char* fn )
521 615
   // allocate the trk msg index vector: msgV[]
522 616
   mfp->msgV = cmMemAllocZ(cmMidiTrackMsg_t*, mfp->msgN);
523 617
 
524
-  // store a pointer to every trk msg in msgV[] 
525
-  // and convert tick to absolute tick
526 618
   mfp->nextUid = 0;
527 619
 
620
+  // store a pointer to every trk msg in msgV[]  and set 'uid'  
621
+  for(i=0,j=0; i<mfp->trkN; ++i)
622
+  {
623
+    cmMidiTrackMsg_t* m = mfp->trkV[i].base;
624
+    
625
+    for(; m!=NULL; m=m->link)
626
+    {
627
+      assert( j < mfp->msgN );
628
+      
629
+      mfp->msgV[j++] = m;
630
+      m->uid         = mfp->nextUid++;
631
+    }
632
+  }
633
+
634
+  /*
528 635
   double microsPerQN  = 60000000/120; // default tempo;
529 636
   double microsPerTick;
530 637
   
638
+  double maxDMicro = 60.0 * 1000000.0; // max time between events (60 seconds)
639
+  
531 640
   unsigned i = 0;
532 641
   for(trkIdx=0; trkIdx<mfp->trkN; ++trkIdx)
533 642
   {
534
-    unsigned        tick = 0;
643
+    unsigned          tick = 0;
535 644
     cmMidiTrackMsg_t* tmp  = mfp->trkV[ trkIdx ].base;
536 645
     
537 646
     microsPerTick = microsPerQN / mfp->ticksPerQN;
@@ -540,29 +649,42 @@ cmMfRC_t cmMidiFileOpen( cmCtx_t* ctx, cmMidiFileH_t* hPtr, const char* fn )
540 649
     {
541 650
       assert( i < mfp->msgN);
542 651
 
543
-      tick          += tmp->dtick;     // convert delta-ticks to absolute ticks
544
-      tmp->atick     = tick;
545
-      tmp->uid       = mfp->nextUid++; // assign the msg uid
546
-      mfp->msgV[i]   = tmp;
652
+      // convert dtick to microseconds
653
+      unsigned dmicro = round(tmp->dtick * microsPerTick);
654
+
655
+      if( dmicro > maxDMicro )
656
+      {
657
+        tmp->dtick = round(maxDMicro / microsPerTick);
658
+        cmErrWarnMsg(&mfp->err,kLargeDeltaTickMfRC,"A message delta time of %f seconds was decreased to %f seconds.",(double)dmicro/1000000.0,(double)maxDMicro/1000000.0);        
659
+      }
660
+      
661
+      tick        += tmp->dtick;              // convert delta-ticks to absolute ticks
662
+      tmp->atick   = tick;
663
+      tmp->uid     = mfp->nextUid++;          // assign the msg uid
664
+      tmp->dmicro  = dmicro;
665
+      mfp->msgV[i] = tmp;
547 666
 
667
+      
668
+      
548 669
       // track tempo changes
549 670
       if( tmp->status == kMetaStId && tmp->metaId == kTempoMdId )
550 671
         microsPerTick = tmp->u.iVal / mfp->ticksPerQN;
551
-
552
-      // convert dtick to microseconds
553
-      tmp->dmicro = round(tmp->dtick * microsPerTick);
554
-      
672
+ 
555 673
       tmp            = tmp->link;
556 674
       ++i;
557 675
     }  
558 676
   }
677
+  */
559 678
 
560
-
561
-  
562
-
679
+  // 
680
+  _cmMidiFileSetAccumulateTicks(mfp);
681
+    
563 682
   // sort msgV[] in ascending order on atick
564 683
   qsort( mfp->msgV, mfp->msgN, sizeof(cmMidiTrackMsg_t*), _cmMidiFileSortFunc );
565 684
 
685
+  _cmMidiFileSetAbsoluteTime(mfp);
686
+  
687
+  /*
566 688
   // set the amicro field of each midi message to the
567 689
   // absolute time offset in microseconds
568 690
   unsigned mi;
@@ -587,6 +709,7 @@ cmMfRC_t cmMidiFileOpen( cmCtx_t* ctx, cmMidiFileH_t* hPtr, const char* fn )
587 709
     amicro     += microsPerTick * dtick;
588 710
     mp->amicro  = round(amicro);
589 711
   }
712
+  */
590 713
   
591 714
   //for(i=0; i<25; ++i)
592 715
   //  printf("%i 0x%x 0x%x\n",mfp->msgV[i]->tick,mfp->msgV[i]->status,mfp->msgV[i]->metaId);
@@ -1378,8 +1501,8 @@ void _cmMidiFilePrintHdr( const _cmMidiFile_t* mfp, cmRpt_t* rpt )
1378 1501
 
1379 1502
   cmRptPrintf(rpt,"fmt:%i ticksPerQN:%i tracks:%i\n",mfp->fmtId,mfp->ticksPerQN,mfp->trkN);
1380 1503
 
1381
-  cmRptPrintf(rpt," UID     dtick     dmicro     atick      amicro     type  ch  D0  D1\n");
1382
-  cmRptPrintf(rpt,"----- ---------- ---------- ---------- ---------- : ---- --- --- ---\n");
1504
+  cmRptPrintf(rpt," UID     dtick     atick      amicro     type  ch  D0  D1\n");
1505
+  cmRptPrintf(rpt,"----- ---------- ---------- ---------- : ---- --- --- ---\n");
1383 1506
   
1384 1507
 }
1385 1508
 
@@ -1388,7 +1511,6 @@ void _cmMidiFilePrintMsg( cmRpt_t* rpt, const cmMidiTrackMsg_t* tmp )
1388 1511
   cmRptPrintf(rpt,"%5i %10u %10u %10u %10u : ",
1389 1512
     tmp->uid,
1390 1513
     tmp->dtick,
1391
-    tmp->dmicro,
1392 1514
     tmp->atick,
1393 1515
     tmp->amicro );
1394 1516
 

+ 2
- 2
cmMidiFile.h View File

@@ -65,7 +65,6 @@ extern "C" {
65 65
   {
66 66
     unsigned                   uid;     // uid's are unique among all msg's in the file
67 67
     unsigned                   dtick;   // delta ticks between events on this track
68
-    unsigned                   dmicro;  // delta microseconds between events on this track adjusted for tempo changes
69 68
     unsigned                   atick;   // global (all tracks interleaved) accumulated ticks
70 69
     unsigned                   amicro;  // global (all tracks interleaved) accumulated microseconds adjusted for tempo changes
71 70
     cmMidiByte_t               status;  // ch msg's have the channel value removed (it is stored in u.chMsgPtr->ch)
@@ -101,7 +100,8 @@ extern "C" {
101 100
     kInvalidHandleMfRC,  //  7 
102 101
     kMissingNoteOffMfRC, //  8
103 102
     kInvalidStatusMfRC,  //  9
104
-    kSustainPedalMfRC    // 10
103
+    kSustainPedalMfRC,   // 10
104
+    kLargeDeltaTickMfRC  // 11 (a large delta tick value was filtered)
105 105
   };
106 106
 
107 107
   extern cmMidiFileH_t cmMidiFileNullHandle;

Loading…
Cancel
Save