Browse Source

Merge branch 'develop' of gitea.larke.org:klarke/libcm into develop

master
kevin 3 years ago
parent
commit
8848b03412
10 changed files with 200 additions and 64 deletions
  1. 2
    1
      src/app/cmMidiScoreFollow.c
  2. 1
    1
      src/app/cmTakeSeqBldr.c
  3. 1
    1
      src/app/cmTimeLine.c
  4. 37
    20
      src/app/cmXScore.c
  5. 3
    3
      src/app/cmXScore.h
  6. 1
    1
      src/cmDList.c
  7. 3
    3
      src/cmMidi.h
  8. 130
    26
      src/cmMidiFile.c
  9. 19
    8
      src/cmMidiFile.h
  10. 3
    0
      src/cmXml.c

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

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

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

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

+ 37
- 20
src/app/cmXScore.c View File

@@ -681,12 +681,13 @@ cmXsRC_t _cmXScoreParseNote(cmXScore_t* p, cmXsMeas_t* meas, const cmXmlNode_t*
681 681
   return _cmXScorePushNote(p, meas, voiceId, note );
682 682
 }
683 683
 
684
-cmXsRC_t _cmXScorePushNonNote( cmXScore_t* p, cmXsMeas_t* meas, const cmXmlNode_t* noteXmlNode, unsigned tick, unsigned duration, double rvalue, const cmChar_t* tvalue, unsigned flags )
684
+cmXsRC_t _cmXScorePushNonNote( cmXScore_t* p, cmXsMeas_t* meas, const cmXmlNode_t* noteXmlNode, unsigned tick, unsigned duration, unsigned staff, double rvalue, const cmChar_t* tvalue, unsigned flags )
685 685
 {
686 686
   cmXsNote_t* note    = cmLhAllocZ(p->lhH,cmXsNote_t,1);
687 687
   unsigned    voiceId = 0;    // non-note's are always assigned to voiceId=0;
688 688
 
689 689
   note->tick     = tick;
690
+  note->staff    = staff;
690 691
   note->flags    = flags;
691 692
   note->rvalue   = rvalue;
692 693
   note->tvalue   = tvalue;
@@ -822,7 +823,7 @@ cmXsRC_t  _cmXScoreParseDirection(cmXScore_t* p, cmXsMeas_t* meas, const cmXmlNo
822 823
   }
823 824
 
824 825
   if( pushFl )
825
-   rc = _cmXScorePushNonNote(p,meas,dnp,tick+offset,duration,rvalue,tvalue,flags);
826
+    rc = _cmXScorePushNonNote(p,meas,dnp,tick+offset,duration,staff,rvalue,tvalue,flags);
826 827
 
827 828
   return rc;
828 829
 }
@@ -868,7 +869,7 @@ cmXsRC_t _cmXScoreParseMeasure(cmXScore_t* p, cmXsPart_t* pp, const cmXmlNode_t*
868 869
   }
869 870
 
870 871
   // store the bar line
871
-  if((rc = _cmXScorePushNonNote(p,meas,mnp,tick,0,0,NULL,kBarXsFl)) != kOkXsRC )
872
+  if((rc = _cmXScorePushNonNote(p,meas,mnp,tick,0,0,0,NULL,kBarXsFl)) != kOkXsRC )
872 873
     return rc;
873 874
 
874 875
   np = mnp->children;
@@ -1562,7 +1563,7 @@ void _cmXScoreFixBarLines( cmXScore_t* p )
1562 1563
 }
1563 1564
 
1564 1565
 // Assign pedal down durations to pedal down events.
1565
-cmXsRC_t _cmXScoreProcessPedals( cmXScore_t* p )
1566
+cmXsRC_t _cmXScoreProcessPedals( cmXScore_t* p, bool reportFl )
1566 1567
 {
1567 1568
   cmXsRC_t    rc = kOkXsRC;
1568 1569
   cmXsPart_t* pp = p->partL;
@@ -1584,11 +1585,14 @@ cmXsRC_t _cmXScoreProcessPedals( cmXScore_t* p )
1584 1585
           case 0:
1585 1586
             break;
1586 1587
             
1587
-          case kDampDnXsFl:
1588
+          case kDampDnXsFl:            
1588 1589
             if( dnp != NULL )
1589 1590
               cmErrWarnMsg(&p->err,kPedalStateErrorXsRc,"Damper down not preceded by damper up in measure:%i.",mp->number);
1590 1591
             else
1591 1592
               dnp = np;
1593
+
1594
+            if( reportFl )
1595
+              cmRptPrintf(p->err.rpt,"Damp Down : staff:%i meas:%i tick:%i\n", np->staff, mp->number, np->tick);
1592 1596
             break;
1593 1597
             
1594 1598
           case kDampUpXsFl:
@@ -1599,6 +1603,10 @@ cmXsRC_t _cmXScoreProcessPedals( cmXScore_t* p )
1599 1603
               dnp->duration = np->tick - dnp->tick;
1600 1604
               dnp = NULL;
1601 1605
             }
