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

cmXScore.h/c : Added _cmXScoreAbsoluteTime(),_cmXScoreSpreadGraceNotes(),_cmXScoreSetMeasGroups()

master
kevin 8 роки тому
джерело
коміт
f9505d0f43
2 змінених файлів з 275 додано та 234 видалено
  1. 273
    232
      app/cmXScore.c
  2. 2
    2
      app/cmXScore.h

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

@@ -67,10 +67,16 @@ typedef struct cmXsNote_str
67 67
   unsigned                    staff;    // 1=treble 2=bass
68 68
   unsigned                    tick;     // 
69 69
   unsigned                    duration; // duration in ticks
70
-  unsigned                    locIdx;    // location index (chords share the same location index)
70
+  double                      secs;     // absolute time in seconds
71
+  double                      dsecs;    // delta time in seconds since previous event
72
+  unsigned                    locIdx;   // location index (chords share the same location index)
71 73
   double                      rvalue;   // 1/rvalue = rythmic value (1/0.5 double whole 1/1 whole 1/2 half 1/4=quarter note, 1/8=eighth note, ...)
72 74
   const cmChar_t*             tvalue;   // text value
73 75
 
76
+  unsigned                    evenGroupId;   // eveness group id
77
+  unsigned                    dynGroupId;    // dynamics group id
78
+  unsigned                    tempoGroupId;  // tempo group id
79
+
74 80
   struct cmXsVoice_str*       voice;    // voice this note belongs to 
75 81
   struct cmXsMeas_str*        meas;     // measure this note belongs to
76 82
 
