|
@@ -84,11 +84,13 @@ typedef struct cmXsNote_str
|
84
|
84
|
unsigned staff; // 1=treble 2=bass
|
85
|
85
|
unsigned tick; //
|
86
|
86
|
unsigned duration; // duration in ticks
|
|
87
|
+ unsigned tied_dur; // duration in ticks (including all tied notes)
|
87
|
88
|
double secs; // absolute time in seconds
|
88
|
89
|
double dsecs; // delta time in seconds since previous event
|
89
|
90
|
unsigned locIdx; // location index (chords share the same location index)
|
90
|
91
|
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, ...)
|
91
|
92
|
const cmChar_t* tvalue; // text value
|
|
93
|
+ unsigned mf_uid; // MIDI file uid assigned to this event
|
92
|
94
|
|
93
|
95
|
unsigned evenGroupId; // eveness group id
|
94
|
96
|
unsigned dynGroupId; // dynamics group id
|
|
@@ -239,8 +241,9 @@ cmXsRC_t _cmXScorePushNote( cmXScore_t* p, cmXsMeas_t* meas, unsigned voiceId, c
|
239
|
241
|
n->mlink = note;
|
240
|
242
|
}
|
241
|
243
|
|
242
|
|
- note->voice = v;
|
243
|
|
- note->uid = p->nextUid++;
|
|
244
|
+ note->voice = v;
|
|
245
|
+ note->uid = p->nextUid++;
|
|
246
|
+ note->tied_dur = note->duration;
|
244
|
247
|
|
245
|
248
|
return kOkXsRC;
|
246
|
249
|
}
|
|
@@ -605,6 +608,7 @@ cmXsRC_t _cmXScorePushNonNote( cmXScore_t* p, cmXsMeas_t* meas, const cmXmlNode_
|
605
|
608
|
note->rvalue = rvalue;
|
606
|
609
|
note->tvalue = tvalue;
|
607
|
610
|
note->duration = duration;
|
|
611
|
+ note->tied_dur = duration;
|
608
|
612
|
note->meas = meas;
|
609
|
613
|
note->xmlNode = noteXmlNode;
|
610
|
614
|
|
|
@@ -1065,6 +1069,7 @@ void _cmXScoreSpreadGraceNotes( cmXScore_t* p )
|
1065
|
1069
|
|
1066
|
1070
|
bool _cmXScoreFindTiedNote( cmXScore_t* p, cmXsMeas_t* mp, cmXsNote_t* n0p, bool rptFl )
|
1067
|
1071
|
{
|
|
1072
|
+ cmXsNote_t* nbp = n0p;
|
1068
|
1073
|
cmXsNote_t* nnp = n0p->slink; // begin w/ note following np
|
1069
|
1074
|
unsigned measNumb = mp->number;
|
1070
|
1075
|
cmChar_t acc = n0p->alter==-1?'b' : (n0p->alter==1?'#':' ');
|
|
@@ -1093,9 +1098,11 @@ bool _cmXScoreFindTiedNote( cmXScore_t* p, cmXsMeas_t* mp, cmXsNote_t* n0p, boo
|
1093
|
1098
|
// if this note is tied to the originating note (np)
|
1094
|
1099
|
if( nnp->voice->id == n0p->voice->id && nnp->step == n0p->step && nnp->octave == n0p->octave )
|
1095
|
1100
|
{
|
1096
|
|
- nnp->flags |= kTieProcXsFl;
|
1097
|
|
- nnp->flags = cmClrFlag(nnp->flags,kOnsetXsFl);
|
1098
|
|
- n0p->tied = nnp;
|
|
1101
|
+ nnp->flags |= kTieProcXsFl;
|
|
1102
|
+ nnp->flags = cmClrFlag(nnp->flags,kOnsetXsFl);
|
|
1103
|
+ n0p->tied = nnp;
|
|
1104
|
+ nbp->tied_dur += nnp->duration;
|
|
1105
|
+ nnp->tied_dur = 0;
|
1099
|
1106
|
|
1100
|
1107
|
if( rptFl )
|
1101
|
1108
|
printf("---> %i %i %s ",nnp->meas->number,nnp->tick,cmMidiToSciPitch(nnp->pitch,NULL,0));
|
|
@@ -1118,10 +1125,10 @@ bool _cmXScoreFindTiedNote( cmXScore_t* p, cmXsMeas_t* mp, cmXsNote_t* n0p, boo
|
1118
|
1125
|
|
1119
|
1126
|
void _cmXScoreResolveTiesAndLoc( cmXScore_t* p )
|
1120
|
1127
|
{
|
1121
|
|
- unsigned n = 0;
|
1122
|
|
- unsigned m = 0;
|
1123
|
|
- bool rptFl = false;
|
1124
|
|
- cmXsPart_t* pp = p->partL;
|
|
1128
|
+ unsigned n = 0; // count of notes which begin a tie
|
|
1129
|
+ unsigned m = 0; // count of tied notes that are correctly terminated.
|
|
1130
|
+ bool rptFl = false;
|
|
1131
|
+ cmXsPart_t* pp = p->partL;
|
1125
|
1132
|
|
1126
|
1133
|
// for each part
|
1127
|
1134
|
for(; pp!=NULL; pp=pp->link)
|
|
@@ -1227,7 +1234,7 @@ cmXsNote_t* _cmXScoreFindOverlappingNote( cmXScore_t* p, const cmXsNote_t* knp
|
1227
|
1234
|
&& cmIsFlag(np->flags,kOnsetXsFl)
|
1228
|
1235
|
&& knp->pitch == np->pitch
|
1229
|
1236
|
&& knp->tick >= np->tick
|
1230
|
|
- && knp->tick < (np->tick + np->duration) )
|
|
1237
|
+ && knp->tick < (np->tick + np->tied_dur) )
|
1231
|
1238
|
{
|
1232
|
1239
|
return np;
|
1233
|
1240
|
}
|
|
@@ -1256,7 +1263,7 @@ void _cmXScoreProcessOverlappingNotes( cmXScore_t* p )
|
1256
|
1263
|
if( cmIsFlag(np->flags,kOnsetXsFl) && (fnp = _cmXScoreFindOverlappingNote(p,np)) != NULL)
|
1257
|
1264
|
{
|
1258
|
1265
|
// is np entirely contained inside fnp
|
1259
|
|
- bool embeddedFl = fnp->tick + fnp->duration > np->tick + np->duration;
|
|
1266
|
+ bool embeddedFl = fnp->tick + fnp->tied_dur > np->tick + np->tied_dur;
|
1260
|
1267
|
|
1261
|
1268
|
//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');
|
1262
|
1269
|
|
|
@@ -1270,14 +1277,14 @@ void _cmXScoreProcessOverlappingNotes( cmXScore_t* p )
|
1270
|
1277
|
}
|
1271
|
1278
|
else
|
1272
|
1279
|
{
|
1273
|
|
- int d = (fnp->tick+fnp->duration) - np->tick;
|
|
1280
|
+ int d = (fnp->tick+fnp->tied_dur) - np->tick;
|
1274
|
1281
|
|
1275
|
1282
|
// shorten the first note
|
1276
|
|
- if( d > 0 && d < fnp->duration )
|
1277
|
|
- fnp->duration -= d;
|
|
1283
|
+ if( d > 0 && d < fnp->tied_dur )
|
|
1284
|
+ fnp->tied_dur -= d;
|
1278
|
1285
|
|
1279
|
1286
|
// move the second note just past it
|
1280
|
|
- np->tick = fnp->tick + fnp->duration + 1;
|
|
1287
|
+ np->tick = fnp->tick + fnp->tied_dur + 1;
|
1281
|
1288
|
}
|
1282
|
1289
|
}
|
1283
|
1290
|
}
|
|
@@ -1404,7 +1411,7 @@ cmXsRC_t _cmXScoreWriteScorePlotFile( cmXScore_t* p, const cmChar_t* fn )
|
1404
|
1411
|
{
|
1405
|
1412
|
if( cmIsFlag(np->flags,kMetronomeXsFl) )
|
1406
|
1413
|
{
|
1407
|
|
- double bps = np->duration / 60.0;
|
|
1414
|
+ double bps = np->tied_dur / 60.0;
|
1408
|
1415
|
|
1409
|
1416
|
// t b t
|
1410
|
1417
|
// - = - -
|
|
@@ -1418,7 +1425,7 @@ cmXsRC_t _cmXScoreWriteScorePlotFile( cmXScore_t* p, const cmChar_t* fn )
|
1418
|
1425
|
{
|
1419
|
1426
|
onset_secs += (np->tick - tick0) / ticks_per_sec;
|
1420
|
1427
|
tick0 = np->tick;
|
1421
|
|
- cmFilePrintf(fH,"n %f %f %i %s %s\n",onset_secs,np->duration/ticks_per_sec,np->uid,cmMidiToSciPitch(np->pitch,NULL,0),cmIsFlag(np->flags,kGraceXsFl)?"G":"N");
|
|
1428
|
+ cmFilePrintf(fH,"n %f %f %i %s %s\n",onset_secs,np->tied_dur/ticks_per_sec,np->uid,cmMidiToSciPitch(np->pitch,NULL,0),cmIsFlag(np->flags,kGraceXsFl)?"G":"N");
|
1422
|
1429
|
}
|
1423
|
1430
|
}
|
1424
|
1431
|
}
|
|
@@ -1700,7 +1707,7 @@ cmXsRC_t _cmXScoreProcessGraceNotes( cmXScore_t* p )
|
1700
|
1707
|
|
1701
|
1708
|
// set each grace note to have 1/20 of a second duration
|
1702
|
1709
|
if( cmIsFlag(np->flags,kGraceXsFl) )
|
1703
|
|
- np->duration = floor(ticksPerSec * graceDurSec);
|
|
1710
|
+ np->duration = np->tied_dur = floor(ticksPerSec * graceDurSec);
|
1704
|
1711
|
|
1705
|
1712
|
gN += 1;
|
1706
|
1713
|
}
|
|
@@ -2938,7 +2945,7 @@ void _cmXScoreReportNote( cmRpt_t* rpt, const cmXsNote_t* note,unsigned index )
|
2938
|
2945
|
note->voice->id,
|
2939
|
2946
|
note->locIdx,
|
2940
|
2947
|
note->tick,
|
2941
|
|
- note->duration,
|
|
2948
|
+ note->tied_dur,
|
2942
|
2949
|
note->rvalue,
|
2943
|
2950
|
N,B,R,G,D,C,e,d,t,P,s,S,H,T0,T1,O);
|
2944
|
2951
|
|
|
@@ -3072,8 +3079,11 @@ cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
|
3072
|
3079
|
{
|
3073
|
3080
|
case kOnsetXsFl:
|
3074
|
3081
|
{
|
3075
|
|
- if( cmMidiFileInsertTrackChMsg(mfH, 1, np->tick, kNoteOnMdId, np->pitch, np->vel ) != kOkMfRC
|
3076
|
|
- ||cmMidiFileInsertTrackChMsg(mfH, 1, np->tick + np->duration, kNoteOffMdId, np->pitch, 0 ) != kOkMfRC )
|
|
3082
|
+ if( np->tied_dur <= 0 )
|
|
3083
|
+ 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));
|
|
3084
|
+
|
|
3085
|
+ if( cmMidiFileInsertTrackChMsg(mfH, 1, np->tick, kNoteOnMdId, np->pitch, np->vel, &np->mf_uid ) != kOkMfRC
|
|
3086
|
+ ||cmMidiFileInsertTrackChMsg(mfH, 1, np->tick + np->tied_dur, kNoteOffMdId, np->pitch, 0, &np->mf_uid ) != kOkMfRC )
|
3077
|
3087
|
{
|
3078
|
3088
|
rc = kMidiFailXsRC;
|
3079
|
3089
|
}
|
|
@@ -3084,9 +3094,12 @@ cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
|
3084
|
3094
|
case kDampUpDnXsFl:
|
3085
|
3095
|
case kSostDnXsFl:
|
3086
|
3096
|
{
|
|
3097
|
+ if( np->duration <= 0 )
|
|
3098
|
+ cmErrWarnMsg(&p->err,kOkXsRC,"A zero length pedal event was encountered bar:%i tick:%i",np->meas->number,np->tick);
|
|
3099
|
+
|
3087
|
3100
|
cmMidiByte_t d0 = cmIsFlag(np->flags,kSostDnXsFl) ? kSostenutoCtlMdId : kSustainCtlMdId;
|
3088
|
|
- if( (cmMidiFileInsertTrackChMsg(mfH, 1, np->tick, kCtlMdId, d0, 127 ) != kOkMfRC )
|
3089
|
|
- ||(cmMidiFileInsertTrackChMsg(mfH, 1, np->tick + np->duration, kCtlMdId, d0, 0 ) != kOkMfRC ) )
|
|
3101
|
+ if( (cmMidiFileInsertTrackChMsg(mfH, 1, np->tick, kCtlMdId, d0, 127, &np->mf_uid ) != kOkMfRC )
|
|
3102
|
+ ||(cmMidiFileInsertTrackChMsg(mfH, 1, np->tick + np->duration, kCtlMdId, d0, 0, &np->mf_uid ) != kOkMfRC ) )
|
3090
|
3103
|
{
|
3091
|
3104
|
rc = kMidiFailXsRC;
|
3092
|
3105
|
}
|
|
@@ -3094,7 +3107,7 @@ cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
|
3094
|
3107
|
break;
|
3095
|
3108
|
|
3096
|
3109
|
case kMetronomeXsFl:
|
3097
|
|
- if( cmMidFileInsertTrackTempoMsg(mfH, 0, np->tick, np->duration ) != kOkMfRC )
|
|
3110
|
+ if( cmMidFileInsertTrackTempoMsg(mfH, 0, np->tick, np->duration, &np->mf_uid ) != kOkMfRC )
|
3098
|
3111
|
rc = kMidiFailXsRC;
|
3099
|
3112
|
break;
|
3100
|
3113
|
|
|
@@ -3141,6 +3154,7 @@ typedef struct cmXsSvgEvt_str
|
3141
|
3154
|
unsigned voice; // score voice number
|
3142
|
3155
|
unsigned d0; // MIDI d0 (barNumb)
|
3143
|
3156
|
unsigned d1; // MIDI d1
|
|
3157
|
+ unsigned mf_uid;
|
3144
|
3158
|
struct cmXsSvgEvt_str* link;
|
3145
|
3159
|
} cmXsSvgEvt_t;
|
3146
|
3160
|
|
|
@@ -3162,7 +3176,7 @@ cmXsRC_t _cmXsWriteMidiSvg( cmCtx_t* ctx, cmXScore_t* p, cmXsMidiFile_t* mf, con
|
3162
|
3176
|
unsigned noteHeight = 10;
|
3163
|
3177
|
cmChar_t* fn0 = cmMemAllocStr( fn );
|
3164
|
3178
|
const cmChar_t* svgFn = cmFsMakeFn(dir,fn0 = cmTextAppendSS(fn0,"_midi_svg"),"html",NULL);
|
3165
|
|
- const cmChar_t* cssFn = cmFsMakeFn(NULL,fn,"css",NULL);
|
|
3179
|
+ const cmChar_t* cssFn = cmFsMakeFn(NULL,"score_midi_svg","css",NULL);
|
3166
|
3180
|
cmChar_t* t0 = NULL; // temporary dynamic string
|
3167
|
3181
|
|
3168
|
3182
|
cmMemFree(fn0);
|
|
@@ -3193,8 +3207,12 @@ cmXsRC_t _cmXsWriteMidiSvg( cmCtx_t* ctx, cmXScore_t* p, cmXsMidiFile_t* mf, con
|
3193
|
3207
|
if( cmSvgWriterRect(svgH, e->tick, e->d0 * noteHeight, e->durTicks, noteHeight-1, t0 ) != kOkSvgRC )
|
3194
|
3208
|
rc = kSvgFailXsRC;
|
3195
|
3209
|
else
|
3196
|
|
- if( cmSvgWriterText(svgH, e->tick + e->durTicks/2, e->d0 * noteHeight + noteHeight/2, cmMidiToSciPitch( e->d0, NULL, 0), "pitch") != kOkSvgRC )
|
|
3210
|
+ {
|
|
3211
|
+ t0 = cmTsPrintfP(t0,"%s %i",cmMidiToSciPitch( e->d0, NULL, 0),e->mf_uid);
|
|
3212
|
+
|
|
3213
|
+ if( cmSvgWriterText(svgH, e->tick + e->durTicks/2, e->d0 * noteHeight + noteHeight/2, t0, "pitch") != kOkSvgRC )
|
3197
|
3214
|
rc = kSvgFailXsRC;
|
|
3215
|
+ }
|
3198
|
3216
|
}
|
3199
|
3217
|
break;
|
3200
|
3218
|
|
|
@@ -3241,7 +3259,7 @@ cmXsRC_t _cmXsWriteMidiSvg( cmCtx_t* ctx, cmXScore_t* p, cmXsMidiFile_t* mf, con
|
3241
|
3259
|
}
|
3242
|
3260
|
|
3243
|
3261
|
|
3244
|
|
-void _cmXsPushSvgEvent( cmXScore_t* p, cmXsMidiFile_t* mf, unsigned flags, unsigned tick, unsigned durTick, unsigned voice, unsigned d0, unsigned d1 )
|
|
3262
|
+void _cmXsPushSvgEvent( cmXScore_t* p, cmXsMidiFile_t* mf, unsigned flags, unsigned tick, unsigned durTick, unsigned voice, unsigned d0, unsigned d1, unsigned mf_uid )
|
3245
|
3263
|
{
|
3246
|
3264
|
cmXsSvgEvt_t* e = cmLhAllocZ(p->lhH,cmXsSvgEvt_t,1);
|
3247
|
3265
|
e->flags = flags;
|
|
@@ -3250,6 +3268,8 @@ void _cmXsPushSvgEvent( cmXScore_t* p, cmXsMidiFile_t* mf, unsigned flags, unsig
|
3250
|
3268
|
e->voice = voice;
|
3251
|
3269
|
e->d0 = d0; // note=pitch bar=number pedal=ctl# metronome=BPM
|
3252
|
3270
|
e->d1 = d1;
|
|
3271
|
+ e->mf_uid = mf_uid;
|
|
3272
|
+
|
3253
|
3273
|
if( mf->eol != NULL )
|
3254
|
3274
|
mf->eol->link = e;
|
3255
|
3275
|
else
|
|
@@ -3286,7 +3306,7 @@ cmXsRC_t _cmXScoreGenSvg( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const cm
|
3286
|
3306
|
if( cmIsFlag(note->flags,kMetronomeXsFl) )
|
3287
|
3307
|
{
|
3288
|
3308
|
// set BPM as d0
|
3289
|
|
- _cmXsPushSvgEvent(p,&mf,note->flags,note->tick,0,0,note->duration,0);
|
|
3309
|
+ _cmXsPushSvgEvent(p,&mf,note->flags,note->tick,0,0,note->duration,0,note->mf_uid);
|
3290
|
3310
|
continue;
|
3291
|
3311
|
|
3292
|
3312
|
}
|
|
@@ -3295,21 +3315,21 @@ cmXsRC_t _cmXScoreGenSvg( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const cm
|
3295
|
3315
|
if( cmIsFlag(note->flags,kOnsetXsFl) )
|
3296
|
3316
|
{
|
3297
|
3317
|
unsigned d0 = cmSciPitchToMidiPitch( note->step, note->alter, note->octave );
|
3298
|
|
- unsigned durTick = note->duration;
|
|
3318
|
+ unsigned durTick = note->tied_dur;
|
3299
|
3319
|
if( note->tied != NULL )
|
3300
|
3320
|
{
|
3301
|
3321
|
cmXsNote_t* tn = note->tied;
|
3302
|
3322
|
for(; tn!=NULL; tn=tn->tied)
|
3303
|
|
- durTick += tn->duration;
|
|
3323
|
+ durTick += tn->tied_dur;
|
3304
|
3324
|
}
|
3305
|
|
- _cmXsPushSvgEvent(p,&mf,note->flags,note->tick,durTick,note->voice->id,d0,note->vel);
|
|
3325
|
+ _cmXsPushSvgEvent(p,&mf,note->flags,note->tick,durTick,note->voice->id,d0,note->vel,note->mf_uid);
|
3306
|
3326
|
continue;
|
3307
|
3327
|
}
|
3308
|
3328
|
|
3309
|
3329
|
// if this is a bar event
|
3310
|
3330
|
if( cmIsFlag(note->flags,kBarXsFl) )
|
3311
|
3331
|
{
|
3312
|
|
- _cmXsPushSvgEvent(p,&mf,note->flags,note->tick,0,0,note->meas->number,0);
|
|
3332
|
+ _cmXsPushSvgEvent(p,&mf,note->flags,note->tick,0,0,note->meas->number,0, note->mf_uid);
|
3313
|
3333
|
continue;
|
3314
|
3334
|
}
|
3315
|
3335
|
|
|
@@ -3317,7 +3337,7 @@ cmXsRC_t _cmXScoreGenSvg( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const cm
|
3317
|
3337
|
if( cmIsFlag(note->flags,kDampDnXsFl|kDampUpDnXsFl|kSostDnXsFl) )
|
3318
|
3338
|
{
|
3319
|
3339
|
unsigned d0 = cmIsFlag(note->flags,kSostDnXsFl) ? kSostenutoCtlMdId : kSustainCtlMdId;
|
3320
|
|
- _cmXsPushSvgEvent(p,&mf,note->flags,note->tick,note->duration,0,d0,127);
|
|
3340
|
+ _cmXsPushSvgEvent(p,&mf,note->flags,note->tick,note->duration,0,d0,127,note->mf_uid);
|
3321
|
3341
|
continue;
|
3322
|
3342
|
}
|
3323
|
3343
|
|
|
@@ -3353,7 +3373,7 @@ cmXsRC_t cmXScoreTest(
|
3353
|
3373
|
// assign durations to pedal down events
|
3354
|
3374
|
_cmXScoreProcessPedals(_cmXScoreHandleToPtr(h));
|
3355
|
3375
|
|
3356
|
|
- // remove some notes which share a pitch which are overlapped or embedded
|
|
3376
|
+ // remove some notes which share a pitch and are overlapped or embedded within another note.
|
3357
|
3377
|
_cmXScoreProcessOverlappingNotes(_cmXScoreHandleToPtr(h));
|
3358
|
3378
|
|
3359
|
3379
|
if( csvOutFn != NULL )
|
|
@@ -3381,16 +3401,16 @@ cmXsRC_t cmXScoreTest(
|
3381
|
3401
|
if( midiOutFn != NULL )
|
3382
|
3402
|
{
|
3383
|
3403
|
cmFileSysPathPart_t* pp = cmFsPathParts(midiOutFn);
|
3384
|
|
-
|
3385
|
|
- _cmXScoreGenSvg( ctx, h, pp->dirStr, pp->fnStr );
|
3386
|
3404
|
|
3387
|
3405
|
_cmXsWriteMidiFile(ctx, h, pp->dirStr, pp->fnStr );
|
|
3406
|
+
|
|
3407
|
+ _cmXScoreGenSvg( ctx, h, pp->dirStr, pp->fnStr );
|
3388
|
3408
|
|
3389
|
3409
|
cmFsFreePathParts(pp);
|
3390
|
3410
|
|
3391
|
3411
|
}
|
3392
|
3412
|
|
3393
|
|
- //cmXScoreReport(h,&ctx->rpt,true);
|
|
3413
|
+ cmXScoreReport(h,&ctx->rpt,true);
|
3394
|
3414
|
|
3395
|
3415
|
errLabel:
|
3396
|
3416
|
return cmXScoreFinalize(&h);
|