cmXScore.h/c : Added 'tied_dur' field to cmXsNote_t for use in determining the length of a MIDI note events.
This commit is contained in:
parent
3ef0c6fd3a
commit
84c5097a8d
@ -84,11 +84,13 @@ typedef struct cmXsNote_str
|
||||
unsigned staff; // 1=treble 2=bass
|
||||
unsigned tick; //
|
||||
unsigned duration; // duration in ticks
|
||||
unsigned tied_dur; // duration in ticks (including all tied notes)
|
||||
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 mf_uid; // MIDI file uid assigned to this event
|
||||
|
||||
unsigned evenGroupId; // eveness group id
|
||||
unsigned dynGroupId; // dynamics group id
|
||||
@ -241,6 +243,7 @@ cmXsRC_t _cmXScorePushNote( cmXScore_t* p, cmXsMeas_t* meas, unsigned voiceId, c
|
||||
|
||||
note->voice = v;
|
||||
note->uid = p->nextUid++;
|
||||
note->tied_dur = note->duration;
|
||||
|
||||
return kOkXsRC;
|
||||
}
|
||||
@ -605,6 +608,7 @@ cmXsRC_t _cmXScorePushNonNote( cmXScore_t* p, cmXsMeas_t* meas, const cmXmlNode_
|
||||
note->rvalue = rvalue;
|
||||
note->tvalue = tvalue;
|
||||
note->duration = duration;
|
||||
note->tied_dur = duration;
|
||||
note->meas = meas;
|
||||
note->xmlNode = noteXmlNode;
|
||||
|
||||
@ -1065,6 +1069,7 @@ void _cmXScoreSpreadGraceNotes( cmXScore_t* p )
|
||||
|
||||
bool _cmXScoreFindTiedNote( cmXScore_t* p, cmXsMeas_t* mp, cmXsNote_t* n0p, bool rptFl )
|
||||
{
|
||||
cmXsNote_t* nbp = n0p;
|
||||
cmXsNote_t* nnp = n0p->slink; // begin w/ note following np
|
||||
unsigned measNumb = mp->number;
|
||||
cmChar_t acc = n0p->alter==-1?'b' : (n0p->alter==1?'#':' ');
|
||||
@ -1096,6 +1101,8 @@ bool _cmXScoreFindTiedNote( cmXScore_t* p, cmXsMeas_t* mp, cmXsNote_t* n0p, boo
|
||||
nnp->flags |= kTieProcXsFl;
|
||||
nnp->flags = cmClrFlag(nnp->flags,kOnsetXsFl);
|
||||
n0p->tied = nnp;
|
||||
nbp->tied_dur += nnp->duration;
|
||||
nnp->tied_dur = 0;
|
||||
|
||||
if( rptFl )
|
||||
printf("---> %i %i %s ",nnp->meas->number,nnp->tick,cmMidiToSciPitch(nnp->pitch,NULL,0));
|
||||
@ -1118,8 +1125,8 @@ bool _cmXScoreFindTiedNote( cmXScore_t* p, cmXsMeas_t* mp, cmXsNote_t* n0p, boo
|
||||
|
||||
void _cmXScoreResolveTiesAndLoc( cmXScore_t* p )
|
||||
{
|
||||
unsigned n = 0;
|
||||
unsigned m = 0;
|
||||
unsigned n = 0; // count of notes which begin a tie
|
||||
unsigned m = 0; // count of tied notes that are correctly terminated.
|
||||
bool rptFl = false;
|
||||
cmXsPart_t* pp = p->partL;
|
||||
|
||||
@ -1227,7 +1234,7 @@ cmXsNote_t* _cmXScoreFindOverlappingNote( cmXScore_t* p, const cmXsNote_t* knp
|
||||
&& cmIsFlag(np->flags,kOnsetXsFl)
|
||||
&& knp->pitch == np->pitch
|
||||
&& knp->tick >= np->tick
|
||||
&& knp->tick < (np->tick + np->duration) )
|
||||
&& knp->tick < (np->tick + np->tied_dur) )
|
||||
{
|
||||
return np;
|
||||
}
|
||||
@ -1256,7 +1263,7 @@ void _cmXScoreProcessOverlappingNotes( cmXScore_t* p )
|
||||
if( cmIsFlag(np->flags,kOnsetXsFl) && (fnp = _cmXScoreFindOverlappingNote(p,np)) != NULL)
|
||||
{
|
||||
// is np entirely contained inside fnp
|
||||
bool embeddedFl = fnp->tick + fnp->duration > np->tick + np->duration;
|
||||
bool embeddedFl = fnp->tick + fnp->tied_dur > np->tick + np->tied_dur;
|
||||
|
||||
//printf("bar=%3i %4s voice:%2i %2i : %7i %7i : %7i %7i : %7i : %c \n",np->meas->number,cmMidiToSciPitch(np->pitch,NULL,0),np->voice->id,fnp->voice->id,fnp->tick,fnp->tick+fnp->duration,np->tick,np->tick+np->duration, (fnp->tick+fnp->duration) - np->tick, embeddedFl ? 'E' : 'O');
|
||||
|
||||
@ -1270,14 +1277,14 @@ void _cmXScoreProcessOverlappingNotes( cmXScore_t* p )
|
||||
}
|
||||
else
|
||||
{
|
||||
int d = (fnp->tick+fnp->duration) - np->tick;
|
||||
int d = (fnp->tick+fnp->tied_dur) - np->tick;
|
||||
|
||||
// shorten the first note
|
||||
if( d > 0 && d < fnp->duration )
|
||||
fnp->duration -= d;
|
||||
if( d > 0 && d < fnp->tied_dur )
|
||||
fnp->tied_dur -= d;
|
||||
|
||||
// move the second note just past it
|
||||
np->tick = fnp->tick + fnp->duration + 1;
|
||||
np->tick = fnp->tick + fnp->tied_dur + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1404,7 +1411,7 @@ cmXsRC_t _cmXScoreWriteScorePlotFile( cmXScore_t* p, const cmChar_t* fn )
|
||||
{
|
||||
if( cmIsFlag(np->flags,kMetronomeXsFl) )
|
||||
{
|
||||
double bps = np->duration / 60.0;
|
||||
double bps = np->tied_dur / 60.0;
|
||||
|
||||
// t b t
|
||||
// - = - -
|
||||
@ -1418,7 +1425,7 @@ cmXsRC_t _cmXScoreWriteScorePlotFile( cmXScore_t* p, const cmChar_t* fn )
|
||||
{
|
||||
onset_secs += (np->tick - tick0) / ticks_per_sec;
|
||||
tick0 = np->tick;
|
||||
cmFilePrintf(fH,"n %f %f %i %s %s\n",onset_secs,np->duration/ticks_per_sec,np->uid,cmMidiToSciPitch(np->pitch,NULL,0),cmIsFlag(np->flags,kGraceXsFl)?"G":"N");
|
||||
cmFilePrintf(fH,"n %f %f %i %s %s\n",onset_secs,np->tied_dur/ticks_per_sec,np->uid,cmMidiToSciPitch(np->pitch,NULL,0),cmIsFlag(np->flags,kGraceXsFl)?"G":"N");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1700,7 +1707,7 @@ cmXsRC_t _cmXScoreProcessGraceNotes( cmXScore_t* p )
|
||||
|
||||
// set each grace note to have 1/20 of a second duration
|
||||
if( cmIsFlag(np->flags,kGraceXsFl) )
|
||||
np->duration = floor(ticksPerSec * graceDurSec);
|
||||
np->duration = np->tied_dur = floor(ticksPerSec * graceDurSec);
|
||||
|
||||
gN += 1;
|
||||
}
|
||||
@ -2938,7 +2945,7 @@ void _cmXScoreReportNote( cmRpt_t* rpt, const cmXsNote_t* note,unsigned index )
|
||||
note->voice->id,
|
||||
note->locIdx,
|
||||
note->tick,
|
||||
note->duration,
|
||||
note->tied_dur,
|
||||
note->rvalue,
|
||||
N,B,R,G,D,C,e,d,t,P,s,S,H,T0,T1,O);
|
||||
|
||||
@ -3072,8 +3079,11 @@ cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
|
||||
{
|
||||
case kOnsetXsFl:
|
||||
{
|
||||
if( cmMidiFileInsertTrackChMsg(mfH, 1, np->tick, kNoteOnMdId, np->pitch, np->vel ) != kOkMfRC
|
||||
||cmMidiFileInsertTrackChMsg(mfH, 1, np->tick + np->duration, kNoteOffMdId, np->pitch, 0 ) != kOkMfRC )
|
||||
if( np->tied_dur <= 0 )
|
||||
cmErrWarnMsg(&p->err,kOkXsRC,"A zero length note was encountered bar:%i tick:%i %s",np->meas->number,np->tick,cmMidiToSciPitch(np->pitch,NULL,0));
|
||||
|
||||
if( cmMidiFileInsertTrackChMsg(mfH, 1, np->tick, kNoteOnMdId, np->pitch, np->vel, &np->mf_uid ) != kOkMfRC
|
||||
||cmMidiFileInsertTrackChMsg(mfH, 1, np->tick + np->tied_dur, kNoteOffMdId, np->pitch, 0, &np->mf_uid ) != kOkMfRC )
|
||||
{
|
||||
rc = kMidiFailXsRC;
|
||||
}
|
||||
@ -3084,9 +3094,12 @@ cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
|
||||
case kDampUpDnXsFl:
|
||||
case kSostDnXsFl:
|
||||
{
|
||||
if( np->duration <= 0 )
|
||||
cmErrWarnMsg(&p->err,kOkXsRC,"A zero length pedal event was encountered bar:%i tick:%i",np->meas->number,np->tick);
|
||||
|
||||
cmMidiByte_t d0 = cmIsFlag(np->flags,kSostDnXsFl) ? kSostenutoCtlMdId : kSustainCtlMdId;
|
||||
if( (cmMidiFileInsertTrackChMsg(mfH, 1, np->tick, kCtlMdId, d0, 127 ) != kOkMfRC )
|
||||
||(cmMidiFileInsertTrackChMsg(mfH, 1, np->tick + np->duration, kCtlMdId, d0, 0 ) != kOkMfRC ) )
|
||||
if( (cmMidiFileInsertTrackChMsg(mfH, 1, np->tick, kCtlMdId, d0, 127, &np->mf_uid ) != kOkMfRC )
|
||||
||(cmMidiFileInsertTrackChMsg(mfH, 1, np->tick + np->duration, kCtlMdId, d0, 0, &np->mf_uid ) != kOkMfRC ) )
|
||||
{
|
||||
rc = kMidiFailXsRC;
|
||||
}
|
||||
@ -3094,7 +3107,7 @@ cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
|
||||
break;
|
||||
|
||||
case kMetronomeXsFl:
|
||||
if( cmMidFileInsertTrackTempoMsg(mfH, 0, np->tick, np->duration ) != kOkMfRC )
|
||||
if( cmMidFileInsertTrackTempoMsg(mfH, 0, np->tick, np->duration, &np->mf_uid ) != kOkMfRC )
|
||||
rc = kMidiFailXsRC;
|
||||
break;
|
||||
|
||||
@ -3141,6 +3154,7 @@ typedef struct cmXsSvgEvt_str
|
||||
unsigned voice; // score voice number
|
||||
unsigned d0; // MIDI d0 (barNumb)
|
||||
unsigned d1; // MIDI d1
|
||||
unsigned mf_uid;
|
||||
struct cmXsSvgEvt_str* link;
|
||||
} cmXsSvgEvt_t;
|
||||
|
||||
@ -3162,7 +3176,7 @@ cmXsRC_t _cmXsWriteMidiSvg( cmCtx_t* ctx, cmXScore_t* p, cmXsMidiFile_t* mf, con
|
||||
unsigned noteHeight = 10;
|
||||
cmChar_t* fn0 = cmMemAllocStr( fn );
|
||||
const cmChar_t* svgFn = cmFsMakeFn(dir,fn0 = cmTextAppendSS(fn0,"_midi_svg"),"html",NULL);
|
||||
const cmChar_t* cssFn = cmFsMakeFn(NULL,fn,"css",NULL);
|
||||
const cmChar_t* cssFn = cmFsMakeFn(NULL,"score_midi_svg","css",NULL);
|
||||
cmChar_t* t0 = NULL; // temporary dynamic string
|
||||
|
||||
cmMemFree(fn0);
|
||||
@ -3193,9 +3207,13 @@ cmXsRC_t _cmXsWriteMidiSvg( cmCtx_t* ctx, cmXScore_t* p, cmXsMidiFile_t* mf, con
|
||||
if( cmSvgWriterRect(svgH, e->tick, e->d0 * noteHeight, e->durTicks, noteHeight-1, t0 ) != kOkSvgRC )
|
||||
rc = kSvgFailXsRC;
|
||||
else
|
||||
if( cmSvgWriterText(svgH, e->tick + e->durTicks/2, e->d0 * noteHeight + noteHeight/2, cmMidiToSciPitch( e->d0, NULL, 0), "pitch") != kOkSvgRC )
|
||||
{
|
||||
t0 = cmTsPrintfP(t0,"%s %i",cmMidiToSciPitch( e->d0, NULL, 0),e->mf_uid);
|
||||
|
||||
if( cmSvgWriterText(svgH, e->tick + e->durTicks/2, e->d0 * noteHeight + noteHeight/2, t0, "pitch") != kOkSvgRC )
|
||||
rc = kSvgFailXsRC;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// if this is a bar
|
||||
@ -3241,7 +3259,7 @@ cmXsRC_t _cmXsWriteMidiSvg( cmCtx_t* ctx, cmXScore_t* p, cmXsMidiFile_t* mf, con
|
||||
}
|
||||
|
||||
|
||||
void _cmXsPushSvgEvent( cmXScore_t* p, cmXsMidiFile_t* mf, unsigned flags, unsigned tick, unsigned durTick, unsigned voice, unsigned d0, unsigned d1 )
|
||||
void _cmXsPushSvgEvent( cmXScore_t* p, cmXsMidiFile_t* mf, unsigned flags, unsigned tick, unsigned durTick, unsigned voice, unsigned d0, unsigned d1, unsigned mf_uid )
|
||||
{
|
||||
cmXsSvgEvt_t* e = cmLhAllocZ(p->lhH,cmXsSvgEvt_t,1);
|
||||
e->flags = flags;
|
||||
@ -3250,6 +3268,8 @@ void _cmXsPushSvgEvent( cmXScore_t* p, cmXsMidiFile_t* mf, unsigned flags, unsig
|
||||
e->voice = voice;
|
||||
e->d0 = d0; // note=pitch bar=number pedal=ctl# metronome=BPM
|
||||
e->d1 = d1;
|
||||
e->mf_uid = mf_uid;
|
||||
|
||||
if( mf->eol != NULL )
|
||||
mf->eol->link = e;
|
||||
else
|
||||
@ -3286,7 +3306,7 @@ cmXsRC_t _cmXScoreGenSvg( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const cm
|
||||
if( cmIsFlag(note->flags,kMetronomeXsFl) )
|
||||
{
|
||||
// set BPM as d0
|
||||
_cmXsPushSvgEvent(p,&mf,note->flags,note->tick,0,0,note->duration,0);
|
||||
_cmXsPushSvgEvent(p,&mf,note->flags,note->tick,0,0,note->duration,0,note->mf_uid);
|
||||
continue;
|
||||
|
||||
}
|
||||
@ -3295,21 +3315,21 @@ cmXsRC_t _cmXScoreGenSvg( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const cm
|
||||
if( cmIsFlag(note->flags,kOnsetXsFl) )
|
||||
{
|
||||
unsigned d0 = cmSciPitchToMidiPitch( note->step, note->alter, note->octave );
|
||||
unsigned durTick = note->duration;
|
||||
unsigned durTick = note->tied_dur;
|
||||
if( note->tied != NULL )
|
||||
{
|
||||
cmXsNote_t* tn = note->tied;
|
||||
for(; tn!=NULL; tn=tn->tied)
|
||||
durTick += tn->duration;
|
||||
durTick += tn->tied_dur;
|
||||
}
|
||||
_cmXsPushSvgEvent(p,&mf,note->flags,note->tick,durTick,note->voice->id,d0,note->vel);
|
||||
_cmXsPushSvgEvent(p,&mf,note->flags,note->tick,durTick,note->voice->id,d0,note->vel,note->mf_uid);
|
||||
continue;
|
||||
}
|
||||
|
||||
// if this is a bar event
|
||||
if( cmIsFlag(note->flags,kBarXsFl) )
|
||||
{
|
||||
_cmXsPushSvgEvent(p,&mf,note->flags,note->tick,0,0,note->meas->number,0);
|
||||
_cmXsPushSvgEvent(p,&mf,note->flags,note->tick,0,0,note->meas->number,0, note->mf_uid);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -3317,7 +3337,7 @@ cmXsRC_t _cmXScoreGenSvg( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const cm
|
||||
if( cmIsFlag(note->flags,kDampDnXsFl|kDampUpDnXsFl|kSostDnXsFl) )
|
||||
{
|
||||
unsigned d0 = cmIsFlag(note->flags,kSostDnXsFl) ? kSostenutoCtlMdId : kSustainCtlMdId;
|
||||
_cmXsPushSvgEvent(p,&mf,note->flags,note->tick,note->duration,0,d0,127);
|
||||
_cmXsPushSvgEvent(p,&mf,note->flags,note->tick,note->duration,0,d0,127,note->mf_uid);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -3353,7 +3373,7 @@ cmXsRC_t cmXScoreTest(
|
||||
// assign durations to pedal down events
|
||||
_cmXScoreProcessPedals(_cmXScoreHandleToPtr(h));
|
||||
|
||||
// remove some notes which share a pitch which are overlapped or embedded
|
||||
// remove some notes which share a pitch and are overlapped or embedded within another note.
|
||||
_cmXScoreProcessOverlappingNotes(_cmXScoreHandleToPtr(h));
|
||||
|
||||
if( csvOutFn != NULL )
|
||||
@ -3382,15 +3402,15 @@ cmXsRC_t cmXScoreTest(
|
||||
{
|
||||
cmFileSysPathPart_t* pp = cmFsPathParts(midiOutFn);
|
||||
|
||||
_cmXScoreGenSvg( ctx, h, pp->dirStr, pp->fnStr );
|
||||
|
||||
_cmXsWriteMidiFile(ctx, h, pp->dirStr, pp->fnStr );
|
||||
|
||||
_cmXScoreGenSvg( ctx, h, pp->dirStr, pp->fnStr );
|
||||
|
||||
cmFsFreePathParts(pp);
|
||||
|
||||
}
|
||||
|
||||
//cmXScoreReport(h,&ctx->rpt,true);
|
||||
cmXScoreReport(h,&ctx->rpt,true);
|
||||
|
||||
errLabel:
|
||||
return cmXScoreFinalize(&h);
|
||||
|
@ -19,7 +19,8 @@ extern "C" {
|
||||
kMidiFailXsRC,
|
||||
kFileFailXsRC,
|
||||
kSvgFailXsRC,
|
||||
kOverlapWarnXsRC
|
||||
kOverlapWarnXsRC,
|
||||
kZeroLengthEventXsRC
|
||||
};
|
||||
|
||||
typedef cmRC_t cmXsRC_t;
|
||||
|
Loading…
Reference in New Issue
Block a user