@@ -275,8 +281,8 @@ cmXsRC_t  _cmXScoreParsePitch( cmXScore_t* p, const cmXmlNode_t* nnp, cmXsNote_t
275 281
   cmChar_t buf[3] = { *step, '0', '\0'};
276 282
   unsigned midi = cmSciPitchToMidi(buf);
277 283
 
278
-  midi         += (12 * octave);
279
-  midi         += alter;
284
+  midi      += (12 * octave);
285
+  midi      += alter;
280 286
 
281 287
   np->pitch  = midi;
282 288
   np->step   = *step;
@@ -522,15 +528,15 @@ cmXsRC_t _cmXScorePushOctaveShift(cmXScore_t* p, cmXsMeas_t* meas, unsigned staf
522 528
   }
523 529
   else
524 530
   {
525
-    s = cmLhAllocZ(p->lhH,cmXsSpan_t,1);
526
-    s->staff  = staff;
527
-    s->meas   = meas;
528
-    s->number = span_number;
529
-    s->tick0  = tick;
530
-    s->tick1  = -1;
531
+    s               = cmLhAllocZ(p->lhH,cmXsSpan_t,1);
532
+    s->staff        = staff;
533
+    s->meas         = meas;
534
+    s->number       = span_number;
535
+    s->tick0        = tick;
536
+    s->tick1        = -1;
531 537
     s->pitch_offset = cmTextCmp(type_str,"up")==0 ? -12 : 12;
532
-    s->link   = p->spanL;
533
-    p->spanL  = s;    
538
+    s->link         = p->spanL;
539
+    p->spanL        = s;    
534 540
   }
535 541
 
536 542
   return kOkXsRC;
@@ -731,9 +737,16 @@ cmXsRC_t _cmXScoreParsePart( cmXScore_t* p, cmXsPart_t* pp )
731 737
 // Return a pointer to the base of the list after the insertion.
732 738
 cmXsNote_t*  _cmXScoreInsertSortedNote( cmXsNote_t* s0, cmXsNote_t* np )
733 739
 {
740
+  assert( np != NULL );
741
+
742
+  // np->slink is not NULL if the list is being resorted
743
+  np->slink = NULL;
744
+
745
+  // this list is empty so np is the first element on the list
734 746
   if( s0 == NULL )
735 747
     return np;
736 748
 
749
+  // np is before the first element on the list
737 750
   if( np->tick < s0->tick )
738 751
   {
739 752
     np->slink = s0;
@@ -770,7 +783,10 @@ void _cmXScoreSort( cmXScore_t* p )
770 783
     // for each measure in this part
771 784
     cmXsMeas_t* mp = pp->measL;
772 785
     for(; mp!=NULL; mp=mp->link)
773
-    {   
786
+    {
787
+      // explicitely set noteL to NULL to in case we are re-sorting
788
+      mp->noteL = NULL;
789
+      
774 790
       // for each voice in this measure
775 791
       cmXsVoice_t* vp = mp->voiceL;
776 792
       for(; vp!=NULL; vp=vp->link)
@@ -784,6 +800,157 @@ void _cmXScoreSort( cmXScore_t* p )
784 800
   }
785 801
 }
786 802
 
803
+void _cmXScoreSetAbsoluteTime( cmXScore_t* p )
804
+{
805
+  double          tpqn         = 0; // ticks per quarter note
806
+  double          tps          = 0; // ticks per second
807
+  unsigned        metro_tick   = 0;
808
+  double          metro_sec    = 0;
809
+  double          sec0         = 0;
810
+  
811
+  cmXsPart_t* pp = p->partL;
812
+  for(; pp!=NULL; pp=pp->link)
813
+  {
814
+    cmXsMeas_t* mp = pp->measL;
815
+    for(; mp!=NULL; mp=mp->link) 
816
+    {
817
+      if( mp->divisions != 0 )
818
+        tpqn = mp->divisions;
819
+      
820
+      cmXsNote_t* np = mp->noteL;
821
+      
822
+      for(; np!=NULL; np=np->slink)
823
+      {
824
+
825
+        // Seconds are calculated as:
826
+        // dticks = np->tick - metro_tick;     // where metro_tick is the absolute tick of the last metro event
827
+        // secs   = (dticks/tps) + metro_secs; // where metro_secs is the absoute time of the last metro event
828
+        
829
+        unsigned dticks = np->tick - metro_tick;
830
+        double   secs   = tps==0 ? 0 : (dticks/tps) + metro_sec;
831
+        double   dsecs  = secs - sec0;
832
+
833
+        //  
834
+        if( cmIsFlag(np->flags,kMetronomeXsFl) )
835
+        {
836
+          double bpm = np->duration;
837
+          double bps = bpm / 60.0;
838
+          tps        = bps * tpqn;
839
+          metro_tick = np->tick;
840
+          metro_sec  = secs;
841
+        }
842
+
843
+        if( cmIsFlag(np->flags,kBarXsFl|kPedalDnXsFl|kPedalUpXsFl|kPedalUpDnXsFl|kOnsetXsFl|kSectionXsFl) )
844
+        {
845
+          np->secs  = secs;
846
+          np->dsecs = dsecs;
847
+          sec0      = secs;
848
+        }
849
+      }
850
+    }
851
+  }  
852
+}
853
+
854
+// All notes in a[aN] are on the same tick
855
+unsigned  _cmXsSpreadGraceNotes( cmXsNote_t** a, unsigned aN )
856
+{
857
+  unsigned i;
858
+  bool barFl = false;
859
+
860
+  // set barFl to true if a bar marker is included in the notes
861
+  for(i=0; i<aN; ++i)
862
+    if( cmIsFlag(a[i]->flags,kBarXsFl) )
863
+      barFl = true;
864
+
865
+  // spread any grace notes by one tick
866
+  unsigned nextGraceTick = UINT_MAX;
867
+  for(i=0; i<aN; ++i)
868
+    if( cmIsFlag(a[i]->flags,kGraceXsFl) )
869
+    {
870
+      if( nextGraceTick == UINT_MAX )
871
+        nextGraceTick = a[i]->tick + 1;
872
+      else
873
+      {
874
+        a[i]->tick     = nextGraceTick;
875
+        nextGraceTick += 1;
876
+      }
877
+    }
878
+
879
+  // if this tick group includes the bar ... 
880
+  if( barFl && nextGraceTick != UINT_MAX )
881
+  {
882
+    // ... then move all non-grace note events (except the bar marker) after
883
+    // the grace notes
884
+    for(i=0; i<aN; ++i)
885
+      if( cmIsNotFlag(a[i]->flags,kGraceXsFl) && cmIsNotFlag(a[i]->flags,kBarXsFl) )
886
+        a[i]->tick = nextGraceTick;
887
+  }
888
+  
889
+  return nextGraceTick==UINT_MAX ? 0 : nextGraceTick;
890
+}
891
+
892
+void _cmXScoreSpreadGraceNotes( cmXScore_t* p )
893
+{
894
+  cmXsPart_t* pp = p->partL;
895
+  for(; pp!=NULL; pp=pp->link)
896
+  {
897
+    // tick1 is the location of the minimum current tick
898
+    // (or 0 if it should be ignored)
899
+    unsigned    tick1 = 0; 
900
+    
901
+    cmXsMeas_t* mp = pp->measL;
902
+    for(; mp!=NULL; mp=mp->link)
903
+    {
904
+      cmXsNote_t* np = mp->noteL;
905
+      unsigned    aN = 128;
906
+      cmXsNote_t* a[ aN ];
907
+      unsigned    ai = 0;
908
+
909
+      // The first event in a measure may have been forced ahead
910
+      // by spreading at the end of the previous measure
911
+      if( tick1 > np->tick )
912
+        np->tick = tick1;
913
+      else
914
+        tick1 = 0;
915
+
916
+      // tick0 is the tick of the current tick group we are examining
917
+      // A tick group is a group of events that share the same tick.
918
+      unsigned    tick0 = np->tick;
919
+      
920
+      for(; np!=NULL; np=np->slink)
921
+      {
922
+        // if this event is the first of a new tick group
923
+        if( np->tick != tick0 )
924
+        {
925
+          // if there is more than one event in the completed tick group ...
926
+          if( ai > 1 )
927
+            tick1 = _cmXsSpreadGraceNotes(a,ai); // ... then process the group
928
+
929
+          
930
+          ai    = 0;        // empty the tick group array
931
+          tick0 = np->tick; // update the current group's common tick
932
+        }
933
+
934
+        // if the min. current tick is ahead of this event then move the event ahead
935
+        if( tick1 > np->tick )
936
+          np->tick = tick1;
937
+        else
938
+          tick1 = 0; // otherwise disable tick1
939
+
940
+        // add this event to the tick group
941
+        assert(ai<aN);
942
+        a[ai++] = np;
943
+       
944
+      }
945
+
946
+      // if there are events in the group array then process them
947
+      if( ai > 1 )
948
+         tick1 = _cmXsSpreadGraceNotes(a,ai);
949
+    }
950
+  }
951
+}
952
+
953
+
787 954
 bool  _cmXScoreFindTiedNote( cmXScore_t* p, cmXsMeas_t* mp, cmXsNote_t* n0p, bool rptFl )
788 955
 {
789 956
   cmXsNote_t* nnp       = n0p->slink;  // begin w/ note following np
@@ -827,8 +994,7 @@ bool  _cmXScoreFindTiedNote( cmXScore_t* p, cmXsMeas_t* mp, cmXsNote_t* n0p, boo
827 994
         // record the measure number of the last note with a tie-start
828 995
         measNumb = mp->number;
829 996
       }
830
-    }
831
-    
997
+    }    
832 998
   }
833 999
   
834 1000
   cmErrWarnMsg(&p->err,kUnterminatedTieXsRC,"The tied %c%c%i in measure %i was not terminated.",n0p->step,acc,n0p->octave,measNumb);
@@ -886,7 +1052,6 @@ void  _cmXScoreResolveTiesAndLoc( cmXScore_t* p )
886 1052
           np->locIdx = locIdx;
887 1053
           n0         = np;
888 1054
         }