1606
+            
1607
+            if( reportFl )
1608
+              cmRptPrintf(p->err.rpt,"Damp Up   : staff:%i meas:%i tick:%i\n", np->staff, mp->number, np->tick);
1609
+            
1602 1610
             break;
1603 1611
             
1604 1612
           case kDampUpDnXsFl:
@@ -1609,13 +1617,19 @@ cmXsRC_t _cmXScoreProcessPedals( cmXScore_t* p )
1609 1617
               dnp->duration = np->tick - dnp->tick;
1610 1618
               dnp = np;
1611 1619
             }
1620
+            
1621
+            if( reportFl )
1622
+              cmRptPrintf(p->err.rpt,"Damp UpDn : staff:%i meas:%i tick:%i\n", np->staff, mp->number, np->tick);
1612 1623
             break;
1613 1624
             
1614 1625
           case kSostDnXsFl:
1615 1626
             if( snp != NULL )
1616 1627
               cmErrWarnMsg(&p->err,kPedalStateErrorXsRc,"Sostenuto down not preceded by sostenuto up in measure:%i.",mp->number);
1617 1628
             else
1618
-              snp = np;            
1629
+              snp = np;
1630
+            
1631
+            if( reportFl )
1632
+              cmRptPrintf(p->err.rpt,"Sost Down : staff:%i meas:%i tick:%i\n", np->staff, mp->number, np->tick);
1619 1633
             break;
1620 1634
             
1621 1635
           case kSostUpXsFl:
@@ -1626,6 +1640,8 @@ cmXsRC_t _cmXScoreProcessPedals( cmXScore_t* p )
1626 1640
               snp->duration = np->tick - snp->tick;
1627 1641
               snp = NULL;
1628 1642
             }
1643
+            if( reportFl )
1644
+              cmRptPrintf(p->err.rpt,"Sost Up   : staff:%i meas:%i tick:%i\n", np->staff, mp->number, np->tick);
1629 1645
             break;
1630 1646
             
1631 1647
           default:
@@ -2706,7 +2722,7 @@ cmXsRC_t _cmXsApplyEditFile( cmXScore_t* p, const cmChar_t* fn )
2706 2722
 
2707 2723
 
2708 2724
 
2709
-cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn, const cmChar_t* editFn )
2725
+cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn, const cmChar_t* editFn, bool damperRptFl )
2710 2726
 {
2711 2727
   cmXsRC_t rc = kOkXsRC;
2712 2728
 
@@ -2771,7 +2787,7 @@ cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn, c
2771 2787
   }
2772 2788
 
2773 2789
   // assign durations to pedal down events
2774
-  _cmXScoreProcessPedals(p);
2790
+  _cmXScoreProcessPedals(p,damperRptFl);
2775 2791
 
2776 2792
   // remove some notes which share a pitch and are overlapped or embedded within another note.
2777 2793
   _cmXScoreProcessOverlappingNotes(p);
@@ -3408,7 +3424,7 @@ void _cmXScoreGenEditFileWrite( void* arg, const cmChar_t* text )
3408 3424
   }
3409 3425
 }
3410 3426
 
