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