889
-
890 1055
       } 
891 1056
     }
892 1057
   }
@@ -917,8 +1082,6 @@ cmXsRC_t  _cmXScoreResolveOctaveShift( cmXScore_t* p )
917 1082
       for(; note!=NULL; note=note->slink)
918 1083
         if( note->staff==s->staff && s->tick0 <= note->tick && note->tick < s->tick1 )
919 1084
           note->pitch += s->pitch_offset;
920
-      
921
-      
922 1085
     }
923 1086
   }
924 1087
 
@@ -957,63 +1120,54 @@ void _cmXScoreRemoveDuplicateNotes( cmXScore_t* p )
957 1120
   }
958 1121
 }
959 1122
 
960
-      
961
-
962
-cmXsMeas_t* _cmXScoreNextNonEmptyMeas( cmXsPart_t* pp, cmXsMeas_t* meas )
1123
+void  _cmXScoreSetMeasGroups( cmXScore_t* p, unsigned flag )
963 1124
 {
964
-  if( meas == NULL )
965
-  {
966
-    if( pp==NULL || pp->measL==NULL )
967
-      return NULL;
968
-    
969
-    meas = pp->measL;
970
-  }
971
-  else
1125
+  unsigned sectionId = 0;
1126
+  cmXsNote_t* n0 = NULL;
1127
+  
1128
+  cmXsPart_t* pp = p->partL;
1129
+ 
1130
+  // for each part
1131
+  for(; pp!=NULL; pp=pp->link)
972 1132
   {
973
-    meas = meas->link;
974
-  }
975
-
976
-  while( meas != NULL && meas->noteL == NULL )
977
-    meas=meas->link;
978
-
979
-  return meas;
980
-}
1133
+    cmXsMeas_t* mp = pp->measL;
981 1134
 
