cmScore.h/c : Pedal events are now handled similarly to Note-on events and given

their own type: kPedalEvtScId and pedal down messages are assigned the
pedal event duration in cmScEvent_t.durSecs.
This commit is contained in:
Kevin Larke 2015-02-25 15:14:37 -08:00
parent 7d55b16257
commit a7cecdd678
2 changed files with 124 additions and 63 deletions

View File

@ -723,7 +723,7 @@ cmScRC_t _cmScParseNoteOn( cmSc_t* p, unsigned rowIdx, cmScoreEvt_t* s, unsigned
if((midiPitch = cmSciPitchToMidi(sciPitch)) == kInvalidMidiPitch) if((midiPitch = cmSciPitchToMidi(sciPitch)) == kInvalidMidiPitch)
return cmErrMsg(&p->err,kSyntaxErrScRC,"Unable to convert the scientific pitch '%s' to a MIDI value. "); return cmErrMsg(&p->err,kSyntaxErrScRC,"Unable to convert the scientific pitch '%s' to a MIDI value. ");
// it is possible that note delta-secs field is empty - so default to 0 // get the sec's field - or DBL_MAX if it is not set
if((secs = cmCsvCellDouble(p->cH, rowIdx, kSecsColScIdx )) == DBL_MAX) // Returns DBL_MAX on error. if((secs = cmCsvCellDouble(p->cH, rowIdx, kSecsColScIdx )) == DBL_MAX) // Returns DBL_MAX on error.
flags += kInvalidScFl; flags += kInvalidScFl;
@ -801,6 +801,96 @@ cmScRC_t _cmScParseNoteOn( cmSc_t* p, unsigned rowIdx, cmScoreEvt_t* s, unsigned
return rc; return rc;
} }
cmScRC_t _cmScParseMidiCtlMsg( cmSc_t* p, unsigned rowIdx, cmScoreEvt_t* s, unsigned scoreIdx, int barNumb, unsigned barNoteIdx, cmScoreEvt_t** pedalV, unsigned pedalN )
{
cmScRC_t rc = kOkScRC;
unsigned flags = 0;
const cmChar_t* attr;
double secs = DBL_MAX;
double durSecs = 0;
const unsigned pedalBaseMidiId = 64;
s += scoreIdx;
// get the sec's field - or DBL_MAX if it is not set
if((secs = cmCsvCellDouble(p->cH, rowIdx, kSecsColScIdx )) == DBL_MAX) // Returns DBL_MAX on error.
flags += kInvalidScFl;
// skip attribute
if((attr = cmCsvCellText(p->cH,rowIdx,kSkipColScIdx)) != NULL && *attr == 's' )
flags += kSkipScFl;
// get MIDI ctl msg data byte 1
unsigned d0 = cmCsvCellUInt( p->cH,rowIdx,kD0ColScIdx);
// get MIDI ctl msg data byte 2
unsigned d1 = cmCsvCellUInt( p->cH,rowIdx,kD1ColScIdx);
// if this is a pedal event
if( pedalBaseMidiId <= d0 && d0 < pedalBaseMidiId + pedalN )
{
bool pedalDnFl = d1 >= 64;
unsigned pedalIdx = d0 - pedalBaseMidiId;
// if this is a pedal-down message ...
if( pedalDnFl )
{
flags += kPedalDnScFl;
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
{
// Don't store a pointer to a skipped pedal down msg because it will not
// not exist in p->array[] when the associated 'pedal-up' message is
// encountered. Note the the 'postProcFl' controlled section of
// _cmScParseFile() effectively eliminates cmScoreEvt_t records from
// p->array[] that are marked with kSkipScFl.
if( cmIsFlag(flags,kSkipScFl) )
cmErrWarnMsg(&p->err,kPedalInvalidScRC,"A 'pedal-down' msg is marked to skip in or near bar %i this will probably produce a 'missing pedal-down' warning.",barNumb );
else
pedalV[pedalIdx] = s; // ... store a pointer to the scEvt recd in pedalV[]
}
}
else // ... else this is a pedal-up msg ...
{
flags += kPedalUpScFl;
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.
{
if( secs == DBL_MAX )
cmErrWarnMsg(&p->err,kPedalInvalidScRC,"A pedal-up message was encountered with an invalid time-stamp in or near bar %i the pedal down duration could therefore not be calculated.",barNumb);
else
{
// update the pedal down event record with the pedal down duration
pedalV[pedalIdx]->durSecs = secs - pedalV[pedalIdx]->secs;
}
pedalV[pedalIdx] = NULL;
}
}
}
s->type = kPedalEvtScId;
s->secs = secs;
s->pitch = d0; // store the pedal type identifer in the pitch field
s->flags = flags;
s->dynVal = 0;
s->barNumb = barNumb;
s->barNoteIdx = barNoteIdx;
s->durSecs = durSecs;
s->csvRowNumb = rowIdx+1;
return rc;
}
cmScRC_t _cmScParseSectionColumn( cmSc_t* p, unsigned rowIdx, unsigned evtIdx, cmScSect_t* sectList ) cmScRC_t _cmScParseSectionColumn( cmSc_t* p, unsigned rowIdx, unsigned evtIdx, cmScSect_t* sectList )
{ {
const cmCsvCell_t* cell; const cmCsvCell_t* cell;
@ -1224,7 +1314,6 @@ cmScRC_t _cmScParseFile( cmSc_t* p, cmCtx_t* ctx, const cmChar_t* fn )
double secs; double secs;
double cur_secs = 0; double cur_secs = 0;
const unsigned pedalBaseMidiId = 64;
const unsigned pedalN = 3; const unsigned pedalN = 3;
cmScoreEvt_t* pedalV[] = { NULL,NULL,NULL }; cmScoreEvt_t* pedalV[] = { NULL,NULL,NULL };
@ -1263,6 +1352,8 @@ cmScRC_t _cmScParseFile( cmSc_t* p, cmCtx_t* ctx, const cmChar_t* fn )
// skip labels line - start on line 1 // skip labels line - start on line 1
for(i=1,j=0; i<p->cnt && rc==kOkScRC; ++i) for(i=1,j=0; i<p->cnt && rc==kOkScRC; ++i)
{ {
bool postProcFl = false;
// get the row 'type' label // get the row 'type' label
const char* typeLabel; const char* typeLabel;
if((typeLabel = cmCsvCellText(p->cH,i,kTypeLabelColScIdx)) == NULL ) if((typeLabel = cmCsvCellText(p->cH,i,kTypeLabelColScIdx)) == NULL )
@ -1299,78 +1390,48 @@ cmScRC_t _cmScParseFile( cmSc_t* p, cmCtx_t* ctx, const cmChar_t* fn )
case kNonEvtScId: // parse note-on events case kNonEvtScId: // parse note-on events
if((rc = _cmScParseNoteOn(p, i, p->array, j, barNumb, barNoteIdx )) == kOkScRC ) if((rc = _cmScParseNoteOn(p, i, p->array, j, barNumb, barNoteIdx )) == kOkScRC )
{ {
// this note was successfully parsed so time has advanced postProcFl = true;
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; // ... otherwise advance j
++j;
}
++barNoteIdx; ++barNoteIdx;
} }
break; break;
case kCtlEvtScId: case kCtlEvtScId:
if((rc = _cmScParseMidiCtlMsg(p, i, p->array, j, barNumb, barNoteIdx, pedalV, pedalN )) == kOkScRC )
{ {
unsigned d0 = cmCsvCellUInt( p->cH,i,kD0ColScIdx); postProcFl = true;
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 <= d0 && 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 break;
default: default:
// Returns DBL_MAX on error. // Returns DBL_MAX on error.
secs = cmCsvCellDouble(p->cH, i, kSecsColScIdx ); secs = cmCsvCellDouble(p->cH, i, kSecsColScIdx );
break; break;
} }
if( postProcFl )
{
// update the 'secs' according to the parsed time
secs = p->array[j].secs;
// it is possible that the parsed time field was blank ...
if( p->array[j].secs == DBL_MAX )
{
// ... so set the msg time to the last valid time
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 msg 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; // ... otherwise advance j
++j;
}
}
if( rc == kOkScRC ) if( rc == kOkScRC )
{ {

View File

@ -45,8 +45,8 @@ extern "C" {
kSkipScFl = 0x008, // This isn't a real event (e.g. tied note) skip over it kSkipScFl = 0x008, // This isn't a real event (e.g. tied note) skip over it
kGraceScFl = 0x010, // This is a grace note 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.) kPedalDnScFl = 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) kPedalUpScFl = 0x080 // This is a pedal up event (pitch holds the pedal id)
}; };