|
@@ -69,7 +69,11 @@ enum
|
69
|
69
|
kNFirstGraceXsFl = 0x08000000, // (n) grace notes start as soon as possible after first note and add time
|
70
|
70
|
kDeleteXsFl = 0x10000000,
|
71
|
71
|
kDynBegForkXsFl = 0x20000000,
|
72
|
|
- kDynEndForkXsFl = 0x40000000
|
|
72
|
+ kDynEndForkXsFl = 0x40000000,
|
|
73
|
+
|
|
74
|
+ kDynEndXsFl = 0x100000000,
|
|
75
|
+ kEvenEndXsFl = 0x200000000,
|
|
76
|
+ kTempoEndXsFl = 0x400000000
|
73
|
77
|
|
74
|
78
|
};
|
75
|
79
|
|
|
@@ -90,7 +94,7 @@ typedef struct cmXsComplexity_str
|
90
|
94
|
typedef struct cmXsNote_str
|
91
|
95
|
{
|
92
|
96
|
unsigned uid; // unique id of this note record
|
93
|
|
- unsigned flags; // See k???XsFl
|
|
97
|
+ unsigned long long flags; // See k???XsFl
|
94
|
98
|
unsigned pitch; // midi pitch
|
95
|
99
|
unsigned dynamics; // dynamic level 1=pppp 9=fff
|
96
|
100
|
unsigned vel; // score specified MIDI velocity
|
|
@@ -515,33 +519,44 @@ cmXsRC_t _cmXScoreParseColor( cmXScore_t* p, const cmXmlNode_t* nnp, cmXsNote_t
|
515
|
519
|
|
516
|
520
|
typedef struct map_str
|
517
|
521
|
{
|
518
|
|
- unsigned value;
|
|
522
|
+ unsigned long long value;
|
519
|
523
|
const cmChar_t* label;
|
520
|
524
|
} map_t;
|
521
|
525
|
|
522
|
526
|
map_t mapV[] =
|
523
|
527
|
{
|
524
|
|
- { kEvenXsFl, "#0000FF" }, // blue (even)
|
525
|
|
- { kTempoXsFl, "#00FF00" }, // green (tempo)
|
526
|
|
- { kDynXsFl, "#FF0000" }, // red (dynamics)
|
527
|
|
- { kTempoXsFl | kEvenXsFl, "#00FFFF" }, // green + blue (turquoise)
|
528
|
|
- { kDynXsFl | kEvenXsFl, "#FF00FF" }, // red + blue
|
529
|
|
- { kDynXsFl | kEvenXsFl, "#FF0CF7" }, // magenta (even+dyn)
|
530
|
|
- { kDynXsFl | kTempoXsFl, "#FF7F00" }, // red + green (brown)
|
531
|
|
- { kTempoXsFl | kEvenXsFl | kDynXsFl, "#996633" }, // (purple)
|
532
|
|
- { kDynXsFl, "#FF6A03" }, // 176 orange (dynamics)
|
533
|
|
- { kEvenXsFl, "#2F00E8" }, // 1001 blue (even)
|
534
|
|
- { kTempoXsFl, "#01CD1F" }, // 1196 green (tempo)
|
535
|
|
- { kEvenXsFl, "#3600E8" }, // 1627 blue (even)
|
536
|
|
- { kDynXsFl | kTempoXsFl, "#9E8F15" }, // 8827 brown (dyn + tempo)
|
537
|
|
- { kEvenXsFl, "#2E00E6" }, // 5393 blue (even)
|
538
|
|
- { kEvenXsFl, "#2C00DD" }, // 5895 blue (even)
|
539
|
|
- { kDynXsFl, "#FF5B03" }, // 6498 orange (dyn)
|
540
|
|
- { kDynXsFl, "#FF6104" }, // 6896 orange
|
541
|
|
- { kEvenXsFl, "#2A00E6" }, // 7781 blue
|
542
|
|
- { kEvenXsFl, "#2300DD" }, // 8300 blue (even)
|
543
|
|
- { kTempoXsFl, "#03CD22" }, // 10820 green (tempo)
|
544
|
|
- { kEvenXsFl, "#3400DB" }, // 11627 blue (dyn)
|
|
528
|
+ { kEvenXsFl, "#0000FF" }, // blue (even)
|
|
529
|
+ { kEvenXsFl | kEvenEndXsFl, "#0000FE" }, // blue (even end)
|
|
530
|
+ { kEvenXsFl | kEvenEndXsFl, "#0000FD" }, // blue (even end)
|
|
531
|
+ { kTempoXsFl, "#00FF00" }, // green (tempo)
|
|
532
|
+ { kTempoXsFl | kTempoEndXsFl, "#00FE00" }, // green (tempo end)
|
|
533
|
+ { kDynXsFl, "#FF0000" }, // red (dynamics)
|
|
534
|
+ { kDynXsFl | kDynEndXsFl, "#FE0000" }, // red (dynamics end)
|
|
535
|
+ { kDynXsFl | kDynEndXsFl, "#FD0000" }, // red (dynamics end)
|
|
536
|
+ { kTempoXsFl | kEvenXsFl, "#00FFFF" }, // green + blue (turquoise)
|
|
537
|
+ { kTempoXsFl | kEvenXsFl | kEvenEndXsFl, "#00FFFE" }, // green + blue (turquoise) (end)
|
|
538
|
+ { kDynXsFl | kEvenXsFl, "#FF00FF" }, // red + blue
|
|
539
|
+ { kDynXsFl | kEvenXsFl | kEvenEndXsFl, "#FF00FE" }, // red + blue (end)
|
|
540
|
+ { kDynXsFl | kEvenXsFl | kEvenEndXsFl, "#FF00FD" }, // red + blue (end)
|
|
541
|
+ { kDynXsFl | kEvenXsFl, "#FF0CF7" }, // magenta (even+dyn)
|
|
542
|
+ { kDynXsFl | kTempoXsFl, "#FF7F00" }, // red + green (brown)
|
|
543
|
+ { kDynXsFl | kTempoXsFl, "#FE7F00" }, // red + green (brown) (end)
|
|
544
|
+ { kDynXsFl | kTempoXsFl, "#FD7F00" }, // red + green (brown) (end)
|
|
545
|
+ { kTempoXsFl | kEvenXsFl | kDynXsFl, "#996633" }, // (purple)
|
|
546
|
+ { kTempoXsFl | kEvenXsFl | kDynXsFl | kDynEndXsFl, "#996632" }, // (purple)
|
|
547
|
+ { kDynXsFl, "#FF6A03" }, // 176 orange (dynamics)
|
|
548
|
+ { kEvenXsFl, "#2F00E8" }, // 1001 blue (even)
|
|
549
|
+ { kTempoXsFl, "#01CD1F" }, // 1196 green (tempo)
|
|
550
|
+ { kEvenXsFl, "#3600E8" }, // 1627 blue (even)
|
|
551
|
+ { kDynXsFl | kTempoXsFl, "#9E8F15" }, // 8827 brown (dyn + tempo)
|
|
552
|
+ { kEvenXsFl, "#2E00E6" }, // 5393 blue (even)
|
|
553
|
+ { kEvenXsFl, "#2C00DD" }, // 5895 blue (even)
|
|
554
|
+ { kDynXsFl, "#FF5B03" }, // 6498 orange (dyn)
|
|
555
|
+ { kDynXsFl, "#FF6104" }, // 6896 orange
|
|
556
|
+ { kEvenXsFl, "#2A00E6" }, // 7781 blue
|
|
557
|
+ { kEvenXsFl, "#2300DD" }, // 8300 blue (even)
|
|
558
|
+ { kTempoXsFl, "#03CD22" }, // 10820 green (tempo)
|
|
559
|
+ { kEvenXsFl, "#3400DB" }, // 11627 blue (dyn)
|
545
|
560
|
{ -1, "" }
|
546
|
561
|
};
|
547
|
562
|
|
|
@@ -1785,7 +1800,7 @@ cmXsRC_t _cmXScoreProcessGraceNotes( cmXScore_t* p, unsigned nextGraceGroupId )
|
1785
|
1800
|
// grace note groups must have at least 3 members
|
1786
|
1801
|
if( gN < 3 )
|
1787
|
1802
|
{
|
1788
|
|
- rc = cmErrMsg(&p->err,kSyntaxErrorXsRC,"The grace not group (groupid=%i) ending in meas %i has fewer than 3 (%i) members.", gn1p->graceGroupId, gn1p->meas->number, gN );
|
|
1803
|
+ rc = cmErrMsg(&p->err,kSyntaxErrorXsRC,"The grace note group (groupid=%i) ending in meas %i has fewer than 3 (%i) members.", gn1p->graceGroupId, gn1p->meas->number, gN );
|
1789
|
1804
|
break;
|
1790
|
1805
|
}
|
1791
|
1806
|
|
|
@@ -2214,7 +2229,7 @@ cmXsRC_t _cmXScoreReorderMeas( cmXScore_t* p, unsigned measNumb, cmXsReorder_t*
|
2214
|
2229
|
|
2215
|
2230
|
}
|
2216
|
2231
|
|
2217
|
|
-cmXsRC_t _cmXScoreReorderParseDyn(cmXScore_t* p, const cmChar_t* b, unsigned lineNumb, unsigned* dynIdxRef, unsigned* flagsRef )
|
|
2232
|
+cmXsRC_t _cmXScoreReorderParseDyn(cmXScore_t* p, const cmChar_t* b, unsigned lineNumb, unsigned* dynIdxRef, unsigned* flagsRef, int measNumb )
|
2218
|
2233
|
{
|
2219
|
2234
|
cmXsRC_t rc = kOkXsRC;
|
2220
|
2235
|
const cmChar_t* s = NULL;
|
|
@@ -2239,6 +2254,7 @@ cmXsRC_t _cmXScoreReorderParseDyn(cmXScore_t* p, const cmChar_t* b, unsigned lin
|
2239
|
2254
|
|
2240
|
2255
|
if( *s == '!')
|
2241
|
2256
|
{
|
|
2257
|
+ //printf("E %3i %5i %s\n",measNumb,lineNumb,b);
|
2242
|
2258
|
endForkFl = true;
|
2243
|
2259
|
++s;
|
2244
|
2260
|
}
|
|
@@ -2251,7 +2267,11 @@ cmXsRC_t _cmXScoreReorderParseDyn(cmXScore_t* p, const cmChar_t* b, unsigned lin
|
2251
|
2267
|
if( isupper(*s) )
|
2252
|
2268
|
{
|
2253
|
2269
|
if( !endForkFl)
|
|
2270
|
+ {
|
2254
|
2271
|
begForkFl=true;
|
|
2272
|
+ //printf("B %3i %5i %s\n",measNumb,lineNumb,b);
|
|
2273
|
+
|
|
2274
|
+ }
|
2255
|
2275
|
}
|
2256
|
2276
|
else
|
2257
|
2277
|
{
|
|
@@ -2431,7 +2451,11 @@ cmXsRC_t _cmXScoreReorderParseGrace(cmXScore_t* p, const cmChar_t* b, unsigned
|
2431
|
2451
|
continue;
|
2432
|
2452
|
|
2433
|
2453
|
default:
|
2434
|
|
- { assert(0); }
|
|
2454
|
+ {
|
|
2455
|
+ return cmErrMsg(&p->err,kSyntaxErrorXsRC,"Unexpected grace note reorder character code %c on line %i.",*s,line);
|
|
2456
|
+
|
|
2457
|
+ assert(0);
|
|
2458
|
+ }
|
2435
|
2459
|
}
|
2436
|
2460
|
|
2437
|
2461
|
break;
|
|
@@ -2457,7 +2481,7 @@ cmXsRC_t _cmXScoreReorderParsePitch(cmXScore_t* p, const cmChar_t* b, unsigned
|
2457
|
2481
|
++s;
|
2458
|
2482
|
|
2459
|
2483
|
j=2;
|
2460
|
|
- for(i=0; i<j && s[i]; ++i,++s)
|
|
2484
|
+ for(i=0; i<j && *s; ++i,++s)
|
2461
|
2485
|
{
|
2462
|
2486
|
buf[i] = *s;
|
2463
|
2487
|
|
|
@@ -2479,8 +2503,9 @@ cmXsRC_t _cmXScoreReorderParsePitch(cmXScore_t* p, const cmChar_t* b, unsigned
|
2479
|
2503
|
if( pitch<kInvalidMidiByte)
|
2480
|
2504
|
*pitchRef = pitch;
|
2481
|
2505
|
else
|
|
2506
|
+ {
|
2482
|
2507
|
rc = cmErrMsg(&p->err,kSyntaxErrorXsRC,"Pitch conversion from '%s' failed on line %i.",buf,line);
|
2483
|
|
-
|
|
2508
|
+ }
|
2484
|
2509
|
return rc;
|
2485
|
2510
|
}
|
2486
|
2511
|
|
|
@@ -2563,7 +2588,7 @@ cmXsRC_t _cmXsApplyEditFile( cmXScore_t* p, const cmChar_t* fn )
|
2563
|
2588
|
goto errLabel;
|
2564
|
2589
|
|
2565
|
2590
|
// parse the dynamic marking following a '!'
|
2566
|
|
- if((rc = _cmXScoreReorderParseDyn(p,b,ln+1,&r.dynIdx, &r.newFlags)) != kOkXsRC )
|
|
2591
|
+ if((rc = _cmXScoreReorderParseDyn(p,b,ln+1,&r.dynIdx, &r.newFlags, measNumb)) != kOkXsRC )
|
2567
|
2592
|
goto errLabel;
|
2568
|
2593
|
|
2569
|
2594
|
// parse the @newtick marker
|
|
@@ -3062,12 +3087,13 @@ cmXsRC_t _cmXScoreWriteCsvRow(
|
3062
|
3087
|
return rc;
|
3063
|
3088
|
}
|
3064
|
3089
|
|
3065
|
|
-cmXsRC_t cmXScoreWriteCsv( cmXsH_t h, const cmChar_t* csvFn )
|
|
3090
|
+cmXsRC_t cmXScoreWriteCsv( cmXsH_t h, int begMeasNumb, const cmChar_t* csvFn )
|
3066
|
3091
|
{
|
3067
|
3092
|
cmXsRC_t rc = kOkXsRC;
|
3068
|
3093
|
cmXScore_t* p = _cmXScoreHandleToPtr(h);
|
3069
|
3094
|
unsigned rowIdx = 1;
|
3070
|
3095
|
const cmChar_t* sectionIdStr = NULL;
|
|
3096
|
+ double baseSecs = -1;
|
3071
|
3097
|
|
3072
|
3098
|
if( !cmCsvIsValid(p->csvH) )
|
3073
|
3099
|
return cmErrMsg(&p->err,kCsvFailXsRC,"The CSV output object is not initialized.");
|
|
@@ -3079,12 +3105,22 @@ cmXsRC_t cmXScoreWriteCsv( cmXsH_t h, const cmChar_t* csvFn )
|
3079
|
3105
|
for(; pp!=NULL; pp=pp->link)
|
3080
|
3106
|
{
|
3081
|
3107
|
cmXsMeas_t* mp = pp->measL;
|
|
3108
|
+
|
3082
|
3109
|
for(; mp!=NULL; mp=mp->link)
|
3083
|
3110
|
{
|
|
3111
|
+
|
|
3112
|
+ if( mp->number < begMeasNumb)
|
|
3113
|
+ continue;
|
|
3114
|
+
|
3084
|
3115
|
cmXsNote_t* np = mp->noteL;
|
|
3116
|
+
|
|
3117
|
+ if( baseSecs == -1 )
|
|
3118
|
+ baseSecs = np->secs;
|
|
3119
|
+
|
3085
|
3120
|
for(; np!=NULL; np=np->slink)
|
3086
|
3121
|
{
|
3087
|
|
-
|
|
3122
|
+ double thisSecs = np->secs - baseSecs;
|
|
3123
|
+
|
3088
|
3124
|
// if this is a section event
|
3089
|
3125
|
if( cmIsFlag(np->flags,kSectionXsFl) )
|
3090
|
3126
|
sectionIdStr = np->tvalue;
|
|
@@ -3092,7 +3128,7 @@ cmXsRC_t cmXScoreWriteCsv( cmXsH_t h, const cmChar_t* csvFn )
|
3092
|
3128
|
// if this is a bar event
|
3093
|
3129
|
if( cmIsFlag(np->flags,kBarXsFl) )
|
3094
|
3130
|
{
|
3095
|
|
- _cmXScoreWriteCsvRow(p,rowIdx,-1,mp->number,sectionIdStr,"bar",np->dsecs,np->secs,0,0,-1,0,"",np->flags,"","");
|
|
3131
|
+ _cmXScoreWriteCsvRow(p,rowIdx,-1,mp->number,sectionIdStr,"bar",np->dsecs,thisSecs,0,0,-1,0,"",np->flags,"","");
|
3096
|
3132
|
sectionIdStr = NULL;
|
3097
|
3133
|
}
|
3098
|
3134
|
else
|
|
@@ -3102,14 +3138,14 @@ cmXsRC_t cmXScoreWriteCsv( cmXsH_t h, const cmChar_t* csvFn )
|
3102
|
3138
|
{
|
3103
|
3139
|
unsigned d0 = cmIsFlag(np->flags,kSostDnXsFl |kSostUpXsFl) ? 66 : 64; // pedal MIDI ctl id
|
3104
|
3140
|
unsigned d1 = cmIsFlag(np->flags,kDampDnXsFl|kSostDnXsFl) ? 64 : 0; // pedal-dn: d1>=64 pedal-up:<64
|
3105
|
|
- _cmXScoreWriteCsvRow(p,rowIdx,-1,mp->number,sectionIdStr,"ctl",np->dsecs,np->secs,d0,d1,-1,0,"",np->flags,"","");
|
|
3141
|
+ _cmXScoreWriteCsvRow(p,rowIdx,-1,mp->number,sectionIdStr,"ctl",np->dsecs,thisSecs,d0,d1,-1,0,"",np->flags,"","");
|
3106
|
3142
|
sectionIdStr = NULL;
|
3107
|
3143
|
|
3108
|
3144
|
if( cmIsFlag(np->flags,kDampUpDnXsFl) )
|
3109
|
3145
|
{
|
3110
|
3146
|
rowIdx += 1;
|
3111
|
3147
|
double millisecond = 0.0;
|
3112
|
|
- _cmXScoreWriteCsvRow(p,rowIdx,-1,mp->number,sectionIdStr,"ctl",millisecond,np->secs+millisecond,d0,64,-1,0,"",np->flags,"","");
|
|
3148
|
+ _cmXScoreWriteCsvRow(p,rowIdx,-1,mp->number,sectionIdStr,"ctl",millisecond,thisSecs+millisecond,d0,64,-1,0,"",np->flags,"","");
|
3113
|
3149
|
}
|
3114
|
3150
|
|
3115
|
3151
|
}
|
|
@@ -3123,14 +3159,13 @@ cmXsRC_t cmXScoreWriteCsv( cmXsH_t h, const cmChar_t* csvFn )
|
3123
|
3159
|
cmChar_t ebuf[ bufN+1]; ebuf[bufN] = 0;
|
3124
|
3160
|
cmChar_t dbuf[ bufN+1]; dbuf[bufN] = 0;
|
3125
|
3161
|
cmChar_t tbuf[ bufN+1]; tbuf[bufN] = 0;
|
3126
|
|
-
|
3127
|
|
-
|
|
3162
|
+
|
3128
|
3163
|
double frac = np->rvalue + (cmIsFlag(np->flags,kDotXsFl) ? (np->rvalue/2) : 0);
|
3129
|
3164
|
const cmChar_t* dyn = _cmXScoreTranslateDynamics( p, np, dbuf, bufN );
|
3130
|
3165
|
unsigned vel = np->vel==0 ? 60 : np->vel;
|
3131
|
3166
|
|
3132
|
|
- //
|
3133
|
|
- _cmXScoreWriteCsvRow(p,rowIdx,np->uid,mp->number,sectionIdStr,"non",np->dsecs,np->secs,np->pitch,vel,np->pitch,frac,dyn,np->flags,
|
|
3167
|
+ //
|
|
3168
|
+ _cmXScoreWriteCsvRow(p,rowIdx,np->uid,mp->number,sectionIdStr,"non",np->dsecs,thisSecs,np->pitch,vel,np->pitch,frac,dyn,np->flags,
|
3134
|
3169
|
cmXsFormatMeasurementCsvField(np->flags, kEvenXsFl, 'e', np->evenGroupId, ebuf, bufN ),
|
3135
|
3170
|
cmXsFormatMeasurementCsvField(np->flags, kTempoXsFl,'t', np->tempoGroupId, tbuf, bufN ));
|
3136
|
3171
|
|
|
@@ -3157,6 +3192,30 @@ cmXsRC_t cmXScoreWriteCsv( cmXsH_t h, const cmChar_t* csvFn )
|
3157
|
3192
|
return rc;
|
3158
|
3193
|
}
|
3159
|
3194
|
|
|
3195
|
+bool _cmXsIsCsvValid(cmCtx_t* ctx, cmXsH_t h, const cmChar_t* outFn)
|
|
3196
|
+{
|
|
3197
|
+ bool retFl = true;
|
|
3198
|
+ cmScH_t scH = cmScNullHandle;
|
|
3199
|
+ double srate = 44100.0;
|
|
3200
|
+ cmSymTblH_t stH = cmSymTblCreate(cmSymTblNullHandle, 0, ctx );
|
|
3201
|
+
|
|
3202
|
+ if( cmScoreInitialize( ctx, &scH, outFn, srate, NULL, 0, NULL, NULL, stH) != kOkScRC )
|
|
3203
|
+ {
|
|
3204
|
+ cmErrMsg(&ctx->err,kFileFailXsRC,"The generated CSV file (%s) could not be parsed.",cmStringNullGuard(outFn));
|
|
3205
|
+ retFl = false;
|
|
3206
|
+ }
|
|
3207
|
+ else
|
|
3208
|
+ {
|
|
3209
|
+ //cmScorePrintSets(scH,&ctx->rpt);
|
|
3210
|
+ //cmScorePrint(scH,&ctx->rpt);
|
|
3211
|
+
|
|
3212
|
+ cmScoreFinalize(&scH);
|
|
3213
|
+ }
|
|
3214
|
+
|
|
3215
|
+ cmSymTblDestroy(&stH);
|
|
3216
|
+
|
|
3217
|
+ return retFl;
|
|
3218
|
+}
|
3160
|
3219
|
|
3161
|
3220
|
void _cmXScoreReportTitle( cmRpt_t* rpt )
|
3162
|
3221
|
{
|
|
@@ -3171,9 +3230,6 @@ void _cmXScoreReportNote( cmRpt_t* rpt, const cmXsNote_t* note,unsigned index )
|
3171
|
3230
|
const cmChar_t* G = cmIsFlag(note->flags,kGraceXsFl) ? "G" : "-";
|
3172
|
3231
|
const cmChar_t* D = cmIsFlag(note->flags,kDotXsFl) ? "." : "-";
|
3173
|
3232
|
const cmChar_t* C = cmIsFlag(note->flags,kChordXsFl) ? "C" : "-";
|
3174
|
|
- const cmChar_t* e = cmIsFlag(note->flags,kEvenXsFl) ? "e" : "-";
|
3175
|
|
- const cmChar_t* d = cmIsFlag(note->flags,kDynXsFl) ? "d" : "-";
|
3176
|
|
- const cmChar_t* t = cmIsFlag(note->flags,kTempoXsFl) ? "t" : "-";
|
3177
|
3233
|
const cmChar_t* P = cmIsFlag(note->flags,kDampDnXsFl) ? "V" : "-";
|
3178
|
3234
|
const cmChar_t* s = cmIsFlag(note->flags,kSostDnXsFl) ? "{" : "-";
|
3179
|
3235
|
const cmChar_t* S = cmIsFlag(note->flags,kSectionXsFl) ? "S" : "-";
|
|
@@ -3181,6 +3237,15 @@ void _cmXScoreReportNote( cmRpt_t* rpt, const cmXsNote_t* note,unsigned index )
|
3181
|
3237
|
const cmChar_t* T0 = cmIsFlag(note->flags,kTieBegXsFl) ? "T" : "-";
|
3182
|
3238
|
const cmChar_t* T1 = cmIsFlag(note->flags,kTieEndXsFl) ? "_" : "-";
|
3183
|
3239
|
const cmChar_t* O = cmIsFlag(note->flags,kOnsetXsFl) ? "*" : "-";
|
|
3240
|
+
|
|
3241
|
+ const cmChar_t* e = cmIsFlag(note->flags,kEvenXsFl) ? "e" : "-";
|
|
3242
|
+ const cmChar_t* d = cmIsFlag(note->flags,kDynXsFl) ? "d" : "-";
|
|
3243
|
+ const cmChar_t* t = cmIsFlag(note->flags,kTempoXsFl) ? "t" : "-";
|
|
3244
|
+
|
|
3245
|
+ if( cmIsFlag(note->flags,kEvenEndXsFl) ) e="E";
|
|
3246
|
+ if( cmIsFlag(note->flags,kDynEndXsFl) ) d="D";
|
|
3247
|
+ if( cmIsFlag(note->flags,kTempoEndXsFl) ) t="T";
|
|
3248
|
+
|
3184
|
3249
|
P = cmIsFlag(note->flags,kDampUpXsFl) ? "^" : P;
|
3185
|
3250
|
P = cmIsFlag(note->flags,kDampUpDnXsFl) ? "X" : P;
|
3186
|
3251
|
s = cmIsFlag(note->flags,kSostUpXsFl) ? "}" : s;
|
|
@@ -3547,7 +3612,7 @@ cmXsRC_t _cmXsMeasComplexity( cmXsH_t h, double wndSecs )
|
3547
|
3612
|
return rc;
|
3548
|
3613
|
}
|
3549
|
3614
|
|
3550
|
|
-cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const cmChar_t* fn )
|
|
3615
|
+cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, int beginMeasNumb, int beginBPM, const cmChar_t* dir, const cmChar_t* fn )
|
3551
|
3616
|
{
|
3552
|
3617
|
cmXsRC_t rc = kOkXsRC;
|
3553
|
3618
|
cmXScore_t* p = _cmXScoreHandleToPtr(h);
|
|
@@ -3559,9 +3624,11 @@ cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
|
3559
|
3624
|
unsigned trkN = 2;
|
3560
|
3625
|
unsigned ticksPerQN = p->partL->measL->divisions;
|
3561
|
3626
|
const cmChar_t* outFn = cmFsMakeFn(dir,fn,"mid",NULL);
|
|
3627
|
+ unsigned baseTick = -1;
|
|
3628
|
+ unsigned bpm = beginBPM==0 ? 60 : beginBPM;
|
3562
|
3629
|
|
3563
|
|
- if( cmMidiFileCreate( ctx, &mfH, trkN, ticksPerQN ) != kOkMfRC )
|
3564
|
|
- return cmErrMsg(&p->err,kMidiFailXsRC,"Unable to create the MIDI file object.");
|
|
3630
|
+ //if( cmMidiFileCreate( ctx, &mfH, trkN, ticksPerQN ) != kOkMfRC )
|
|
3631
|
+ // return cmErrMsg(&p->err,kMidiFailXsRC,"Unable to create the MIDI file object.");
|
3565
|
3632
|
|
3566
|
3633
|
cmXsPart_t* pp = p->partL;
|
3567
|
3634
|
|
|
@@ -3573,8 +3640,33 @@ cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
|
3573
|
3640
|
// for each measure
|
3574
|
3641
|
for(; mp!=NULL; mp=mp->link)
|
3575
|
3642
|
{
|
|
3643
|
+
|
|
3644
|
+ // skip all measures until we reach the first measure to output
|
|
3645
|
+ if(mp->number < beginMeasNumb)
|
|
3646
|
+ continue;
|
|
3647
|
+
|
|
3648
|
+ // if the MIDI file has not yet been created
|
|
3649
|
+ if( !cmMidiFileIsValid(mfH) )
|
|
3650
|
+ {
|
|
3651
|
+ ticksPerQN = mp->divisions;
|
|
3652
|
+
|
|
3653
|
+ // create the MIDI file
|
|
3654
|
+ if( cmMidiFileCreate( ctx, &mfH, trkN, ticksPerQN ) != kOkMfRC )
|
|
3655
|
+ {
|
|
3656
|
+ rc = cmErrMsg(&p->err,kMidiFailXsRC,"Unable to create the MIDI file object.");
|
|
3657
|
+ goto errLabel;
|
|
3658
|
+ }
|
|
3659
|
+
|
|
3660
|
+ // set the starting tempo
|
|
3661
|
+ cmMidFileInsertTrackTempoMsg(mfH, 0, 0, bpm );
|
|
3662
|
+
|
|
3663
|
+ }
|
|
3664
|
+
|
3576
|
3665
|
cmXsNote_t* np = mp->noteL;
|
3577
|
3666
|
|
|
3667
|
+ if( baseTick == -1 )
|
|
3668
|
+ baseTick = np->tick;
|
|
3669
|
+
|
3578
|
3670
|
if( mp->divisions != ticksPerQN )
|
3579
|
3671
|
cmErrWarnMsg(&p->err,kMidiFailXsRC,"The 'tick per quarter note' (divisions) field in measure %i does not match the value in the first measure (%i).",mp->divisions,ticksPerQN);
|
3580
|
3672
|
|
|
@@ -3582,12 +3674,15 @@ cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
|
3582
|
3674
|
// for each note in this measure
|
3583
|
3675
|
for(; np!=NULL; np=np->slink,++ni)
|
3584
|
3676
|
{
|
|
3677
|
+ unsigned thisTick = np->tick - baseTick;
|
|
3678
|
+
|
3585
|
3679
|
switch( np->flags & (kOnsetXsFl|kMetronomeXsFl|kDampDnXsFl|kDampUpDnXsFl|kSostDnXsFl) )
|
3586
|
3680
|
{
|
3587
|
3681
|
case kOnsetXsFl:
|
|
3682
|
+ if( cmMidiFileIsValid(mfH) )
|
3588
|
3683
|
{
|
3589
|
3684
|
if( np->tied_dur <= 0 )
|
3590
|
|
- cmErrWarnMsg(&p->err,kOkXsRC,"A zero length note was encountered bar:%i tick:%i %s",np->meas->number,np->tick,cmMidiToSciPitch(np->pitch,NULL,0));
|
|
3685
|
+ cmErrWarnMsg(&p->err,kOkXsRC,"A zero length note was encountered bar:%i tick:%i (%i) %s",np->meas->number,np->tick,thisTick,cmMidiToSciPitch(np->pitch,NULL,0));
|
3591
|
3686
|
|
3592
|
3687
|
/*
|
3593
|
3688
|
if( mp->number == 20 )
|
|
@@ -3596,9 +3691,12 @@ cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
|
3596
|
3691
|
cmRptPrintf(ctx->err.rpt,"\n");
|
3597
|
3692
|
}
|
3598
|
3693
|
*/
|
3599
|
|
-
|
3600
|
|
- if( cmMidiFileInsertTrackChMsg(mfH, 1, np->tick, kNoteOnMdId, np->pitch, np->vel ) != kOkMfRC
|
3601
|
|
- ||cmMidiFileInsertTrackChMsg(mfH, 1, np->tick + np->tied_dur, kNoteOffMdId, np->pitch, 0 ) != kOkMfRC )
|
|
3694
|
+
|
|
3695
|
+ if( np->vel == 0 )
|
|
3696
|
+ cmErrWarnMsg(&p->err,kOkXsRC,"A sounding note with zero velocity was encountered at bar:%i tick:%i pitch:%s.",np->meas->number,np->tick,cmMidiToSciPitch(np->pitch,NULL,0));
|
|
3697
|
+
|
|
3698
|
+ if( cmMidiFileInsertTrackChMsg(mfH, 1, thisTick, kNoteOnMdId, np->pitch, np->vel ) != kOkMfRC
|
|
3699
|
+ ||cmMidiFileInsertTrackChMsg(mfH, 1, thisTick + np->tied_dur, kNoteOffMdId, np->pitch, 0 ) != kOkMfRC )
|
3602
|
3700
|
{
|
3603
|
3701
|
rc = kMidiFailXsRC;
|
3604
|
3702
|
}
|
|
@@ -3608,13 +3706,14 @@ cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
|
3608
|
3706
|
case kDampDnXsFl:
|
3609
|
3707
|
case kDampUpDnXsFl:
|
3610
|
3708
|
case kSostDnXsFl:
|
|
3709
|
+ if( cmMidiFileIsValid(mfH) )
|
3611
|
3710
|
{
|
3612
|
3711
|
if( np->duration <= 0 )
|
3613
|
|
- cmErrWarnMsg(&p->err,kOkXsRC,"A zero length pedal event was encountered bar:%i tick:%i",np->meas->number,np->tick);
|
|
3712
|
+ cmErrWarnMsg(&p->err,kOkXsRC,"A zero length pedal event was encountered bar:%i tick:%i (%i)",np->meas->number,np->tick,thisTick);
|
3614
|
3713
|
|
3615
|
3714
|
cmMidiByte_t d0 = cmIsFlag(np->flags,kSostDnXsFl) ? kSostenutoCtlMdId : kSustainCtlMdId;
|
3616
|
|
- if( (cmMidiFileInsertTrackChMsg(mfH, 1, np->tick, kCtlMdId, d0, 127 ) != kOkMfRC )
|
3617
|
|
- ||(cmMidiFileInsertTrackChMsg(mfH, 1, np->tick + np->duration, kCtlMdId, d0, 0 ) != kOkMfRC ) )
|
|
3715
|
+ if( (cmMidiFileInsertTrackChMsg(mfH, 1, thisTick, kCtlMdId, d0, 127 ) != kOkMfRC )
|
|
3716
|
+ ||(cmMidiFileInsertTrackChMsg(mfH, 1, thisTick + np->duration, kCtlMdId, d0, 0 ) != kOkMfRC ) )
|
3618
|
3717
|
{
|
3619
|
3718
|
rc = kMidiFailXsRC;
|
3620
|
3719
|
}
|
|
@@ -3622,8 +3721,10 @@ cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
|
3622
|
3721
|
break;
|
3623
|
3722
|
|
3624
|
3723
|
case kMetronomeXsFl:
|
3625
|
|
- if( cmMidFileInsertTrackTempoMsg(mfH, 0, np->tick, np->duration ) != kOkMfRC )
|
3626
|
|
- rc = kMidiFailXsRC;
|
|
3724
|
+ bpm = np->duration;
|
|
3725
|
+ if( cmMidiFileIsValid(mfH) )
|
|
3726
|
+ if( cmMidFileInsertTrackTempoMsg(mfH, 0, thisTick, bpm ) != kOkMfRC )
|
|
3727
|
+ rc = kMidiFailXsRC;
|
3627
|
3728
|
break;
|
3628
|
3729
|
|
3629
|
3730
|
case 0:
|
|
@@ -3641,12 +3742,13 @@ cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
|
3641
|
3742
|
}
|
3642
|
3743
|
}
|
3643
|
3744
|
}
|
3644
|
|
-
|
3645
|
|
- if( cmMidiFileWrite(mfH,outFn) != kOkMfRC )
|
3646
|
|
- {
|
3647
|
|
- rc = cmErrMsg(&p->err,kMidiFailXsRC,"MIDI file write failed on '%s'.",cmStringNullGuard(outFn));
|
3648
|
|
- goto errLabel;
|
3649
|
|
- }
|
|
3745
|
+
|
|
3746
|
+ if( cmMidiFileIsValid(mfH) )
|
|
3747
|
+ if( cmMidiFileWrite(mfH,outFn) != kOkMfRC )
|
|
3748
|
+ {
|
|
3749
|
+ rc = cmErrMsg(&p->err,kMidiFailXsRC,"MIDI file write failed on '%s'.",cmStringNullGuard(outFn));
|
|
3750
|
+ goto errLabel;
|
|
3751
|
+ }
|
3650
|
3752
|
|
3651
|
3753
|
errLabel:
|
3652
|
3754
|
cmFsFreeFn(outFn);
|
|
@@ -3659,6 +3761,23 @@ cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
|
3659
|
3761
|
return rc;
|
3660
|
3762
|
}
|
3661
|
3763
|
|
|
3764
|
+bool _cmXsIsMidiFileValid( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const cmChar_t* fn )
|
|
3765
|
+{
|
|
3766
|
+ const cmChar_t* midiFn = cmFsMakeFn(dir,fn,"mid",NULL);
|
|
3767
|
+ cmMidiFileH_t mfH = cmMidiFileNullHandle;
|
|
3768
|
+
|
|
3769
|
+ if( cmMidiFileOpen( ctx, &mfH, midiFn ) == kOkMfRC )
|
|
3770
|
+ {
|
|
3771
|
+ cmMidiFileClose(&mfH);
|
|
3772
|
+ return true;
|
|
3773
|
+ }
|
|
3774
|
+
|
|
3775
|
+ cmXScore_t* p = _cmXScoreHandleToPtr(h);
|
|
3776
|
+ cmErrMsg(&p->err,kMidiFailXsRC,"The generated MIDI file '%s' is not valid.", cmStringNullGuard(midiFn));
|
|
3777
|
+
|
|
3778
|
+ return false;
|
|
3779
|
+}
|
|
3780
|
+
|
3662
|
3781
|
typedef struct cmXsSvgEvt_str
|
3663
|
3782
|
{
|
3664
|
3783
|
unsigned flags; // k???XsFl
|
|
@@ -3864,7 +3983,7 @@ void _cmXsPushSvgEvent( cmXScore_t* p, cmXsMidiFile_t* mf, unsigned flags, unsig
|
3864
|
3983
|
mf->eol = e;
|
3865
|
3984
|
}
|
3866
|
3985
|
|
3867
|
|
-cmXsRC_t _cmXScoreGenSvg( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const cmChar_t* fn )
|
|
3986
|
+cmXsRC_t _cmXScoreGenSvg( cmCtx_t* ctx, cmXsH_t h, int beginMeasNumb, const cmChar_t* dir, const cmChar_t* fn )
|
3868
|
3987
|
{
|
3869
|
3988
|
cmXScore_t* p = _cmXScoreHandleToPtr(h);
|
3870
|
3989
|
cmXsPart_t* pp = p->partL;
|
|
@@ -3877,6 +3996,8 @@ cmXsRC_t _cmXScoreGenSvg( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const cm
|
3877
|
3996
|
const cmXsMeas_t* meas = pp->measL;
|
3878
|
3997
|
for(; meas!=NULL; meas=meas->link)
|
3879
|
3998
|
{
|
|
3999
|
+ if( meas->number < beginMeasNumb )
|
|
4000
|
+ continue;
|
3880
|
4001
|
|
3881
|
4002
|
const cmXsNote_t* note = meas->noteL;
|
3882
|
4003
|
for(; note!=NULL; note=note->slink)
|
|
@@ -3929,11 +4050,14 @@ cmXsRC_t _cmXScoreGenSvg( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const cm
|
3929
|
4050
|
|
3930
|
4051
|
|
3931
|
4052
|
cmXsRC_t cmXScoreTest(
|
3932
|
|
- cmCtx_t* ctx,
|
|
4053
|
+ cmCtx_t* ctx,
|
3933
|
4054
|
const cmChar_t* xmlFn,
|
3934
|
4055
|
const cmChar_t* editFn,
|
3935
|
4056
|
const cmChar_t* csvOutFn,
|
3936
|
|
- const cmChar_t* midiOutFn)
|
|
4057
|
+ const cmChar_t* midiOutFn,
|
|
4058
|
+ bool reportFl,
|
|
4059
|
+ int beginMeasNumb,
|
|
4060
|
+ int beginBPM )
|
3937
|
4061
|
{
|
3938
|
4062
|
cmXsRC_t rc;
|
3939
|
4063
|
cmXsH_t h = cmXsNullHandle;
|
|
@@ -3952,45 +4076,33 @@ cmXsRC_t cmXScoreTest(
|
3952
|
4076
|
|
3953
|
4077
|
if( csvOutFn != NULL )
|
3954
|
4078
|
{
|
3955
|
|
- cmScH_t scH = cmScNullHandle;
|
3956
|
|
- double srate = 44100.0;
|
3957
|
|
-
|
3958
|
|
- cmXScoreWriteCsv(h,csvOutFn);
|
3959
|
|
-
|
3960
|
|
- cmSymTblH_t stH = cmSymTblCreate(cmSymTblNullHandle, 0, ctx );
|
3961
|
4079
|
|
3962
|
|
- if( cmScoreInitialize( ctx, &scH, csvOutFn, srate, NULL, 0, NULL, NULL, stH) != kOkScRC )
|
3963
|
|
- cmErrMsg(&ctx->err,kFileFailXsRC,"The generated CSV file could not be parsed.");
|
3964
|
|
- else
|
3965
|
|
- {
|
3966
|
|
- //cmScorePrintSets(scH,&ctx->rpt);
|
3967
|
|
- //cmScorePrint(scH,&ctx->rpt);
|
3968
|
|
-
|
3969
|
|
- cmScoreFinalize(&scH);
|
3970
|
|
- }
|
|
4080
|
+ cmXScoreWriteCsv(h,beginMeasNumb,csvOutFn);
|
3971
|
4081
|
|
3972
|
|
- cmSymTblDestroy(&stH);
|
|
4082
|
+ _cmXsIsCsvValid(ctx,h,csvOutFn);
|
3973
|
4083
|
}
|
3974
|
4084
|
|
3975
|
4085
|
if( midiOutFn != NULL )
|
3976
|
4086
|
{
|
3977
|
|
-
|
3978
|
4087
|
// measure the score complexity
|
3979
|
4088
|
double wndSecs = 1.0;
|
|
4089
|
+
|
3980
|
4090
|
_cmXsMeasComplexity(h,wndSecs);
|
3981
|
|
-
|
3982
|
4091
|
|
3983
|
4092
|
cmFileSysPathPart_t* pp = cmFsPathParts(midiOutFn);
|
3984
|
4093
|
|
3985
|
|
- _cmXsWriteMidiFile(ctx, h, pp->dirStr, pp->fnStr );
|
|
4094
|
+ _cmXsWriteMidiFile(ctx, h, beginMeasNumb, beginBPM, pp->dirStr, pp->fnStr );
|
|
4095
|
+
|
|
4096
|
+ _cmXsIsMidiFileValid(ctx, h, pp->dirStr, pp->fnStr );
|
3986
|
4097
|
|
3987
|
|
- _cmXScoreGenSvg( ctx, h, pp->dirStr, pp->fnStr );
|
|
4098
|
+ _cmXScoreGenSvg( ctx, h, beginMeasNumb, pp->dirStr, pp->fnStr );
|
3988
|
4099
|
|
3989
|
4100
|
cmFsFreePathParts(pp);
|
3990
|
4101
|
|
3991
|
4102
|
}
|
3992
|
|
-
|
3993
|
|
- cmXScoreReport(h,&ctx->rpt,true);
|
|
4103
|
+
|
|
4104
|
+ if(reportFl)
|
|
4105
|
+ cmXScoreReport(h,&ctx->rpt,true);
|
3994
|
4106
|
|
3995
|
4107
|
return cmXScoreFinalize(&h);
|
3996
|
4108
|
|