982
-cmXsNote_t* _cmXScoreNextNote( cmXsPart_t* pp, cmXsNote_t* note )
983
-{
984
-  // meas should always be valid (unless this is the first note in the score)
985
-  cmXsMeas_t* meas = note==NULL ? NULL : note->meas;
986
-  
987
-  do
988
-  { 
989
-    if( note == NULL || note->slink==NULL )
990
-    {
991
-      if((meas = _cmXScoreNextNonEmptyMeas(pp,meas)) == NULL)
992
-        return NULL;
993
-      
994
-      assert( meas->noteL != NULL );
995
-      
996
-      note = meas->noteL;
997
-    }
998
-    else
1135
+    // for each measure
1136
+    for(; mp!=NULL; mp=mp->link)
999 1137
     {
1000
-      note = note->slink;        
1001
-    }
1138
+      cmXsNote_t* np = mp->noteL;
1002 1139
 
1003
-    assert( note != NULL );
1004
-    
1005
-    meas = note->meas;
1140
+      // for each note in this measure
1141
+      for(; np!=NULL; np=np->slink)
1142
+      {
1143
+        if( cmIsFlag(np->flags,flag) )
1144
+          n0 = np;         
1145
+          
1146
+       
1147
+        if( cmIsFlag(np->flags,kSectionXsFl)  )
1148
+        {
1149
+          if( n0 != NULL )
1150
+          {
1151
+            switch( flag )
1152
+            {
1153
+              case kEvenXsFl:  n0->evenGroupId = sectionId; break;
1154
+              case kDynXsFl:   n0->dynGroupId  = sectionId; break;
1155
+              case kTempoXsFl: n0->tempoGroupId= sectionId; break;
1156
+            }
1157
+          }
1006 1158
 
1007
-    // note is now set to a non-NULL candidate note - advance to a sounding note
1008
-    while( note!=NULL && cmIsNotFlag(note->flags,kOnsetXsFl) )
1009
-      note = note->slink;
1159
+          if( cmIsFlag(np->flags,kSectionXsFl) )
1160
+            sectionId = np->tvalue==NULL ? 0 : strtol(np->tvalue,NULL,10);
1161
+          
1162
+          n0       = NULL;
1163
+        }
1164
+      }
1165
+    }
1166
+  }
1010 1167
 
1011
-    // if no note was found in this measure
1012
-  }while( note == NULL );
1013
-     
1014
-  return note;
1015 1168
 }
1016 1169
 
1170
+
1017 1171
 cmXsRC_t _cmXScoreWriteScorePlotFile( cmXScore_t* p, const cmChar_t* fn )
1018 1172
 {
1019 1173
   cmXsRC_t  rc            = kOkXsRC;
@@ -1066,115 +1220,6 @@ cmXsRC_t _cmXScoreWriteScorePlotFile( cmXScore_t* p, const cmChar_t* fn )
1066 1220
   return rc;
1067 1221
 }
1068 1222
 
1069
-cmXsRC_t _cmXScoreWriteMidiPlotFile( cmXScore_t* p, cmChar_t* fn, const cmMidiTrackMsg_t** m, unsigned mN )
1070
-{
1071
-  cmXsRC_t  rc = kOkXsRC;
1072
-  cmFileH_t fH = cmFileNullHandle;
1073
-  unsigned  i  = 0;
1074
-  
1075
-  if( cmFileOpen(&fH,fn,kWriteFileFl,p->err.rpt) != kOkFileRC )
1076
-    return cmErrMsg(&p->err,kFileFailXsRC,"Unable to create the file '%s'.",cmStringNullGuard(fn));
1077
-
1078
-  for(i=0; i<mN; ++i)
1079
-    if( (m[i]!=NULL) && cmMidiIsChStatus(m[i]->status) && cmMidiIsNoteOn(m[i]->status) && (m[i]->u.chMsgPtr->d1>0) )
1080
-      cmFilePrintf(fH,"n %f %f %i %s\n",m[i]->amicro/1000000.0,m[i]->u.chMsgPtr->durMicros/1000000.0,m[i]->uid,cmMidiToSciPitch(m[i]->u.chMsgPtr->d0,NULL,0));
1081
-
1082
-  
1083
-  cmFileClose(&fH);
1084
-  return rc;
1085
-}
1086
-
1087
-
1088
-cmXsRC_t    _cmXScoreProcessMidi(cmXScore_t* p, cmCtx_t* ctx, const cmChar_t* midiFn)
1089
-{
1090
-  cmXsRC_t                 rc   = kOkXsRC;
1091
-  cmMidiFileH_t            mfH  = cmMidiFileNullHandle;
1092
-  const cmMidiTrackMsg_t** m    = NULL;
1093
-  unsigned                 mN   = 0;
1094
-  unsigned                 i    = 0;
1095
-  unsigned                 j    = 0;
1096
-  cmXsNote_t*              note = NULL;
1097
-  
1098
-  if( cmMidiFileOpen(ctx, &mfH, midiFn ) != kOkMfRC )
1099
-    return cmErrMsg(&p->err,kMidiFailXsRC,"The MIDI file object could not be opened from '%s'.",cmStringNullGuard(midiFn));
1100
-
1101
-  if( (m = cmMidiFileMsgArray(mfH)) == NULL || (mN = cmMidiFileMsgCount(mfH)) == 0 )
1102
-  {
1103
-    rc = cmErrMsg(&p->err,kMidiFailXsRC,"The MIDI file object appears to be empty.");
1104
-    goto errLabel;
1105
-  }
1106
-
1107
-  if((note = _cmXScoreNextNote(p->partL,NULL)) == NULL)
1108
-  {
1109
-    rc = cmErrWarnMsg(&p->err,kSyntaxErrorXsRC,"No MIDI processing to be done. The score appears to be empty.");
1110
-    goto errLabel;
1111
-  }
1112
-
1113
-  cmCtx*        c = cmCtxAlloc( NULL, p->err.rpt, cmLHeapNullHandle, cmSymTblNullHandle );
1114
-  cmSeqAlign_t* s = cmSeqAlignAlloc(c,NULL);
1115
-  unsigned      offs = 0;
1116
-  
1117
-  for(; note!=NULL; note=_cmXScoreNextNote(p->partL,note))
1118
-  {
1119
-    if( cmIsFlag(note->flags,kGraceXsFl) )
1120
-      offs += 1;
1121
-    
1122
-    cmSeqAlignInsert(s,0,note->locIdx+offs,note->pitch);
1123
-  }
1124
-
1125
-  unsigned locIdx = 1;
1126
-  for(i=0,j=0; i<mN; ++i)
1127
-    if( (m[i]!=NULL) && cmMidiIsChStatus(m[i]->status) && cmMidiIsNoteOn(m[i]->status) && (m[i]->u.chMsgPtr->d1>0) )
1128
-    {
1129
-      if( m[j]->atick != m[i]->atick )
1130
-        locIdx += 1;
1131
-      
1132
-      cmSeqAlignInsert(s,1,locIdx,m[i]->u.chMsgPtr->d0);
1133
-
1134
-      //printf("%i : %s\n",locIdx,cmMidiToSciPitch(m[i]->u.chMsgPtr->d0,NULL,0));
1135
-      
1136
-      j = i;
1137
-    }
1138
-
1139
-  cmMidiFileCalcNoteDurations( mfH );
1140
-  
1141
-  _cmXScoreWriteScorePlotFile(p, "/Users/kevin/temp/score.txt" );
1142
-  _cmXScoreWriteMidiPlotFile(p,  "/Users/kevin/temp/midi.txt", m, mN );
1143
-
1144
-
1145
-  cmSeqAlignReport(s,p->err.rpt);
1146
-  cmSeqAlignFree(&s);
1147
-  cmCtxFree(&c);
1148
-  goto errLabel;
1149
-
1150
-  printf(" i     j    score    midi\n");
1151
-  printf("---- ---- --- ---- --- ----\n");
1152
-  
1153
-  for(j=0; note!=NULL; note=_cmXScoreNextNote(p->partL,note),++j)
1154
-  {
1155
-    unsigned midiPitch = 0;
1156
-    for(; i<mN; ++i)
1157
-      if( m[i]!=NULL && cmMidiIsChStatus(m[i]->status) && cmMidiIsNoteOn(m[i]->status) && m[i]->u.chMsgPtr->d1>0 )
1158
-      {
1159
-        midiPitch = m[i]->u.chMsgPtr->d0;
1160
-        ++i;
1161
-        break;
1162
-      }
1163
-
1164
-    char buf[6];
1165
-    printf("%4i %4i %3i %4s %3i %4s\n",j,i,
1166
-      note->pitch,
1167
-      cmMidiToSciPitch(note->pitch,NULL,0),
1168
-      midiPitch,
1169
-      cmMidiToSciPitch(midiPitch,buf,5));
1170
-    
1171
-  }
1172
-
1173
- errLabel:
1174
-  cmMidiFileClose(&mfH);
1175
-  return rc;
1176
-}
1177
-
1178 1223
 cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn, const cmChar_t* midiFn )
