소스 검색

cmMidiFile.h/c : Fixed bug where tempo changes were not being applied dtick instead of atick.

Added atick,dmicro, and amicro field to cmMidiTrackMsg_t.
Replaced durTicks w/ durMicros in cmMidiChMsg_t.
Deleted cmMidiFIleTickToMicros() and cmMidiFileTickToSamples().
master
kevin 8 년 전
부모
커밋
c8062faafe
2개의 변경된 파일76개의 추가작업 그리고 99개의 파일을 삭제
  1. 71
    89
      cmMidiFile.c
  2. 5
    10
      cmMidiFile.h

+ 71
- 89
cmMidiFile.c 파일 보기

@@ -246,7 +246,7 @@ cmMfRC_t _cmMidiFileReadChannelMsg( _cmMidiFile_t* mfp, cmMidiByte_t* rsPtr, cmM
246 246
   tmp->byteCnt = sizeof(cmMidiChMsg_t);
247 247
   tmp->status  = statusCh & 0xf0;
248 248
   p->ch        = statusCh & 0x0f;
249
-  p->durTicks  = 0;
249
+  p->durMicros = 0;
250 250
 
251 251
   unsigned byteN = cmMidiStatusToByteCount(tmp->status);
252 252
   
@@ -416,8 +416,6 @@ cmMfRC_t _cmMidiFileReadHdr( _cmMidiFile_t* mfp )
416 416
 
417 417
 int _cmMidiFileSortFunc( const void *p0, const void* p1 )
418 418
 {  
419
-  //printf("%i %i\n",(*(cmMidiTrackMsg_t**)p0)->dticks,(*(cmMidiTrackMsg_t**)p1)->dticks);
420
-
421 419
   if( (*(cmMidiTrackMsg_t**)p0)->atick == (*(cmMidiTrackMsg_t**)p1)->atick )
422 420
     return 0;
423 421
 
@@ -526,12 +524,20 @@ cmMfRC_t cmMidiFileOpen( const char* fn, cmMidiFileH_t* hPtr, cmCtx_t* ctx )
526 524
   // store a pointer to every trk msg in msgV[] 
527 525
   // and convert tick to absolute tick
528 526
   mfp->nextUid = 0;
527
+
528
+  double microsPerQN  = 60000000/120; // default tempo;
529
+  double microsPerTick;
530
+  
529 531
   unsigned i = 0;
530 532
   for(trkIdx=0; trkIdx<mfp->trkN; ++trkIdx)
531 533
   {
532 534
     unsigned        tick = 0;
533 535
     cmMidiTrackMsg_t* tmp  = mfp->trkV[ trkIdx ].base;
534 536
 
537
+    
538
+    microsPerTick = microsPerQN / mfp->ticksPerQN;
539
+  
540
+    
535 541
     while( tmp != NULL )
536 542
     {
537 543
       assert( i < mfp->msgN);
@@ -540,6 +546,14 @@ cmMfRC_t cmMidiFileOpen( const char* fn, cmMidiFileH_t* hPtr, cmCtx_t* ctx )
540 546
       tmp->atick     = tick;
541 547
       tmp->uid       = mfp->nextUid++; // assign the msg uid
542 548
       mfp->msgV[i]   = tmp;
549
+
550
+      // track tempo changes
551
+      if( tmp->status == kMetaStId && tmp->metaId == kTempoMdId )
552
+        microsPerTick = tmp->u.iVal / mfp->ticksPerQN;
553
+
554
+      // convert dtick to microseconds
555
+      tmp->dmicro = round(tmp->dtick * microsPerTick);
556
+      
543 557
       tmp            = tmp->link;
544 558
       ++i;
545 559
     }  
@@ -548,6 +562,31 @@ cmMfRC_t cmMidiFileOpen( const char* fn, cmMidiFileH_t* hPtr, cmCtx_t* ctx )
548 562
   // sort msgV[] in ascending order on atick
549 563
   qsort( mfp->msgV, mfp->msgN, sizeof(cmMidiTrackMsg_t*), _cmMidiFileSortFunc );
550 564
 
565
+  // set the amicro field of each midi message to the
566
+  // absolute time offset in microseconds
567
+  unsigned mi;
568
+  unsigned amicro = 0;
569
+  microsPerTick = microsPerQN / mfp->ticksPerQN;
570
+
571
+  for(mi=0; mi<mfp->msgN; ++mi)
572
+  {
573
+    cmMidiTrackMsg_t* mp = mfp->msgV[mi];
574
+
575
+    // track tempo changes
576
+    if( mp->status == kMetaStId && mp->metaId == kTempoMdId )
577
+      microsPerTick = mp->u.iVal / mfp->ticksPerQN;
578
+
579
+    unsigned dtick = 0;
580
+    if( mi > 0 )
581
+    {
582
+      assert( mp->atick >= mfp->msgV[mi-1]->atick );
583
+      dtick = mp->atick -  mfp->msgV[mi-1]->atick;
584
+    }
585
+    
586
+    amicro += round(microsPerTick*dtick);
587
+    mp->amicro = amicro;
588
+  }
589
+  
551 590
   //for(i=0; i<25; ++i)
552 591
   //  printf("%i 0x%x 0x%x\n",mfp->msgV[i]->tick,mfp->msgV[i]->status,mfp->msgV[i]->metaId);
553 592
 
@@ -1054,15 +1093,25 @@ unsigned  cmMidiFileSeekUsecs( cmMidiFileH_t h, unsigned offsUSecs, unsigned* ms
1054 1093
   for(mi=0; mi<p->msgN; ++mi)
1055 1094
   {
1056 1095
     const cmMidiTrackMsg_t* mp = p->msgV[mi];
1057
-
1096
+    /*
1058 1097
     if( mp->status == kMetaStId && mp->metaId == kTempoMdId )
1059 1098
       microsPerTick = mp->u.iVal / p->ticksPerQN;
1060 1099
 
1061
-    accUSecs += mp->dtick * microsPerTick ;
1100
+    unsigned dtick = 0;
1101
+    if( mi > 0 )
1102
+    {
1103
+      assert( mp->atick >= p->msgV[mi-1]->atick )
1104
+      dtick = mp->atick - p->msgV[mi-1]->atick;
1105
+    }
1106
+    
1107
+    accUSecs += dtick * microsPerTick ;
1062 1108
 
1063 1109
     if( accUSecs >= offsUSecs )
1064 1110
       break;
1111
+    */
1065 1112
 
1113
+    if( mp->amicro >= offsUSecs )
1114
+      break;
1066 1115
   }
1067 1116
   
1068 1117
   if( mi == p->msgN )
@@ -1080,90 +1129,17 @@ unsigned  cmMidiFileSeekUsecs( cmMidiFileH_t h, unsigned offsUSecs, unsigned* ms
1080 1129
 double  cmMidiFileDurSecs( cmMidiFileH_t h )
1081 1130
 {
1082 1131
   _cmMidiFile_t* mfp           = _cmMidiFileHandleToPtr(h);
1083
-  unsigned       mi;
1084
-  double         durSecs       = 0;
1085
-  double         r             = 1.0; //1000.0/(1000-.8);
1086
-  double         microsPerQN   = r*60000000.0/120.0;
1087
-  double         microsPerTick = microsPerQN / mfp->ticksPerQN;
1088
-
1089
-  for(mi=0; mi<mfp->msgN; ++mi)
1090
-  {
1091
-    cmMidiTrackMsg_t* mp = mfp->msgV[mi];
1092
-
1093
-    if( mp->status == kMetaStId && mp->metaId == kTempoMdId )
1094
-      microsPerTick = r*mp->u.iVal / mfp->ticksPerQN;
1095
-
1096
-    // update the accumulated seconds
1097
-    durSecs += (mp->dtick * microsPerTick) / 1000000.0;
1098 1132
 
1099
-  }
1100
-
1101
-  return durSecs;
1102
-}
1103
-
1104
-void cmMidiFileTickToMicros( cmMidiFileH_t h )
1105
-{
1106
-  _cmMidiFile_t* p;
1107
-
1108
-  if((p = _cmMidiFileHandleToPtr(h)) == NULL )
1109
-    return;
1110
-
1111
-  if( p->msgN == 0 )
1112
-    return;
1113
-
1114
-  unsigned mi;
1115
-  double microsPerQN   = 60000000/120; // default tempo
1116
-  double microsPerTick = microsPerQN / p->ticksPerQN;
1117
-
1118
-  for(mi=0; mi<p->msgN; ++mi)
1119
-  {
1120
-    cmMidiTrackMsg_t* mp = p->msgV[mi];
1121
-
1122
-    if( mp->status == kMetaStId && mp->metaId == kTempoMdId )
1123
-      microsPerTick = mp->u.iVal / p->ticksPerQN;
1124
-    
1125
-    mp->dtick = round(microsPerTick*mp->dtick);
1126
-  }
1127
-  
1128
-}
1129
-
1130
-void cmMidiFileTickToSamples( cmMidiFileH_t h, double srate, bool absFl )
1131
-{
1132
-  _cmMidiFile_t* p;
1133
-
1134
-  if((p = _cmMidiFileHandleToPtr(h)) == NULL )
1135
-    return;
1136
-
1137
-  if( p->msgN == 0 )
1138
-    return;
1139
-
1140
-  unsigned mi;
1141
-  double microsPerQN   = 60000000/120; // default tempo
1142
-  double microsPerTick = microsPerQN / p->ticksPerQN;
1143
-  double absSmp = 0;
1144
-
1145
-  for(mi=0; mi<p->msgN; ++mi)
1146
-  {
1147
-    cmMidiTrackMsg_t* mp = p->msgV[mi];
1148
-
1149
-    if( mp->status == kMetaStId && mp->metaId == kTempoMdId )
1150
-      microsPerTick = mp->u.iVal / p->ticksPerQN;
1151
-
1152
-    double delta = microsPerTick*mp->dtick*srate/1000000.0;
1153
-
1154
-    absSmp += delta;
1155
-
1156
-    mp->dtick  = round(absFl ? absSmp : delta);
1157
-
1158
-  }
1133
+  if( mfp->msgN == 0 )
1134
+    return 0;
1159 1135
   
1136
+  return mfp->msgV[ mfp->msgN-1 ]->amicro / 1000000.0;
1160 1137
 }
1161 1138
 
1162
-
1163 1139
 typedef struct _cmMidiVoice_str
1164 1140
 {
1165 1141
   const  cmMidiTrackMsg_t*  mp;
1166
-  unsigned                  durTicks;
1142
+  unsigned                  durMicros;
1167 1143
   bool                      sustainFl;
1168 1144
   struct _cmMidiVoice_str*  link;
1169 1145
 } _cmMidiVoice_t;
@@ -1176,7 +1152,7 @@ void _cmMidFileCalcNoteDurationReleaseNote( _cmMidiVoice_t** listPtrPtr, _cmMidi
1176 1152
   // store the duration of the note into the track msg 
1177 1153
   // assoc'd with the note-on msg
1178 1154
   cmMidiChMsg_t* cmp = (cmMidiChMsg_t*)vp->mp->u.chMsgPtr; // cast away const
1179
-  cmp->durTicks = vp->durTicks;
1155
+  cmp->durMicros = vp->durMicros;
1180 1156
 
1181 1157
   _cmMidiVoice_t* np = vp->link;
1182 1158
 
@@ -1224,13 +1200,20 @@ void cmMidiFileCalcNoteDurations( cmMidiFileH_t h )
1224 1200
   {
1225 1201
     cmMidiTrackMsg_t* mp    = p->msgV[mi];
1226 1202
 
1203
+    unsigned d_amicro = 0;
1204
+    if( mi > 0 )
1205
+    {
1206
+      assert(    mp->amicro >= p->msgV[mi-1]->amicro );
1207
+      d_amicro = mp->amicro -  p->msgV[mi-1]->amicro;
1208
+    }
1209
+    
1227 1210
     // update the duration of the sounding notes
1228 1211
     for(vp = list; vp!=NULL; vp=vp->link)
1229
-      vp->durTicks += mp->dtick;    
1212
+      vp->durMicros += d_amicro;    
1230 1213
 
1231 1214
     // update the sustain pedal duration
1232 1215
     if( sustainPedalDownMsg != NULL )
1233
-      ((cmMidiChMsg_t*)(sustainPedalDownMsg->u.chMsgPtr))->durTicks += mp->dtick;  // cast away const
1216
+      ((cmMidiChMsg_t*)(sustainPedalDownMsg->u.chMsgPtr))->durMicros += d_amicro;  // cast away const
1234 1217
 
1235 1218
     //
1236 1219
     // If this is sustain pedal msg
@@ -1255,7 +1238,7 @@ void cmMidiFileCalcNoteDurations( cmMidiFileH_t h )
1255 1238
         else
1256 1239
         {
1257 1240
           sustainPedalDownMsg = mp;
1258
-          ((cmMidiChMsg_t*)(sustainPedalDownMsg->u.chMsgPtr))->durTicks = 0;  // cast away const
1241
+          ((cmMidiChMsg_t*)(sustainPedalDownMsg->u.chMsgPtr))->durMicros = 0;  // cast away const
1259 1242
         }
1260 1243
 
1261 1244
         _cmMidiFileCalcNoteDurationsAllocVoice( &list, mp, true );
@@ -1397,8 +1380,7 @@ void _cmMidiFilePrintHdr( const _cmMidiFile_t* mfp, cmRpt_t* rpt )
1397 1380
 
1398 1381
 void _cmMidiFilePrintMsg( cmRpt_t* rpt, const cmMidiTrackMsg_t* tmp )
1399 1382
 {
1400
-  //cmRptPrintf(rpt,"%5.5f ", tmp->dtick/1000000.0 );
1401
-  cmRptPrintf(rpt,"%f ",    (double)tmp->dtick );
1383
+  cmRptPrintf(rpt,"%8i %8i %8i %8i : ",   tmp->dtick, tmp->dmicro, tmp->atick, tmp->amicro );
1402 1384
 
1403 1385
   if( tmp->status == kMetaStId )
1404 1386
     cmRptPrintf(rpt,"%s ", cmMidiMetaStatusToLabel(tmp->metaId)); 
@@ -1502,7 +1484,7 @@ void cmMidiFileTest( const char* fn, cmCtx_t* ctx )
1502 1484
   if( 1 )
1503 1485
   {
1504 1486
     //cmMidiFileTickToMicros( h );
1505
-    cmMidiFileTickToSamples(h,96000,false);
1487
+    //cmMidiFileTickToSamples(h,96000,false);
1506 1488
     cmMidiFilePrintMsgs(h,&ctx->rpt);
1507 1489
   }
1508 1490
 

+ 5
- 10
cmMidiFile.h 파일 보기

@@ -57,15 +57,17 @@ extern "C" {
57 57
     cmMidiByte_t ch;
58 58
     cmMidiByte_t d0;
59 59
     cmMidiByte_t d1;
60
-    unsigned     durTicks; // note duration calc'd by cmMidiFileCalcNoteDurations();
60
+    unsigned     durMicros;  // note duration in microseconds (corrected for tempo changes)
61 61
   } cmMidiChMsg_t;
62 62
 
63 63
 
64 64
   typedef struct cmMidiTrackMsg_str
65 65
   {
66 66
     unsigned                   uid;     // uid's are unique among all msg's in the file
67
-    unsigned                   dtick;   // delta ticks
68
-    unsigned                   atick;   // accumulated ticks
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
+    unsigned                   atick;   // global (all tracks interleaved) accumulated ticks
70
+    unsigned                   amicro;  // global (all tracks interleaved) accumulated microseconds adjusted for tempo changes
69 71
     cmMidiByte_t               status;  // ch msg's have the channel value removed (it is stored in u.chMsgPtr->ch)
70 72
     cmMidiByte_t               metaId;  //
71 73
     unsigned short             trkIdx;  //  
@@ -153,13 +155,6 @@ extern "C" {
153 155
 
154 156
   double                cmMidiFileDurSecs( cmMidiFileH_t h );
155 157
 
156
-  // Convert the track message 'dtick' field to delta-microseconds.
157
-  void                  cmMidiFileTickToMicros( cmMidiFileH_t h );
158
-
159
-  // Convert the track message 'dtick' field to samples.
160
-  // If the absFl is set then the delta times are converted to absolute time.
161
-  void                  cmMidiFileTickToSamples( cmMidiFileH_t h, double srate, bool absFl );
162
-
163 158
   // Calculate Note Duration 
164 159
   void                  cmMidiFileCalcNoteDurations( cmMidiFileH_t h );
165 160
 

Loading…
취소
저장