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