1179 1224
 {
1180 1225
   cmXsRC_t rc = kOkXsRC;
@@ -1212,15 +1257,22 @@ cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn, c
1212 1257
   // fill in the note->slink chain to link the notes in each measure in time order
1213 1258
   _cmXScoreSort(p);
1214 1259
 
1260
+  _cmXScoreSpreadGraceNotes(p);
1261
+  
1262
+  _cmXScoreSort(p);
1263
+  
1264
+  _cmXScoreSetAbsoluteTime(p);
1265
+
1215 1266
   _cmXScoreResolveTiesAndLoc(p);
1216 1267
 
1217 1268
   _cmXScoreRemoveDuplicateNotes(p);
1269
+
1270
+  _cmXScoreSetMeasGroups(p,kEvenXsFl);
1271
+  _cmXScoreSetMeasGroups(p,kDynXsFl);
1272
+  _cmXScoreSetMeasGroups(p,kTempoXsFl);
1218 1273
   
1219 1274
   //_cmXScoreResolveOctaveShift(p);
1220 1275
 
1221
-  //if( midiFn != NULL )
1222
-  //  _cmXScoreProcessMidi(p,ctx,midiFn);
1223
-
1224 1276
   // CSV output initialize failed.
1225 1277
   if( cmCsvInitialize(&p->csvH,ctx) != kOkCsvRC )
1226 1278
     rc = cmErrMsg(&p->err,kCsvFailXsRC,"CSV output object create failed.");
@@ -1386,7 +1438,7 @@ cmXsRC_t cmXScoreInsertDynamics( cmXsH_t h, const cmChar_t* dynFn )
1386 1438
         {
1387 1439
           if( ai >= aN || aV[ai].bar != mp->number || aV[ai].pitch != np->pitch || aV[ai].rval != np->rvalue )
1388 1440
           {
1389
-            rc = cmErrMsg(&p->err,kSyntaxErrorXsRC,"Dynamics file mismatch error on dynamics line:%i.\n",aV[ai].line);
1441
+            rc = cmErrMsg(&p->err,kSyntaxErrorXsRC,"Dynamics file mismatch error on dynamics line:%i. expected:%s %f actual:%s %f\n",aV[ai].line,aV[ai].rval,cmMidiToSciPitch(aV[ai].pitch,NULL,0),cmMidiToSciPitch(np->pitch,NULL,0),np->rvalue);
1390 1442
             goto errLabel;
1391 1443
           }
1392 1444
 
@@ -1676,12 +1728,7 @@ cmXsRC_t cmXScoreWriteCsv( cmXsH_t h, const cmChar_t* csvFn )
1676 1728
   cmXsRC_t        rc           = kOkXsRC;
1677 1729
   cmXScore_t*     p            = _cmXScoreHandleToPtr(h);
1678 1730
   unsigned        rowIdx       = 1;
1679
-  double          tpqn         = 0; // ticks per quarter note
1680
-  double          tps          = 0; // ticks per second
1681 1731
   const cmChar_t* sectionIdStr = NULL;
1682
-  unsigned        metro_tick   = 0;
1683
-  double          metro_sec    = 0;
1684
-  double          sec0         = 0;
1685 1732
   
1686 1733
   if( !cmCsvIsValid(p->csvH) )
1687 1734
     return cmErrMsg(&p->err,kCsvFailXsRC,"The CSV output object is not initialized.");
@@ -1695,66 +1742,45 @@ cmXsRC_t cmXScoreWriteCsv( cmXsH_t h, const cmChar_t* csvFn )
1695 1742
     cmXsMeas_t* mp = pp->measL;
1696 1743
     for(; mp!=NULL; mp=mp->link)
1697 1744
     {
1698
-      if( mp->divisions != 0 )
1699
-        tpqn = mp->divisions;
1700
-      
1701
-      cmXsNote_t* np = mp->noteL;
1702
-      
1745
+      cmXsNote_t* np = mp->noteL;      
1703 1746
       for(; np!=NULL; np=np->slink)
1704 1747
       {
1705 1748
 
1706
-        // Seconds are calculated as:
1707
-        // dticks = np->tick - metro_tick;     // where metro_tick is the absolute tick of the last metro event
1708
-        // secs   = (dticks/tps) + metro_secs; // where metro_secs is the absoute time of the last metro event
1709
-        
1710
-        unsigned dticks = np->tick - metro_tick;
1711
-        double   secs   = tps==0 ? 0 : (dticks/tps) + metro_sec;
1712
-        double   dsecs  = secs - sec0;
1713
-        
1714
-        //  
1715
-        if( cmIsFlag(np->flags,kMetronomeXsFl) )
1716
-        {
1717
-          double bpm = np->duration;
1718
-          double bps = bpm / 60.0;
1719
-          tps = bps * tpqn;
1720
-          metro_tick = np->tick;
1721
-          metro_sec  = secs;
1722
-        }
1723
-                
1724 1749
         // if this is a section event
1725 1750
         if( cmIsFlag(np->flags,kSectionXsFl) )
1726 1751
           sectionIdStr = np->tvalue;
1727 1752
         
1728 1753
         // if this is a bar event
1729
-        if( cmIsFlag(np->flags,kBarXsFl) )
1754
+        if( cmIsFlag(np->flags,kBarXsFl)  )
1730 1755
         {
1731
-          _cmXScoreWriteCsvRow(p,rowIdx,-1,mp->number,NULL,"bar",dsecs,secs,0,0,-1,0,"",np->flags);
1732
-          sec0 = secs;
1756
+          _cmXScoreWriteCsvRow(p,rowIdx,-1,mp->number,sectionIdStr,"bar",np->dsecs,np->secs,0,0,-1,0,"",np->flags);
1757
+          sectionIdStr = NULL;
1733 1758
         }
1734 1759
         else
1735
-          
1736
-        // if this is a pedal event
1737
-        if( cmIsFlag(np->flags,kPedalDnXsFl|kPedalUpXsFl|kPedalUpDnXsFl) )
1738 1760
         {
1739
-          unsigned d0 = 64; // pedal MIDI ctl id
1740
-          unsigned d1 = cmIsFlag(np->flags,kPedalDnXsFl) ? 64 : 0; // pedal-dn: d1>=64 pedal-up:<64
1741
-          _cmXScoreWriteCsvRow(p,rowIdx,-1,mp->number,NULL,"ctl",dsecs,secs,d0,d1,-1,0,"",np->flags);
1742
-          sec0 = secs;
1743
-        }
1744
-        else 
1745
-
1746
-
1747
-          // if this is a sounding note event
1748
-          if( cmIsFlag(np->flags,kOnsetXsFl) )
1761
+          // if this is a pedal event
1762
+          if( cmIsFlag(np->flags,kPedalDnXsFl|kPedalUpXsFl|kPedalUpDnXsFl) )
1749 1763
           {
1750
-            double          frac = np->rvalue + (cmIsFlag(np->flags,kDotXsFl) ? (np->rvalue/2) : 0);
1751
-            const cmChar_t* dyn  = _cmXScoreTranslateDynamics( p,  np );
1752
-            
1753
-            // 
1754
-            _cmXScoreWriteCsvRow(p,rowIdx,np->uid,mp->number,sectionIdStr,"non",dsecs,secs,np->pitch,60,np->pitch,frac,dyn,np->flags);
1755
-            sec0 = secs;
1764
+            unsigned d0 = 64; // pedal MIDI ctl id
1765
+            unsigned d1 = cmIsFlag(np->flags,kPedalDnXsFl) ? 64 : 0; // pedal-dn: d1>=64 pedal-up:<64
1766
+            _cmXScoreWriteCsvRow(p,rowIdx,-1,mp->number,sectionIdStr,"ctl",np->dsecs,np->secs,d0,d1,-1,0,"",np->flags);
1756 1767
             sectionIdStr = NULL;
1757 1768
           }
1769
+          else 
1770
+          {
1771
+
1772
+            // if this is a sounding note event
1773
+            if( cmIsFlag(np->flags,kOnsetXsFl) )
1774
+            {
1775
+              double          frac  = np->rvalue + (cmIsFlag(np->flags,kDotXsFl) ? (np->rvalue/2) : 0);
1776
+              const cmChar_t* dyn   = _cmXScoreTranslateDynamics( p,  np );
1777
+              
1778
+              // 
1779
+              _cmXScoreWriteCsvRow(p,rowIdx,np->uid,mp->number,sectionIdStr,"non",np->dsecs,np->secs,np->pitch,60,np->pitch,frac,dyn,np->flags);
1780
+              sectionIdStr = NULL;
1781
+            }
1782
+          }
1783
+        }
1758 1784
         
1759 1785
         rowIdx += 1;
1760 1786
       }
@@ -1762,6 +1788,11 @@ cmXsRC_t cmXScoreWriteCsv( cmXsH_t h, const cmChar_t* csvFn )
1762 1788
     }    
1763 1789
   }
