cmXScore.h : Added cmXScoreMergedEditFiles().

This commit is contained in:
kevin 2020-10-13 15:12:19 -04:00
parent 4942b48206
commit 033204dd04
2 changed files with 579 additions and 64 deletions

View File

@ -110,12 +110,14 @@ typedef struct cmXsNote_str
unsigned locIdx; // location index (chords share the same location index) unsigned locIdx; // location index (chords share the same location index)
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, ...) 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, ...)
const cmChar_t* tvalue; // text value const cmChar_t* tvalue; // text value
const cmChar_t* editStr; // merged manual edit string
unsigned evenGroupId; // eveness group id unsigned evenGroupId; // eveness group id
unsigned dynGroupId; // dynamics group id unsigned dynGroupId; // dynamics group id
unsigned tempoGroupId; // tempo group id unsigned tempoGroupId; // tempo group id
unsigned graceGroupId; // grace note group id unsigned graceGroupId; // grace note group id
struct cmXsVoice_str* voice; // voice this note belongs to struct cmXsVoice_str* voice; // voice this note belongs to
struct cmXsMeas_str* meas; // measure this note belongs to struct cmXsMeas_str* meas; // measure this note belongs to
@ -230,6 +232,33 @@ cmXsVoice_t* _cmXScoreIdToVoice( cmXsMeas_t* meas, unsigned voiceId )
return NULL; return NULL;
} }
cmXsMeas_t* _cmXsFindMeas( cmXsPart_t* part, unsigned measNumb )
{
cmXsMeas_t* m = part->measL;
for(; m!=NULL; m=m->link)
if( m->number == measNumb )
return m;
return NULL;
}
cmXsNote_t* _cmXsFindNote( cmXsMeas_t* m, unsigned idx, unsigned midi, double rval, unsigned durtn, unsigned* idxRef )
{
unsigned i;
cmXsNote_t* np = m->noteL;
for(i=0; np!=NULL; np=np->slink,++i)
{
//printf("idx:%i %i midi:%i %i rval:%f %f durtn:%i %i\n", i,idx, np->pitch,midi, np->rvalue,rval, np->tied_dur,durtn);
if( i>=idx && np->pitch==midi && np->rvalue==rval && np->tied_dur==durtn )
{
*idxRef = i;
return np;
}
}
return NULL;
}
cmXsRC_t _cmXScorePushNote( cmXScore_t* p, cmXsMeas_t* meas, unsigned voiceId, cmXsNote_t* note ) cmXsRC_t _cmXScorePushNote( cmXScore_t* p, cmXsMeas_t* meas, unsigned voiceId, cmXsNote_t* note )
{ {
cmXsVoice_t* v; cmXsVoice_t* v;
@ -612,6 +641,7 @@ cmXsRC_t _cmXScoreParseNote(cmXScore_t* p, cmXsMeas_t* meas, const cmXmlNode_t*
cmXsNote_t* note = cmLhAllocZ(p->lhH,cmXsNote_t,1); cmXsNote_t* note = cmLhAllocZ(p->lhH,cmXsNote_t,1);
unsigned voiceId; unsigned voiceId;
note->pitch = kInvalidMidiPitch;
note->meas = meas; note->meas = meas;
note->xmlNode = nnp; note->xmlNode = nnp;
@ -686,6 +716,7 @@ cmXsRC_t _cmXScorePushNonNote( cmXScore_t* p, cmXsMeas_t* meas, const cmXmlNode_
cmXsNote_t* note = cmLhAllocZ(p->lhH,cmXsNote_t,1); cmXsNote_t* note = cmLhAllocZ(p->lhH,cmXsNote_t,1);
unsigned voiceId = 0; // non-note's are always assigned to voiceId=0; unsigned voiceId = 0; // non-note's are always assigned to voiceId=0;
note->pitch = kInvalidMidiPitch;
note->tick = tick; note->tick = tick;
note->staff = staff; note->staff = staff;
note->flags = flags; note->flags = flags;
@ -798,6 +829,11 @@ cmXsRC_t _cmXScoreParseDirection(cmXScore_t* p, cmXsMeas_t* meas, const cmXmlNo
flags = kSectionXsFl; flags = kSectionXsFl;
} }
else
{
// we only care about 'words' in 'enclosures'
pushFl = false;
}
} }
else else
@ -2028,7 +2064,7 @@ cmXsRC_t _cmXScoreProcessDynamicForks( cmXScore_t* p )
//------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------
typedef struct typedef struct _cmXsReorder_str
{ {
unsigned idx; // Fields from the reordering input file which are unsigned idx; // Fields from the reordering input file which are
unsigned voice; // used to match the reorder record to unsigned voice; // used to match the reorder record to
@ -2046,8 +2082,26 @@ typedef struct
unsigned graceFlags; // 0=ignore See kXXXGraceXsFl unsigned graceFlags; // 0=ignore See kXXXGraceXsFl
unsigned graceGroupId; // 0=ignore >0=grace note group id unsigned graceGroupId; // 0=ignore >0=grace note group id
unsigned pitch; // 0=ignore >0 new pitch unsigned pitch; // 0=ignore >0 new pitch
const char* editStr;
struct _cmXsReorder_str* link;
} cmXsReorder_t; } cmXsReorder_t;
typedef struct _cmXsReorderMeas_str
{
unsigned measNumb;
cmXsReorder_t* beg;
cmXsReorder_t* end;
struct _cmXsReorderMeas_str* link;
} cmXsReorderMeas_t;
typedef struct
{
cmXsReorderMeas_t* beg;
cmXsReorderMeas_t* end;
} cmXsReorderFile_t;
typedef struct _cmXScoreDynMark_str typedef struct _cmXScoreDynMark_str
{ {
const cmChar_t* mark; // const cmChar_t* mark; //
@ -2088,6 +2142,90 @@ _cmXScoreDynMark_t _cmXScoreDynMarkArray[] =
}; };
cmXsReorderMeas_t* _cmXsReorderFileAllocMeas( cmXScore_t* p, cmXsReorderFile_t* rfp, unsigned measNumb )
{
cmXsReorderMeas_t* m = cmLhAllocZ(p->lhH,cmXsReorderMeas_t,1);
m->measNumb = measNumb;
if( rfp->end == NULL )
{
rfp->beg = m;
rfp->end = m;
}
else
{
rfp->end->link = m;
rfp->end = m;
}
return m;
}
cmXsReorderMeas_t* _cmXsReorderFileFindMeas( cmXsReorderFile_t* rfp, unsigned measNumb )
{
cmXsReorderMeas_t* m = rfp->beg;
for(; m!=NULL; m=m->link)
if( m->measNumb == measNumb )
return m;
return NULL;
}
cmXsReorder_t* _cmXsReorderMeasAllocEvent( cmXScore_t* p, cmXsReorderMeas_t* m )
{
cmXsReorder_t* r = cmLhAllocZ(p->lhH, cmXsReorder_t,1);
r->midi = kInvalidMidiPitch;
if( m->end == NULL )
{
m->beg = r;
m->end = r;
}
else
{
m->end->link = r;
m->end = r;
}
return r;
}
// find key in meas (m) by searching after event idx0.
cmXsReorder_t* _cmXsReorderFindEvent( cmXsReorderMeas_t* m, unsigned idx0, cmXsReorder_t* key )
{
cmXsReorder_t* r;
for(r=m->beg; r!=NULL; r=r->link)
if( r->idx >= idx0 && r->midi==key->midi && r->rval==key->rval && r->durtn==key->durtn )
return r;
return NULL;
}
cmXsReorder_t* _cmXsReorderMeasPop( cmXsReorderMeas_t* m )
{
cmXsReorder_t* r0 = NULL;
cmXsReorder_t* r = NULL;
for(r=m->beg; r!=NULL; r=r->link)
{
if( r == m->end )
break;
r0 = r;
}
if( r0 == NULL )
{
m->beg = NULL;
m->end = NULL;
}
else
{
m->end = r0;
m->end->link = NULL;
}
return r;
}
cmXsNote_t* _cmXsReorderFindNote( cmXScore_t* p, unsigned measNumb, const cmXsReorder_t* r, unsigned iii ) cmXsNote_t* _cmXsReorderFindNote( cmXScore_t* p, unsigned measNumb, const cmXsReorder_t* r, unsigned iii )
{ {
@ -2139,6 +2277,7 @@ void _cmXScoreInsertPedalEvent( cmXScore_t* p, const cmXsReorder_t* r, unsigned
// Create a new score event record // Create a new score event record
cmXsNote_t* nn = cmLhAllocZ(p->lhH,cmXsNote_t,1); cmXsNote_t* nn = cmLhAllocZ(p->lhH,cmXsNote_t,1);
nn->pitch = kInvalidMidiPitch;
nn->uid = p->nextUid++; nn->uid = p->nextUid++;
nn->voice = r->note->voice; nn->voice = r->note->voice;
nn->meas = r->note->meas; nn->meas = r->note->meas;
@ -2165,7 +2304,108 @@ void _cmXScoreInsertPedalEvent( cmXScore_t* p, const cmXsReorder_t* r, unsigned
} }
cmXsRC_t _cmXScoreReorderMeas( cmXScore_t* p, unsigned measNumb, cmXsReorder_t* rV, unsigned rN ) cmXsRC_t _cmXScoreReorderMeas( cmXScore_t* p, cmXsReorderMeas_t* m )
{
unsigned i;
cmXsReorder_t* r;
if( m->beg == NULL )
return kOkXsRC;
// set the 'note' field on each cmXsReorder_t record
for(r=m->beg,i=0; r!=NULL; r=r->link,++i)
if((r->note = _cmXsReorderFindNote(p,m->measNumb,r,i)) == NULL )
return kSyntaxErrorXsRC;
// remove deleted notes
for(r=m->beg; r!=NULL; r=r->link)
if( cmIsFlag(r->newFlags,kDeleteXsFl) )
if( _cmXScoreRemoveNote( r->note ) != kOkXsRC )
return cmErrMsg(&p->err,kSyntaxErrorXsRC,"Event marked to skip was not found in measure: %i",m->measNumb);
cmXsMeas_t* mp = m->beg->note->meas;
cmXsNote_t* n0p = NULL;
assert( mp->number == m->measNumb );
// Reassign the slink of the cmXsNote_t records in this measure
// according to their order in rV[].
for(r=m->beg; r!=NULL; r=r->link)
{
if( cmIsFlag(r->newFlags,kDeleteXsFl) )
continue;
if( n0p == NULL )
mp->noteL = r->note;
else
n0p->slink = r->note;
// if a new tick was specified
if( r->newTick != 0 )
r->note->tick = r->newTick;
// if a dynamic or velocity mark was included
if( r->dynIdx != cmInvalidIdx )
{
r->note->dynamics = _cmXScoreDynMarkArray[ r->dynIdx ].dyn;
r->note->vel = _cmXScoreDynMarkArray[ r->dynIdx ].vel;
}
// Set the dynamic fork begin/end flags for later _cmXScoreProcessDynamicForks()
if( cmIsFlag(r->newFlags,kDynBegForkXsFl) )
r->note->flags = cmSetFlag(r->note->flags,kDynBegForkXsFl);
if( cmIsFlag(r->newFlags,kDynEndForkXsFl) )
r->note->flags = cmSetFlag(r->note->flags,kDynEndForkXsFl);
// if the tie end flag was set
if( cmIsFlag(r->newFlags,kTieEndXsFl) )
{
r->note->flags |= kTieEndXsFl;
r->note->flags = cmClrFlag( r->note->flags, kOnsetXsFl );
r->newFlags = cmClrFlag( r->newFlags, kTieEndXsFl);
}
// if a new note value was specified
if( r->pitch != 0 )
r->note->pitch = r->pitch;
r->note->flags |= r->graceFlags;
r->note->graceGroupId = r->graceGroupId;
n0p = r->note;
n0p->slink = NULL;
}
// Insert new note records for pedal up/dn events.
for(r=m->beg; r!=NULL; r=r->link)
{
if( r->newFlags != 0 )
{
if( cmIsFlag(r->newFlags,kDampDnXsFl ) )
_cmXScoreInsertPedalEvent(p,r,kDampDnXsFl);
if( cmIsFlag(r->newFlags,kSostDnXsFl ) )
_cmXScoreInsertPedalEvent(p,r,kSostDnXsFl);
if( cmIsFlag(r->newFlags,kDampUpXsFl ) )
_cmXScoreInsertPedalEvent(p,r,kDampUpXsFl);
if( cmIsFlag(r->newFlags,kSostUpXsFl ) )
_cmXScoreInsertPedalEvent(p,r,kSostUpXsFl);
}
}
return kOkXsRC;
}
cmXsRC_t _cmXScoreReorderMeas0( cmXScore_t* p, unsigned measNumb, cmXsReorder_t* rV, unsigned rN )
{ {
unsigned i; unsigned i;
@ -2266,13 +2506,13 @@ cmXsRC_t _cmXScoreReorderMeas( cmXScore_t* p, unsigned measNumb, cmXsReorder_t*
} }
cmXsRC_t _cmXScoreReorderParseDyn(cmXScore_t* p, const cmChar_t* b, unsigned lineNumb, unsigned* dynIdxRef, unsigned* flagsRef, int measNumb )
{
cmXsRC_t rc = kOkXsRC;
const cmChar_t* s = NULL;
bool begForkFl = false;
bool endForkFl = false;
cmXsRC_t _cmXScoreReorderParseDyn(cmXScore_t* p, const cmChar_t* b, unsigned lineNumb, char** s0, unsigned* dynIdxRef, unsigned* flagsRef, int measNumb )
{
cmXsRC_t rc = kOkXsRC;
cmChar_t* s = NULL;
bool begForkFl = false;
bool endForkFl = false;
*dynIdxRef = cmInvalidIdx; *dynIdxRef = cmInvalidIdx;
@ -2280,6 +2520,9 @@ cmXsRC_t _cmXScoreReorderParseDyn(cmXScore_t* p, const cmChar_t* b, unsigned lin
if( (s = strchr(b,'!')) == NULL ) if( (s = strchr(b,'!')) == NULL )
return rc; return rc;
if( *s0==NULL || s<*s0 )
*s0 = s;
++s; // increment past the '!' ++s; // increment past the '!'
if( *s == 0 ) if( *s == 0 )
@ -2373,12 +2616,12 @@ cmXsRC_t _cmXScoreReorderParseDyn(cmXScore_t* p, const cmChar_t* b, unsigned lin
} }
cmXsRC_t _cmXScoreReorderParseFlags(cmXScore_t* p, const cmChar_t* b, unsigned line, unsigned* newFlagsRef ) cmXsRC_t _cmXScoreReorderParseFlags(cmXScore_t* p, const cmChar_t* b, unsigned line, char** s0, unsigned* newFlagsRef )
{ {
cmXsRC_t rc = kOkXsRC; cmXsRC_t rc = kOkXsRC;
const cmChar_t* s; cmChar_t* s;
bool doneFl = false; bool doneFl = false;
unsigned i = 0; unsigned i = 0;
*newFlagsRef = 0; *newFlagsRef = 0;
@ -2386,6 +2629,9 @@ cmXsRC_t _cmXScoreReorderParseFlags(cmXScore_t* p, const cmChar_t* b, unsigned
if((s = strchr(b,'~')) == NULL ) if((s = strchr(b,'~')) == NULL )
return rc; return rc;
if( *s0==NULL || s<*s0)
*s0 = s;
do do
{ {
++s; ++s;
@ -2434,14 +2680,17 @@ cmXsRC_t _cmXScoreReorderParseFlags(cmXScore_t* p, const cmChar_t* b, unsigned
return rc; return rc;
} }
cmXsRC_t _cmXScoreReorderParseTick(cmXScore_t* p, const cmChar_t* b, unsigned line, unsigned* tickRef ) cmXsRC_t _cmXScoreReorderParseTick(cmXScore_t* p, const cmChar_t* b, unsigned line, char** s0, unsigned* tickRef )
{ {
cmXsRC_t rc = kOkXsRC; cmXsRC_t rc = kOkXsRC;
const cmChar_t* s; cmChar_t* s;
if((s = strchr(b,'@')) == NULL ) if((s = strchr(b,'@')) == NULL )
return rc; return rc;
if( *s0 == NULL || s<*s0 )
*s0 = s;
++s; ++s;
if(!isdigit(*s)) if(!isdigit(*s))
@ -2453,14 +2702,17 @@ cmXsRC_t _cmXScoreReorderParseTick(cmXScore_t* p, const cmChar_t* b, unsigned l
return rc; return rc;
} }
cmXsRC_t _cmXScoreReorderParseGrace(cmXScore_t* p, const cmChar_t* b, unsigned line, cmXsReorder_t* r, unsigned* graceGroupIdRef ) cmXsRC_t _cmXScoreReorderParseGrace(cmXScore_t* p, const cmChar_t* b, unsigned line, char** s0, cmXsReorder_t* r, unsigned* graceGroupIdRef )
{ {
cmXsRC_t rc = kOkXsRC; cmXsRC_t rc = kOkXsRC;
const cmChar_t* s; cmChar_t* s;
if((s = strchr(b,'%')) == NULL ) if((s = strchr(b,'%')) == NULL )
return rc; return rc;
if( *s0==NULL || s<*s0 )
*s0 = s;
++s; ++s;
r->graceGroupId = *graceGroupIdRef; r->graceGroupId = *graceGroupIdRef;
@ -2502,12 +2754,12 @@ cmXsRC_t _cmXScoreReorderParseGrace(cmXScore_t* p, const cmChar_t* b, unsigned
} }
cmXsRC_t _cmXScoreReorderParsePitch(cmXScore_t* p, const cmChar_t* b, unsigned line, unsigned* pitchRef ) cmXsRC_t _cmXScoreReorderParsePitch(cmXScore_t* p, const cmChar_t* b, unsigned line, char** s0, unsigned* pitchRef )
{ {
cmXsRC_t rc = kOkXsRC; cmXsRC_t rc = kOkXsRC;
cmChar_t* s; cmChar_t* s;
cmChar_t buf[4]; cmChar_t buf[4];
unsigned i,j; unsigned i,j;
memset(buf,0,sizeof(buf)); memset(buf,0,sizeof(buf));
*pitchRef = 0; *pitchRef = 0;
@ -2515,6 +2767,9 @@ cmXsRC_t _cmXScoreReorderParsePitch(cmXScore_t* p, const cmChar_t* b, unsigned
if((s = strchr(b,'$')) == NULL ) if((s = strchr(b,'$')) == NULL )
return rc; return rc;
if( *s0==NULL || s<*s0)
*s0 = s;
++s; ++s;
j=2; j=2;
@ -2546,7 +2801,232 @@ cmXsRC_t _cmXScoreReorderParsePitch(cmXScore_t* p, const cmChar_t* b, unsigned
return rc; return rc;
} }
cmXsRC_t _cmXsReadEditFile( cmXScore_t* p, const cmChar_t* fn, unsigned* graceGroupIdPtr, cmXsReorderFile_t* rfp )
{
typedef enum { kFindMeasStId, kFindEventStId, kReadEventStId } stateId_t;
cmXsRC_t rc = kOkXsRC;
cmFileH_t fH = cmFileNullHandle;
cmChar_t* b = NULL;
unsigned bN = 0;
unsigned ln = 0;
stateId_t stateId = kFindMeasStId;
cmXsReorderMeas_t* curMeas = NULL;
*graceGroupIdPtr = 1;
if( cmFileOpen(&fH,fn,kReadFileFl,p->err.rpt) != kOkFileRC )
{
rc = cmErrMsg(&p->err,kFileFailXsRC,"The reordering file '%s' could not be opened.",cmStringNullGuard(fn));
return rc;
}
for(; cmFileGetLineAuto(fH,&b,&bN) == kOkFileRC; ++ln)
{
switch( stateId )
{
case kFindEventStId: // scanning past labels to an event line
{
unsigned voice,loc;
if( sscanf(b,"%i %i",&voice,&loc) != 2 )
continue;
stateId = kReadEventStId;
}
// fall through
case kReadEventStId:
{
cmXsReorder_t* r = _cmXsReorderMeasAllocEvent(p, curMeas );
char pitchStr[4];
char* s0 = NULL;
// parse an event line
if( sscanf(b,"%i %i %i %i %i %f",&r->idx,&r->voice,&r->locIdx,&r->tick,&r->durtn,&r->rval) == 6 )
{
assert( strlen(b)>=52);
int PC = 39; // text file column where first pitch char occurs
if( b[PC] == ' ')
r->midi = kInvalidMidiPitch;
else
{
pitchStr[0] = b[PC+0];
pitchStr[1] = b[PC+1];
pitchStr[2] = b[PC+2];
pitchStr[3] = 0;
if( !isdigit(pitchStr[2]) )
r->midi = kInvalidMidiPitch;
else
{
if( pitchStr[1] == ' ')
{
pitchStr[1] = pitchStr[2];
pitchStr[2] = 0;
}
r->midi = cmSciPitchToMidi(pitchStr);
//printf("%i %i %s %s\n",curMeas->measNumb,r->midi,pitchStr,fn);
}
}
// parse the flag edits following a '~'
if((rc = _cmXScoreReorderParseFlags(p,b,ln+1, &s0, &r->newFlags)) != kOkXsRC )
goto errLabel;
// parse the dynamic marking following a '!'
if((rc = _cmXScoreReorderParseDyn(p,b,ln+1, &s0, &r->dynIdx, &r->newFlags, curMeas->measNumb)) != kOkXsRC )
goto errLabel;
// parse the @newtick marker
if((rc = _cmXScoreReorderParseTick(p, b, ln+1, &s0, &r->newTick)) != kOkXsRC )
goto errLabel;
// parse the %grace note marker
if((rc = _cmXScoreReorderParseGrace(p, b, ln+1, &s0, r, graceGroupIdPtr)) != kOkXsRC )
goto errLabel;
// parse the $pitch marker
if((rc = _cmXScoreReorderParsePitch(p, b, ln+1, &s0, &r->pitch )) != kOkXsRC )
goto errLabel;
if( s0 != NULL )
r->editStr = cmTextTrimEnd(cmLhAllocStrN( p->lhH, s0, strlen(s0)+1 ));
continue;
}
// remove the last reorder record because it was not filled
_cmXsReorderMeasPop(curMeas);
stateId = kFindMeasStId;
// fall through
}
case kFindMeasStId: // scanning for a bar-line
{
char colon;
unsigned measNumb = 0;
if( sscanf(b,"%i %c",&measNumb,&colon) == 2 && colon == ':' )
{
curMeas = _cmXsReorderFileAllocMeas( p, rfp, measNumb );
stateId = kFindEventStId;
}
}
break;
}
}
errLabel:
cmMemFree(b);
cmFileClose(&fH);
return rc;
}
cmXsRC_t _cmXsApplyEditFile( cmXScore_t* p, const cmChar_t* fn ) cmXsRC_t _cmXsApplyEditFile( cmXScore_t* p, const cmChar_t* fn )
{
cmXsRC_t rc = kOkXsRC;
unsigned graceGroupId = 1;
cmXsReorderFile_t rf;
cmXsReorderMeas_t* m;
memset(&rf,0,sizeof(rf));
if((rc = _cmXsReadEditFile( p, fn, &graceGroupId, &rf )) != kOkXsRC )
return rc;
// reorder each measure
for(m=rf.beg; m!=NULL; m=m->link)
if((rc = _cmXScoreReorderMeas(p, m)) != kOkXsRC )
goto errLabel;
// the ticks may have changed so the 'secs' and 'dsecs' must be updated
_cmXScoreSetAbsoluteTime( p );
// the bar lines should be the first event in the measure
_cmXScoreFixBarLines(p);
// resort to force the links to be correct
_cmXScoreSort(p);
// process the grace notes.
_cmXScoreProcessGraceNotes( p, graceGroupId );
// inserting grace notes may have left the score unsorted
_cmXScoreSort(p);
// process the dynamic forks
_cmXScoreProcessDynamicForks(p);
//_cmXScoreReport(p, NULL, true );
errLabel:
return rc;
}
cmXsRC_t _cmXsMergeEditFiles( cmXScore_t* p, unsigned measNumb0, const cmChar_t* keyEditFn, unsigned keyMeasNumb, const cmChar_t* outFn )
{
cmXsRC_t rc = kOkXsRC;
unsigned graceGroup1Id = 1;
unsigned measNumb1 = keyMeasNumb;
cmXsReorderFile_t rf1;
memset(&rf1,0,sizeof(rf1));
if((rc = _cmXsReadEditFile( p, keyEditFn, &graceGroup1Id, &rf1 )) != kOkXsRC )
return rc;
while(1)
{
cmXsMeas_t* m0 = _cmXsFindMeas( p->partL, measNumb0 );
cmXsReorderMeas_t* m1 = _cmXsReorderFileFindMeas( &rf1, measNumb1 );
cmXsReorder_t* key = NULL;
unsigned idx0 = 0;
if( m1==NULL )
{
rc = cmErrMsg(&p->err,kEventNotFoundXsRC,"The measure %i was not found in the key edit file '%s'.",keyMeasNumb,cmStringNullGuard(keyEditFn));
break;
}
key = m1->beg;
for(; key!=NULL; key=key->link)
{
unsigned idx1 = cmInvalidIdx;
cmXsNote_t* np = _cmXsFindNote( m0, idx0, key->midi, key->rval, key->durtn, &idx1);
if( np==NULL )
{
if( key->editStr != NULL )
{
const char* sciPitch = key->midi!=kInvalidMidiPitch ? cmMidiToSciPitch(key->midi,NULL,0) : "<non-pitch>";
cmErrWarnMsg(&p->err,kEventNotFoundXsRC,"Sync error: meas: ref:%i key:%i index:%i %s (midi:%i) edit:%s did not match to the reference edit file.", measNumb0,m1->measNumb,key->idx, sciPitch, key->midi, key->editStr);
}
}
else
{
np->editStr = key->editStr;
if( key->editStr != NULL )
idx0 = idx1;
}
}
++measNumb0;
++measNumb1;
}
return rc;
}
cmXsRC_t _cmXsApplyEditFile0( cmXScore_t* p, const cmChar_t* fn )
{ {
typedef enum { kFindMeasStId, kFindEventStId, kReadEventStId } stateId_t; typedef enum { kFindMeasStId, kFindEventStId, kReadEventStId } stateId_t;
@ -2586,6 +3066,7 @@ cmXsRC_t _cmXsApplyEditFile( cmXScore_t* p, const cmChar_t* fn )
{ {
cmXsReorder_t r; cmXsReorder_t r;
char pitchStr[4]; char pitchStr[4];
char* s0 = NULL;
memset(&r,0,sizeof(r)); memset(&r,0,sizeof(r));
@ -2596,7 +3077,7 @@ cmXsRC_t _cmXsApplyEditFile( cmXScore_t* p, const cmChar_t* fn )
int PC = 39; // text file column where first pitch char occurs int PC = 39; // text file column where first pitch char occurs
if( b[PC] == ' ') if( b[PC] == ' ')
r.midi = 0; r.midi = kInvalidMidiPitch;
else else
{ {
pitchStr[0] = b[PC+0]; pitchStr[0] = b[PC+0];
@ -2605,7 +3086,7 @@ cmXsRC_t _cmXsApplyEditFile( cmXScore_t* p, const cmChar_t* fn )
pitchStr[3] = 0; pitchStr[3] = 0;
if( !isdigit(pitchStr[2]) ) if( !isdigit(pitchStr[2]) )
r.midi = 0; r.midi = kInvalidMidiPitch;
else else
{ {
if( pitchStr[1] == ' ') if( pitchStr[1] == ' ')
@ -2621,41 +3102,25 @@ cmXsRC_t _cmXsApplyEditFile( cmXScore_t* p, const cmChar_t* fn )
// parse the flag edits following a '~' // parse the flag edits following a '~'
if((rc = _cmXScoreReorderParseFlags(p,b,ln+1, &r.newFlags)) != kOkXsRC ) if((rc = _cmXScoreReorderParseFlags(p,b,ln+1, &s0, &r.newFlags)) != kOkXsRC )
goto errLabel; goto errLabel;
// parse the dynamic marking following a '!' // parse the dynamic marking following a '!'
if((rc = _cmXScoreReorderParseDyn(p,b,ln+1,&r.dynIdx, &r.newFlags, measNumb)) != kOkXsRC ) if((rc = _cmXScoreReorderParseDyn(p,b,ln+1,&s0, &r.dynIdx, &r.newFlags, measNumb)) != kOkXsRC )
goto errLabel; goto errLabel;
// parse the @newtick marker // parse the @newtick marker
if((rc = _cmXScoreReorderParseTick(p, b, ln+1, &r.newTick)) != kOkXsRC ) if((rc = _cmXScoreReorderParseTick(p, b, ln+1, &s0, &r.newTick)) != kOkXsRC )
goto errLabel; goto errLabel;
// parse the %grace note marker // parse the %grace note marker
if((rc = _cmXScoreReorderParseGrace(p, b, ln+1, &r, &graceGroupId)) != kOkXsRC ) if((rc = _cmXScoreReorderParseGrace(p, b, ln+1, &s0, &r, &graceGroupId)) != kOkXsRC )
goto errLabel; goto errLabel;
// parse the $pitch marker // parse the $pitch marker
if((rc = _cmXScoreReorderParsePitch(p, b, ln+1, &r.pitch )) != kOkXsRC ) if((rc = _cmXScoreReorderParsePitch(p, b, ln+1, &s0, &r.pitch )) != kOkXsRC )
goto errLabel; goto errLabel;
// process grace notes - these need to be processed separate from
// the _cmXScoreReorderMeas() because grace notes may cross measure boundaries.
/*
if( r.graceType != 0 )
{
r.graceGroupId = graceGroupId;
// if this is an end of a grace note group
if( r.graceType != 'g' && r.graceType != 'b' )
{
graceGroupId += 1;
}
}
*/
// store the record // store the record
assert( ri < rN ); assert( ri < rN );
@ -2666,7 +3131,7 @@ cmXsRC_t _cmXsApplyEditFile( cmXScore_t* p, const cmChar_t* fn )
// the end of the measure was encountered - // the end of the measure was encountered -
// reorder the measure based on the cmXsReorder_t in rV[ri] // reorder the measure based on the cmXsReorder_t in rV[ri]
if((rc = _cmXScoreReorderMeas(p, measNumb, rV, ri )) != kOkXsRC ) if((rc = _cmXScoreReorderMeas0(p, measNumb, rV, ri )) != kOkXsRC )
goto errLabel; goto errLabel;
ri = 0; ri = 0;
@ -2692,7 +3157,7 @@ cmXsRC_t _cmXsApplyEditFile( cmXScore_t* p, const cmChar_t* fn )
// If reorder records remain to be processed // If reorder records remain to be processed
if( ri > 0 ) if( ri > 0 )
if((rc = _cmXScoreReorderMeas(p, measNumb, rV, ri )) != kOkXsRC ) if((rc = _cmXScoreReorderMeas0(p, measNumb, rV, ri )) != kOkXsRC )
goto errLabel; goto errLabel;
@ -2724,8 +3189,7 @@ cmXsRC_t _cmXsApplyEditFile( cmXScore_t* p, const cmChar_t* fn )
} }
cmXsRC_t cmXScoreAlloc( cmCtx_t* ctx, cmXsH_t* hp )
cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn, const cmChar_t* editFn, bool damperRptFl )
{ {
cmXsRC_t rc = kOkXsRC; cmXsRC_t rc = kOkXsRC;
@ -2740,6 +3204,21 @@ cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn, c
if( cmLHeapIsValid( p->lhH = cmLHeapCreate(8196,ctx)) == false ) if( cmLHeapIsValid( p->lhH = cmLHeapCreate(8196,ctx)) == false )
return cmErrMsg(&p->err,kLHeapFailXsRC,"Lheap create failed."); return cmErrMsg(&p->err,kLHeapFailXsRC,"Lheap create failed.");
hp->h = p;
return rc;
}
cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn, const cmChar_t* editFn, bool damperRptFl )
{
cmXsRC_t rc;
cmXScore_t* p = NULL;
if((rc = cmXScoreAlloc(ctx,hp)) != kOkXsRC )
goto errLabel;
p = _cmXScoreHandleToPtr(*hp);
// open the music xml file // open the music xml file
if( cmXmlAlloc(ctx, &p->xmlH, xmlFn) != kOkXmlRC ) if( cmXmlAlloc(ctx, &p->xmlH, xmlFn) != kOkXmlRC )
{ {
@ -2798,9 +3277,8 @@ cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn, c
errLabel: errLabel:
if( rc != kOkXsRC ) if( rc != kOkXsRC )
_cmXScoreFinalize(p); cmXScoreFinalize(hp);
else
hp->h = p;
return rc; return rc;
} }
@ -3322,6 +3800,9 @@ void _cmXScoreReportNote( cmRpt_t* rpt, const cmXsNote_t* note,unsigned index )
if( note->dynamics != 0) if( note->dynamics != 0)
cmRptPrintf(rpt," dyn=%i %i",note->dynamics,note->vel); cmRptPrintf(rpt," dyn=%i %i",note->dynamics,note->vel);
if( note->editStr != NULL )
cmRptPrintf(rpt, " %s", note->editStr );
/* /*
if( cmIsFlag(note->flags,kBegGraceXsFl) ) if( cmIsFlag(note->flags,kBegGraceXsFl) )
cmRptPrintf(rpt," B"); cmRptPrintf(rpt," B");
@ -3371,6 +3852,7 @@ void _cmXScoreReport( cmXScore_t* p, cmRpt_t* rpt, bool sortFl )
t1 = note->slink==NULL ? note->tick : note->slink->tick; t1 = note->slink==NULL ? note->tick : note->slink->tick;
// check that this note is in tick order
if( !(t0 <= note->tick && note->tick <= t1) ) if( !(t0 <= note->tick && note->tick <= t1) )
{ {
cmRptPrintf(rpt," +"); cmRptPrintf(rpt," +");
@ -3427,33 +3909,42 @@ void _cmXScoreGenEditFileWrite( void* arg, const cmChar_t* text )
} }
} }
cmXsRC_t cmXScoreGenEditFile( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* outFn, bool damperRptFl ) cmXsRC_t _cmXScoreEditFileRpt( cmCtx_t* ctx, cmXScore_t* p, const cmChar_t* outFn, bool damperRptFl )
{ {
cmXsH_t xsH = cmXsNullHandle;
cmFileH_t fH = cmFileNullHandle;
cmXsRC_t rc = kOkXsRC; cmXsRC_t rc = kOkXsRC;
cmErr_t err; cmErr_t err;
cmRpt_t rpt; cmRpt_t rpt;
cmFileH_t fH = cmFileNullHandle;
cmErrSetup(&err,&ctx->rpt,"cmXScoreGenEditFile"); cmErrSetup(&err,&ctx->rpt,"cmXScoreGenEditFile");
cmRptSetup(&rpt,_cmXScoreGenEditFileWrite,_cmXScoreGenEditFileWrite,&fH); cmRptSetup(&rpt,_cmXScoreGenEditFileWrite,_cmXScoreGenEditFileWrite,&fH);
if((rc = cmXScoreInitialize(ctx,&xsH,xmlFn,NULL,damperRptFl)) != kOkXsRC )
return rc;
if( cmFileOpen(&fH,outFn,kWriteFileFl,&ctx->rpt) != kOkFileRC ) if( cmFileOpen(&fH,outFn,kWriteFileFl,&ctx->rpt) != kOkFileRC )
{ {
cmErrMsg(&err,kFileFailXsRC,"Unable to open the output file '%s'.",cmStringNullGuard(outFn)); cmErrMsg(&err,kFileFailXsRC,"Unable to open the output file '%s'.",cmStringNullGuard(outFn));
goto errLabel; goto errLabel;
} }
cmXScoreReport(xsH,&rpt,true); _cmXScoreReport(p,&rpt,true);
errLabel: errLabel:
if( cmFileClose(&fH) != kOkFileRC ) if( cmFileClose(&fH) != kOkFileRC )
rc = cmErrMsg(&err,kFileFailXsRC,"File close failed on '%s'.",cmStringNullGuard(outFn)); rc = cmErrMsg(&err,kFileFailXsRC,"File close failed on '%s'.",cmStringNullGuard(outFn));
return rc;
}
cmXsRC_t cmXScoreGenEditFile( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* outFn, bool damperRptFl )
{
cmXsH_t xsH = cmXsNullHandle;
cmXsRC_t rc = kOkXsRC;
if((rc = cmXScoreInitialize(ctx,&xsH,xmlFn,NULL,damperRptFl)) != kOkXsRC )
return rc;
rc = _cmXScoreEditFileRpt( ctx, _cmXScoreHandleToPtr(xsH), outFn, damperRptFl );
cmXScoreFinalize(&xsH); cmXScoreFinalize(&xsH);
return rc; return rc;
@ -4148,3 +4639,24 @@ cmXsRC_t cmXScoreTest(
return cmXScoreFinalize(&h); return cmXScoreFinalize(&h);
} }
cmXsRC_t cmXScoreMergeEditFiles( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* refEditFn, unsigned refBegMeasNumb, const cmChar_t* editFn, unsigned keyMeasNumb, const cmChar_t* outFn )
{
cmXsH_t h = cmXsNullHandle;
cmXsRC_t rc;
bool damperRptFl = false;
if((rc = cmXScoreInitialize(ctx, &h, xmlFn, refEditFn, damperRptFl )) == kOkXsRC )
{
cmXScore_t* p = _cmXScoreHandleToPtr(h);
if((rc = _cmXsMergeEditFiles(p, refBegMeasNumb, editFn, keyMeasNumb, outFn )) == kOkXsRC )
rc = _cmXScoreEditFileRpt( ctx, p, outFn, damperRptFl );
cmXScoreFinalize(&h);
}
return rc;
}

View File

@ -20,7 +20,8 @@ extern "C" {
kFileFailXsRC, kFileFailXsRC,
kSvgFailXsRC, kSvgFailXsRC,
kOverlapWarnXsRC, kOverlapWarnXsRC,
kZeroLengthEventXsRC kZeroLengthEventXsRC,
kEventNotFoundXsRC
}; };
typedef cmRC_t cmXsRC_t; typedef cmRC_t cmXsRC_t;
@ -74,6 +75,8 @@ extern "C" {
// Set begBPM to 0 to use the tempo from the score otherwise set it to the tempo at begMeasNumb. // Set begBPM to 0 to use the tempo from the score otherwise set it to the tempo at begMeasNumb.
cmXsRC_t cmXScoreTest( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* reorderFn, const cmChar_t* csvOutFn, const cmChar_t* midiOutFn, const cmChar_t* svgOutFn, bool reportFl, int begMeasNumb, int begBPM, bool svgStandAloneFl, bool svgPanZoomFl, bool damperRptFl ); cmXsRC_t cmXScoreTest( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* reorderFn, const cmChar_t* csvOutFn, const cmChar_t* midiOutFn, const cmChar_t* svgOutFn, bool reportFl, int begMeasNumb, int begBPM, bool svgStandAloneFl, bool svgPanZoomFl, bool damperRptFl );
cmXsRC_t cmXScoreMergeEditFiles( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* refEditFn, unsigned refBegMeasNumb, const cmChar_t* editFn, unsigned keyMeasNumb, const cmChar_t* outFn );
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif