Browse Source

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

cmMidi.h : Fixed bug in cmMidiIsNoteOn() macro.
master
kevin 3 years ago
parent
commit
f3af534ad5
9 changed files with 167 additions and 48 deletions
  1. 2
    1
      src/app/cmMidiScoreFollow.c
  2. 1
    1
      src/app/cmTakeSeqBldr.c
  3. 1
    1
      src/app/cmTimeLine.c
  4. 7
    7
      src/app/cmXScore.c
  5. 1
    1
      src/cmDList.c
  6. 3
    3
      src/cmMidi.h
  7. 130
    26
      src/cmMidiFile.c
  8. 19
    8
      src/cmMidiFile.h
  9. 3
    0
      src/cmXml.c

+ 2
- 1
src/app/cmMidiScoreFollow.c View File

149
   return scUid;
149
   return scUid;
150
 }
150
 }
151
 
151
 
152
+// This is the score follower callback function 
152
 void _cmMsf_ScoreFollowCb( struct cmScMatcher_str* p, void* arg, cmScMatcherResult_t* rp )
153
 void _cmMsf_ScoreFollowCb( struct cmScMatcher_str* p, void* arg, cmScMatcherResult_t* rp )
153
 {
154
 {
154
   _cmMsf_ScoreFollow_t* r = (_cmMsf_ScoreFollow_t*)arg;
155
   _cmMsf_ScoreFollow_t* r = (_cmMsf_ScoreFollow_t*)arg;
193
     goto errLabel;
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
   if((sfr.rAllocN  = cmScoreEvtCount( scH )*2) == 0)
198
   if((sfr.rAllocN  = cmScoreEvtCount( scH )*2) == 0)
198
   {
199
   {
199
     rc = cmErrMsg(&err,kFailMsfRC,"The score %s appears to be empty.",cmStringNullGuard(scoreCsvFn));
200
     rc = cmErrMsg(&err,kFailMsfRC,"The score %s appears to be empty.",cmStringNullGuard(scoreCsvFn));

+ 1
- 1
src/app/cmTakeSeqBldr.c View File

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

+ 1
- 1
src/app/cmTimeLine.c View File

733
   //cmMidiFileTickToSamples(mfH,p->srate,false);
733
   //cmMidiFileTickToSamples(mfH,p->srate,false);
734
 
734
 
735
   // assign note durations to all note-on msg's
735
   // assign note durations to all note-on msg's
736
-  cmMidiFileCalcNoteDurations(mfH);
736
+  cmMidiFileCalcNoteDurations(mfH,0);
737
 
737
 
738
   unsigned recdByteCnt = sizeof(cmTlMidiFile_t) + strlen(fn) + 1;
738
   unsigned recdByteCnt = sizeof(cmTlMidiFile_t) + strlen(fn) + 1;
739
 
739
 

+ 7
- 7
src/app/cmXScore.c View File

4084
 
4084
 
4085
   if( editFn!=NULL && !cmFsIsFile(editFn) )
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
     cmXScoreGenEditFile(ctx,xmlFn,editFn);
4088
     cmXScoreGenEditFile(ctx,xmlFn,editFn);
4089
     editFn = NULL;
4089
     editFn = NULL;
4090
   }
4090
   }
4101
 
4101
 
4102
     _cmXsIsCsvValid(ctx,h,csvOutFn);
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
   if( midiOutFn != NULL )
4110
   if( midiOutFn != NULL )
4106
-  {
4107
-    // measure the score complexity
4108
-    double wndSecs = 1.0;
4109
-    
4110
-    _cmXsMeasComplexity(h,wndSecs);
4111
-    
4111
+  {  
4112
     cmFileSysPathPart_t* pp = cmFsPathParts(midiOutFn);
4112
     cmFileSysPathPart_t* pp = cmFsPathParts(midiOutFn);
4113
 
4113
 
4114
     _cmXsWriteMidiFile(ctx, h, beginMeasNumb, beginBPM, pp->dirStr, pp->fnStr );
4114
     _cmXsWriteMidiFile(ctx, h, beginMeasNumb, beginBPM, pp->dirStr, pp->fnStr );

+ 1
- 1
src/cmDList.c View File

150
       // x is the first index
150
       // x is the first index
151
       if( x0 == NULL )
151
       if( x0 == NULL )
152
       {
152
       {
153
-        assert( x1 = p->indexes );
153
+        assert( x1 == p->indexes );
154
         p->indexes = x->link;
154
         p->indexes = x->link;
155
       }
155
       }
156
       else
156
       else

+ 3
- 3
src/cmMidi.h View File

88
 #define cmMidiIsStatus( s )   (kNoteOffMdId <= (s) /*&& ((unsigned)(s)) <= kSysRtResetMdId*/ )
88
 #define cmMidiIsStatus( s )   (kNoteOffMdId <= (s) /*&& ((unsigned)(s)) <= kSysRtResetMdId*/ )
89
 #define cmMidiIsChStatus( s ) (kNoteOffMdId <= (s) && (s) <  kSysExMdId)
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
 #define cmMidiIsSustainPedal(     s, d0 )    ( kCtlMdId <= (s) && (s) <= (kCtlMdId + kMidiChCnt) && (d0)== kSustainCtlMdId )
95
 #define cmMidiIsSustainPedal(     s, d0 )    ( kCtlMdId <= (s) && (s) <= (kCtlMdId + kMidiChCnt) && (d0)== kSustainCtlMdId )
96
 #define cmMidiIsSustainPedalDown( s, d0, d1) ( cmMidiIsSustainPedal(s,d0) && (d1)>=64 )
96
 #define cmMidiIsSustainPedalDown( s, d0, d1) ( cmMidiIsSustainPedal(s,d0) && (d1)>=64 )

+ 130
- 26
src/cmMidiFile.c View File

423
   return rc;
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
 int _cmMidiFileSortFunc( const void *p0, const void* p1 )
454
 int _cmMidiFileSortFunc( const void *p0, const void* p1 )
427
 {  
455
 {  
428
   if( (*(cmMidiTrackMsg_t**)p0)->atick == (*(cmMidiTrackMsg_t**)p1)->atick )
456
   if( (*(cmMidiTrackMsg_t**)p0)->atick == (*(cmMidiTrackMsg_t**)p1)->atick )
1369
   mfp->msgVDirtyFl = true;
1397
   mfp->msgVDirtyFl = true;
1370
 
1398
 
1371
   return kOkMfRC;
1399
   return kOkMfRC;
1372
-
1373
 }
1400
 }
1374
 
1401
 
1375
 cmMfRC_t  cmMidiFileInsertTrackMsg( cmMidiFileH_t h, unsigned trkIdx, const cmMidiTrackMsg_t* msg )
1402
 cmMfRC_t  cmMidiFileInsertTrackMsg( cmMidiFileH_t h, unsigned trkIdx, const cmMidiTrackMsg_t* msg )
1532
   return mi;
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
 double  cmMidiFileDurSecs( cmMidiFileH_t h )
1594
 double  cmMidiFileDurSecs( cmMidiFileH_t h )
1536
 {
1595
 {
1537
   _cmMidiFile_t* mfp = _cmMidiFileHandleToPtr(h);
1596
   _cmMidiFile_t* mfp = _cmMidiFileHandleToPtr(h);
1544
   return msgV[ mfp->msgN-1 ]->amicro / 1000000.0;
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
 void _cmMidiFileSetDur( cmMidiTrackMsg_t* m0, cmMidiTrackMsg_t* m1 )
1607
 void _cmMidiFileSetDur( cmMidiTrackMsg_t* m0, cmMidiTrackMsg_t* m1 )
1557
 {
1608
 {
1574
   return true;
1625
   return true;
1575
 }
1626
 }
1576
 
1627
 
1577
-void cmMidiFileCalcNoteDurations( cmMidiFileH_t h )
1628
+void cmMidiFileCalcNoteDurations( cmMidiFileH_t h, unsigned flags )
1578
 {
1629
 {
1579
   _cmMidiFile_t* p;
1630
   _cmMidiFile_t* p;
1580
-
1631
+  bool warningFl = cmIsFlag(flags,kWarningsMfFl);
1632
+  
1581
   if((p = _cmMidiFileHandleToPtr(h)) == NULL )
1633
   if((p = _cmMidiFileHandleToPtr(h)) == NULL )
1582
     return;
1634
     return;
1583
 
1635
 
1586
 
1638
 
1587
   unsigned          mi = cmInvalidId;
1639
   unsigned          mi = cmInvalidId;
1588
   cmMidiTrackMsg_t* noteM[     kMidiNoteCnt * kMidiChCnt ];  // ptr to note-on or NULL if the note is not sounding
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
   int               noteGateM[ kMidiNoteCnt * kMidiChCnt ];  // true if the associated note key is depressed
1643
   int               noteGateM[ kMidiNoteCnt * kMidiChCnt ];  // true if the associated note key is depressed
1592
   bool              sostGateM[ kMidiNoteCnt * kMidiChCnt ];  // true if the associated note was active when the sost. pedal went down
1644
   bool              sostGateM[ kMidiNoteCnt * kMidiChCnt ];  // true if the associated note was active when the sost. pedal went down
1593
   int               sustGateV[ kMidiChCnt];                  // true if the associated sustain pedal is down
1645
   int               sustGateV[ kMidiChCnt];                  // true if the associated sustain pedal is down
1594
   int               sostGateV[ kMidiChCnt];                  // true if the associated sostenuto pedal is down
1646
   int               sostGateV[ kMidiChCnt];                  // true if the associated sostenuto pedal is down
1595
   unsigned          i,j;
1647
   unsigned          i,j;
1648
+  unsigned          n = 0;
1596
   
1649
   
1597
   const cmMidiTrackMsg_t** msgV = _cmMidiFileMsgArray(p);
1650
   const cmMidiTrackMsg_t** msgV = _cmMidiFileMsgArray(p);
1598
   
1651
   
1634
       unsigned  k = ch*kMidiNoteCnt + d0;
1687
       unsigned  k = ch*kMidiNoteCnt + d0;
1635
 
1688
 
1636
       // there should be no existing sounding note instance for this pitch
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
       if( noteM[k] != NULL )
1703
       if( noteM[k] != NULL )
1641
         noteGateM[k] += 1;
1704
         noteGateM[k] += 1;
1642
-      else
1705
+      else // this is a new attack
1643
       {
1706
       {
1644
         noteM[k]     = m;
1707
         noteM[k]     = m;
1645
         noteGateM[k] = 1;
1708
         noteGateM[k] = 1;
1676
         if( cmMidiFileIsSustainPedalDown(m) )
1739
         if( cmMidiFileIsSustainPedalDown(m) )
1677
         {
1740
         {
1678
           // if the sustain channel is already down
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
           sustGateV[ch] += 1;
1745
           sustGateV[ch] += 1;
1683
 
1746
 
1722
             if( cmMidiFileIsSostenutoPedalDown(m) )
1785
             if( cmMidiFileIsSostenutoPedalDown(m) )
1723
             {
1786
             {
1724
               // if the sustain channel is already down
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
               // record the notes that are active when the sostenuto pedal went down
1791
               // record the notes that are active when the sostenuto pedal went down
1729
               unsigned k = ch * kMidiNoteCnt;
1792
               unsigned k = ch * kMidiNoteCnt;
1770
               }
1833
               }
1771
     
1834
     
1772
   } // for each midi file event
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
 void cmMidiFileSetDelay( cmMidiFileH_t h, unsigned ticks )
1878
 void cmMidiFileSetDelay( cmMidiFileH_t h, unsigned ticks )
1833
 
1936
 
1834
   cmRptPrintf(rpt,"fmt:%i ticksPerQN:%i tracks:%i\n",mfp->fmtId,mfp->ticksPerQN,mfp->trkN);
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
 void _cmMidiFilePrintMsg( cmRpt_t* rpt, const cmMidiTrackMsg_t* tmp )
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
     tmp->uid,
1947
     tmp->uid,
1948
+    tmp->trkIdx,
1845
     tmp->dtick,
1949
     tmp->dtick,
1846
     tmp->atick,
1950
     tmp->atick,
1847
     tmp->amicro );
1951
     tmp->amicro );
1980
     goto errLabel;
2084
     goto errLabel;
1981
   }
2085
   }
1982
   
2086
   
1983
-  cmMidiFileCalcNoteDurations( mfH );
2087
+  cmMidiFileCalcNoteDurations( mfH, 0 );
1984
   
2088
   
1985
   if( cmFileOpen(&fH,outFn,kWriteFileFl,p->err.rpt) != kOkFileRC )
2089
   if( cmFileOpen(&fH,outFn,kWriteFileFl,p->err.rpt) != kOkFileRC )
1986
     return cmErrMsg(&p->err,kFileFailMfRC,"Unable to create the file '%s'.",cmStringNullGuard(outFn));
2090
     return cmErrMsg(&p->err,kFileFailMfRC,"Unable to create the file '%s'.",cmStringNullGuard(outFn));
2013
     goto errLabel;
2117
     goto errLabel;
2014
   }
2118
   }
2015
 
2119
 
2016
- cmMidiFileCalcNoteDurations( mfH );
2120
+  cmMidiFileCalcNoteDurations( mfH, 0 );
2017
 
2121
 
2018
   msgN = cmMidiFileMsgCount(mfH);
2122
   msgN = cmMidiFileMsgCount(mfH);
2019
   msgs = cmMidiFileMsgArray(mfH);
2123
   msgs = cmMidiFileMsgArray(mfH);
2159
     return;
2263
     return;
2160
   }
2264
   }
2161
 
2265
 
2162
-  cmMidiFileCalcNoteDurations(  h );
2266
+  cmMidiFileCalcNoteDurations(  h, 0 );
2163
 
2267
 
2164
   if( 1 )
2268
   if( 1 )
2165
   {
2269
   {

+ 19
- 8
src/cmMidiFile.h View File

63
     struct cmMidiTrackMsg_str* end; // note-off or pedal-up message
63
     struct cmMidiTrackMsg_str* end; // note-off or pedal-up message
64
   } cmMidiChMsg_t;
64
   } cmMidiChMsg_t;
65
 
65
 
66
+  enum
67
+  {
68
+   kDropTrkMsgFl = 0x01
69
+  };
66
 
70
 
67
   typedef struct cmMidiTrackMsg_str
71
   typedef struct cmMidiTrackMsg_str
68
   {
72
   {
73
+    unsigned                   flags;   // see k???TrkMsgFl
69
     unsigned                   uid;     // uid's are unique among all msg's in the file
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
     unsigned long long         atick;   // global (all tracks interleaved) accumulated ticks
76
     unsigned long long         atick;   // global (all tracks interleaved) accumulated ticks
72
     unsigned long long         amicro;  // global (all tracks interleaved) accumulated microseconds adjusted for tempo changes
77
     unsigned long long         amicro;  // global (all tracks interleaved) accumulated microseconds adjusted for tempo changes
73
     cmMidiByte_t               status;  // ch msg's have the channel value removed (it is stored in u.chMsgPtr->ch)
78
     cmMidiByte_t               status;  // ch msg's have the channel value removed (it is stored in u.chMsgPtr->ch)
91
     } u;
96
     } u;
92
   } cmMidiTrackMsg_t;
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
 #define cmMidiFileIsNoteOff(m)        (cmMidiIsNoteOff((m)->status,(m)->u.chMsgPtr->d1))
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
 #define cmMidiFileIsSustainPedalUp(m)     (cmMidiIsSustainPedalUp(    (m)->status,(m)->u.chMsgPtr->d0,(m)->u.chMsgPtr->d1))
105
 #define cmMidiFileIsSustainPedalUp(m)     (cmMidiIsSustainPedalUp(    (m)->status,(m)->u.chMsgPtr->d0,(m)->u.chMsgPtr->d1))
98
 #define cmMidiFileIsSustainPedalDown(m)   (cmMidiIsSustainPedalDown(  (m)->status,(m)->u.chMsgPtr->d0,(m)->u.chMsgPtr->d1))
106
 #define cmMidiFileIsSustainPedalDown(m)   (cmMidiIsSustainPedalDown(  (m)->status,(m)->u.chMsgPtr->d0,(m)->u.chMsgPtr->d1))
99
   
107
   
118
     kUidNotFoundMfRC,    // 13
126
     kUidNotFoundMfRC,    // 13
119
     kUidNotANoteMsgMfRC, // 14
127
     kUidNotANoteMsgMfRC, // 14
120
     kInvalidTrkIndexMfRC,// 15
128
     kInvalidTrkIndexMfRC,// 15
121
-    kSvgFailMfRC         // 16
129
+    kSvgFailMfRC,        // 16
130
+    kMsgNotFoundMfRC,     // 17
131
+    kEventTerminationMfRC // 18
122
   };
132
   };