1764 1790
 
1791
+  // Section labels are output on the next bar/pedal/note
1792
+  // but what if there is no bar pedal note-on after the section label
1793
+  if( sectionIdStr != NULL )
1794
+    cmErrMsg(&p->err,kSyntaxErrorXsRC,"The section label '%s' was ignored because it was not followed by a score event.",sectionIdStr);
1795
+
1765 1796
   if( cmCsvWrite( p->csvH, csvFn ) != kOkCsvRC )
1766 1797
     rc = cmErrMsg(&p->err,kCsvFailXsRC,"The CSV output write failed on file '%s'.",csvFn);
1767 1798
 
@@ -1781,7 +1812,7 @@ void _cmXScoreReportNote( cmRpt_t* rpt, const cmXsNote_t* note )
1781 1812
   const cmChar_t* B  = cmIsFlag(note->flags,kBarXsFl)       ? "|" : "-";
1782 1813
   const cmChar_t* R  = cmIsFlag(note->flags,kRestXsFl)      ? "R" : "-";
1783 1814
   const cmChar_t* G  = cmIsFlag(note->flags,kGraceXsFl)     ? "G" : "-";
1784
-  const cmChar_t* D  = cmIsFlag(note->flags,kDotXsFl)       ? "D" : "-";
1815
+  const cmChar_t* D  = cmIsFlag(note->flags,kDotXsFl)       ? "." : "-";
1785 1816
   const cmChar_t* C  = cmIsFlag(note->flags,kChordXsFl)     ? "C" : "-";
1786 1817
   const cmChar_t* e  = cmIsFlag(note->flags,kEvenXsFl)      ? "e" : "-";
1787 1818
   const cmChar_t* d  = cmIsFlag(note->flags,kDynXsFl)       ? "d" : "-";