3411
-cmXsRC_t cmXScoreGenEditFile( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* outFn )
3427
+cmXsRC_t cmXScoreGenEditFile( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* outFn, bool damperRptFl )
3412 3428
 {
3413 3429
   cmXsH_t   xsH = cmXsNullHandle;
3414 3430
   cmFileH_t fH  = cmFileNullHandle;
@@ -3419,7 +3435,7 @@ cmXsRC_t cmXScoreGenEditFile( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_
3419 3435
   cmErrSetup(&err,&ctx->rpt,"cmXScoreGenEditFile");
3420 3436
   cmRptSetup(&rpt,_cmXScoreGenEditFileWrite,_cmXScoreGenEditFileWrite,&fH);
3421 3437
 
3422
-  if((rc = cmXScoreInitialize(ctx,&xsH,xmlFn,NULL)) != kOkXsRC )
3438
+  if((rc = cmXScoreInitialize(ctx,&xsH,xmlFn,NULL,damperRptFl)) != kOkXsRC )
3423 3439
     return rc;
3424 3440
 
3425 3441
   if( cmFileOpen(&fH,outFn,kWriteFileFl,&ctx->rpt) != kOkFileRC )
@@ -4077,21 +4093,22 @@ cmXsRC_t cmXScoreTest(
4077 4093
   int             beginMeasNumb,
4078 4094
   int             beginBPM,
4079 4095
   bool            standAloneFl,
4080
-  bool            panZoomFl )
4096
+  bool            panZoomFl,
4097
+  bool            damperRptFl)
4081 4098
 {
4082 4099
   cmXsRC_t rc;
4083 4100
   cmXsH_t h = cmXsNullHandle;
4084 4101
 
4085 4102
   if( editFn!=NULL && !cmFsIsFile(editFn) )
4086 4103
   {
4087
-    cmRptPrintf(&ctx->rpt,"The edit file %s does not exist. A new edit file will be created.",editFn);
4088
-    cmXScoreGenEditFile(ctx,xmlFn,editFn);
4104
+    cmRptPrintf(&ctx->rpt,"The edit file %s does not exist. A new edit file will be created.\n",editFn);
4105
+    cmXScoreGenEditFile(ctx,xmlFn,editFn,damperRptFl);
4089 4106
     editFn = NULL;
4090 4107
   }
4091 4108
   
4092 4109
 
4093 4110
   // Parse the XML file and apply the changes in editFn.
4094
-  if((rc = cmXScoreInitialize( ctx, &h, xmlFn,editFn)) != kOkXsRC )
4111
+  if((rc = cmXScoreInitialize( ctx, &h, xmlFn,editFn, damperRptFl )) != kOkXsRC )
4095 4112
     return cmErrMsg(&ctx->err,rc,"XScore alloc failed.");
4096 4113
 
4097 4114
   if( csvOutFn != NULL )
@@ -4101,14 +4118,14 @@ cmXsRC_t cmXScoreTest(
4101 4118
 
4102 4119
     _cmXsIsCsvValid(ctx,h,csvOutFn);
4103 4120
   }
4121
+
4122
+  // measure the score complexity
4123
+  double wndSecs = 1.0;
4124
+    
4125
+  _cmXsMeasComplexity(h,wndSecs);
4104 4126
   
4105 4127
   if( midiOutFn != NULL )
4106
-  {
4107
-    // measure the score complexity
4108
-    double wndSecs = 1.0;
4109
-    
4110
-    _cmXsMeasComplexity(h,wndSecs);
4111
-    
4128
+  {  
4112 4129
     cmFileSysPathPart_t* pp = cmFsPathParts(midiOutFn);
4113 4130
 
4114 4131
     _cmXsWriteMidiFile(ctx, h, beginMeasNumb, beginBPM, pp->dirStr, pp->fnStr );

+ 3
- 3
src/app/cmXScore.h View File

@@ -47,7 +47,7 @@ extern "C" {
47 47
   // Initialize an cmXScore object from a Sibelius generated MusicXML file.
48 48
   // 'editFn' is used to add additional information to the score.
49 49
   // See cmXScoreGenEditFile()
50
-  cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn, const cmChar_t* editFn );
50
+  cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn, const cmChar_t* editFn, bool damperRptFl );
51 51
   cmXsRC_t cmXScoreFinalize( cmXsH_t* hp );
52 52
 
53 53
   
@@ -60,7 +60,7 @@ extern "C" {
60 60
   // Generate a template 'edit file'. This file can be edited by hand to included additional
61 61
   // information in the score. See the 'editFn' argument to cmXScoreInitialize() for where
62 62
   // this file is used.
63
-  cmXsRC_t cmXScoreGenEditFile( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* outFn );
63
+  cmXsRC_t cmXScoreGenEditFile( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* outFn, bool damperRptFl );
64 64
 
65 65
   // Generate the CSV file suitable for use by cmScore.
66 66
   //
@@ -72,7 +72,7 @@ extern "C" {
72 72
   // Set reportFl to true to print a report of the score following processing.
73 73
   // Set begMeasNumb to the first measure the to be written to the output csv, MIDI and SVG files.
74 74
   // Set begBPM to 0 to use the tempo from the score otherwise set it to the tempo at begMeasNumb.
75
-  cmXsRC_t cmXScoreTest( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* reorderFn, const cmChar_t* csvOutFn, const cmChar_t* midiOutFn, const cmChar_t* svgOutFn, bool reportFl, int begMeasNumb, int begBPM, bool svgStandAloneFl, bool svgPanZoomFl );
75
+  cmXsRC_t cmXScoreTest( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* reorderFn, const cmChar_t* csvOutFn, const cmChar_t* midiOutFn, const cmChar_t* svgOutFn, bool reportFl, int begMeasNumb, int begBPM, bool svgStandAloneFl, bool svgPanZoomFl, bool damperRptFl );
76 76
   
77 77
 #ifdef __cplusplus
78 78
 }

+ 1
- 1
src/cmDList.c View File

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

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

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

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

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

Loading…
Cancel
Save