|
@@ -423,6 +423,34 @@ cmMfRC_t _cmMidiFileReadHdr( _cmMidiFile_t* mfp )
|
423
|
423
|
return rc;
|
424
|
424
|
}
|
425
|
425
|
|
|
426
|
+void _cmMidiFileDrop( _cmMidiFile_t* p )
|
|
427
|
+{
|
|
428
|
+ unsigned i;
|
|
429
|
+ unsigned n = 0;
|
|
430
|
+ for(i=0; i<p->trkN; ++i)
|
|
431
|
+ {
|
|
432
|
+ _cmMidiTrack_t* trk = p->trkV + i;
|
|
433
|
+ cmMidiTrackMsg_t* m0 = NULL;
|
|
434
|
+ cmMidiTrackMsg_t* m = trk->base;
|
|
435
|
+
|
|
436
|
+ for(; m!=NULL; m=m->link)
|
|
437
|
+ {
|
|
438
|
+ if( cmIsFlag(m->flags,kDropTrkMsgFl) )
|
|
439
|
+ {
|
|
440
|
+ ++n;
|
|
441
|
+ if( m0 == NULL )
|
|
442
|
+ trk->base = m->link;
|
|
443
|
+ else
|
|
444
|
+ m0->link = m->link;
|
|
445
|
+ }
|
|
446
|
+ else
|
|
447
|
+ {
|
|
448
|
+ m0 = m;
|
|
449
|
+ }
|
|
450
|
+ }
|
|
451
|
+ }
|
|
452
|
+}
|
|
453
|
+
|
426
|
454
|
int _cmMidiFileSortFunc( const void *p0, const void* p1 )
|
427
|
455
|
{
|
428
|
456
|
if( (*(cmMidiTrackMsg_t**)p0)->atick == (*(cmMidiTrackMsg_t**)p1)->atick )
|
|
@@ -1369,7 +1397,6 @@ cmMfRC_t cmMidiFileInsertMsg( cmMidiFileH_t h, unsigned uid, int dtick, cmMidiBy
|
1369
|
1397
|
mfp->msgVDirtyFl = true;
|
1370
|
1398
|
|
1371
|
1399
|
return kOkMfRC;
|
1372
|
|
-
|
1373
|
1400
|
}
|
1374
|
1401
|
|
1375
|
1402
|
cmMfRC_t cmMidiFileInsertTrackMsg( cmMidiFileH_t h, unsigned trkIdx, const cmMidiTrackMsg_t* msg )
|
|
@@ -1532,6 +1559,38 @@ unsigned cmMidiFileSeekUsecs( cmMidiFileH_t h, unsigned long long offsUSecs, un
|
1532
|
1559
|
return mi;
|
1533
|
1560
|
}
|
1534
|
1561
|
|
|
1562
|
+/*
|
|
1563
|
+1.Move closest previous tempo msg to begin.
|
|
1564
|
+2.The first msg in each track must be the first msg >= begin.time
|
|
1565
|
+3.Remove all msgs > end.time - except the 'endMsg' for each note/pedal that is active at end time.
|
|
1566
|
+
|
|
1567
|
+
|
|
1568
|
+ */
|
|
1569
|
+
|
|
1570
|
+unsigned _cmMidiFileIsEndMsg( cmMidiTrackMsg_t* m, cmMidiTrackMsg_t** endMsgArray, unsigned n )
|
|
1571
|
+{
|
|
1572
|
+ unsigned i = 0;
|
|
1573
|
+ for(; i<n; ++i)
|
|
1574
|
+ if( endMsgArray[i] == m )
|
|
1575
|
+ return i;
|
|
1576
|
+
|
|
1577
|
+ return cmInvalidIdx;
|
|
1578
|
+}
|
|
1579
|
+
|
|
1580
|
+bool _cmMidiFileAllEndMsgFound( cmMidiTrackMsg_t** noteMsgArray, unsigned n0, cmMidiTrackMsg_t** pedalMsgArray, unsigned n1 )
|
|
1581
|
+{
|
|
1582
|
+ unsigned i=0;
|
|
1583
|
+ for(; i<n0; ++i)
|
|
1584
|
+ if( noteMsgArray[i] != NULL )
|
|
1585
|
+ return false;
|
|
1586
|
+
|
|
1587
|
+ for(i=0; i<n1; ++i)
|
|
1588
|
+ if( pedalMsgArray[i] != NULL )
|
|
1589
|
+ return false;
|
|
1590
|
+
|
|
1591
|
+ return true;
|
|
1592
|
+}
|
|
1593
|
+
|
1535
|
1594
|
double cmMidiFileDurSecs( cmMidiFileH_t h )
|
1536
|
1595
|
{
|
1537
|
1596
|
_cmMidiFile_t* mfp = _cmMidiFileHandleToPtr(h);
|
|
@@ -1544,14 +1603,6 @@ double cmMidiFileDurSecs( cmMidiFileH_t h )
|
1544
|
1603
|
return msgV[ mfp->msgN-1 ]->amicro / 1000000.0;
|
1545
|
1604
|
}
|
1546
|
1605
|
|
1547
|
|
-typedef struct _cmMidiVoice_str
|
1548
|
|
-{
|
1549
|
|
- const cmMidiTrackMsg_t* mp;
|
1550
|
|
- unsigned durMicros;
|
1551
|
|
- bool sustainFl;
|
1552
|
|
- struct _cmMidiVoice_str* link;
|
1553
|
|
-} _cmMidiVoice_t;
|
1554
|
|
-
|
1555
|
1606
|
|
1556
|
1607
|
void _cmMidiFileSetDur( cmMidiTrackMsg_t* m0, cmMidiTrackMsg_t* m1 )
|
1557
|
1608
|
{
|
|
@@ -1574,10 +1625,11 @@ bool _cmMidiFileCalcNoteDur( cmMidiTrackMsg_t* m0, cmMidiTrackMsg_t* m1, int not
|
1574
|
1625
|
return true;
|
1575
|
1626
|
}
|
1576
|
1627
|
|
1577
|
|
-void cmMidiFileCalcNoteDurations( cmMidiFileH_t h )
|
|
1628
|
+void cmMidiFileCalcNoteDurations( cmMidiFileH_t h, unsigned flags )
|
1578
|
1629
|
{
|
1579
|
1630
|
_cmMidiFile_t* p;
|
1580
|
|
-
|
|
1631
|
+ bool warningFl = cmIsFlag(flags,kWarningsMfFl);
|
|
1632
|
+
|
1581
|
1633
|
if((p = _cmMidiFileHandleToPtr(h)) == NULL )
|
1582
|
1634
|
return;
|
1583
|
1635
|
|
|
@@ -1586,13 +1638,14 @@ void cmMidiFileCalcNoteDurations( cmMidiFileH_t h )
|
1586
|
1638
|
|
1587
|
1639
|
unsigned mi = cmInvalidId;
|
1588
|
1640
|
cmMidiTrackMsg_t* noteM[ kMidiNoteCnt * kMidiChCnt ]; // ptr to note-on or NULL if the note is not sounding
|
1589
|
|
- cmMidiTrackMsg_t* sustV[ kMidiChCnt ];
|
1590
|
|
- cmMidiTrackMsg_t* sostV[ kMidiChCnt ];
|
|
1641
|
+ cmMidiTrackMsg_t* sustV[ kMidiChCnt ]; // ptr to last sustain pedal down msg or NULL if susteain pedal is not down
|
|
1642
|
+ cmMidiTrackMsg_t* sostV[ kMidiChCnt ]; // ptr to last sost. pedal down msg or NULL if sost. pedal is not down
|
1591
|
1643
|
int noteGateM[ kMidiNoteCnt * kMidiChCnt ]; // true if the associated note key is depressed
|
1592
|
1644
|
bool sostGateM[ kMidiNoteCnt * kMidiChCnt ]; // true if the associated note was active when the sost. pedal went down
|
1593
|
1645
|
int sustGateV[ kMidiChCnt]; // true if the associated sustain pedal is down
|
1594
|
1646
|
int sostGateV[ kMidiChCnt]; // true if the associated sostenuto pedal is down
|
1595
|
1647
|
unsigned i,j;
|
|
1648
|
+ unsigned n = 0;
|
1596
|
1649
|
|
1597
|
1650
|
const cmMidiTrackMsg_t** msgV = _cmMidiFileMsgArray(p);
|
1598
|
1651
|
|
|
@@ -1634,12 +1687,22 @@ void cmMidiFileCalcNoteDurations( cmMidiFileH_t h )
|
1634
|
1687
|
unsigned k = ch*kMidiNoteCnt + d0;
|
1635
|
1688
|
|
1636
|
1689
|
// there should be no existing sounding note instance for this pitch
|
1637
|
|
- //if( noteGateM[k] == 0 && noteM[k] != NULL )
|
1638
|
|
- // cmErrWarnMsg(&p->err,kMissingNoteOffMfRC,"%i : Missing note-off instance for note on:%s",m->uid,cmMidiToSciPitch(d0,NULL,0));
|
|
1690
|
+ if( noteGateM[k] == 0 && noteM[k] != NULL )
|
|
1691
|
+ {
|
|
1692
|
+ if( warningFl )
|
|
1693
|
+ cmErrWarnMsg(&p->err,kMissingNoteOffMfRC,"%i : Missing note-off instance for note on:%s",m->uid,cmMidiToSciPitch(d0,NULL,0));
|
1639
|
1694
|
|
|
1695
|
+ if( cmIsFlag(flags,kDropReattacksMfFl) )
|
|
1696
|
+ {
|
|
1697
|
+ m->flags |= kDropTrkMsgFl;
|
|
1698
|
+ n += 1;
|
|
1699
|
+ }
|
|
1700
|
+
|
|
1701
|
+ }
|
|
1702
|
+ // if this is a re-attack
|
1640
|
1703
|
if( noteM[k] != NULL )
|
1641
|
1704
|
noteGateM[k] += 1;
|
1642
|
|
- else
|
|
1705
|
+ else // this is a new attack
|
1643
|
1706
|
{
|
1644
|
1707
|
noteM[k] = m;
|
1645
|
1708
|
noteGateM[k] = 1;
|
|
@@ -1676,8 +1739,8 @@ void cmMidiFileCalcNoteDurations( cmMidiFileH_t h )
|
1676
|
1739
|
if( cmMidiFileIsSustainPedalDown(m) )
|
1677
|
1740
|
{
|
1678
|
1741
|
// if the sustain channel is already down
|
1679
|
|
- //if( sustGateV[ch] )
|
1680
|
|
- // cmErrWarnMsg(&p->err,kSustainPedalMfRC,"%i : The sustain pedal went down twice with no intervening release.",m->uid);
|
|
1742
|
+ if( warningFl && sustGateV[ch] )
|
|
1743
|
+ cmErrWarnMsg(&p->err,kSustainPedalMfRC,"%i : The sustain pedal went down twice with no intervening release.",m->uid);
|
1681
|
1744
|
|
1682
|
1745
|
sustGateV[ch] += 1;
|
1683
|
1746
|
|
|
@@ -1722,8 +1785,8 @@ void cmMidiFileCalcNoteDurations( cmMidiFileH_t h )
|
1722
|
1785
|
if( cmMidiFileIsSostenutoPedalDown(m) )
|
1723
|
1786
|
{
|
1724
|
1787
|
// if the sustain channel is already down
|
1725
|
|
- //if( sostGateV[ch] )
|
1726
|
|
- // cmErrWarnMsg(&p->err,kSostenutoPedalMfRC,"%i : The sostenuto pedal went down twice with no intervening release.",m->uid);
|
|
1788
|
+ if( warningFl && sostGateV[ch] )
|
|
1789
|
+ cmErrWarnMsg(&p->err,kSostenutoPedalMfRC,"%i : The sostenuto pedal went down twice with no intervening release.",m->uid);
|
1727
|
1790
|
|
1728
|
1791
|
// record the notes that are active when the sostenuto pedal went down
|
1729
|
1792
|
unsigned k = ch * kMidiNoteCnt;
|
|
@@ -1770,6 +1833,46 @@ void cmMidiFileCalcNoteDurations( cmMidiFileH_t h )
|
1770
|
1833
|
}
|
1771
|
1834
|
|
1772
|
1835
|
} // for each midi file event
|
|
1836
|
+
|
|
1837
|
+
|
|
1838
|
+ if( warningFl )
|
|
1839
|
+ {
|
|
1840
|
+ unsigned sustChN = 0; // count of channels where the sustain pedal was left on at the end of the file
|
|
1841
|
+ unsigned sostChN = 0; // sostenuto
|
|
1842
|
+ unsigned sustInstN = 0; // count of sustain on with no previous sustain off
|
|
1843
|
+ unsigned sostInstN = 0; // sostenuto on
|
|
1844
|
+ unsigned noteN = 0; // count of notes left on at the end of the file
|
|
1845
|
+ unsigned noteInstN = 0; // count of reattacks
|
|
1846
|
+
|
|
1847
|
+ // initialize the state tracking variables
|
|
1848
|
+ for(i=0; i<kMidiChCnt; ++i)
|
|
1849
|
+ {
|
|
1850
|
+ if( sustV[i]!=NULL )
|
|
1851
|
+ sustChN += 1;
|
|
1852
|
+
|
|
1853
|
+ sustInstN += sustGateV[i];
|
|
1854
|
+
|
|
1855
|
+ if( sostV[i] != NULL )
|
|
1856
|
+ sostChN += 1;
|
|
1857
|
+
|
|
1858
|
+ sostInstN += sostGateV[i] = 0;
|
|
1859
|
+
|
|
1860
|
+ for(j=0; j<kMidiNoteCnt; ++j)
|
|
1861
|
+ {
|
|
1862
|
+ noteN += noteM[ i*kMidiNoteCnt + j ] != NULL;
|
|
1863
|
+ noteInstN += noteGateM[ i*kMidiNoteCnt + j ];
|
|
1864
|
+ }
|
|
1865
|
+ }
|
|
1866
|
+
|
|
1867
|
+ cmErrWarnMsg(&p->err,kEventTerminationMfRC,"note:%i inst:%i sustain: %i inst: %i sost: %i inst: %i",noteN,noteInstN,sustChN,sustInstN,sostChN,sostInstN);
|
|
1868
|
+ }
|
|
1869
|
+
|
|
1870
|
+ // drop
|
|
1871
|
+ if( cmIsFlag(flags,kDropReattacksMfFl) )
|
|
1872
|
+ _cmMidiFileDrop(p);
|
|
1873
|
+
|
|
1874
|
+
|
|
1875
|
+
|
1773
|
1876
|
}
|
1774
|
1877
|
|
1775
|
1878
|
void cmMidiFileSetDelay( cmMidiFileH_t h, unsigned ticks )
|
|
@@ -1833,15 +1936,16 @@ void _cmMidiFilePrintHdr( const _cmMidiFile_t* mfp, cmRpt_t* rpt )
|
1833
|
1936
|
|
1834
|
1937
|
cmRptPrintf(rpt,"fmt:%i ticksPerQN:%i tracks:%i\n",mfp->fmtId,mfp->ticksPerQN,mfp->trkN);
|
1835
|
1938
|
|
1836
|
|
- cmRptPrintf(rpt," UID dtick atick amicro type ch D0 D1\n");
|
1837
|
|
- cmRptPrintf(rpt,"----- ---------- ---------- ---------- : ---- --- --- ---\n");
|
|
1939
|
+ cmRptPrintf(rpt," UID trk dtick atick amicro type ch D0 D1\n");
|
|
1940
|
+ cmRptPrintf(rpt,"----- --- ---------- ---------- ---------- : ---- --- --- ---\n");
|
1838
|
1941
|
|
1839
|
1942
|
}
|
1840
|
1943
|
|
1841
|
1944
|
void _cmMidiFilePrintMsg( cmRpt_t* rpt, const cmMidiTrackMsg_t* tmp )
|
1842
|
1945
|
{
|
1843
|
|
- cmRptPrintf(rpt,"%5i %10u %10llu %10llu : ",
|
|
1946
|
+ cmRptPrintf(rpt,"%5i %3i %10u %10llu %10llu : ",
|
1844
|
1947
|
tmp->uid,
|
|
1948
|
+ tmp->trkIdx,
|
1845
|
1949
|
tmp->dtick,
|
1846
|
1950
|
tmp->atick,
|
1847
|
1951
|
tmp->amicro );
|
|
@@ -1980,7 +2084,7 @@ cmMfRC_t cmMidiFileGenPlotFile( cmCtx_t* ctx, const cmChar_t* midiFn, const cmCh
|
1980
|
2084
|
goto errLabel;
|
1981
|
2085
|
}
|
1982
|
2086
|
|
1983
|
|
- cmMidiFileCalcNoteDurations( mfH );
|
|
2087
|
+ cmMidiFileCalcNoteDurations( mfH, 0 );
|
1984
|
2088
|
|
1985
|
2089
|
if( cmFileOpen(&fH,outFn,kWriteFileFl,p->err.rpt) != kOkFileRC )
|
1986
|
2090
|
return cmErrMsg(&p->err,kFileFailMfRC,"Unable to create the file '%s'.",cmStringNullGuard(outFn));
|
|
@@ -2013,7 +2117,7 @@ cmMfRC_t cmMidiFileGenSvgFile( cmCtx_t* ctx, const cmChar_t* midiFn, const cmCha
|
2013
|
2117
|
goto errLabel;
|
2014
|
2118
|
}
|
2015
|
2119
|
|
2016
|
|
- cmMidiFileCalcNoteDurations( mfH );
|
|
2120
|
+ cmMidiFileCalcNoteDurations( mfH, 0 );
|
2017
|
2121
|
|
2018
|
2122
|
msgN = cmMidiFileMsgCount(mfH);
|
2019
|
2123
|
msgs = cmMidiFileMsgArray(mfH);
|
|
@@ -2159,7 +2263,7 @@ void cmMidiFileTest( const char* fn, cmCtx_t* ctx )
|
2159
|
2263
|
return;
|
2160
|
2264
|
}
|
2161
|
2265
|
|
2162
|
|
- cmMidiFileCalcNoteDurations( h );
|
|
2266
|
+ cmMidiFileCalcNoteDurations( h, 0 );
|
2163
|
2267
|
|
2164
|
2268
|
if( 1 )
|
2165
|
2269
|
{
|