@@ -1791,6 +1822,7 @@ void _cmXScoreReportNote( cmRpt_t* rpt, const cmXsNote_t* note )
1791 1822
   const cmChar_t* H  = cmIsFlag(note->flags,kHeelXsFl)      ? "H" : "-";
1792 1823
   const cmChar_t* T0 = cmIsFlag(note->flags,kTieBegXsFl)    ? "T" : "-";
1793 1824
   const cmChar_t* T1 = cmIsFlag(note->flags,kTieEndXsFl)    ? "_" : "-";
1825
+  const cmChar_t* O  = cmIsFlag(note->flags,kOnsetXsFl)     ? "*" : "-";
1794 1826
   P = cmIsFlag(note->flags,kPedalUpXsFl)   ? "^" : P;
1795 1827
   P = cmIsFlag(note->flags,kPedalUpDnXsFl) ? "X" : P;
1796 1828
   //const cmChar_t* N = note->pitch==0 ? " " : cmMidiToSciPitch( note->pitch, NULL, 0 );
@@ -1799,13 +1831,13 @@ void _cmXScoreReportNote( cmRpt_t* rpt, const cmXsNote_t* note )
1799 1831
   cmChar_t acc = note->alter==-1?'b':(note->alter==1?'#':' ');
1800 1832
   snprintf(N,4,"%c%c%1i",note->step,acc,note->octave);
1801 1833
     
1802
-  cmRptPrintf(rpt,"      %3i %5i %7i %5i %4.1f %3s %s%s%s%s%s%s%s%s%s%s%s%s%s",
1834
+  cmRptPrintf(rpt,"      %3i %5i %7i %5i %4.1f %3s %s%s%s%s%s%s%s%s%s%s%s%s%s%s",
1803 1835
     note->voice->id,
1804 1836
     note->locIdx,
1805 1837
     note->tick,
1806 1838
     note->duration,
1807 1839
     note->rvalue,
1808
-    N,B,R,G,D,C,e,d,t,P,S,H,T0,T1);
1840
+    N,B,R,G,D,C,e,d,t,P,S,H,T0,T1,O);
1809 1841
 
1810 1842
   if( cmIsFlag(note->flags,kSectionXsFl) )
1811 1843
     cmRptPrintf(rpt," %s",cmStringNullGuard(note->tvalue));
@@ -1813,6 +1845,15 @@ void _cmXScoreReportNote( cmRpt_t* rpt, const cmXsNote_t* note )
1813 1845
   if( cmIsFlag(note->flags,kMetronomeXsFl) )
1814 1846
     cmRptPrintf(rpt," %i bpm",note->duration);
1815 1847
 
1848
+  if( note->evenGroupId != 0 )
1849
+    cmRptPrintf(rpt," e=%i",note->evenGroupId);
1850
+  
1851
+  if( note->dynGroupId != 0 )
1852
+    cmRptPrintf(rpt," d=%i",note->dynGroupId);
1853
+  
1854
+  if( note->tempoGroupId != 0 )
1855
+    cmRptPrintf(rpt," t=%i",note->tempoGroupId);
1856
+
1816 1857
 }
1817 1858
 
1818 1859
 
@@ -1909,7 +1950,7 @@ cmXsRC_t cmXScoreTest( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* midi
1909 1950
   if( outFn != NULL )
1910 1951
     cmXScoreWriteCsv(h,outFn);
1911 1952
   
1912
-  //cmXScoreReport(h,&ctx->rpt,true);
1953
+  cmXScoreReport(h,&ctx->rpt,true);
1913 1954
   
1914 1955
   return cmXScoreFinalize(&h);
1915 1956
 

+ 2
- 2
app/cmXScore.h Переглянути файл

@@ -54,13 +54,13 @@ extern "C" {
54 54
   cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn, const cmChar_t* midiFn );
55 55
   cmXsRC_t cmXScoreFinalize( cmXsH_t* hp );
56 56
 
57
-  bool cmXScoreIsValid( cmXsH_t h );
57
+  bool     cmXScoreIsValid( cmXsH_t h );
58 58
 
59 59
   cmXsRC_t cmXScoreWriteCsv( cmXsH_t h, const cmChar_t* csvFn );
60 60
 
61 61
   cmXsRC_t cmXScoreWriteMidi( cmXsH_t h, const cmChar_t* fn );
62 62
 
63
-  void cmXScoreReport( cmXsH_t h, cmRpt_t* rpt, bool sortFl );
63
+  void     cmXScoreReport( cmXsH_t h, cmRpt_t* rpt, bool sortFl );
64 64
 
65 65
   cmXsRC_t cmXScoreTest( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* midiFn, const cmChar_t* outFn, const cmChar_t* dynFn );
66 66
   

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