cmXScore.h/c : Began tie processing.
This commit is contained in:
parent
0bd988e2df
commit
5c27c2455f
237
app/cmXScore.c
237
app/cmXScore.c
@ -29,12 +29,16 @@ enum
|
||||
kEvenXsFl = 0x0080,
|
||||
kTempoXsFl = 0x0100,
|
||||
kHeelXsFl = 0x0200,
|
||||
kPedalDnXsFl = 0x0400,
|
||||
kPedalUpXsFl = 0x0800,
|
||||
kPedalUpDnXsFl = 0x1000,
|
||||
kMetronomeXsFl = 0x2000 // duration holds BPM
|
||||
kTieBegXsFl = 0x0400,
|
||||
kTieEndXsFl = 0x0800,
|
||||
kPedalDnXsFl = 0x1000,
|
||||
kPedalUpXsFl = 0x2000,
|
||||
kPedalUpDnXsFl = 0x4000,
|
||||
kMetronomeXsFl = 0x8000 // duration holds BPM
|
||||
};
|
||||
|
||||
struct cmXsMeas_str;
|
||||
struct cmXsVoice_str;
|
||||
|
||||
typedef struct cmXsNote_str
|
||||
{
|
||||
@ -42,12 +46,28 @@ typedef struct cmXsNote_str
|
||||
unsigned pitch; // midi pitch
|
||||
unsigned tick; //
|
||||
unsigned duration; // duration in ticks
|
||||
unsigned pticks; // play ticks (0 for non-sounding notes)
|
||||
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 struct cmXsVoice_str* voice; // voice this note belongs to
|
||||
const struct cmXsMeas_str* meas; // measure this note belongs to
|
||||
const cmXmlNode_t* xmlNode; // note xml ptr
|
||||
|
||||
struct cmXsNote_str* mlink; // measure note list
|
||||
struct cmXsNote_str* slink; // time sorted event list
|
||||
|
||||
} cmXsNote_t;
|
||||
|
||||
typedef struct cmXsConnect_str
|
||||
{
|
||||
bool doneFl; // this tie has been completed (slurs only occur in pairs)
|
||||
bool closeFl;// this tie was properly closed
|
||||
const cmXsNote_t* note; // associated
|
||||
struct cmXsConnect_str* nlink; // next connected note
|
||||
struct cmXsConnect_str* link; // p->tieL,p->slurL links
|
||||
} cmXsConnect_t;
|
||||
|
||||
typedef struct cmXsVoice_str
|
||||
{
|
||||
unsigned id; // Voice id
|
||||
@ -81,7 +101,10 @@ typedef struct
|
||||
cmXmlH_t xmlH;
|
||||
cmLHeapH_t lhH;
|
||||
cmXsPart_t* partL;
|
||||
cmCsvH_t csvH;
|
||||
cmCsvH_t csvH;
|
||||
|
||||
cmXsConnect_t* slurL;
|
||||
cmXsConnect_t* tieL;
|
||||
} cmXScore_t;
|
||||
|
||||
cmXScore_t* _cmXScoreHandleToPtr( cmXsH_t h )
|
||||
@ -165,6 +188,8 @@ cmXsRC_t _cmXScorePushNote( cmXScore_t* p, cmXsMeas_t* meas, unsigned voiceId, c
|
||||
n->mlink = note;
|
||||
}
|
||||
|
||||
note->voice = v;
|
||||
|
||||
return kOkXsRC;
|
||||
}
|
||||
|
||||
@ -234,6 +259,164 @@ cmXsRC_t _cmXScoreParsePitch( cmXScore_t* p, const cmXmlNode_t* nnp, unsigned*
|
||||
return rc;
|
||||
}
|
||||
|
||||
cmXsConnect_t* _cmXScoreFindTie( const cmXScore_t* p, unsigned pitch )
|
||||
{
|
||||
cmXsConnect_t* c = p->tieL;
|
||||
for(; c!=NULL; c=c->link)
|
||||
{
|
||||
assert( c->note != NULL );
|
||||
if( c->doneFl == false && c->note->pitch == pitch )
|
||||
return c;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cmXsRC_t _cmXScoreNewTie( cmXScore_t* p, const cmXsNote_t* note )
|
||||
{
|
||||
cmXsConnect_t* c;
|
||||
|
||||
// check that an open tie with the same pitch does not exist
|
||||
if((c = _cmXScoreFindTie(p,note->pitch)) != NULL )
|
||||
{
|
||||
cmErrWarnMsg(&p->err,kUnterminatedTieXsRC,"The tie begun from note on line %i was not terminated. (pitch=%i)",c->note->xmlNode->line,c->note->pitch);
|
||||
c->doneFl = true; // close the unterminated tie
|
||||
}
|
||||
|
||||
// allocate a new connection record
|
||||
c = cmLhAllocZ(p->lhH,cmXsConnect_t,1);
|
||||
|
||||
// set the first note in the connection
|
||||
c->note = note;
|
||||
|
||||
// append the new record to the end of the tie list
|
||||
if(p->tieL == NULL )
|
||||
p->tieL = c;
|
||||
else
|
||||
{
|
||||
cmXsConnect_t* cp = p->tieL;
|
||||
while( cp->link != NULL )
|
||||
cp = cp->link;
|
||||
|
||||
cp->link = c;
|
||||
}
|
||||
|
||||
return kOkXsRC;
|
||||
}
|
||||
|
||||
cmXsRC_t _cmXScoreContinueTie( cmXScore_t* p, const cmXsNote_t* note, unsigned measNumb )
|
||||
{
|
||||
cmXsConnect_t* c;
|
||||
|
||||
// find an open tie with the same pitch
|
||||
if((c = _cmXScoreFindTie(p,note->pitch)) == NULL )
|
||||
{
|
||||
cmErrWarnMsg(&p->err,kUnterminatedTieXsRC,"The tie ending on the note on line %i does not have an associated starting note. (pitch=%i)",note->xmlNode->line,note->pitch);
|
||||
return kOkXsRC;
|
||||
}
|
||||
|
||||
// allocate a new connection record
|
||||
cmXsConnect_t* nc = cmLhAllocZ(p->lhH,cmXsConnect_t,1);
|
||||
nc->note = note;
|
||||
|
||||
// add the note to the end of the tie list
|
||||
if( c->nlink == NULL )
|
||||
c->nlink = nc;
|
||||
else
|
||||
{
|
||||
cmXsConnect_t* cp = c->nlink;
|
||||
while( cp->nlink != NULL )
|
||||
cp=cp->nlink;
|
||||
cp->nlink = nc;
|
||||
}
|
||||
|
||||
// if this is the last note in the tie ...
|
||||
if( cmIsFlag(note->flags,kTieEndXsFl) && cmIsNotFlag(note->flags,kTieBegXsFl) )
|
||||
{
|
||||
c->doneFl = true; // ... mark the tie list as complete ...
|
||||
c->closeFl= true; // ... and properly closed
|
||||
printf("tie done: meas=%i line=%i pitch=%i\n",measNumb,note->xmlNode->line,note->pitch);
|
||||
}
|
||||
return kOkXsRC;
|
||||
}
|
||||
|
||||
cmXsRC_t _cmXScoreProcessTie( cmXScore_t* p, const cmXmlNode_t* np, cmXsNote_t* note, unsigned measNumb )
|
||||
{
|
||||
cmXsRC_t rc = kOkXsRC;
|
||||
|
||||
// is this is first note in a tied pair
|
||||
if( cmXmlNodeHasChildWithAttrAndValue(np,"tie","type","start",NULL) )
|
||||
note->flags |= kTieBegXsFl;
|
||||
|
||||
// is this is second note in a tied pair
|
||||
if( cmXmlNodeHasChildWithAttrAndValue(np,"tie","type","stop",NULL) )
|
||||
note->flags |= kTieEndXsFl;
|
||||
|
||||
// if this is a tie start (and not a tie continue)
|
||||
if( cmIsFlag(note->flags,kTieBegXsFl) && cmIsNotFlag(note->flags,kTieEndXsFl) )
|
||||
rc = _cmXScoreNewTie(p,note);
|
||||
else
|
||||
// if this is a tie continue or end
|
||||
if( cmIsFlag(note->flags,kTieEndXsFl) )
|
||||
rc = _cmXScoreContinueTie(p,note,measNumb); // this is a tie end or continue
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
const cmXsNote_t* _cmXScoreResolveTie( const cmXsNote_t* note )
|
||||
{
|
||||
const cmXsMeas_t* m = note->meas;
|
||||
const cmXsNote_t* n = note->slink;
|
||||
|
||||
while( n!=NULL )
|
||||
{
|
||||
for(; n!=NULL; n=n->slink)
|
||||
if( note->pitch==n->pitch && note->voice==n->voice )
|
||||
return n;
|
||||
|
||||
if( m->link == NULL )
|
||||
break;
|
||||
|
||||
// got to next measure
|
||||
if((m = m->link) == NULL )
|
||||
break;
|
||||
|
||||
n = m->noteL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cmXsRC_t _cmXScoreResolveTies( cmXScore_t* p )
|
||||
{
|
||||
cmXsRC_t rc = kOkXsRC;
|
||||
|
||||
cmXsPart_t* pp = p->partL;
|
||||
for(; pp!=NULL; pp=pp->link)
|
||||
{
|
||||
cmXsMeas_t* mp = pp->measL;
|
||||
for(; mp!=NULL; mp=mp->link)
|
||||
{
|
||||
cmXsNote_t* np = mp->noteL;
|
||||
for(; np!=NULL; np=np->slink)
|
||||
if( cmIsFlag(np->flags,kTieBegXsFl) )
|
||||
{
|
||||
const cmXsNote_t* tnp;
|
||||
if((tnp = _cmXScoreResolveTie(np)) == NULL)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
cmXsRC_t _cmXScoreParseNoteRValue( cmXScore_t* p, const cmXmlNode_t* nnp, const cmChar_t* label, double* rvalueRef )
|
||||
{
|
||||
typedef struct map_str
|
||||
@ -356,6 +539,9 @@ cmXsRC_t _cmXScoreParseNote(cmXScore_t* p, cmXsMeas_t* meas, const cmXmlNode_t*
|
||||
cmXsNote_t* note = cmLhAllocZ(p->lhH,cmXsNote_t,1);
|
||||
unsigned voiceId;
|
||||
|
||||
note->meas = meas;
|
||||
note->xmlNode = nnp;
|
||||
|
||||
// get the voice id for this node
|
||||
if( cmXmlNodeUInt(nnp,&voiceId,"voice",NULL) != kOkXmlRC )
|
||||
return _cmXScoreMissingNode(p,nnp,"voice");
|
||||
@ -384,6 +570,10 @@ cmXsRC_t _cmXScoreParseNote(cmXScore_t* p, cmXsMeas_t* meas, const cmXmlNode_t*
|
||||
if( cmXmlNodeHasChild(nnp,"chord",NULL) )
|
||||
note->flags |= kChordXsFl;
|
||||
|
||||
// process ties attached to this note
|
||||
if((rc = _cmXScoreProcessTie(p,nnp,note,meas->number)) != kOkXsRC )
|
||||
return rc;
|
||||
|
||||
// has 'heel' mark
|
||||
if( cmXmlNodeHasChild(nnp,"notations","technical","heel",NULL) )
|
||||
note->flags |= kHeelXsFl;
|
||||
@ -404,7 +594,7 @@ cmXsRC_t _cmXScoreParseNote(cmXScore_t* p, cmXsMeas_t* meas, const cmXmlNode_t*
|
||||
return _cmXScorePushNote(p, meas, voiceId, note );
|
||||
}
|
||||
|
||||
cmXsRC_t _cmXScorePushNonNote( cmXScore_t* p, cmXsMeas_t* meas, unsigned tick, unsigned duration, double rvalue, const cmChar_t* tvalue, unsigned flags )
|
||||
cmXsRC_t _cmXScorePushNonNote( cmXScore_t* p, cmXsMeas_t* meas, const cmXmlNode_t* noteXmlNode, unsigned tick, unsigned duration, double rvalue, const cmChar_t* tvalue, unsigned flags )
|
||||
{
|
||||
cmXsNote_t* note = cmLhAllocZ(p->lhH,cmXsNote_t,1);
|
||||
unsigned voiceId = 0; // non-note's are always assigned to voiceId=0;
|
||||
@ -414,6 +604,8 @@ cmXsRC_t _cmXScorePushNonNote( cmXScore_t* p, cmXsMeas_t* meas, unsigned tick, u
|
||||
note->rvalue = rvalue;
|
||||
note->tvalue = tvalue;
|
||||
note->duration = duration;
|
||||
note->meas = meas;
|
||||
note->xmlNode = noteXmlNode;
|
||||
|
||||
return _cmXScorePushNote(p, meas, voiceId, note );
|
||||
}
|
||||
@ -477,7 +669,7 @@ cmXsRC_t _cmXScoreParseDirection(cmXScore_t* p, cmXsMeas_t* meas, const cmXmlNo
|
||||
}
|
||||
}
|
||||
|
||||
return _cmXScorePushNonNote(p,meas,tick+offset,duration,rvalue,tvalue,flags);
|
||||
return _cmXScorePushNonNote(p,meas,dnp,tick+offset,duration,rvalue,tvalue,flags);
|
||||
|
||||
}
|
||||
|
||||
@ -515,7 +707,7 @@ cmXsRC_t _cmXScoreParseMeasure(cmXScore_t* p, cmXsPart_t* pp, const cmXmlNode_t*
|
||||
}
|
||||
|
||||
// store the bar line
|
||||
if((rc = _cmXScorePushNonNote(p,meas,tick,0,0,NULL,kBarXsFl)) != kOkXsRC )
|
||||
if((rc = _cmXScorePushNonNote(p,meas,mnp,tick,0,0,NULL,kBarXsFl)) != kOkXsRC )
|
||||
return rc;
|
||||
|
||||
|
||||
@ -661,6 +853,10 @@ cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn )
|
||||
// CSV output initialize failed.
|
||||
if( cmCsvInitialize(&p->csvH,ctx) != kOkCsvRC )
|
||||
rc = cmErrMsg(&p->err,kCsvFailXsRC,"CSV output object create failed.");
|
||||
|
||||
cmXsConnect_t* c = p->tieL;
|
||||
for(; c!=NULL; c=c->link)
|
||||
cmErrWarnMsg(&p->err,kUnterminatedTieXsRC,"The tie begun from note on line %i was not terminated. (pitch=%i)",c->note->xmlNode->line,c->note->pitch);
|
||||
|
||||
errLabel:
|
||||
if( rc != kOkXsRC )
|
||||
@ -694,22 +890,25 @@ bool cmXScoreIsValid( cmXsH_t h )
|
||||
|
||||
void _cmXScoreReportNote( cmRpt_t* rpt, const cmXsNote_t* note )
|
||||
{
|
||||
const cmChar_t* B = cmIsFlag(note->flags,kBarXsFl) ? "|" : "-";
|
||||
const cmChar_t* R = cmIsFlag(note->flags,kRestXsFl) ? "R" : "-";
|
||||
const cmChar_t* G = cmIsFlag(note->flags,kGraceXsFl) ? "G" : "-";
|
||||
const cmChar_t* D = cmIsFlag(note->flags,kDotXsFl) ? "D" : "-";
|
||||
const cmChar_t* C = cmIsFlag(note->flags,kChordXsFl) ? "C" : "-";
|
||||
const cmChar_t* e = cmIsFlag(note->flags,kEvenXsFl) ? "e" : "-";
|
||||
const cmChar_t* d = cmIsFlag(note->flags,kDynXsFl) ? "d" : "-";
|
||||
const cmChar_t* t = cmIsFlag(note->flags,kTempoXsFl) ? "t" : "-";
|
||||
const cmChar_t* P = cmIsFlag(note->flags,kPedalDnXsFl) ? "V" : "-";
|
||||
const cmChar_t* B = cmIsFlag(note->flags,kBarXsFl) ? "|" : "-";
|
||||
const cmChar_t* R = cmIsFlag(note->flags,kRestXsFl) ? "R" : "-";
|
||||
const cmChar_t* G = cmIsFlag(note->flags,kGraceXsFl) ? "G" : "-";
|
||||
const cmChar_t* D = cmIsFlag(note->flags,kDotXsFl) ? "D" : "-";
|
||||
const cmChar_t* C = cmIsFlag(note->flags,kChordXsFl) ? "C" : "-";
|
||||
const cmChar_t* e = cmIsFlag(note->flags,kEvenXsFl) ? "e" : "-";
|
||||
const cmChar_t* d = cmIsFlag(note->flags,kDynXsFl) ? "d" : "-";
|
||||
const cmChar_t* t = cmIsFlag(note->flags,kTempoXsFl) ? "t" : "-";
|
||||
const cmChar_t* P = cmIsFlag(note->flags,kPedalDnXsFl) ? "V" : "-";
|
||||
const cmChar_t* H = cmIsFlag(note->flags,kHeelXsFl) ? "H" : "-";
|
||||
const cmChar_t* T0 = cmIsFlag(note->flags,kTieBegXsFl) ? "T" : "-";
|
||||
const cmChar_t* T1 = cmIsFlag(note->flags,kTieEndXsFl) ? "_" : "-";
|
||||
P = cmIsFlag(note->flags,kPedalUpXsFl) ? "^" : P;
|
||||
P = cmIsFlag(note->flags,kPedalUpDnXsFl) ? "X" : P;
|
||||
const cmChar_t* N = note->pitch==0 ? " " : cmMidiToSciPitch( note->pitch, NULL, 0 );
|
||||
cmRptPrintf(rpt," %5i %5i %4.1f %3s %s%s%s%s%s%s%s%s%s",note->tick,note->duration,note->rvalue,N,B,R,G,D,C,e,d,t,P);
|
||||
cmRptPrintf(rpt," %5i %5i %4.1f %3s %s%s%s%s%s%s%s%s%s%s%s%s",note->tick,note->duration,note->rvalue,N,B,R,G,D,C,e,d,t,P,H,T0,T1);
|
||||
|
||||
if( cmIsFlag(note->flags,kSectionXsFl) )
|
||||
cmRptPrintf(rpt," %i",cmStringNullGuard(note->tvalue));
|
||||
cmRptPrintf(rpt," %s",cmStringNullGuard(note->tvalue));
|
||||
|
||||
printf("\n");
|
||||
|
||||
|
@ -11,7 +11,9 @@ extern "C" {
|
||||
kXmlFailXsRC,
|
||||
kLHeapFailXsRC,
|
||||
kSyntaxErrorXsRC,
|
||||
kCsvFailXsRC
|
||||
kCsvFailXsRC,
|
||||
kUnterminatedTieXsRC,
|
||||
kUnterminatedSlurXsRC
|
||||
};
|
||||
|
||||
typedef cmRC_t cmXsRC_t;
|
||||
@ -24,6 +26,7 @@ extern "C" {
|
||||
// 1) Convert XML to UTF-8:
|
||||
// a. Change: encoding='UTF-16' to encoding='UTF-8'
|
||||
// b. Emacs C-x <RET> f utf-8 <RET>
|
||||
// c. Change: <?xml ... encoding='UTF-16' to encoding='UTF-8' ...?>
|
||||
//
|
||||
// 2) Replace "DoletSibelius Unknown Symbol Index" with "DoletSibelius unknownSymIdx"
|
||||
//
|
||||
@ -32,10 +35,12 @@ extern "C" {
|
||||
// 5) Heel is being parsed but not used.
|
||||
// 6) Sostenuto pedal events are not being parsed because they are not pedal events.
|
||||
// 7) What is a 'pedal-change' event vs. a 'pedal-stop' event.
|
||||
// 8) Verify the colors.
|
||||
// 9) Remove blank bars at end.
|
||||
// 8) Verify the colors. (done)
|
||||
// 9) Remove blank bars at end (done in xml - do in score)
|
||||
//10) Need to assign section targets (always default to next section)
|
||||
//11) Mark tied notes for skip.
|
||||
//11) Mark tied notes for skip. (done)
|
||||
//12) Determine note off locations based on ties and slurs - defer 'pedal' to player
|
||||
|
||||
|
||||
cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn );
|
||||
cmXsRC_t cmXScoreFinalize( cmXsH_t* hp );
|
||||
|
Loading…
Reference in New Issue
Block a user