From f9505d0f430c25d00d298ac45ce9b4a1270b8315 Mon Sep 17 00:00:00 2001 From: kevin Date: Thu, 31 Mar 2016 19:07:48 -0400 Subject: [PATCH] cmXScore.h/c : Added _cmXScoreAbsoluteTime(),_cmXScoreSpreadGraceNotes(),_cmXScoreSetMeasGroups() --- app/cmXScore.c | 509 ++++++++++++++++++++++++++----------------------- app/cmXScore.h | 4 +- 2 files changed, 277 insertions(+), 236 deletions(-) diff --git a/app/cmXScore.c b/app/cmXScore.c index a4d52a5..d485422 100644 --- a/app/cmXScore.c +++ b/app/cmXScore.c @@ -67,10 +67,16 @@ typedef struct cmXsNote_str unsigned staff; // 1=treble 2=bass unsigned tick; // unsigned duration; // duration in ticks - unsigned locIdx; // location index (chords share the same location index) + double secs; // absolute time in seconds + double dsecs; // delta time in seconds since previous event + 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, ...) const cmChar_t* tvalue; // text value + unsigned evenGroupId; // eveness group id + unsigned dynGroupId; // dynamics group id + unsigned tempoGroupId; // tempo group id + struct cmXsVoice_str* voice; // voice this note belongs to struct cmXsMeas_str* meas; // measure this note belongs to @@ -275,8 +281,8 @@ cmXsRC_t _cmXScoreParsePitch( cmXScore_t* p, const cmXmlNode_t* nnp, cmXsNote_t cmChar_t buf[3] = { *step, '0', '\0'}; unsigned midi = cmSciPitchToMidi(buf); - midi += (12 * octave); - midi += alter; + midi += (12 * octave); + midi += alter; np->pitch = midi; np->step = *step; @@ -522,15 +528,15 @@ cmXsRC_t _cmXScorePushOctaveShift(cmXScore_t* p, cmXsMeas_t* meas, unsigned staf } else { - s = cmLhAllocZ(p->lhH,cmXsSpan_t,1); - s->staff = staff; - s->meas = meas; - s->number = span_number; - s->tick0 = tick; - s->tick1 = -1; + s = cmLhAllocZ(p->lhH,cmXsSpan_t,1); + s->staff = staff; + s->meas = meas; + s->number = span_number; + s->tick0 = tick; + s->tick1 = -1; s->pitch_offset = cmTextCmp(type_str,"up")==0 ? -12 : 12; - s->link = p->spanL; - p->spanL = s; + s->link = p->spanL; + p->spanL = s; } return kOkXsRC; @@ -731,9 +737,16 @@ cmXsRC_t _cmXScoreParsePart( cmXScore_t* p, cmXsPart_t* pp ) // Return a pointer to the base of the list after the insertion. cmXsNote_t* _cmXScoreInsertSortedNote( cmXsNote_t* s0, cmXsNote_t* np ) { + assert( np != NULL ); + + // np->slink is not NULL if the list is being resorted + np->slink = NULL; + + // this list is empty so np is the first element on the list if( s0 == NULL ) return np; + // np is before the first element on the list if( np->tick < s0->tick ) { np->slink = s0; @@ -770,7 +783,10 @@ void _cmXScoreSort( cmXScore_t* p ) // for each measure in this part cmXsMeas_t* mp = pp->measL; for(; mp!=NULL; mp=mp->link) - { + { + // explicitely set noteL to NULL to in case we are re-sorting + mp->noteL = NULL; + // for each voice in this measure cmXsVoice_t* vp = mp->voiceL; for(; vp!=NULL; vp=vp->link) @@ -784,6 +800,157 @@ void _cmXScoreSort( cmXScore_t* p ) } } +void _cmXScoreSetAbsoluteTime( cmXScore_t* p ) +{ + double tpqn = 0; // ticks per quarter note + double tps = 0; // ticks per second + unsigned metro_tick = 0; + double metro_sec = 0; + double sec0 = 0; + + cmXsPart_t* pp = p->partL; + for(; pp!=NULL; pp=pp->link) + { + cmXsMeas_t* mp = pp->measL; + for(; mp!=NULL; mp=mp->link) + { + if( mp->divisions != 0 ) + tpqn = mp->divisions; + + cmXsNote_t* np = mp->noteL; + + for(; np!=NULL; np=np->slink) + { + + // Seconds are calculated as: + // dticks = np->tick - metro_tick; // where metro_tick is the absolute tick of the last metro event + // secs = (dticks/tps) + metro_secs; // where metro_secs is the absoute time of the last metro event + + unsigned dticks = np->tick - metro_tick; + double secs = tps==0 ? 0 : (dticks/tps) + metro_sec; + double dsecs = secs - sec0; + + // + if( cmIsFlag(np->flags,kMetronomeXsFl) ) + { + double bpm = np->duration; + double bps = bpm / 60.0; + tps = bps * tpqn; + metro_tick = np->tick; + metro_sec = secs; + } + + if( cmIsFlag(np->flags,kBarXsFl|kPedalDnXsFl|kPedalUpXsFl|kPedalUpDnXsFl|kOnsetXsFl|kSectionXsFl) ) + { + np->secs = secs; + np->dsecs = dsecs; + sec0 = secs; + } + } + } + } +} + +// All notes in a[aN] are on the same tick +unsigned _cmXsSpreadGraceNotes( cmXsNote_t** a, unsigned aN ) +{ + unsigned i; + bool barFl = false; + + // set barFl to true if a bar marker is included in the notes + for(i=0; iflags,kBarXsFl) ) + barFl = true; + + // spread any grace notes by one tick + unsigned nextGraceTick = UINT_MAX; + for(i=0; iflags,kGraceXsFl) ) + { + if( nextGraceTick == UINT_MAX ) + nextGraceTick = a[i]->tick + 1; + else + { + a[i]->tick = nextGraceTick; + nextGraceTick += 1; + } + } + + // if this tick group includes the bar ... + if( barFl && nextGraceTick != UINT_MAX ) + { + // ... then move all non-grace note events (except the bar marker) after + // the grace notes + for(i=0; iflags,kGraceXsFl) && cmIsNotFlag(a[i]->flags,kBarXsFl) ) + a[i]->tick = nextGraceTick; + } + + return nextGraceTick==UINT_MAX ? 0 : nextGraceTick; +} + +void _cmXScoreSpreadGraceNotes( cmXScore_t* p ) +{ + cmXsPart_t* pp = p->partL; + for(; pp!=NULL; pp=pp->link) + { + // tick1 is the location of the minimum current tick + // (or 0 if it should be ignored) + unsigned tick1 = 0; + + cmXsMeas_t* mp = pp->measL; + for(; mp!=NULL; mp=mp->link) + { + cmXsNote_t* np = mp->noteL; + unsigned aN = 128; + cmXsNote_t* a[ aN ]; + unsigned ai = 0; + + // The first event in a measure may have been forced ahead + // by spreading at the end of the previous measure + if( tick1 > np->tick ) + np->tick = tick1; + else + tick1 = 0; + + // tick0 is the tick of the current tick group we are examining + // A tick group is a group of events that share the same tick. + unsigned tick0 = np->tick; + + for(; np!=NULL; np=np->slink) + { + // if this event is the first of a new tick group + if( np->tick != tick0 ) + { + // if there is more than one event in the completed tick group ... + if( ai > 1 ) + tick1 = _cmXsSpreadGraceNotes(a,ai); // ... then process the group + + + ai = 0; // empty the tick group array + tick0 = np->tick; // update the current group's common tick + } + + // if the min. current tick is ahead of this event then move the event ahead + if( tick1 > np->tick ) + np->tick = tick1; + else + tick1 = 0; // otherwise disable tick1 + + // add this event to the tick group + assert(ai 1 ) + tick1 = _cmXsSpreadGraceNotes(a,ai); + } + } +} + + bool _cmXScoreFindTiedNote( cmXScore_t* p, cmXsMeas_t* mp, cmXsNote_t* n0p, bool rptFl ) { cmXsNote_t* nnp = n0p->slink; // begin w/ note following np @@ -827,8 +994,7 @@ bool _cmXScoreFindTiedNote( cmXScore_t* p, cmXsMeas_t* mp, cmXsNote_t* n0p, boo // record the measure number of the last note with a tie-start measNumb = mp->number; } - } - + } } cmErrWarnMsg(&p->err,kUnterminatedTieXsRC,"The tied %c%c%i in measure %i was not terminated.",n0p->step,acc,n0p->octave,measNumb); @@ -886,7 +1052,6 @@ void _cmXScoreResolveTiesAndLoc( cmXScore_t* p ) np->locIdx = locIdx; n0 = np; } - } } } @@ -917,8 +1082,6 @@ cmXsRC_t _cmXScoreResolveOctaveShift( cmXScore_t* p ) for(; note!=NULL; note=note->slink) if( note->staff==s->staff && s->tick0 <= note->tick && note->tick < s->tick1 ) note->pitch += s->pitch_offset; - - } } @@ -957,63 +1120,54 @@ void _cmXScoreRemoveDuplicateNotes( cmXScore_t* p ) } } - - -cmXsMeas_t* _cmXScoreNextNonEmptyMeas( cmXsPart_t* pp, cmXsMeas_t* meas ) +void _cmXScoreSetMeasGroups( cmXScore_t* p, unsigned flag ) { - if( meas == NULL ) - { - if( pp==NULL || pp->measL==NULL ) - return NULL; - - meas = pp->measL; - } - else - { - meas = meas->link; - } - - while( meas != NULL && meas->noteL == NULL ) - meas=meas->link; - - return meas; -} - -cmXsNote_t* _cmXScoreNextNote( cmXsPart_t* pp, cmXsNote_t* note ) -{ - // meas should always be valid (unless this is the first note in the score) - cmXsMeas_t* meas = note==NULL ? NULL : note->meas; + unsigned sectionId = 0; + cmXsNote_t* n0 = NULL; - do - { - if( note == NULL || note->slink==NULL ) + cmXsPart_t* pp = p->partL; + + // for each part + for(; pp!=NULL; pp=pp->link) + { + cmXsMeas_t* mp = pp->measL; + + // for each measure + for(; mp!=NULL; mp=mp->link) { - if((meas = _cmXScoreNextNonEmptyMeas(pp,meas)) == NULL) - return NULL; - - assert( meas->noteL != NULL ); - - note = meas->noteL; - } - else - { - note = note->slink; + cmXsNote_t* np = mp->noteL; + + // for each note in this measure + for(; np!=NULL; np=np->slink) + { + if( cmIsFlag(np->flags,flag) ) + n0 = np; + + + if( cmIsFlag(np->flags,kSectionXsFl) ) + { + if( n0 != NULL ) + { + switch( flag ) + { + case kEvenXsFl: n0->evenGroupId = sectionId; break; + case kDynXsFl: n0->dynGroupId = sectionId; break; + case kTempoXsFl: n0->tempoGroupId= sectionId; break; + } + } + + if( cmIsFlag(np->flags,kSectionXsFl) ) + sectionId = np->tvalue==NULL ? 0 : strtol(np->tvalue,NULL,10); + + n0 = NULL; + } + } } + } - assert( note != NULL ); - - meas = note->meas; - - // note is now set to a non-NULL candidate note - advance to a sounding note - while( note!=NULL && cmIsNotFlag(note->flags,kOnsetXsFl) ) - note = note->slink; - - // if no note was found in this measure - }while( note == NULL ); - - return note; } + cmXsRC_t _cmXScoreWriteScorePlotFile( cmXScore_t* p, const cmChar_t* fn ) { cmXsRC_t rc = kOkXsRC; @@ -1066,115 +1220,6 @@ cmXsRC_t _cmXScoreWriteScorePlotFile( cmXScore_t* p, const cmChar_t* fn ) return rc; } -cmXsRC_t _cmXScoreWriteMidiPlotFile( cmXScore_t* p, cmChar_t* fn, const cmMidiTrackMsg_t** m, unsigned mN ) -{ - cmXsRC_t rc = kOkXsRC; - cmFileH_t fH = cmFileNullHandle; - unsigned i = 0; - - if( cmFileOpen(&fH,fn,kWriteFileFl,p->err.rpt) != kOkFileRC ) - return cmErrMsg(&p->err,kFileFailXsRC,"Unable to create the file '%s'.",cmStringNullGuard(fn)); - - for(i=0; istatus) && cmMidiIsNoteOn(m[i]->status) && (m[i]->u.chMsgPtr->d1>0) ) - cmFilePrintf(fH,"n %f %f %i %s\n",m[i]->amicro/1000000.0,m[i]->u.chMsgPtr->durMicros/1000000.0,m[i]->uid,cmMidiToSciPitch(m[i]->u.chMsgPtr->d0,NULL,0)); - - - cmFileClose(&fH); - return rc; -} - - -cmXsRC_t _cmXScoreProcessMidi(cmXScore_t* p, cmCtx_t* ctx, const cmChar_t* midiFn) -{ - cmXsRC_t rc = kOkXsRC; - cmMidiFileH_t mfH = cmMidiFileNullHandle; - const cmMidiTrackMsg_t** m = NULL; - unsigned mN = 0; - unsigned i = 0; - unsigned j = 0; - cmXsNote_t* note = NULL; - - if( cmMidiFileOpen(ctx, &mfH, midiFn ) != kOkMfRC ) - return cmErrMsg(&p->err,kMidiFailXsRC,"The MIDI file object could not be opened from '%s'.",cmStringNullGuard(midiFn)); - - if( (m = cmMidiFileMsgArray(mfH)) == NULL || (mN = cmMidiFileMsgCount(mfH)) == 0 ) - { - rc = cmErrMsg(&p->err,kMidiFailXsRC,"The MIDI file object appears to be empty."); - goto errLabel; - } - - if((note = _cmXScoreNextNote(p->partL,NULL)) == NULL) - { - rc = cmErrWarnMsg(&p->err,kSyntaxErrorXsRC,"No MIDI processing to be done. The score appears to be empty."); - goto errLabel; - } - - cmCtx* c = cmCtxAlloc( NULL, p->err.rpt, cmLHeapNullHandle, cmSymTblNullHandle ); - cmSeqAlign_t* s = cmSeqAlignAlloc(c,NULL); - unsigned offs = 0; - - for(; note!=NULL; note=_cmXScoreNextNote(p->partL,note)) - { - if( cmIsFlag(note->flags,kGraceXsFl) ) - offs += 1; - - cmSeqAlignInsert(s,0,note->locIdx+offs,note->pitch); - } - - unsigned locIdx = 1; - for(i=0,j=0; istatus) && cmMidiIsNoteOn(m[i]->status) && (m[i]->u.chMsgPtr->d1>0) ) - { - if( m[j]->atick != m[i]->atick ) - locIdx += 1; - - cmSeqAlignInsert(s,1,locIdx,m[i]->u.chMsgPtr->d0); - - //printf("%i : %s\n",locIdx,cmMidiToSciPitch(m[i]->u.chMsgPtr->d0,NULL,0)); - - j = i; - } - - cmMidiFileCalcNoteDurations( mfH ); - - _cmXScoreWriteScorePlotFile(p, "/Users/kevin/temp/score.txt" ); - _cmXScoreWriteMidiPlotFile(p, "/Users/kevin/temp/midi.txt", m, mN ); - - - cmSeqAlignReport(s,p->err.rpt); - cmSeqAlignFree(&s); - cmCtxFree(&c); - goto errLabel; - - printf(" i j score midi\n"); - printf("---- ---- --- ---- --- ----\n"); - - for(j=0; note!=NULL; note=_cmXScoreNextNote(p->partL,note),++j) - { - unsigned midiPitch = 0; - for(; istatus) && cmMidiIsNoteOn(m[i]->status) && m[i]->u.chMsgPtr->d1>0 ) - { - midiPitch = m[i]->u.chMsgPtr->d0; - ++i; - break; - } - - char buf[6]; - printf("%4i %4i %3i %4s %3i %4s\n",j,i, - note->pitch, - cmMidiToSciPitch(note->pitch,NULL,0), - midiPitch, - cmMidiToSciPitch(midiPitch,buf,5)); - - } - - errLabel: - cmMidiFileClose(&mfH); - return rc; -} - cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn, const cmChar_t* midiFn ) { cmXsRC_t rc = kOkXsRC; @@ -1212,15 +1257,22 @@ cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn, c // fill in the note->slink chain to link the notes in each measure in time order _cmXScoreSort(p); + _cmXScoreSpreadGraceNotes(p); + + _cmXScoreSort(p); + + _cmXScoreSetAbsoluteTime(p); + _cmXScoreResolveTiesAndLoc(p); _cmXScoreRemoveDuplicateNotes(p); + + _cmXScoreSetMeasGroups(p,kEvenXsFl); + _cmXScoreSetMeasGroups(p,kDynXsFl); + _cmXScoreSetMeasGroups(p,kTempoXsFl); //_cmXScoreResolveOctaveShift(p); - //if( midiFn != NULL ) - // _cmXScoreProcessMidi(p,ctx,midiFn); - // CSV output initialize failed. if( cmCsvInitialize(&p->csvH,ctx) != kOkCsvRC ) rc = cmErrMsg(&p->err,kCsvFailXsRC,"CSV output object create failed."); @@ -1386,7 +1438,7 @@ cmXsRC_t cmXScoreInsertDynamics( cmXsH_t h, const cmChar_t* dynFn ) { if( ai >= aN || aV[ai].bar != mp->number || aV[ai].pitch != np->pitch || aV[ai].rval != np->rvalue ) { - rc = cmErrMsg(&p->err,kSyntaxErrorXsRC,"Dynamics file mismatch error on dynamics line:%i.\n",aV[ai].line); + rc = cmErrMsg(&p->err,kSyntaxErrorXsRC,"Dynamics file mismatch error on dynamics line:%i. expected:%s %f actual:%s %f\n",aV[ai].line,aV[ai].rval,cmMidiToSciPitch(aV[ai].pitch,NULL,0),cmMidiToSciPitch(np->pitch,NULL,0),np->rvalue); goto errLabel; } @@ -1676,12 +1728,7 @@ cmXsRC_t cmXScoreWriteCsv( cmXsH_t h, const cmChar_t* csvFn ) cmXsRC_t rc = kOkXsRC; cmXScore_t* p = _cmXScoreHandleToPtr(h); unsigned rowIdx = 1; - double tpqn = 0; // ticks per quarter note - double tps = 0; // ticks per second const cmChar_t* sectionIdStr = NULL; - unsigned metro_tick = 0; - double metro_sec = 0; - double sec0 = 0; if( !cmCsvIsValid(p->csvH) ) return cmErrMsg(&p->err,kCsvFailXsRC,"The CSV output object is not initialized."); @@ -1695,66 +1742,45 @@ cmXsRC_t cmXScoreWriteCsv( cmXsH_t h, const cmChar_t* csvFn ) cmXsMeas_t* mp = pp->measL; for(; mp!=NULL; mp=mp->link) { - if( mp->divisions != 0 ) - tpqn = mp->divisions; - - cmXsNote_t* np = mp->noteL; - + cmXsNote_t* np = mp->noteL; for(; np!=NULL; np=np->slink) { - // Seconds are calculated as: - // dticks = np->tick - metro_tick; // where metro_tick is the absolute tick of the last metro event - // secs = (dticks/tps) + metro_secs; // where metro_secs is the absoute time of the last metro event - - unsigned dticks = np->tick - metro_tick; - double secs = tps==0 ? 0 : (dticks/tps) + metro_sec; - double dsecs = secs - sec0; - - // - if( cmIsFlag(np->flags,kMetronomeXsFl) ) - { - double bpm = np->duration; - double bps = bpm / 60.0; - tps = bps * tpqn; - metro_tick = np->tick; - metro_sec = secs; - } - // if this is a section event if( cmIsFlag(np->flags,kSectionXsFl) ) sectionIdStr = np->tvalue; // if this is a bar event - if( cmIsFlag(np->flags,kBarXsFl) ) + if( cmIsFlag(np->flags,kBarXsFl) ) { - _cmXScoreWriteCsvRow(p,rowIdx,-1,mp->number,NULL,"bar",dsecs,secs,0,0,-1,0,"",np->flags); - sec0 = secs; + _cmXScoreWriteCsvRow(p,rowIdx,-1,mp->number,sectionIdStr,"bar",np->dsecs,np->secs,0,0,-1,0,"",np->flags); + sectionIdStr = NULL; } else - - // if this is a pedal event - if( cmIsFlag(np->flags,kPedalDnXsFl|kPedalUpXsFl|kPedalUpDnXsFl) ) { - unsigned d0 = 64; // pedal MIDI ctl id - unsigned d1 = cmIsFlag(np->flags,kPedalDnXsFl) ? 64 : 0; // pedal-dn: d1>=64 pedal-up:<64 - _cmXScoreWriteCsvRow(p,rowIdx,-1,mp->number,NULL,"ctl",dsecs,secs,d0,d1,-1,0,"",np->flags); - sec0 = secs; - } - else - - - // if this is a sounding note event - if( cmIsFlag(np->flags,kOnsetXsFl) ) + // if this is a pedal event + if( cmIsFlag(np->flags,kPedalDnXsFl|kPedalUpXsFl|kPedalUpDnXsFl) ) { - double frac = np->rvalue + (cmIsFlag(np->flags,kDotXsFl) ? (np->rvalue/2) : 0); - const cmChar_t* dyn = _cmXScoreTranslateDynamics( p, np ); - - // - _cmXScoreWriteCsvRow(p,rowIdx,np->uid,mp->number,sectionIdStr,"non",dsecs,secs,np->pitch,60,np->pitch,frac,dyn,np->flags); - sec0 = secs; + unsigned d0 = 64; // pedal MIDI ctl id + unsigned d1 = cmIsFlag(np->flags,kPedalDnXsFl) ? 64 : 0; // pedal-dn: d1>=64 pedal-up:<64 + _cmXScoreWriteCsvRow(p,rowIdx,-1,mp->number,sectionIdStr,"ctl",np->dsecs,np->secs,d0,d1,-1,0,"",np->flags); sectionIdStr = NULL; } + else + { + + // if this is a sounding note event + if( cmIsFlag(np->flags,kOnsetXsFl) ) + { + double frac = np->rvalue + (cmIsFlag(np->flags,kDotXsFl) ? (np->rvalue/2) : 0); + const cmChar_t* dyn = _cmXScoreTranslateDynamics( p, np ); + + // + _cmXScoreWriteCsvRow(p,rowIdx,np->uid,mp->number,sectionIdStr,"non",np->dsecs,np->secs,np->pitch,60,np->pitch,frac,dyn,np->flags); + sectionIdStr = NULL; + } + } + } rowIdx += 1; } @@ -1762,6 +1788,11 @@ cmXsRC_t cmXScoreWriteCsv( cmXsH_t h, const cmChar_t* csvFn ) } } + // Section labels are output on the next bar/pedal/note + // but what if there is no bar pedal note-on after the section label + if( sectionIdStr != NULL ) + cmErrMsg(&p->err,kSyntaxErrorXsRC,"The section label '%s' was ignored because it was not followed by a score event.",sectionIdStr); + if( cmCsvWrite( p->csvH, csvFn ) != kOkCsvRC ) rc = cmErrMsg(&p->err,kCsvFailXsRC,"The CSV output write failed on file '%s'.",csvFn); @@ -1781,7 +1812,7 @@ 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* D = cmIsFlag(note->flags,kDotXsFl) ? "." : "-"; 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" : "-"; @@ -1791,6 +1822,7 @@ void _cmXScoreReportNote( cmRpt_t* rpt, const cmXsNote_t* note ) 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) ? "_" : "-"; + const cmChar_t* O = cmIsFlag(note->flags,kOnsetXsFl) ? "*" : "-"; 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 ); @@ -1799,13 +1831,13 @@ void _cmXScoreReportNote( cmRpt_t* rpt, const cmXsNote_t* note ) cmChar_t acc = note->alter==-1?'b':(note->alter==1?'#':' '); snprintf(N,4,"%c%c%1i",note->step,acc,note->octave); - cmRptPrintf(rpt," %3i %5i %7i %5i %4.1f %3s %s%s%s%s%s%s%s%s%s%s%s%s%s", + cmRptPrintf(rpt," %3i %5i %7i %5i %4.1f %3s %s%s%s%s%s%s%s%s%s%s%s%s%s%s", note->voice->id, note->locIdx, note->tick, note->duration, note->rvalue, - N,B,R,G,D,C,e,d,t,P,S,H,T0,T1); + N,B,R,G,D,C,e,d,t,P,S,H,T0,T1,O); if( cmIsFlag(note->flags,kSectionXsFl) ) cmRptPrintf(rpt," %s",cmStringNullGuard(note->tvalue)); @@ -1813,6 +1845,15 @@ void _cmXScoreReportNote( cmRpt_t* rpt, const cmXsNote_t* note ) if( cmIsFlag(note->flags,kMetronomeXsFl) ) cmRptPrintf(rpt," %i bpm",note->duration); + if( note->evenGroupId != 0 ) + cmRptPrintf(rpt," e=%i",note->evenGroupId); + + if( note->dynGroupId != 0 ) + cmRptPrintf(rpt," d=%i",note->dynGroupId); + + if( note->tempoGroupId != 0 ) + cmRptPrintf(rpt," t=%i",note->tempoGroupId); + } @@ -1909,7 +1950,7 @@ cmXsRC_t cmXScoreTest( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* midi if( outFn != NULL ) cmXScoreWriteCsv(h,outFn); - //cmXScoreReport(h,&ctx->rpt,true); + cmXScoreReport(h,&ctx->rpt,true); return cmXScoreFinalize(&h); diff --git a/app/cmXScore.h b/app/cmXScore.h index a24571a..5a35441 100644 --- a/app/cmXScore.h +++ b/app/cmXScore.h @@ -54,13 +54,13 @@ extern "C" { cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn, const cmChar_t* midiFn ); cmXsRC_t cmXScoreFinalize( cmXsH_t* hp ); - bool cmXScoreIsValid( cmXsH_t h ); + bool cmXScoreIsValid( cmXsH_t h ); cmXsRC_t cmXScoreWriteCsv( cmXsH_t h, const cmChar_t* csvFn ); cmXsRC_t cmXScoreWriteMidi( cmXsH_t h, const cmChar_t* fn ); - void cmXScoreReport( cmXsH_t h, cmRpt_t* rpt, bool sortFl ); + void cmXScoreReport( cmXsH_t h, cmRpt_t* rpt, bool sortFl ); cmXsRC_t cmXScoreTest( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* midiFn, const cmChar_t* outFn, const cmChar_t* dynFn );