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