|
@@ -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
|
|
@@ -270,12 +274,13 @@ cmXsRC_t _cmXScorePushNote( cmXScore_t* p, cmXsMeas_t* meas, unsigned voiceId, c
|
270
|
274
|
}
|
271
|
275
|
|
272
|
276
|
|
273
|
|
-void _cmXScoreRemoveNote( cmXsNote_t* note )
|
|
277
|
+cmXsRC_t _cmXScoreRemoveNote( cmXsNote_t* note )
|
274
|
278
|
{
|
275
|
279
|
cmXsNote_t* n0 = NULL;
|
276
|
280
|
cmXsNote_t* n1 = note->voice->noteL;
|
277
|
|
-
|
|
281
|
+ unsigned cnt = 0;
|
278
|
282
|
for(; n1!=NULL; n1=n1->mlink)
|
|
283
|
+ {
|
279
|
284
|
if( n1->uid == note->uid )
|
280
|
285
|
{
|
281
|
286
|
if( n0 == NULL )
|
|
@@ -283,12 +288,17 @@ void _cmXScoreRemoveNote( cmXsNote_t* note )
|
283
|
288
|
else
|
284
|
289
|
n0->mlink = n1->mlink;
|
285
|
290
|
|
|
291
|
+ cnt = 1;
|
286
|
292
|
break;
|
287
|
293
|
}
|
288
|
294
|
|
|
295
|
+ n0 = n1;
|
|
296
|
+ }
|
|
297
|
+
|
289
|
298
|
n0 = NULL;
|
290
|
299
|
n1 = note->meas->noteL;
|
291
|
300
|
for(; n1!=NULL; n1=n1->slink)
|
|
301
|
+ {
|
292
|
302
|
if( n1->uid == note->uid )
|
293
|
303
|
{
|
294
|
304
|
if( n0 == NULL )
|
|
@@ -296,13 +306,20 @@ void _cmXScoreRemoveNote( cmXsNote_t* note )
|
296
|
306
|
else
|
297
|
307
|
n0->slink = n1->slink;
|
298
|
308
|
|
|
309
|
+ cnt = 2;
|
299
|
310
|
break;
|
300
|
311
|
}
|
|
312
|
+
|
|
313
|
+ n0 = n1;
|
|
314
|
+ }
|
|
315
|
+ return cnt == 2 ? kOkXsRC : kSyntaxErrorXsRC;
|
301
|
316
|
|
302
|
317
|
}
|
303
|
318
|
|
304
|
319
|
void _cmXScoreInsertNoteBefore( cmXsNote_t* note, cmXsNote_t* nn )
|
305
|
320
|
{
|
|
321
|
+ assert( note != NULL );
|
|
322
|
+
|
306
|
323
|
// insert the new note into the voice list before 'note'
|
307
|
324
|
cmXsNote_t* n0 = NULL;
|
308
|
325
|
cmXsNote_t* n1 = note->voice->noteL;
|
|
@@ -515,33 +532,44 @@ cmXsRC_t _cmXScoreParseColor( cmXScore_t* p, const cmXmlNode_t* nnp, cmXsNote_t
|
515
|
532
|
|
516
|
533
|
typedef struct map_str
|
517
|
534
|
{
|
518
|
|
- unsigned value;
|
|
535
|
+ unsigned long long value;
|
519
|
536
|
const cmChar_t* label;
|
520
|
537
|
} map_t;
|
521
|
538
|
|
522
|
539
|
map_t mapV[] =
|
523
|
540
|
{
|
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)
|
|
541
|
+ { kEvenXsFl, "#0000FF" }, // blue (even)
|
|
542
|
+ { kEvenXsFl | kEvenEndXsFl, "#0000FE" }, // blue (even end)
|
|
543
|
+ { kEvenXsFl | kEvenEndXsFl, "#0000FD" }, // blue (even end)
|
|
544
|
+ { kTempoXsFl, "#00FF00" }, // green (tempo)
|
|
545
|
+ { kTempoXsFl | kTempoEndXsFl, "#00FE00" }, // green (tempo end)
|
|
546
|
+ { kDynXsFl, "#FF0000" }, // red (dynamics)
|
|
547
|
+ { kDynXsFl | kDynEndXsFl, "#FE0000" }, // red (dynamics end)
|
|
548
|
+ { kDynXsFl | kDynEndXsFl, "#FD0000" }, // red (dynamics end)
|
|
549
|
+ { kTempoXsFl | kEvenXsFl, "#00FFFF" }, // green + blue (turquoise)
|
|
550
|
+ { kTempoXsFl | kEvenXsFl | kEvenEndXsFl, "#00FFFE" }, // green + blue (turquoise) (end)
|
|
551
|
+ { kDynXsFl | kEvenXsFl, "#FF00FF" }, // red + blue
|
|
552
|
+ { kDynXsFl | kEvenXsFl | kEvenEndXsFl, "#FF00FE" }, // red + blue (end)
|
|
553
|
+ { kDynXsFl | kEvenXsFl | kEvenEndXsFl, "#FF00FD" }, // red + blue (end)
|
|
554
|
+ { kDynXsFl | kEvenXsFl, "#FF0CF7" }, // magenta (even+dyn)
|
|
555
|
+ { kDynXsFl | kTempoXsFl, "#FF7F00" }, // red + green (brown)
|
|
556
|
+ { kDynXsFl | kTempoXsFl, "#FE7F00" }, // red + green (brown) (end)
|
|
557
|
+ { kDynXsFl | kTempoXsFl, "#FD7F00" }, // red + green (brown) (end)
|
|
558
|
+ { kTempoXsFl | kEvenXsFl | kDynXsFl, "#996633" }, // (purple)
|
|
559
|
+ { kTempoXsFl | kEvenXsFl | kDynXsFl | kDynEndXsFl, "#996632" }, // (purple)
|
|
560
|
+ { kDynXsFl, "#FF6A03" }, // 176 orange (dynamics)
|
|
561
|
+ { kEvenXsFl, "#2F00E8" }, // 1001 blue (even)
|
|
562
|
+ { kTempoXsFl, "#01CD1F" }, // 1196 green (tempo)
|
|
563
|
+ { kEvenXsFl, "#3600E8" }, // 1627 blue (even)
|
|
564
|
+ { kDynXsFl | kTempoXsFl, "#9E8F15" }, // 8827 brown (dyn + tempo)
|
|
565
|
+ { kEvenXsFl, "#2E00E6" }, // 5393 blue (even)
|
|
566
|
+ { kEvenXsFl, "#2C00DD" }, // 5895 blue (even)
|
|
567
|
+ { kDynXsFl, "#FF5B03" }, // 6498 orange (dyn)
|
|
568
|
+ { kDynXsFl, "#FF6104" }, // 6896 orange
|
|
569
|
+ { kEvenXsFl, "#2A00E6" }, // 7781 blue
|
|
570
|
+ { kEvenXsFl, "#2300DD" }, // 8300 blue (even)
|
|
571
|
+ { kTempoXsFl, "#03CD22" }, // 10820 green (tempo)
|
|
572
|
+ { kEvenXsFl, "#3400DB" }, // 11627 blue (dyn)
|
545
|
573
|
{ -1, "" }
|
546
|
574
|
};
|
547
|
575
|
|
|
@@ -1785,7 +1813,7 @@ cmXsRC_t _cmXScoreProcessGraceNotes( cmXScore_t* p, unsigned nextGraceGroupId )
|
1785
|
1813
|
// grace note groups must have at least 3 members
|
1786
|
1814
|
if( gN < 3 )
|
1787
|
1815
|
{
|
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 );
|
|
1816
|
+ 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
|
1817
|
break;
|
1790
|
1818
|
}
|
1791
|
1819
|
|
|
@@ -2130,7 +2158,8 @@ cmXsRC_t _cmXScoreReorderMeas( cmXScore_t* p, unsigned measNumb, cmXsReorder_t*
|
2130
|
2158
|
// remove deleted notes
|
2131
|
2159
|
for(i=0; i<rN; ++i)
|
2132
|
2160
|
if( cmIsFlag(rV[i].newFlags,kDeleteXsFl) )
|
2133
|
|
- _cmXScoreRemoveNote( rV[i].note );
|
|
2161
|
+ if( _cmXScoreRemoveNote( rV[i].note ) != kOkXsRC )
|
|
2162
|
+ return cmErrMsg(&p->err,kSyntaxErrorXsRC,"Event marked to skip was not found in measure: %i",measNumb);
|
2134
|
2163
|
|
2135
|
2164
|
cmXsMeas_t* mp = rV[0].note->meas;
|
2136
|
2165
|
cmXsNote_t* n0p = NULL;
|
|
@@ -2214,7 +2243,7 @@ cmXsRC_t _cmXScoreReorderMeas( cmXScore_t* p, unsigned measNumb, cmXsReorder_t*
|
2214
|
2243
|
|
2215
|
2244
|
}
|
2216
|
2245
|
|
2217
|
|
-cmXsRC_t _cmXScoreReorderParseDyn(cmXScore_t* p, const cmChar_t* b, unsigned lineNumb, unsigned* dynIdxRef, unsigned* flagsRef )
|
|
2246
|
+cmXsRC_t _cmXScoreReorderParseDyn(cmXScore_t* p, const cmChar_t* b, unsigned lineNumb, unsigned* dynIdxRef, unsigned* flagsRef, int measNumb )
|
2218
|
2247
|
{
|
2219
|
2248
|
cmXsRC_t rc = kOkXsRC;
|
2220
|
2249
|
const cmChar_t* s = NULL;
|
|
@@ -2239,6 +2268,7 @@ cmXsRC_t _cmXScoreReorderParseDyn(cmXScore_t* p, const cmChar_t* b, unsigned lin
|
2239
|
2268
|
|
2240
|
2269
|
if( *s == '!')
|
2241
|
2270
|
{
|
|
2271
|
+ //printf("E %3i %5i %s\n",measNumb,lineNumb,b);
|
2242
|
2272
|
endForkFl = true;
|
2243
|
2273
|
++s;
|
2244
|
2274
|
}
|
|
@@ -2251,7 +2281,11 @@ cmXsRC_t _cmXScoreReorderParseDyn(cmXScore_t* p, const cmChar_t* b, unsigned lin
|
2251
|
2281
|
if( isupper(*s) )
|
2252
|
2282
|
{
|
2253
|
2283
|
if( !endForkFl)
|
|
2284
|
+ {
|
2254
|
2285
|
begForkFl=true;
|
|
2286
|
+ //printf("B %3i %5i %s\n",measNumb,lineNumb,b);
|
|
2287
|
+
|
|
2288
|
+ }
|
2255
|
2289
|
}
|
2256
|
2290
|
else
|
2257
|
2291
|
{
|
|
@@ -2431,7 +2465,11 @@ cmXsRC_t _cmXScoreReorderParseGrace(cmXScore_t* p, const cmChar_t* b, unsigned
|
2431
|
2465
|
continue;
|
2432
|
2466
|
|
2433
|
2467
|
default:
|
2434
|
|
- { assert(0); }
|
|
2468
|
+ {
|
|
2469
|
+ return cmErrMsg(&p->err,kSyntaxErrorXsRC,"Unexpected grace note reorder character code %c on line %i.",*s,line);
|
|
2470
|
+
|
|
2471
|
+ assert(0);
|
|
2472
|
+ }
|
2435
|
2473
|
}
|
2436
|
2474
|
|
2437
|
2475
|
break;
|
|
@@ -2457,7 +2495,7 @@ cmXsRC_t _cmXScoreReorderParsePitch(cmXScore_t* p, const cmChar_t* b, unsigned
|
2457
|
2495
|
++s;
|
2458
|
2496
|
|
2459
|
2497
|
j=2;
|
2460
|
|
- for(i=0; i<j && s[i]; ++i,++s)
|
|
2498
|
+ for(i=0; i<j && *s; ++i,++s)
|
2461
|
2499
|
{
|
2462
|
2500
|
buf[i] = *s;
|
2463
|
2501
|
|
|
@@ -2479,8 +2517,9 @@ cmXsRC_t _cmXScoreReorderParsePitch(cmXScore_t* p, const cmChar_t* b, unsigned
|
2479
|
2517
|
if( pitch<kInvalidMidiByte)
|
2480
|
2518
|
*pitchRef = pitch;
|
2481
|
2519
|
else
|
|
2520
|
+ {
|
2482
|
2521
|
rc = cmErrMsg(&p->err,kSyntaxErrorXsRC,"Pitch conversion from '%s' failed on line %i.",buf,line);
|
2483
|
|
-
|
|
2522
|
+ }
|
2484
|
2523
|
return rc;
|
2485
|
2524
|
}
|
2486
|
2525
|
|
|
@@ -2563,7 +2602,7 @@ cmXsRC_t _cmXsApplyEditFile( cmXScore_t* p, const cmChar_t* fn )
|
2563
|
2602
|
goto errLabel;
|
2564
|
2603
|
|
2565
|
2604
|
// parse the dynamic marking following a '!'
|
2566
|
|
- if((rc = _cmXScoreReorderParseDyn(p,b,ln+1,&r.dynIdx, &r.newFlags)) != kOkXsRC )
|
|
2605
|
+ if((rc = _cmXScoreReorderParseDyn(p,b,ln+1,&r.dynIdx, &r.newFlags, measNumb)) != kOkXsRC )
|
2567
|
2606
|
goto errLabel;
|
2568
|
2607
|
|
2569
|
2608
|
// parse the @newtick marker
|
|
@@ -3062,12 +3101,13 @@ cmXsRC_t _cmXScoreWriteCsvRow(
|
3062
|
3101
|
return rc;
|
3063
|
3102
|
}
|
3064
|
3103
|
|
3065
|
|
-cmXsRC_t cmXScoreWriteCsv( cmXsH_t h, const cmChar_t* csvFn )
|
|
3104
|
+cmXsRC_t cmXScoreWriteCsv( cmXsH_t h, int begMeasNumb, const cmChar_t* csvFn )
|
3066
|
3105
|
{
|
3067
|
3106
|
cmXsRC_t rc = kOkXsRC;
|
3068
|
3107
|
cmXScore_t* p = _cmXScoreHandleToPtr(h);
|
3069
|
3108
|
unsigned rowIdx = 1;
|
3070
|
3109
|
const cmChar_t* sectionIdStr = NULL;
|
|
3110
|
+ double baseSecs = -1;
|
3071
|
3111
|
|
3072
|
3112
|
if( !cmCsvIsValid(p->csvH) )
|
3073
|
3113
|
return cmErrMsg(&p->err,kCsvFailXsRC,"The CSV output object is not initialized.");
|
|
@@ -3079,12 +3119,22 @@ cmXsRC_t cmXScoreWriteCsv( cmXsH_t h, const cmChar_t* csvFn )
|
3079
|
3119
|
for(; pp!=NULL; pp=pp->link)
|
3080
|
3120
|
{
|
3081
|
3121
|
cmXsMeas_t* mp = pp->measL;
|
|
3122
|
+
|
3082
|
3123
|
for(; mp!=NULL; mp=mp->link)
|
3083
|
3124
|
{
|
|
3125
|
+
|
|
3126
|
+ if( mp->number < begMeasNumb)
|
|
3127
|
+ continue;
|
|
3128
|
+
|
3084
|
3129
|
cmXsNote_t* np = mp->noteL;
|
|
3130
|
+
|
|
3131
|
+ if( baseSecs == -1 )
|
|
3132
|
+ baseSecs = np->secs;
|
|
3133
|
+
|
3085
|
3134
|
for(; np!=NULL; np=np->slink)
|
3086
|
3135
|
{
|
3087
|
|
-
|
|
3136
|
+ double thisSecs = np->secs - baseSecs;
|
|
3137
|
+
|
3088
|
3138
|
// if this is a section event
|
3089
|
3139
|
if( cmIsFlag(np->flags,kSectionXsFl) )
|
3090
|
3140
|
sectionIdStr = np->tvalue;
|
|
@@ -3092,7 +3142,7 @@ cmXsRC_t cmXScoreWriteCsv( cmXsH_t h, const cmChar_t* csvFn )
|
3092
|
3142
|
// if this is a bar event
|
3093
|
3143
|
if( cmIsFlag(np->flags,kBarXsFl) )
|
3094
|
3144
|
{
|
3095
|
|
- _cmXScoreWriteCsvRow(p,rowIdx,-1,mp->number,sectionIdStr,"bar",np->dsecs,np->secs,0,0,-1,0,"",np->flags,"","");
|
|
3145
|
+ _cmXScoreWriteCsvRow(p,rowIdx,-1,mp->number,sectionIdStr,"bar",np->dsecs,thisSecs,0,0,-1,0,"",np->flags,"","");
|
3096
|
3146
|
sectionIdStr = NULL;
|
3097
|
3147
|
}
|
3098
|
3148
|
else
|
|
@@ -3102,14 +3152,14 @@ cmXsRC_t cmXScoreWriteCsv( cmXsH_t h, const cmChar_t* csvFn )
|
3102
|
3152
|
{
|
3103
|
3153
|
unsigned d0 = cmIsFlag(np->flags,kSostDnXsFl |kSostUpXsFl) ? 66 : 64; // pedal MIDI ctl id
|
3104
|
3154
|
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,"","");
|
|
3155
|
+ _cmXScoreWriteCsvRow(p,rowIdx,-1,mp->number,sectionIdStr,"ctl",np->dsecs,thisSecs,d0,d1,-1,0,"",np->flags,"","");
|
3106
|
3156
|
sectionIdStr = NULL;
|
3107
|
3157
|
|
3108
|
3158
|
if( cmIsFlag(np->flags,kDampUpDnXsFl) )
|
3109
|
3159
|
{
|
3110
|
3160
|
rowIdx += 1;
|
3111
|
3161
|
double millisecond = 0.0;
|
3112
|
|
- _cmXScoreWriteCsvRow(p,rowIdx,-1,mp->number,sectionIdStr,"ctl",millisecond,np->secs+millisecond,d0,64,-1,0,"",np->flags,"","");
|
|
3162
|
+ _cmXScoreWriteCsvRow(p,rowIdx,-1,mp->number,sectionIdStr,"ctl",millisecond,thisSecs+millisecond,d0,64,-1,0,"",np->flags,"","");
|
3113
|
3163
|
}
|
3114
|
3164
|
|
3115
|
3165
|
}
|
|
@@ -3123,14 +3173,13 @@ cmXsRC_t cmXScoreWriteCsv( cmXsH_t h, const cmChar_t* csvFn )
|
3123
|
3173
|
cmChar_t ebuf[ bufN+1]; ebuf[bufN] = 0;
|
3124
|
3174
|
cmChar_t dbuf[ bufN+1]; dbuf[bufN] = 0;
|
3125
|
3175
|
cmChar_t tbuf[ bufN+1]; tbuf[bufN] = 0;
|
3126
|
|
-
|
3127
|
|
-
|
|
3176
|
+
|
3128
|
3177
|
double frac = np->rvalue + (cmIsFlag(np->flags,kDotXsFl) ? (np->rvalue/2) : 0);
|
3129
|
3178
|
const cmChar_t* dyn = _cmXScoreTranslateDynamics( p, np, dbuf, bufN );
|
3130
|
3179
|
unsigned vel = np->vel==0 ? 60 : np->vel;
|
3131
|
3180
|
|
3132
|
|
- //
|
3133
|
|
- _cmXScoreWriteCsvRow(p,rowIdx,np->uid,mp->number,sectionIdStr,"non",np->dsecs,np->secs,np->pitch,vel,np->pitch,frac,dyn,np->flags,
|
|
3181
|
+ //
|
|
3182
|
+ _cmXScoreWriteCsvRow(p,rowIdx,np->uid,mp->number,sectionIdStr,"non",np->dsecs,thisSecs,np->pitch,vel,np->pitch,frac,dyn,np->flags,
|
3134
|
3183
|
cmXsFormatMeasurementCsvField(np->flags, kEvenXsFl, 'e', np->evenGroupId, ebuf, bufN ),
|
3135
|
3184
|
cmXsFormatMeasurementCsvField(np->flags, kTempoXsFl,'t', np->tempoGroupId, tbuf, bufN ));
|
3136
|
3185
|
|
|
@@ -3157,6 +3206,30 @@ cmXsRC_t cmXScoreWriteCsv( cmXsH_t h, const cmChar_t* csvFn )
|
3157
|
3206
|
return rc;
|
3158
|
3207
|
}
|
3159
|
3208
|
|
|
3209
|
+bool _cmXsIsCsvValid(cmCtx_t* ctx, cmXsH_t h, const cmChar_t* outFn)
|
|
3210
|
+{
|
|
3211
|
+ bool retFl = true;
|
|
3212
|
+ cmScH_t scH = cmScNullHandle;
|
|
3213
|
+ double srate = 44100.0;
|
|
3214
|
+ cmSymTblH_t stH = cmSymTblCreate(cmSymTblNullHandle, 0, ctx );
|
|
3215
|
+
|
|
3216
|
+ if( cmScoreInitialize( ctx, &scH, outFn, srate, NULL, 0, NULL, NULL, stH) != kOkScRC )
|
|
3217
|
+ {
|
|
3218
|
+ cmErrMsg(&ctx->err,kFileFailXsRC,"The generated CSV file (%s) could not be parsed.",cmStringNullGuard(outFn));
|
|
3219
|
+ retFl = false;
|
|
3220
|
+ }
|
|
3221
|
+ else
|
|
3222
|
+ {
|
|
3223
|
+ //cmScorePrintSets(scH,&ctx->rpt);
|
|
3224
|
+ //cmScorePrint(scH,&ctx->rpt);
|
|
3225
|
+
|
|
3226
|
+ cmScoreFinalize(&scH);
|
|
3227
|
+ }
|
|
3228
|
+
|
|
3229
|
+ cmSymTblDestroy(&stH);
|
|
3230
|
+
|
|
3231
|
+ return retFl;
|
|
3232
|
+}
|
3160
|
3233
|
|
3161
|
3234
|
void _cmXScoreReportTitle( cmRpt_t* rpt )
|
3162
|
3235
|
{
|
|
@@ -3171,9 +3244,6 @@ void _cmXScoreReportNote( cmRpt_t* rpt, const cmXsNote_t* note,unsigned index )
|
3171
|
3244
|
const cmChar_t* G = cmIsFlag(note->flags,kGraceXsFl) ? "G" : "-";
|
3172
|
3245
|
const cmChar_t* D = cmIsFlag(note->flags,kDotXsFl) ? "." : "-";
|
3173
|
3246
|
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
|
3247
|
const cmChar_t* P = cmIsFlag(note->flags,kDampDnXsFl) ? "V" : "-";
|
3178
|
3248
|
const cmChar_t* s = cmIsFlag(note->flags,kSostDnXsFl) ? "{" : "-";
|
3179
|
3249
|
const cmChar_t* S = cmIsFlag(note->flags,kSectionXsFl) ? "S" : "-";
|
|
@@ -3181,6 +3251,15 @@ void _cmXScoreReportNote( cmRpt_t* rpt, const cmXsNote_t* note,unsigned index )
|
3181
|
3251
|
const cmChar_t* T0 = cmIsFlag(note->flags,kTieBegXsFl) ? "T" : "-";
|
3182
|
3252
|
const cmChar_t* T1 = cmIsFlag(note->flags,kTieEndXsFl) ? "_" : "-";
|
3183
|
3253
|
const cmChar_t* O = cmIsFlag(note->flags,kOnsetXsFl) ? "*" : "-";
|
|
3254
|
+
|
|
3255
|
+ const cmChar_t* e = cmIsFlag(note->flags,kEvenXsFl) ? "e" : "-";
|
|
3256
|
+ const cmChar_t* d = cmIsFlag(note->flags,kDynXsFl) ? "d" : "-";
|
|
3257
|
+ const cmChar_t* t = cmIsFlag(note->flags,kTempoXsFl) ? "t" : "-";
|
|
3258
|
+
|
|
3259
|
+ if( cmIsFlag(note->flags,kEvenEndXsFl) ) e="E";
|
|
3260
|
+ if( cmIsFlag(note->flags,kDynEndXsFl) ) d="D";
|
|
3261
|
+ if( cmIsFlag(note->flags,kTempoEndXsFl) ) t="T";
|
|
3262
|
+
|
3184
|
3263
|
P = cmIsFlag(note->flags,kDampUpXsFl) ? "^" : P;
|
3185
|
3264
|
P = cmIsFlag(note->flags,kDampUpDnXsFl) ? "X" : P;
|
3186
|
3265
|
s = cmIsFlag(note->flags,kSostUpXsFl) ? "}" : s;
|
|
@@ -3226,14 +3305,14 @@ void _cmXScoreReportNote( cmRpt_t* rpt, const cmXsNote_t* note,unsigned index )
|
3226
|
3305
|
|
3227
|
3306
|
if( cmIsFlag(note->flags,kEndGraceXsFl) )
|
3228
|
3307
|
cmRptPrintf(rpt," E");
|
3229
|
|
-
|
3230
|
|
-
|
|
3308
|
+
|
3231
|
3309
|
if( cmIsFlag(note->flags,kDynBegForkXsFl) )
|
3232
|
3310
|
cmRptPrintf(rpt," B");
|
3233
|
3311
|
|
3234
|
3312
|
if( cmIsFlag(note->flags,kDynEndForkXsFl) )
|
3235
|
3313
|
cmRptPrintf(rpt," E");
|
3236
|
|
- */
|
|
3314
|
+ */
|
|
3315
|
+
|
3237
|
3316
|
}
|
3238
|
3317
|
|
3239
|
3318
|
|
|
@@ -3547,7 +3626,7 @@ cmXsRC_t _cmXsMeasComplexity( cmXsH_t h, double wndSecs )
|
3547
|
3626
|
return rc;
|
3548
|
3627
|
}
|
3549
|
3628
|
|
3550
|
|
-cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const cmChar_t* fn )
|
|
3629
|
+cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, int beginMeasNumb, int beginBPM, const cmChar_t* dir, const cmChar_t* fn )
|
3551
|
3630
|
{
|
3552
|
3631
|
cmXsRC_t rc = kOkXsRC;
|
3553
|
3632
|
cmXScore_t* p = _cmXScoreHandleToPtr(h);
|
|
@@ -3559,9 +3638,11 @@ cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
|
3559
|
3638
|
unsigned trkN = 2;
|
3560
|
3639
|
unsigned ticksPerQN = p->partL->measL->divisions;
|
3561
|
3640
|
const cmChar_t* outFn = cmFsMakeFn(dir,fn,"mid",NULL);
|
|
3641
|
+ unsigned baseTick = -1;
|
|
3642
|
+ unsigned bpm = beginBPM==0 ? 60 : beginBPM;
|
3562
|
3643
|
|
3563
|
|
- if( cmMidiFileCreate( ctx, &mfH, trkN, ticksPerQN ) != kOkMfRC )
|
3564
|
|
- return cmErrMsg(&p->err,kMidiFailXsRC,"Unable to create the MIDI file object.");
|
|
3644
|
+ //if( cmMidiFileCreate( ctx, &mfH, trkN, ticksPerQN ) != kOkMfRC )
|
|
3645
|
+ // return cmErrMsg(&p->err,kMidiFailXsRC,"Unable to create the MIDI file object.");
|
3565
|
3646
|
|
3566
|
3647
|
cmXsPart_t* pp = p->partL;
|
3567
|
3648
|
|
|
@@ -3573,8 +3654,33 @@ cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
|
3573
|
3654
|
// for each measure
|
3574
|
3655
|
for(; mp!=NULL; mp=mp->link)
|
3575
|
3656
|
{
|
|
3657
|
+
|
|
3658
|
+ // skip all measures until we reach the first measure to output
|
|
3659
|
+ if(mp->number < beginMeasNumb)
|
|
3660
|
+ continue;
|
|
3661
|
+
|
|
3662
|
+ // if the MIDI file has not yet been created
|
|
3663
|
+ if( !cmMidiFileIsValid(mfH) )
|
|
3664
|
+ {
|
|
3665
|
+ ticksPerQN = mp->divisions;
|
|
3666
|
+
|
|
3667
|
+ // create the MIDI file
|
|
3668
|
+ if( cmMidiFileCreate( ctx, &mfH, trkN, ticksPerQN ) != kOkMfRC )
|
|
3669
|
+ {
|
|
3670
|
+ rc = cmErrMsg(&p->err,kMidiFailXsRC,"Unable to create the MIDI file object.");
|
|
3671
|
+ goto errLabel;
|
|
3672
|
+ }
|
|
3673
|
+
|
|
3674
|
+ // set the starting tempo
|
|
3675
|
+ cmMidFileInsertTrackTempoMsg(mfH, 0, 0, bpm );
|
|
3676
|
+
|
|
3677
|
+ }
|
|
3678
|
+
|
3576
|
3679
|
cmXsNote_t* np = mp->noteL;
|
3577
|
3680
|
|
|
3681
|
+ if( baseTick == -1 )
|
|
3682
|
+ baseTick = np->tick;
|
|
3683
|
+
|
3578
|
3684
|
if( mp->divisions != ticksPerQN )
|
3579
|
3685
|
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
|
3686
|
|
|
@@ -3582,12 +3688,15 @@ cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
|
3582
|
3688
|
// for each note in this measure
|
3583
|
3689
|
for(; np!=NULL; np=np->slink,++ni)
|
3584
|
3690
|
{
|
|
3691
|
+ unsigned thisTick = np->tick - baseTick;
|
|
3692
|
+
|
3585
|
3693
|
switch( np->flags & (kOnsetXsFl|kMetronomeXsFl|kDampDnXsFl|kDampUpDnXsFl|kSostDnXsFl) )
|
3586
|
3694
|
{
|
3587
|
3695
|
case kOnsetXsFl:
|
|
3696
|
+ if( cmMidiFileIsValid(mfH) )
|
3588
|
3697
|
{
|
3589
|
3698
|
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));
|
|
3699
|
+ 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
|
3700
|
|
3592
|
3701
|
/*
|
3593
|
3702
|
if( mp->number == 20 )
|
|
@@ -3596,9 +3705,12 @@ cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
|
3596
|
3705
|
cmRptPrintf(ctx->err.rpt,"\n");
|
3597
|
3706
|
}
|
3598
|
3707
|
*/
|
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 )
|
|
3708
|
+
|
|
3709
|
+ if( np->vel == 0 )
|
|
3710
|
+ 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));
|
|
3711
|
+
|
|
3712
|
+ if( cmMidiFileInsertTrackChMsg(mfH, 1, thisTick, kNoteOnMdId, np->pitch, np->vel ) != kOkMfRC
|
|
3713
|
+ ||cmMidiFileInsertTrackChMsg(mfH, 1, thisTick + np->tied_dur, kNoteOffMdId, np->pitch, 0 ) != kOkMfRC )
|
3602
|
3714
|
{
|
3603
|
3715
|
rc = kMidiFailXsRC;
|
3604
|
3716
|
}
|
|
@@ -3608,13 +3720,14 @@ cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
|
3608
|
3720
|
case kDampDnXsFl:
|
3609
|
3721
|
case kDampUpDnXsFl:
|
3610
|
3722
|
case kSostDnXsFl:
|
|
3723
|
+ if( cmMidiFileIsValid(mfH) )
|
3611
|
3724
|
{
|
3612
|
3725
|
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);
|
|
3726
|
+ cmErrWarnMsg(&p->err,kOkXsRC,"A zero length pedal event was encountered bar:%i tick:%i (%i)",np->meas->number,np->tick,thisTick);
|
3614
|
3727
|
|
3615
|
3728
|
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 ) )
|
|
3729
|
+ if( (cmMidiFileInsertTrackChMsg(mfH, 1, thisTick, kCtlMdId, d0, 127 ) != kOkMfRC )
|
|
3730
|
+ ||(cmMidiFileInsertTrackChMsg(mfH, 1, thisTick + np->duration, kCtlMdId, d0, 0 ) != kOkMfRC ) )
|
3618
|
3731
|
{
|
3619
|
3732
|
rc = kMidiFailXsRC;
|
3620
|
3733
|
}
|
|
@@ -3622,8 +3735,10 @@ cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
|
3622
|
3735
|
break;
|
3623
|
3736
|
|
3624
|
3737
|
case kMetronomeXsFl:
|
3625
|
|
- if( cmMidFileInsertTrackTempoMsg(mfH, 0, np->tick, np->duration ) != kOkMfRC )
|
3626
|
|
- rc = kMidiFailXsRC;
|
|
3738
|
+ bpm = np->duration;
|
|
3739
|
+ if( cmMidiFileIsValid(mfH) )
|
|
3740
|
+ if( cmMidFileInsertTrackTempoMsg(mfH, 0, thisTick, bpm ) != kOkMfRC )
|
|
3741
|
+ rc = kMidiFailXsRC;
|
3627
|
3742
|
break;
|
3628
|
3743
|
|
3629
|
3744
|
case 0:
|
|
@@ -3641,12 +3756,13 @@ cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
|
3641
|
3756
|
}
|
3642
|
3757
|
}
|
3643
|
3758
|
}
|
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
|
|
- }
|
|
3759
|
+
|
|
3760
|
+ if( cmMidiFileIsValid(mfH) )
|
|
3761
|
+ if( cmMidiFileWrite(mfH,outFn) != kOkMfRC )
|
|
3762
|
+ {
|
|
3763
|
+ rc = cmErrMsg(&p->err,kMidiFailXsRC,"MIDI file write failed on '%s'.",cmStringNullGuard(outFn));
|
|
3764
|
+ goto errLabel;
|
|
3765
|
+ }
|
3650
|
3766
|
|
3651
|
3767
|
errLabel:
|
3652
|
3768
|
cmFsFreeFn(outFn);
|
|
@@ -3659,6 +3775,23 @@ cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
|
3659
|
3775
|
return rc;
|
3660
|
3776
|
}
|
3661
|
3777
|
|
|
3778
|
+bool _cmXsIsMidiFileValid( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const cmChar_t* fn )
|
|
3779
|
+{
|
|
3780
|
+ const cmChar_t* midiFn = cmFsMakeFn(dir,fn,"mid",NULL);
|
|
3781
|
+ cmMidiFileH_t mfH = cmMidiFileNullHandle;
|
|
3782
|
+
|
|
3783
|
+ if( cmMidiFileOpen( ctx, &mfH, midiFn ) == kOkMfRC )
|
|
3784
|
+ {
|
|
3785
|
+ cmMidiFileClose(&mfH);
|
|
3786
|
+ return true;
|
|
3787
|
+ }
|
|
3788
|
+
|
|
3789
|
+ cmXScore_t* p = _cmXScoreHandleToPtr(h);
|
|
3790
|
+ cmErrMsg(&p->err,kMidiFailXsRC,"The generated MIDI file '%s' is not valid.", cmStringNullGuard(midiFn));
|
|
3791
|
+
|
|
3792
|
+ return false;
|
|
3793
|
+}
|
|
3794
|
+
|
3662
|
3795
|
typedef struct cmXsSvgEvt_str
|
3663
|
3796
|
{
|
3664
|
3797
|
unsigned flags; // k???XsFl
|
|
@@ -3864,7 +3997,7 @@ void _cmXsPushSvgEvent( cmXScore_t* p, cmXsMidiFile_t* mf, unsigned flags, unsig
|
3864
|
3997
|
mf->eol = e;
|
3865
|
3998
|
}
|
3866
|
3999
|
|
3867
|
|
-cmXsRC_t _cmXScoreGenSvg( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const cmChar_t* fn )
|
|
4000
|
+cmXsRC_t _cmXScoreGenSvg( cmCtx_t* ctx, cmXsH_t h, int beginMeasNumb, const cmChar_t* dir, const cmChar_t* fn )
|
3868
|
4001
|
{
|
3869
|
4002
|
cmXScore_t* p = _cmXScoreHandleToPtr(h);
|
3870
|
4003
|
cmXsPart_t* pp = p->partL;
|
|
@@ -3877,6 +4010,8 @@ cmXsRC_t _cmXScoreGenSvg( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const cm
|
3877
|
4010
|
const cmXsMeas_t* meas = pp->measL;
|
3878
|
4011
|
for(; meas!=NULL; meas=meas->link)
|
3879
|
4012
|
{
|
|
4013
|
+ if( meas->number < beginMeasNumb )
|
|
4014
|
+ continue;
|
3880
|
4015
|
|
3881
|
4016
|
const cmXsNote_t* note = meas->noteL;
|
3882
|
4017
|
for(; note!=NULL; note=note->slink)
|
|
@@ -3929,11 +4064,14 @@ cmXsRC_t _cmXScoreGenSvg( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const cm
|
3929
|
4064
|
|
3930
|
4065
|
|
3931
|
4066
|
cmXsRC_t cmXScoreTest(
|
3932
|
|
- cmCtx_t* ctx,
|
|
4067
|
+ cmCtx_t* ctx,
|
3933
|
4068
|
const cmChar_t* xmlFn,
|
3934
|
4069
|
const cmChar_t* editFn,
|
3935
|
4070
|
const cmChar_t* csvOutFn,
|
3936
|
|
- const cmChar_t* midiOutFn)
|
|
4071
|
+ const cmChar_t* midiOutFn,
|
|
4072
|
+ bool reportFl,
|
|
4073
|
+ int beginMeasNumb,
|
|
4074
|
+ int beginBPM )
|
3937
|
4075
|
{
|
3938
|
4076
|
cmXsRC_t rc;
|
3939
|
4077
|
cmXsH_t h = cmXsNullHandle;
|
|
@@ -3952,45 +4090,33 @@ cmXsRC_t cmXScoreTest(
|
3952
|
4090
|
|
3953
|
4091
|
if( csvOutFn != NULL )
|
3954
|
4092
|
{
|
3955
|
|
- cmScH_t scH = cmScNullHandle;
|
3956
|
|
- double srate = 44100.0;
|
3957
|
4093
|
|
3958
|
|
- cmXScoreWriteCsv(h,csvOutFn);
|
|
4094
|
+ cmXScoreWriteCsv(h,beginMeasNumb,csvOutFn);
|
3959
|
4095
|
|
3960
|
|
- cmSymTblH_t stH = cmSymTblCreate(cmSymTblNullHandle, 0, ctx );
|
3961
|
|
-
|
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
|
|
- }
|
3971
|
|
-
|
3972
|
|
- cmSymTblDestroy(&stH);
|
|
4096
|
+ _cmXsIsCsvValid(ctx,h,csvOutFn);
|
3973
|
4097
|
}
|
3974
|
4098
|
|
3975
|
4099
|
if( midiOutFn != NULL )
|
3976
|
4100
|
{
|
3977
|
|
-
|
3978
|
4101
|
// measure the score complexity
|
3979
|
4102
|
double wndSecs = 1.0;
|
|
4103
|
+
|
3980
|
4104
|
_cmXsMeasComplexity(h,wndSecs);
|
3981
|
|
-
|
3982
|
4105
|
|
3983
|
4106
|
cmFileSysPathPart_t* pp = cmFsPathParts(midiOutFn);
|
3984
|
4107
|
|
3985
|
|
- _cmXsWriteMidiFile(ctx, h, pp->dirStr, pp->fnStr );
|
|
4108
|
+ _cmXsWriteMidiFile(ctx, h, beginMeasNumb, beginBPM, pp->dirStr, pp->fnStr );
|
3986
|
4109
|
|
3987
|
|
- _cmXScoreGenSvg( ctx, h, pp->dirStr, pp->fnStr );
|
|
4110
|
+ _cmXsIsMidiFileValid(ctx, h, pp->dirStr, pp->fnStr );
|
|
4111
|
+
|
|
4112
|
+ _cmXScoreGenSvg( ctx, h, beginMeasNumb, pp->dirStr, pp->fnStr );
|
3988
|
4113
|
|
3989
|
4114
|
cmFsFreePathParts(pp);
|
3990
|
4115
|
|
3991
|
4116
|
}
|
3992
|
|
-
|
3993
|
|
- cmXScoreReport(h,&ctx->rpt,true);
|
|
4117
|
+
|
|
4118
|
+ if(reportFl)
|
|
4119
|
+ cmXScoreReport(h,&ctx->rpt,true);
|
3994
|
4120
|
|
3995
|
4121
|
return cmXScoreFinalize(&h);
|
3996
|
4122
|
|