123
 
133
 
124
   extern cmMidiFileH_t cmMidiFileNullHandle;
134
   extern cmMidiFileH_t cmMidiFileNullHandle;
172
   // Set the velocity of a note-on/off msg identified by 'uid'.
182
   // Set the velocity of a note-on/off msg identified by 'uid'.
173
   cmMfRC_t             cmMidiFileSetVelocity( cmMidiFileH_t h, unsigned uid, cmMidiByte_t vel );
183
   cmMfRC_t             cmMidiFileSetVelocity( cmMidiFileH_t h, unsigned uid, cmMidiByte_t vel );
174
 
184
 
185
+  
175
   // Insert a MIDI message relative to the reference msg identified by 'uid'.
186
   // Insert a MIDI message relative to the reference msg identified by 'uid'.
176
   // If dtick is positive/negative then the new msg is inserted after/before the reference msg.  
187
   // If dtick is positive/negative then the new msg is inserted after/before the reference msg.  
177
   cmMfRC_t             cmMidiFileInsertMsg( cmMidiFileH_t h, unsigned uid, int dtick, cmMidiByte_t ch, cmMidiByte_t status, cmMidiByte_t d0, cmMidiByte_t d1 );
188
   cmMfRC_t             cmMidiFileInsertMsg( cmMidiFileH_t h, unsigned uid, int dtick, cmMidiByte_t ch, cmMidiByte_t status, cmMidiByte_t d0, cmMidiByte_t d1 );
199
 
210
 
200
   double                cmMidiFileDurSecs( cmMidiFileH_t h );
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
   // Set the delay prior to the first non-zero msg.
217
   // Set the delay prior to the first non-zero msg.
206
   void                  cmMidiFileSetDelay( cmMidiFileH_t h, unsigned ticks );
218
   void                  cmMidiFileSetDelay( cmMidiFileH_t h, unsigned ticks );
218
   {
230
   {
219
     unsigned           uid;
231
     unsigned           uid;
220
     unsigned long long amicro;
232
     unsigned long long amicro;
221
-    unsigned           density;
222
-    
233
+    unsigned           density; 
223
   } cmMidiFileDensity_t;
234
   } cmMidiFileDensity_t;
224
 
235
 
225
   // Generate the note onset density measure for each note in the MIDI file.
236
   // Generate the note onset density measure for each note in the MIDI file.

+ 3
- 0
src/cmXml.c View File

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

Loading…
Cancel
Save