Przeglądaj źródła

cmMidiFile.h/c : Added a the unique msg id 'uid' to cmMidiTrackMsg_t.

Changed the dtick to seconds/samples conversions to use doubles
instead of integers to avoid round off error.
master
kpl 11 lat temu
rodzic
commit
bec5f199b4
2 zmienionych plików z 37 dodań i 41 usunięć
  1. 36
    41
      cmMidiFile.c
  2. 1
    0
      cmMidiFile.h

+ 36
- 41
cmMidiFile.c Wyświetl plik

@@ -41,7 +41,7 @@ typedef struct
41 41
   char*              fn;                 // file name or NULL if this object did not originate from a file
42 42
   unsigned           msgN;               // count of msg's in msgV[]
43 43
   cmMidiTrackMsg_t** msgV;               // sorted msg list
44
-  
44
+  unsigned           nextUid;            // next available msg uid
45 45
 } _cmMidiFile_t;
46 46
 
47 47
 
@@ -524,6 +524,7 @@ cmMfRC_t cmMidiFileOpen( const char* fn, cmMidiFileH_t* hPtr, cmCtx_t* ctx )
524 524
 
525 525
   // store a pointer to every trk msg in msgV[] 
526 526
   // and convert tick to absolute tick
527
+  mfp->nextUid = 0;
527 528
   unsigned i = 0;
528 529
   for(trkIdx=0; trkIdx<mfp->trkN; ++trkIdx)
529 530
   {
@@ -534,15 +535,16 @@ cmMfRC_t cmMidiFileOpen( const char* fn, cmMidiFileH_t* hPtr, cmCtx_t* ctx )
534 535
     {
535 536
       assert( i < mfp->msgN);
536 537
 
537
-      tick          += tmp->dtick; // convert delta-ticks to absolute ticks
538
+      tick          += tmp->dtick;     // convert delta-ticks to absolute ticks
538 539
       tmp->atick     = tick;
540
+      tmp->uid       = mfp->nextUid++; // assign the msg uid
539 541
       mfp->msgV[i]   = tmp;
540 542
       tmp            = tmp->link;
541 543
       ++i;
542 544
     }  
543 545
   }
544 546
 
545
-  // sort msgV[] in ascending order on dtick
547
+  // sort msgV[] in ascending order on atick
546 548
   qsort( mfp->msgV, mfp->msgN, sizeof(cmMidiTrackMsg_t*), _cmMidiFileSortFunc );
547 549
 
548 550
   //for(i=0; i<25; ++i)
@@ -552,24 +554,6 @@ cmMfRC_t cmMidiFileOpen( const char* fn, cmMidiFileH_t* hPtr, cmCtx_t* ctx )
552 554
   assert( mfp->fn != NULL );
553 555
   strcpy(mfp->fn,fn);
554 556
 
555
-  //
556
-  // calculate the total duration of the MIDI file and convert absolute ticks back to delta ticks
557
-  //
558
-  /*
559
-  unsigned mi;
560
-  unsigned prvTick       = 0;
561
-
562
-
563
-  for(mi=0; mi<mfp->msgN; ++mi)
564
-  {
565
-    cmMidiTrackMsg_t* mp = mfp->msgV[mi];
566
-
567
-    // convert absolute ticks back to delta ticks
568
-    unsigned dtick = mp->dtick - prvTick; 
569
-    prvTick   = mp->dtick;
570
-    mp->dtick = dtick;
571
-  }
572
-  */
573 557
 
574 558
   hPtr->h = mfp;
575 559
 
