|
@@ -1208,6 +1208,83 @@ cmXsRC_t _cmXScoreResolveOctaveShift( cmXScore_t* p )
|
1208
|
1208
|
return kOkXsRC;
|
1209
|
1209
|
}
|
1210
|
1210
|
|
|
1211
|
+cmXsNote_t* _cmXScoreFindOverlappingNote( cmXScore_t* p, const cmXsNote_t* knp )
|
|
1212
|
+{
|
|
1213
|
+ cmXsPart_t* pp = p->partL;
|
|
1214
|
+
|
|
1215
|
+ // for each part
|
|
1216
|
+ for(; pp!=NULL; pp=pp->link)
|
|
1217
|
+ {
|
|
1218
|
+ cmXsMeas_t* mp = pp->measL;
|
|
1219
|
+
|
|
1220
|
+ // for each measure
|
|
1221
|
+ for(; mp!=NULL; mp=mp->link)
|
|
1222
|
+ {
|
|
1223
|
+ cmXsNote_t* np = mp->noteL;
|
|
1224
|
+
|
|
1225
|
+ // for each note in this measure
|
|
1226
|
+ for(; np!=NULL; np=np->slink)
|
|
1227
|
+ if( np->uid != knp->uid
|
|
1228
|
+ && cmIsFlag(np->flags,kOnsetXsFl)
|
|
1229
|
+ && knp->pitch == np->pitch
|
|
1230
|
+ && knp->tick >= np->tick
|
|
1231
|
+ && knp->tick < (np->tick + np->duration) )
|
|
1232
|
+ {
|
|
1233
|
+ return np;
|
|
1234
|
+ }
|
|
1235
|
+ }
|
|
1236
|
+ }
|
|
1237
|
+ return NULL;
|
|
1238
|
+}
|
|
1239
|
+
|
|
1240
|
+void _cmXScoreProcessOverlappingNotes( cmXScore_t* p )
|
|
1241
|
+{
|
|
1242
|
+ cmXsPart_t* pp = p->partL;
|
|
1243
|
+
|
|
1244
|
+ // for each part
|
|
1245
|
+ for(; pp!=NULL; pp=pp->link)
|
|
1246
|
+ {
|
|
1247
|
+ cmXsMeas_t* mp = pp->measL;
|
|
1248
|
+
|
|
1249
|
+ // for each measure
|
|
1250
|
+ for(; mp!=NULL; mp=mp->link)
|
|
1251
|
+ {
|
|
1252
|
+ cmXsNote_t* np = mp->noteL;
|
|
1253
|
+ cmXsNote_t* fnp;
|
|
1254
|
+
|
|
1255
|
+ // for each note in this measure
|
|
1256
|
+ for(; np!=NULL; np=np->slink)
|
|
1257
|
+ if( cmIsFlag(np->flags,kOnsetXsFl) && (fnp = _cmXScoreFindOverlappingNote(p,np)) != NULL)
|
|
1258
|
+ {
|
|
1259
|
+ // is np entirely contained inside fnp
|
|
1260
|
+ bool embeddedFl = fnp->tick + fnp->duration > np->tick + np->duration;
|
|
1261
|
+
|
|
1262
|
+ //printf("bar=%3i %4s voice:%2i %2i : %7i %7i : %7i %7i : %7i : %c \n",np->meas->number,cmMidiToSciPitch(np->pitch,NULL,0),np->voice->id,fnp->voice->id,fnp->tick,fnp->tick+fnp->duration,np->tick,np->tick+np->duration, (fnp->tick+fnp->duration) - np->tick, embeddedFl ? 'E' : 'O');
|
|
1263
|
+
|
|
1264
|
+ // turn off embedded notes
|
|
1265
|
+ if( embeddedFl )
|
|
1266
|
+ {
|
|
1267
|
+ if( np->voice->id == fnp->voice->id )
|
|
1268
|
+ cmErrWarnMsg(&p->err,kOverlapWarnXsRC,"A time embedded note (bar=%i %s) was removed even though it overlapped with a note in the same voice.",np->meas->number,cmMidiToSciPitch(np->pitch,NULL,0));
|
|
1269
|
+
|
|
1270
|
+ np->flags = cmClrFlag(np->flags,kOnsetXsFl);
|
|
1271
|
+ }
|
|
1272
|
+ else
|
|
1273
|
+ {
|
|
1274
|
+ int d = (fnp->tick+fnp->duration) - np->tick;
|
|
1275
|
+
|
|
1276
|
+ // shorten the first note
|
|
1277
|
+ if( d > 0 && d < fnp->duration )
|
|
1278
|
+ fnp->duration -= d;
|
|
1279
|
+
|
|
1280
|
+ // move the second note just past it
|
|
1281
|
+ np->tick = fnp->tick + fnp->duration + 1;
|
|
1282
|
+ }
|
|
1283
|
+ }
|
|
1284
|
+ }
|
|
1285
|
+ }
|
|
1286
|
+}
|
|
1287
|
+
|
1211
|
1288
|
|
1212
|
1289
|
// The identical pitch may be notated to play simultaneously on different voices.
|
1213
|
1290
|
// As performed on the piano this will equate to a single sounding note.
|
|
@@ -2426,7 +2503,7 @@ cmXsRC_t cmXScoreReorder( cmXsH_t h, const cmChar_t* fn )
|
2426
|
2503
|
|
2427
|
2504
|
|
2428
|
2505
|
|
2429
|
|
-/*
|
|
2506
|
+/* CSV score columns
|
2430
|
2507
|
kMidiFileIdColScIdx= 0,
|
2431
|
2508
|
kTypeLabelColScIdx = 3,
|
2432
|
2509
|
kDSecsColScIdx = 4,
|
|
@@ -2719,7 +2796,6 @@ cmXsRC_t _cmXScoreWriteCsvRow(
|
2719
|
2796
|
|
2720
|
2797
|
errLabel:
|
2721
|
2798
|
return rc;
|
2722
|
|
-
|
2723
|
2799
|
}
|
2724
|
2800
|
|
2725
|
2801
|
cmXsRC_t cmXScoreWriteCsv( cmXsH_t h, const cmChar_t* csvFn )
|
|
@@ -3076,9 +3152,12 @@ cmXsRC_t _cmXsWriteMidiSvg( cmCtx_t* ctx, cmXScore_t* p, cmXsMidiFile_t* mf, con
|
3076
|
3152
|
cmSvgH_t svgH = cmSvgNullHandle;
|
3077
|
3153
|
cmXsSvgEvt_t* e = mf->elist;
|
3078
|
3154
|
unsigned noteHeight = 10;
|
3079
|
|
- const cmChar_t* svgFn = cmFsMakeFn(dir,fn,"html",NULL);
|
|
3155
|
+ cmChar_t* fn0 = cmMemAllocStr( fn );
|
|
3156
|
+ const cmChar_t* svgFn = cmFsMakeFn(dir,fn0 = cmTextAppendSS(fn0,"_midi_svg"),"html",NULL);
|
3080
|
3157
|
const cmChar_t* cssFn = cmFsMakeFn(NULL,fn,"css",NULL);
|
3081
|
3158
|
cmChar_t* t0 = NULL; // temporary dynamic string
|
|
3159
|
+
|
|
3160
|
+ cmMemFree(fn0);
|
3082
|
3161
|
|
3083
|
3162
|
// create the SVG writer
|
3084
|
3163
|
if( cmSvgWriterAlloc(ctx,&svgH) != kOkSvgRC )
|
|
@@ -3265,7 +3344,10 @@ cmXsRC_t cmXScoreTest(
|
3265
|
3344
|
|
3266
|
3345
|
// assign durations to pedal down events
|
3267
|
3346
|
_cmXScoreProcessPedals(_cmXScoreHandleToPtr(h));
|
3268
|
|
-
|
|
3347
|
+
|
|
3348
|
+ // remove some notes which share a pitch which are overlapped or embedded
|
|
3349
|
+ _cmXScoreProcessOverlappingNotes(_cmXScoreHandleToPtr(h));
|
|
3350
|
+
|
3269
|
3351
|
if( csvOutFn != NULL )
|
3270
|
3352
|
{
|
3271
|
3353
|
cmScH_t scH = cmScNullHandle;
|
|
@@ -3287,7 +3369,7 @@ cmXsRC_t cmXScoreTest(
|
3287
|
3369
|
|
3288
|
3370
|
cmSymTblDestroy(&stH);
|
3289
|
3371
|
}
|
3290
|
|
-
|
|
3372
|
+
|
3291
|
3373
|
if( midiOutFn != NULL )
|
3292
|
3374
|
{
|
3293
|
3375
|
cmFileSysPathPart_t* pp = cmFsPathParts(midiOutFn);
|