diff --git a/app/cmScore.c b/app/cmScore.c index 8733fff..827dd61 100644 --- a/app/cmScore.c +++ b/app/cmScore.c @@ -35,6 +35,8 @@ enum kTypeLabelColScIdx = 3, kDSecsColScIdx = 4, kSecsColScIdx = 5, + kD0ColScIdx = 9, + kD1ColScIdx = 10, kPitchColScIdx = 11, kBarColScIdx = 13, kSkipColScIdx = 14, @@ -1222,6 +1224,10 @@ cmScRC_t _cmScParseFile( cmSc_t* p, cmCtx_t* ctx, const cmChar_t* fn ) double secs; double cur_secs = 0; + const unsigned pedalBaseMidiId = 64; + const unsigned pedalN = 3; + cmScoreEvt_t* pedalV[] = { NULL,NULL,NULL }; + p->sectList = cmMemAllocZ(cmScSect_t,1); // section zero //_cmScNewSet(p); // preallocate the first set @@ -1293,20 +1299,72 @@ cmScRC_t _cmScParseFile( cmSc_t* p, cmCtx_t* ctx, const cmChar_t* fn ) case kNonEvtScId: // parse note-on events if((rc = _cmScParseNoteOn(p, i, p->array, j, barNumb, barNoteIdx )) == kOkScRC ) { + // this note was successfully parsed so time has advanced secs = p->array[j].secs; + // if this note was not assigned time a time then set it if( p->array[j].secs == DBL_MAX ) + { p->array[j].secs = cur_secs; + // note that 'secs' is now set to DBL_MAX so cur_secs will not be updated on this row iteration + } + // if this note was marked to skip then don't advance j (and thereby + // write over this scEvt with the next note). ... if( cmIsFlag(p->array[j].flags,kSkipScFl) == false ) { - p->array[j].index = j; + p->array[j].index = j; // ... otherwise advance j ++j; } ++barNoteIdx; } break; + + case kCtlEvtScId: + { + unsigned d0 = cmCsvCellUInt( p->cH,i,kD0ColScIdx); + unsigned d1 = cmCsvCellUInt( p->cH,i,kD1ColScIdx); + + // if this is a pedal event + if( pedalBaseMidiId <= d0 && d0 < pedalBaseMidiId + pedalN ) + { + bool pedalDnFl = d1 >= 64; + unsigned pedalIdx = d0 - pedalBaseMidiId; + + assert( pedalBaseMidiId <= pedalIdx && pedalIdx < pedalN ); + + // store the pedal type identifer in the pitch field + p->array[j].pitch = d0; + + // if this is a pedal-down message ... + if( pedalDnFl ) + { + if( pedalV[pedalIdx] != NULL ) + cmErrWarnMsg(&p->err,kPedalInvalidScRC,"The score contains multiple pedal down messages withouth an intervening pedal up message in or near bar %i.",barNumb ); + else + pedalV[pedalIdx] = p->array + j; // ... store a pointer to the scEvt recd in pedalV[] + + p->array[j].flags |= kPedalDnFl; + } + else // ... else this is a pedal-up msg ... + { + p->array[j].flags |= kPedalUpFl; + + if( pedalV[pedalIdx] == NULL ) + cmErrWarnMsg(&p->err,kPedalInvalidScRC,"The score contains multiple pedal up messages withouth an intervening pedal down message in or near bar %i.",barNumb ); + else // ... update the pedal down duration in the pedal-down message assoc'd w/ this pedal-up msg. + { + pedalV[pedalIdx]->durSecs = p->array[j].secs - pedalV[pedalIdx]->secs; + pedalV[pedalIdx] = NULL; + } + + } + + + } + } + // fall through default: // Returns DBL_MAX on error. @@ -1316,6 +1374,7 @@ cmScRC_t _cmScParseFile( cmSc_t* p, cmCtx_t* ctx, const cmChar_t* fn ) if( rc == kOkScRC ) { + // if sec's is valid then update cur_secs if( secs != DBL_MAX ) cur_secs = secs; @@ -1423,7 +1482,6 @@ cmScRC_t _cmScInitLocArray( cmSc_t* p ) return rc; } - cmScRC_t cmScoreInitialize( cmCtx_t* ctx, cmScH_t* hp, const cmChar_t* fn, double srate, const unsigned* dynRefArray, unsigned dynRefCnt, cmScCb_t cbFunc, void* cbArg, cmSymTblH_t stH ) { cmScRC_t rc = kOkScRC; @@ -2589,3 +2647,5 @@ void cmScoreFix( cmCtx_t* ctx ) cmCsvFinalize(&csvH); } + + diff --git a/app/cmScore.h b/app/cmScore.h index ae93ce5..321d32f 100644 --- a/app/cmScore.h +++ b/app/cmScore.h @@ -13,7 +13,8 @@ extern "C" { kInvalidIdxScRC, kTimeLineFailScRC, kInvalidDynRefCntScRC, - kMidiFileFailScRC + kMidiFileFailScRC, + kPedalInvalidScRC }; enum @@ -31,7 +32,8 @@ extern "C" { kBarEvtScId, kPgmEvtScId, kCtlEvtScId, - kNonEvtScId + kNonEvtScId, + kPedalEvtScId }; // Flags used by cmScoreEvt_t.flags @@ -42,7 +44,9 @@ extern "C" { kTempoScFl = 0x004, // This note is marked for tempo measurement kSkipScFl = 0x008, // This isn't a real event (e.g. tied note) skip over it kGraceScFl = 0x010, // This is a grace note - kInvalidScFl = 0x020 // This note has a calculated time + kInvalidScFl = 0x020, // This note has a calculated time + kPedalDnFl = 0x040, // This is a pedal down event (pitch holds the pedal id and durSecs holds the time the pedal will remain down.) + kPedalUpFl = 0x080 // This is a pedal up event (pitch holds the pedal id) }; @@ -79,7 +83,7 @@ extern "C" { double durSecs; // Duration in seconds unsigned index; // Index of this event in the event array. unsigned locIdx; // Index of the location containing this event - cmMidiByte_t pitch; // MIDI pitch of this note + cmMidiByte_t pitch; // MIDI pitch of this note or the MIDI pedal id of pedal down/up msg (64=sustain 65=sostenuto 66=soft) unsigned flags; // Attribute flags for this event unsigned dynVal; // Dynamcis value pppp to ffff (1 to 11) for this note. double frac; // Note's time value for tempo and non-grace evenness notes.