@@ -1062,9 +1046,9 @@ unsigned  cmMidiFileSeekUsecs( cmMidiFileH_t h, unsigned offsUSecs, unsigned* ms
1062 1046
     return cmInvalidIdx;
1063 1047
 
1064 1048
   unsigned mi;
1065
-  unsigned microsPerQN   = 60000000/120;
1066
-  unsigned microsPerTick = microsPerQN / p->ticksPerQN;
1067
-  unsigned accUSecs      = 0;
1049
+  double microsPerQN   = 60000000.0/120.0;
1050
+  double microsPerTick = microsPerQN / p->ticksPerQN;
1051
+  double accUSecs      = 0;
1068 1052
 
1069 1053
   for(mi=0; mi<p->msgN; ++mi)
1070 1054
   {
@@ -1084,10 +1068,10 @@ unsigned  cmMidiFileSeekUsecs( cmMidiFileH_t h, unsigned offsUSecs, unsigned* ms
1084 1068
     return cmInvalidIdx;
1085 1069
 
1086 1070
   if( msgUsecsPtr != NULL )
1087
-    *msgUsecsPtr = accUSecs - offsUSecs;
1071
+    *msgUsecsPtr = round(accUSecs - offsUSecs);
1088 1072
 
1089 1073
   if( microsPerTickPtr != NULL )
1090
-    *microsPerTickPtr = microsPerTick;
1074
+    *microsPerTickPtr = round(microsPerTick);
1091 1075
 
1092 1076
   return mi;
1093 1077
 }
@@ -1097,15 +1081,16 @@ double  cmMidiFileDurSecs( cmMidiFileH_t h )
1097 1081
   _cmMidiFile_t* mfp           = _cmMidiFileHandleToPtr(h);
1098 1082
   unsigned       mi;
1099 1083
   double         durSecs       = 0;
1100
-  unsigned       microsPerQN   = 60000000/120;
1101
-  unsigned       microsPerTick = microsPerQN / mfp->ticksPerQN;
1084
+  double         r             = 1.0; //1000.0/(1000-.8);
1085
+  double         microsPerQN   = r*60000000.0/120.0;
1086
+  double         microsPerTick = microsPerQN / mfp->ticksPerQN;
1102 1087
 
1103 1088
   for(mi=0; mi<mfp->msgN; ++mi)
1104 1089
   {
1105 1090
     cmMidiTrackMsg_t* mp = mfp->msgV[mi];
1106 1091
 
1107 1092
     if( mp->status == kMetaStId && mp->metaId == kTempoMdId )
1108
-      microsPerTick = mp->u.iVal / mfp->ticksPerQN;
1093
+      microsPerTick = r*mp->u.iVal / mfp->ticksPerQN;
1109 1094
 
1110 1095
     // update the accumulated seconds
1111 1096
     durSecs += (mp->dtick * microsPerTick) / 1000000.0;
@@ -1126,17 +1111,18 @@ void cmMidiFileTickToMicros( cmMidiFileH_t h )
1126 1111
     return;
1127 1112
 
1128 1113
   unsigned mi;
1129
-  unsigned microsPerQN   = 60000000/120; // default tempo
1130
-  unsigned microsPerTick = microsPerQN / p->ticksPerQN;
1114
+  double r             = 1.0; //1000.0/(1000-.8);
1115
+  double microsPerQN   = r*60000000/120; // default tempo
1116
+  double microsPerTick = microsPerQN / p->ticksPerQN;
1131 1117
 
1132 1118
   for(mi=0; mi<p->msgN; ++mi)
1133 1119
   {
1134 1120
     cmMidiTrackMsg_t* mp = p->msgV[mi];
1135 1121
 
1136 1122
     if( mp->status == kMetaStId && mp->metaId == kTempoMdId )
1137
-      microsPerTick = mp->u.iVal / p->ticksPerQN;
1123
+      microsPerTick = r*mp->u.iVal / p->ticksPerQN;
1138 1124
 
1139
-    mp->dtick *= microsPerTick;
1125
+    mp->dtick = round(microsPerTick*mp->dtick);
1140 1126
   }
1141 1127
   
1142 1128
 }
@@ -1144,28 +1130,37 @@ void cmMidiFileTickToMicros( cmMidiFileH_t h )
1144 1130
 void cmMidiFileTickToSamples( cmMidiFileH_t h, double srate, bool absFl )
1145 1131
 {
1146 1132
   _cmMidiFile_t* p;
1147
-  unsigned mi;
1148
-  //bool fl = true;
1149 1133
 
1150 1134
   if((p = _cmMidiFileHandleToPtr(h)) == NULL )
1151 1135
     return;
1152 1136
 
1153
-  cmMidiFileTickToMicros(h);
1137
+  if( p->msgN == 0 )
1138
+    return;
1154 1139
 
1155
-  unsigned absSmp = 0;
1140
+  unsigned mi;
1141
+  double r             = 1.0; //1000.0/(1000-.8);
1142
+  double microsPerQN   = r*60000000/120; // default tempo
1143
+  double microsPerTick = microsPerQN / p->ticksPerQN;
1144
+  double absSmp = 0;
1156 1145
 
1157 1146
   for(mi=0; mi<p->msgN; ++mi)
1158 1147
   {
1159
-    cmMidiTrackMsg_t* mp    = p->msgV[mi];
1160
-    unsigned          delta = floor((mp->dtick*srate)/1000000.0);
1148
+    cmMidiTrackMsg_t* mp = p->msgV[mi];
1161 1149
 
1162
-    absSmp    += delta;    
1150
+    if( mp->status == kMetaStId && mp->metaId == kTempoMdId )
1151
+      microsPerTick = r*mp->u.iVal / p->ticksPerQN;
1152
+
1153
+    double delta = microsPerTick*mp->dtick*srate/1000000.0;
1154
+
1155
+    absSmp += delta;
1163 1156
 
1164
-    mp->dtick  = absFl ? absSmp : delta;
1157
+    mp->dtick  = round(absFl ? absSmp : delta);
1165 1158
 
1166 1159
   }
1160
+  
1167 1161
 }
1168 1162
 
1163
+
1169 1164
 typedef struct _cmMidiVoice_str
1170 1165
 {
1171 1166
   const  cmMidiTrackMsg_t*  mp;

+ 1
- 0
cmMidiFile.h Wyświetl plik

@@ -62,6 +62,7 @@ extern "C" {
62 62
 
63 63
   typedef struct cmMidiTrackMsg_str
64 64
   {
65
+    unsigned                   uid;     // uid's are unique among all msg's in the file
65 66
     unsigned                   dtick;   // delta ticks
66 67
     unsigned                   atick;   
67 68
     cmMidiByte_t               status;  // ch msg's have the channel value removed (it is stored in u.chMsgPtr->ch)

Ładowanie…
Anuluj
Zapisz