Переглянути джерело

cmMidiFile.h/c : Added flags arg. to cmMidiFileCalcNoteDurations(), Added cmMidiFileIsPedalUp/Down() macro.

cmMidi.h : Fixed bug in cmMidiIsNoteOn() macro.
master
kevin 4 роки тому
джерело
коміт
f3af534ad5

+ 2
- 1
src/app/cmMidiScoreFollow.c Переглянути файл

@@ -149,6 +149,7 @@ unsigned _cmMsf_WriteMatchFileLine( cmFileH_t fH, cmScH_t scH, const cmScMatcher
149 149
   return scUid;
150 150
 }
151 151
 
152
+// This is the score follower callback function 
152 153
 void _cmMsf_ScoreFollowCb( struct cmScMatcher_str* p, void* arg, cmScMatcherResult_t* rp )
153 154
 {
154 155
   _cmMsf_ScoreFollow_t* r = (_cmMsf_ScoreFollow_t*)arg;
@@ -193,7 +194,7 @@ cmMsfRC_t cmMidiScoreFollowMain(
193 194
     goto errLabel;
194 195
   }
195 196
 
196
-  // setup the callback record
197
+  // setup the callback record with an array that has twice as many records as there are score events
197 198
   if((sfr.rAllocN  = cmScoreEvtCount( scH )*2) == 0)
198 199
   {
199 200
     rc = cmErrMsg(&err,kFailMsfRC,"The score %s appears to be empty.",cmStringNullGuard(scoreCsvFn));

+ 1
- 1
src/app/cmTakeSeqBldr.c Переглянути файл

@@ -960,7 +960,7 @@ cmTsbRC_t cmTakeSeqBldrLoadTake( cmTakeSeqBldrH_t h, unsigned tlMarkUid, bool ov
960 960
   //cmMidiFileTickToSamples( mfH, cmTimeLineSampleRate(p->tlH), false );
961 961
   
962 962
   // calculate MIDI note and pedal durations (see cmMidiChMsg_t.durTicks)
963
-  cmMidiFileCalcNoteDurations( mfH );
963
+  cmMidiFileCalcNoteDurations( mfH, 0 );
964 964
   
965 965
   unsigned                 i     = 0;
966 966
   unsigned                 n     = cmMidiFileMsgCount(mfH);

+ 1
- 1
src/app/cmTimeLine.c Переглянути файл

@@ -733,7 +733,7 @@ cmTlRC_t _cmTlAllocMidiFileRecd( _cmTl_t* p, const cmChar_t* nameStr, const cmCh
733 733
   //cmMidiFileTickToSamples(mfH,p->srate,false);
734 734
 
735 735
   // assign note durations to all note-on msg's
736
-  cmMidiFileCalcNoteDurations(mfH);
736
+  cmMidiFileCalcNoteDurations(mfH,0);
737 737
 
738 738
   unsigned recdByteCnt = sizeof(cmTlMidiFile_t) + strlen(fn) + 1;
739 739
 

+ 7
- 7
src/app/cmXScore.c Переглянути файл

@@ -4084,7 +4084,7 @@ cmXsRC_t cmXScoreTest(
4084 4084
 
4085 4085
   if( editFn!=NULL && !cmFsIsFile(editFn) )
4086 4086
   {
4087
-    cmRptPrintf(&ctx->rpt,"The edit file %s does not exist. A new edit file will be created.",editFn);
4087
+    cmRptPrintf(&ctx->rpt,"The edit file %s does not exist. A new edit file will be created.\n",editFn);
4088 4088
     cmXScoreGenEditFile(ctx,xmlFn,editFn);
4089 4089
     editFn = NULL;
4090 4090
   }
@@ -4101,14 +4101,14 @@ cmXsRC_t cmXScoreTest(
4101 4101
 
4102 4102
     _cmXsIsCsvValid(ctx,h,csvOutFn);
4103 4103
   }
4104
+
4105
+  // measure the score complexity
4106
+  double wndSecs = 1.0;
4107
+    
4108
+  _cmXsMeasComplexity(h,wndSecs);
4104 4109
   
4105 4110
   if( midiOutFn != NULL )
4106
-  {
4107
-    // measure the score complexity
4108
-    double wndSecs = 1.0;
4109
-    
4110
-    _cmXsMeasComplexity(h,wndSecs);
4111
-    
4111
+  {  
4112 4112
     cmFileSysPathPart_t* pp = cmFsPathParts(midiOutFn);
4113 4113
 
4114 4114
     _cmXsWriteMidiFile(ctx, h, beginMeasNumb, beginBPM, pp->dirStr, pp->fnStr );

+ 1
- 1
src/cmDList.c Переглянути файл

@@ -150,7 +150,7 @@ void _cmDListIndexFree( cmDList_t* p, cmDListIndex_t* x )
150 150
       // x is the first index
151 151
       if( x0 == NULL )
152 152
       {
153
-        assert( x1 = p->indexes );
153
+        assert( x1 == p->indexes );
154 154
         p->indexes = x->link;
155 155
       }
156 156
       else

+ 3
- 3
src/cmMidi.h Переглянути файл

@@ -88,9 +88,9 @@ extern "C" {
88 88
 #define cmMidiIsStatus( s )   (kNoteOffMdId <= (s) /*&& ((unsigned)(s)) <= kSysRtResetMdId*/ )
89 89
 #define cmMidiIsChStatus( s ) (kNoteOffMdId <= (s) && (s) <  kSysExMdId)
90 90
 
91
-#define cmMidiIsNoteOn( s )      ( kNoteOnMdId <= (s) && (s) <= (kNoteOnMdId + kMidiChCnt) )
92
-#define cmMidiIsNoteOff( s, d1 ) ( (cmMidiIsNoteOn(s) && (d1)==0) || (kNoteOffMdId <= (s) && (s) <= (kNoteOffMdId + kMidiChCnt)) )
93
-#define cmMidiIsCtl( s )         ( kCtlMdId <= (s) && (s) <= (kCtlMdId + kMidiChCnt) )
91
+#define cmMidiIsNoteOn( s )      ( kNoteOnMdId <= (s) && (s) < (kNoteOnMdId + kMidiChCnt) )
92
+#define cmMidiIsNoteOff( s, d1 ) ( (cmMidiIsNoteOn(s) && (d1)==0) || (kNoteOffMdId <= (s) && (s) < (kNoteOffMdId + kMidiChCnt)) )
93
+#define cmMidiIsCtl( s )         ( kCtlMdId <= (s) && (s) < (kCtlMdId + kMidiChCnt) )
94 94
 
95 95
 #define cmMidiIsSustainPedal(     s, d0 )    ( kCtlMdId <= (s) && (s) <= (kCtlMdId + kMidiChCnt) && (d0)== kSustainCtlMdId )
96 96
 #define cmMidiIsSustainPedalDown( s, d0, d1) ( cmMidiIsSustainPedal(s,d0) && (d1)>=64 )

+ 130
- 26
src/cmMidiFile.c Переглянути файл

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

+ 19
- 8
src/cmMidiFile.h Переглянути файл

@@ -63,11 +63,16 @@ extern "C" {
63 63
     struct cmMidiTrackMsg_str* end; // note-off or pedal-up message
64 64
   } cmMidiChMsg_t;
65 65
 
66
+  enum
67
+  {
68
+   kDropTrkMsgFl = 0x01
69
+  };
66 70
 
67 71
   typedef struct cmMidiTrackMsg_str
68 72
   {
73
+    unsigned                   flags;   // see k???TrkMsgFl
69 74
     unsigned                   uid;     // uid's are unique among all msg's in the file
70
-    unsigned                   dtick;   // delta ticks between events on this track
75
+    unsigned                   dtick;   // delta ticks between events on this track (ticks between this event and the previous event on this track)
71 76
     unsigned long long         atick;   // global (all tracks interleaved) accumulated ticks
72 77
     unsigned long long         amicro;  // global (all tracks interleaved) accumulated microseconds adjusted for tempo changes
73 78
     cmMidiByte_t               status;  // ch msg's have the channel value removed (it is stored in u.chMsgPtr->ch)
@@ -91,9 +96,12 @@ extern "C" {
91 96
     } u;
92 97
   } cmMidiTrackMsg_t;
93 98
 
94
-#define cmMidiFileIsNoteOn(m)         (cmMidiIsNoteOn((m)->status) && (m)->u.chMsgPtr->d1>0)
99
+#define cmMidiFileIsNoteOn(m)         (cmMidiIsNoteOn((m)->status) && ((m)->u.chMsgPtr->d1>0))
95 100
 #define cmMidiFileIsNoteOff(m)        (cmMidiIsNoteOff((m)->status,(m)->u.chMsgPtr->d1))
96
-  
101
+
102
+#define cmMidiFileIsPedalUp(m)        (cmMidiIsPedalUp(    (m)->status, (m)->u.chMsgPtr->d0, (m)->u.chMsgPtr->d1) )
103
+#define cmMidiFileIsPedalDown(m)      (cmMidiIsPedalDown(  (m)->status, (m)->u.chMsgPtr->d0, (m)->u.chMsgPtr->d1) )
104
+
97 105
 #define cmMidiFileIsSustainPedalUp(m)     (cmMidiIsSustainPedalUp(    (m)->status,(m)->u.chMsgPtr->d0,(m)->u.chMsgPtr->d1))
98 106
 #define cmMidiFileIsSustainPedalDown(m)   (cmMidiIsSustainPedalDown(  (m)->status,(m)->u.chMsgPtr->d0,(m)->u.chMsgPtr->d1))
99 107
   
@@ -118,7 +126,9 @@ extern "C" {
118 126
     kUidNotFoundMfRC,    // 13
119 127
     kUidNotANoteMsgMfRC, // 14
120 128
     kInvalidTrkIndexMfRC,// 15
121
-    kSvgFailMfRC         // 16
129
+    kSvgFailMfRC,        // 16
130
+    kMsgNotFoundMfRC,     // 17
131
+    kEventTerminationMfRC // 18
122 132
   };
123 133
 
124 134
   extern cmMidiFileH_t cmMidiFileNullHandle;
@@ -172,6 +182,7 @@ extern "C" {
172 182
   // Set the velocity of a note-on/off msg identified by 'uid'.
173 183
   cmMfRC_t             cmMidiFileSetVelocity( cmMidiFileH_t h, unsigned uid, cmMidiByte_t vel );
174 184
 
185
+  
175 186
   // Insert a MIDI message relative to the reference msg identified by 'uid'.
176 187
   // If dtick is positive/negative then the new msg is inserted after/before the reference msg.  
177 188
   cmMfRC_t             cmMidiFileInsertMsg( cmMidiFileH_t h, unsigned uid, int dtick, cmMidiByte_t ch, cmMidiByte_t status, cmMidiByte_t d0, cmMidiByte_t d1 );
@@ -199,8 +210,9 @@ extern "C" {
199 210
 
200 211
   double                cmMidiFileDurSecs( cmMidiFileH_t h );
201 212
 
202
-  // Calculate Note Duration 
203
-  void                  cmMidiFileCalcNoteDurations( cmMidiFileH_t h );
213
+  // Calculate Note Duration
214
+  enum { kWarningsMfFl=0x01, kDropReattacksMfFl=0x02 };
215
+  void                  cmMidiFileCalcNoteDurations( cmMidiFileH_t h, unsigned flags );
204 216
 
205 217
   // Set the delay prior to the first non-zero msg.
206 218
   void                  cmMidiFileSetDelay( cmMidiFileH_t h, unsigned ticks );
@@ -218,8 +230,7 @@ extern "C" {
218 230
   {
219 231
     unsigned           uid;
220 232
     unsigned long long amicro;
221
-    unsigned           density;
222
-    
233
+    unsigned           density; 
223 234
   } cmMidiFileDensity_t;
224 235
 
225 236
   // Generate the note onset density measure for each note in the MIDI file.

+ 3
- 0
src/cmXml.c Переглянути файл

@@ -650,6 +650,9 @@ cmXmlRC_t _cmXmlReadNode( cmXml_t* p, cmXmlNode_t* parent )
650 650
       return rc;
651 651
     }
652 652
 
653
+    if( np==NULL && p->stack==NULL)
654
+      break;
655
+
653 656
     // if an  end-tag was just read or node was created but closed then pop the stack
654 657
     if( np==NULL || (np==p->stack && cmIsFlag(np->flags,kClosedXmlFl)) )
655 658
       p->stack = p->stack->parent;

Завантаження…
Відмінити
Зберегти