cmXScore.h/c : Added cmXScoreProcessPedals() and _cmXsWriteMidiFile().
This commit is contained in:
parent
38cdd3012b
commit
9036de70ba
294
app/cmXScore.c
294
app/cmXScore.c
@ -50,9 +50,9 @@ enum
|
|||||||
kTieBegXsFl = 0x000400,
|
kTieBegXsFl = 0x000400,
|
||||||
kTieEndXsFl = 0x000800,
|
kTieEndXsFl = 0x000800,
|
||||||
kTieProcXsFl = 0x001000,
|
kTieProcXsFl = 0x001000,
|
||||||
kPedalDnXsFl = 0x002000,
|
kDampDnXsFl = 0x002000,
|
||||||
kPedalUpXsFl = 0x004000,
|
kDampUpXsFl = 0x004000,
|
||||||
kPedalUpDnXsFl = 0x008000,
|
kDampUpDnXsFl = 0x008000,
|
||||||
kSostDnXsFl = 0x010000,
|
kSostDnXsFl = 0x010000,
|
||||||
kSostUpXsFl = 0x020000,
|
kSostUpXsFl = 0x020000,
|
||||||
kMetronomeXsFl = 0x040000, // duration holds BPM
|
kMetronomeXsFl = 0x040000, // duration holds BPM
|
||||||
@ -680,13 +680,13 @@ cmXsRC_t _cmXScoreParseDirection(cmXScore_t* p, cmXsMeas_t* meas, const cmXmlNo
|
|||||||
return _cmXScoreMissingAttribute(p, np, "type" );
|
return _cmXScoreMissingAttribute(p, np, "type" );
|
||||||
|
|
||||||
if( cmTextCmp(a->value,"start") == 0 )
|
if( cmTextCmp(a->value,"start") == 0 )
|
||||||
flags = kPedalDnXsFl;
|
flags = kDampDnXsFl;
|
||||||
else
|
else
|
||||||
if( cmTextCmp(a->value,"change") == 0 )
|
if( cmTextCmp(a->value,"change") == 0 )
|
||||||
flags = kPedalUpDnXsFl;
|
flags = kDampUpDnXsFl;
|
||||||
else
|
else
|
||||||
if( cmTextCmp(a->value,"stop") == 0 )
|
if( cmTextCmp(a->value,"stop") == 0 )
|
||||||
flags = kPedalUpXsFl;
|
flags = kDampUpXsFl;
|
||||||
else
|
else
|
||||||
return cmErrMsg(&p->err,kSyntaxErrorXsRC,"Unrecognized pedal type:'%s'.",cmStringNullGuard(a->value));
|
return cmErrMsg(&p->err,kSyntaxErrorXsRC,"Unrecognized pedal type:'%s'.",cmStringNullGuard(a->value));
|
||||||
}
|
}
|
||||||
@ -899,6 +899,7 @@ void _cmXScoreSort( cmXScore_t* p )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the cmXsNode_t.secs and dsecs.
|
||||||
void _cmXScoreSetAbsoluteTime( cmXScore_t* p )
|
void _cmXScoreSetAbsoluteTime( cmXScore_t* p )
|
||||||
{
|
{
|
||||||
double tpqn = 0; // ticks per quarter note
|
double tpqn = 0; // ticks per quarter note
|
||||||
@ -932,14 +933,14 @@ void _cmXScoreSetAbsoluteTime( cmXScore_t* p )
|
|||||||
//
|
//
|
||||||
if( cmIsFlag(np->flags,kMetronomeXsFl) )
|
if( cmIsFlag(np->flags,kMetronomeXsFl) )
|
||||||
{
|
{
|
||||||
double bpm = np->duration;
|
double bpm = np->duration; // beats per minute
|
||||||
double bps = bpm / 60.0;
|
double bps = bpm / 60.0; // beats per second
|
||||||
tps = bps * tpqn;
|
tps = bps * tpqn; // ticks per second
|
||||||
metro_tick = np->tick;
|
metro_tick = np->tick; // store tick of the last metronome marker
|
||||||
metro_sec = secs;
|
metro_sec = secs; // store time of the last metronome marker
|
||||||
}
|
}
|
||||||
|
|
||||||
if( cmIsFlag(np->flags,kBarXsFl|kPedalDnXsFl|kPedalUpXsFl|kPedalUpDnXsFl|kSostDnXsFl|kSostUpXsFl|kOnsetXsFl|kSectionXsFl) )
|
if( cmIsFlag(np->flags,kBarXsFl|kDampDnXsFl|kDampUpXsFl|kDampUpDnXsFl|kSostDnXsFl|kSostUpXsFl|kOnsetXsFl|kSectionXsFl) )
|
||||||
{
|
{
|
||||||
np->secs = secs;
|
np->secs = secs;
|
||||||
np->dsecs = dsecs;
|
np->dsecs = dsecs;
|
||||||
@ -1016,9 +1017,10 @@ void _cmXScoreSpreadGraceNotes( cmXScore_t* p )
|
|||||||
// A tick group is a group of events that share the same tick.
|
// A tick group is a group of events that share the same tick.
|
||||||
unsigned tick0 = np->tick;
|
unsigned tick0 = np->tick;
|
||||||
|
|
||||||
|
// for each note
|
||||||
for(; np!=NULL; np=np->slink)
|
for(; np!=NULL; np=np->slink)
|
||||||
{
|
{
|
||||||
// if this event is the first of a new tick group
|
// if this event is the first of a new tick group (then a[] holds a group completed on the previous note)
|
||||||
if( np->tick != tick0 )
|
if( np->tick != tick0 )
|
||||||
{
|
{
|
||||||
// if there is more than one event in the completed tick group ...
|
// if there is more than one event in the completed tick group ...
|
||||||
@ -1370,6 +1372,93 @@ void _cmXScoreFixBarLines( cmXScore_t* p )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Assign pedal down durations to pedal down events.
|
||||||
|
cmXsRC_t _cmXScoreProcessPedals( cmXScore_t* p )
|
||||||
|
{
|
||||||
|
cmXsRC_t rc = kOkXsRC;
|
||||||
|
cmXsPart_t* pp = p->partL;
|
||||||
|
|
||||||
|
for(; pp!=NULL; pp=pp->link)
|
||||||
|
{
|
||||||
|
cmXsNote_t* dnp = NULL; // pointer to last damper down event
|
||||||
|
cmXsNote_t* snp = NULL; // pointer to last sostenuto down event
|
||||||
|
|
||||||
|
cmXsMeas_t* mp = pp->measL;
|
||||||
|
for(; mp!=NULL; mp=mp->link)
|
||||||
|
{
|
||||||
|
cmXsNote_t* np = mp->noteL;
|
||||||
|
for(; np!=NULL; np=np->slink )
|
||||||
|
{
|
||||||
|
unsigned x = np->flags & (kDampDnXsFl|kDampUpXsFl|kDampUpDnXsFl|kSostUpXsFl|kSostDnXsFl);
|
||||||
|
switch( x )
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kDampDnXsFl:
|
||||||
|
if( dnp != NULL )
|
||||||
|
cmErrWarnMsg(&p->err,kPedalStateErrorXsRc,"Damper down not preceded by damper up in measure:%i.",mp->number);
|
||||||
|
else
|
||||||
|
dnp = np;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kDampUpXsFl:
|
||||||
|
if( dnp == NULL )
|
||||||
|
cmErrWarnMsg(&p->err,kPedalStateErrorXsRc,"Damper up not preceded by damper down in measure:%i.",mp->number);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dnp->duration = np->tick - dnp->tick;
|
||||||
|
dnp = NULL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kDampUpDnXsFl:
|
||||||
|
if( dnp == NULL )
|
||||||
|
cmErrWarnMsg(&p->err,kPedalStateErrorXsRc,"Damper up/down not preceded by damper down in measure:%i.",mp->number);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dnp->duration = np->tick - dnp->tick;
|
||||||
|
dnp = np;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kSostDnXsFl:
|
||||||
|
if( snp != NULL )
|
||||||
|
cmErrWarnMsg(&p->err,kPedalStateErrorXsRc,"Sostenuto down not preceded by sostenuto up in measure:%i.",mp->number);
|
||||||
|
else
|
||||||
|
snp = np;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kSostUpXsFl:
|
||||||
|
if( snp == NULL )
|
||||||
|
cmErrWarnMsg(&p->err,kPedalStateErrorXsRc,"Sostenuto up not preceded by sostenuto down in measure:%i.",mp->number);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
snp->duration = np->tick - snp->tick;
|
||||||
|
snp = NULL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
} // switch
|
||||||
|
|
||||||
|
} // for notes
|
||||||
|
|
||||||
|
} // for measures
|
||||||
|
|
||||||
|
if( dnp != NULL )
|
||||||
|
cmErrWarnMsg(&p->err,kPedalStateErrorXsRc,"Damper left down at the end of a part.");
|
||||||
|
|
||||||
|
if( snp != NULL )
|
||||||
|
cmErrWarnMsg(&p->err,kPedalStateErrorXsRc,"Sostenuto left down at the end of a part.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn )
|
cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn )
|
||||||
{
|
{
|
||||||
cmXsRC_t rc = kOkXsRC;
|
cmXsRC_t rc = kOkXsRC;
|
||||||
@ -1472,7 +1561,7 @@ typedef struct
|
|||||||
cmXsNote_t* note; // The cmXsNode_t* associated with this cmXsReorder_t record
|
cmXsNote_t* note; // The cmXsNode_t* associated with this cmXsReorder_t record
|
||||||
|
|
||||||
unsigned dynIdx; // cmInvalidIdx=ignore otherwise index into _cmXScoreDynMarkArray[]
|
unsigned dynIdx; // cmInvalidIdx=ignore otherwise index into _cmXScoreDynMarkArray[]
|
||||||
unsigned newFlags; // 0=ignore | kSostUp/DnXsFl | kPedalUp/DnXsFl | kTieEndXsFl
|
unsigned newFlags; // 0=ignore | kSostUp/DnXsFl | kDampUp/DnXsFl | kTieEndXsFl
|
||||||
unsigned newTick; // 0=ignore >0 new tick value
|
unsigned newTick; // 0=ignore >0 new tick value
|
||||||
unsigned pitch; // 0=ignore >0 new pitch
|
unsigned pitch; // 0=ignore >0 new pitch
|
||||||
} cmXsReorder_t;
|
} cmXsReorder_t;
|
||||||
@ -1560,7 +1649,7 @@ void _cmXScoreInsertPedalEvent( cmXScore_t* p, const cmXsReorder_t* r, unsigned
|
|||||||
nn->flags = flags;
|
nn->flags = flags;
|
||||||
|
|
||||||
// Pedal down events occur after the event they are attached to
|
// Pedal down events occur after the event they are attached to
|
||||||
if( cmIsFlag(flags,kSostDnXsFl | kPedalDnXsFl ) )
|
if( cmIsFlag(flags,kSostDnXsFl | kDampDnXsFl ) )
|
||||||
{
|
{
|
||||||
nn->tick = r->note->tick + 1;
|
nn->tick = r->note->tick + 1;
|
||||||
_cmXScoreInsertNoteAfter(r->note,nn);
|
_cmXScoreInsertNoteAfter(r->note,nn);
|
||||||
@ -1568,7 +1657,7 @@ void _cmXScoreInsertPedalEvent( cmXScore_t* p, const cmXsReorder_t* r, unsigned
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Pedal up events occur before the event they are attached to
|
// Pedal up events occur before the event they are attached to
|
||||||
if( cmIsFlag(flags,kSostUpXsFl | kPedalUpXsFl ) )
|
if( cmIsFlag(flags,kSostUpXsFl | kDampUpXsFl ) )
|
||||||
{
|
{
|
||||||
nn->tick = r->note->tick==0 ? 0 : r->note->tick - 1;
|
nn->tick = r->note->tick==0 ? 0 : r->note->tick - 1;
|
||||||
_cmXScoreInsertNoteBefore(r->note,nn);
|
_cmXScoreInsertNoteBefore(r->note,nn);
|
||||||
@ -1642,14 +1731,14 @@ cmXsRC_t _cmXScoreReorderMeas( cmXScore_t* p, unsigned measNumb, cmXsReorder_t*
|
|||||||
if( rV[i].newFlags != 0 )
|
if( rV[i].newFlags != 0 )
|
||||||
{
|
{
|
||||||
|
|
||||||
if( cmIsFlag(rV[i].newFlags,kPedalDnXsFl ) )
|
if( cmIsFlag(rV[i].newFlags,kDampDnXsFl ) )
|
||||||
_cmXScoreInsertPedalEvent(p,rV + i,kPedalDnXsFl);
|
_cmXScoreInsertPedalEvent(p,rV + i,kDampDnXsFl);
|
||||||
|
|
||||||
if( cmIsFlag(rV[i].newFlags,kSostDnXsFl ) )
|
if( cmIsFlag(rV[i].newFlags,kSostDnXsFl ) )
|
||||||
_cmXScoreInsertPedalEvent(p,rV + i,kSostDnXsFl);
|
_cmXScoreInsertPedalEvent(p,rV + i,kSostDnXsFl);
|
||||||
|
|
||||||
if( cmIsFlag(rV[i].newFlags,kPedalUpXsFl ) )
|
if( cmIsFlag(rV[i].newFlags,kDampUpXsFl ) )
|
||||||
_cmXScoreInsertPedalEvent(p,rV + i,kPedalUpXsFl);
|
_cmXScoreInsertPedalEvent(p,rV + i,kDampUpXsFl);
|
||||||
|
|
||||||
if( cmIsFlag(rV[i].newFlags,kSostUpXsFl ) )
|
if( cmIsFlag(rV[i].newFlags,kSostUpXsFl ) )
|
||||||
_cmXScoreInsertPedalEvent(p,rV + i,kSostUpXsFl);
|
_cmXScoreInsertPedalEvent(p,rV + i,kSostUpXsFl);
|
||||||
@ -1764,11 +1853,11 @@ cmXsRC_t _cmXScoreReorderParseFlags(cmXScore_t* p, const cmChar_t* b, unsigned
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'D':
|
case 'D':
|
||||||
*newFlagsRef |= kPedalDnXsFl; // damper pedal down
|
*newFlagsRef |= kDampDnXsFl; // damper pedal down
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'U':
|
case 'U':
|
||||||
*newFlagsRef |= kPedalUpXsFl; // damper pedal up
|
*newFlagsRef |= kDampUpXsFl; // damper pedal up
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '_':
|
case '_':
|
||||||
@ -2329,14 +2418,14 @@ cmXsRC_t cmXScoreWriteCsv( cmXsH_t h, const cmChar_t* csvFn )
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// if this is a pedal event
|
// if this is a pedal event
|
||||||
if( cmIsFlag(np->flags,kPedalDnXsFl|kPedalUpXsFl|kPedalUpDnXsFl|kSostDnXsFl|kSostUpXsFl) )
|
if( cmIsFlag(np->flags,kDampDnXsFl|kDampUpXsFl|kDampUpDnXsFl|kSostDnXsFl|kSostUpXsFl) )
|
||||||
{
|
{
|
||||||
unsigned d0 = cmIsFlag(np->flags,kSostDnXsFl |kSostUpXsFl) ? 66 : 64; // pedal MIDI ctl id
|
unsigned d0 = cmIsFlag(np->flags,kSostDnXsFl |kSostUpXsFl) ? 66 : 64; // pedal MIDI ctl id
|
||||||
unsigned d1 = cmIsFlag(np->flags,kPedalDnXsFl|kSostDnXsFl) ? 64 : 0; // pedal-dn: d1>=64 pedal-up:<64
|
unsigned d1 = cmIsFlag(np->flags,kDampDnXsFl|kSostDnXsFl) ? 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,"","");
|
_cmXScoreWriteCsvRow(p,rowIdx,-1,mp->number,sectionIdStr,"ctl",np->dsecs,np->secs,d0,d1,-1,0,"",np->flags,"","");
|
||||||
sectionIdStr = NULL;
|
sectionIdStr = NULL;
|
||||||
|
|
||||||
if( cmIsFlag(np->flags,kPedalUpDnXsFl) )
|
if( cmIsFlag(np->flags,kDampUpDnXsFl) )
|
||||||
{
|
{
|
||||||
rowIdx += 1;
|
rowIdx += 1;
|
||||||
double millisecond = 0.0;
|
double millisecond = 0.0;
|
||||||
@ -2405,15 +2494,15 @@ void _cmXScoreReportNote( cmRpt_t* rpt, const cmXsNote_t* note,unsigned index )
|
|||||||
const cmChar_t* e = cmIsFlag(note->flags,kEvenXsFl) ? "e" : "-";
|
const cmChar_t* e = cmIsFlag(note->flags,kEvenXsFl) ? "e" : "-";
|
||||||
const cmChar_t* d = cmIsFlag(note->flags,kDynXsFl) ? "d" : "-";
|
const cmChar_t* d = cmIsFlag(note->flags,kDynXsFl) ? "d" : "-";
|
||||||
const cmChar_t* t = cmIsFlag(note->flags,kTempoXsFl) ? "t" : "-";
|
const cmChar_t* t = cmIsFlag(note->flags,kTempoXsFl) ? "t" : "-";
|
||||||
const cmChar_t* P = cmIsFlag(note->flags,kPedalDnXsFl) ? "V" : "-";
|
const cmChar_t* P = cmIsFlag(note->flags,kDampDnXsFl) ? "V" : "-";
|
||||||
const cmChar_t* s = cmIsFlag(note->flags,kSostDnXsFl) ? "{" : "-";
|
const cmChar_t* s = cmIsFlag(note->flags,kSostDnXsFl) ? "{" : "-";
|
||||||
const cmChar_t* S = cmIsFlag(note->flags,kSectionXsFl) ? "S" : "-";
|
const cmChar_t* S = cmIsFlag(note->flags,kSectionXsFl) ? "S" : "-";
|
||||||
const cmChar_t* H = cmIsFlag(note->flags,kHeelXsFl) ? "H" : "-";
|
const cmChar_t* H = cmIsFlag(note->flags,kHeelXsFl) ? "H" : "-";
|
||||||
const cmChar_t* T0 = cmIsFlag(note->flags,kTieBegXsFl) ? "T" : "-";
|
const cmChar_t* T0 = cmIsFlag(note->flags,kTieBegXsFl) ? "T" : "-";
|
||||||
const cmChar_t* T1 = cmIsFlag(note->flags,kTieEndXsFl) ? "_" : "-";
|
const cmChar_t* T1 = cmIsFlag(note->flags,kTieEndXsFl) ? "_" : "-";
|
||||||
const cmChar_t* O = cmIsFlag(note->flags,kOnsetXsFl) ? "*" : "-";
|
const cmChar_t* O = cmIsFlag(note->flags,kOnsetXsFl) ? "*" : "-";
|
||||||
P = cmIsFlag(note->flags,kPedalUpXsFl) ? "^" : P;
|
P = cmIsFlag(note->flags,kDampUpXsFl) ? "^" : P;
|
||||||
P = cmIsFlag(note->flags,kPedalUpDnXsFl) ? "X" : P;
|
P = cmIsFlag(note->flags,kDampUpDnXsFl) ? "X" : P;
|
||||||
s = cmIsFlag(note->flags,kSostUpXsFl) ? "}" : s;
|
s = cmIsFlag(note->flags,kSostUpXsFl) ? "}" : s;
|
||||||
//const cmChar_t* N = note->pitch==0 ? " " : cmMidiToSciPitch( note->pitch, NULL, 0 );
|
//const cmChar_t* N = note->pitch==0 ? " " : cmMidiToSciPitch( note->pitch, NULL, 0 );
|
||||||
|
|
||||||
@ -2549,6 +2638,7 @@ cmXsRC_t _cmXsWriteMidiSvg( cmCtx_t* ctx, cmXScore_t* p, cmXsMidiFile_t* mf, con
|
|||||||
const cmChar_t* svgFn = cmFsMakeFn(dir,fn,"html",NULL);
|
const cmChar_t* svgFn = cmFsMakeFn(dir,fn,"html",NULL);
|
||||||
const cmChar_t* cssFn = cmFsMakeFn(NULL,fn,"css",NULL);
|
const cmChar_t* cssFn = cmFsMakeFn(NULL,fn,"css",NULL);
|
||||||
cmChar_t* t0 = NULL; // temporary dynamic string
|
cmChar_t* t0 = NULL; // temporary dynamic string
|
||||||
|
|
||||||
// create the SVG writer
|
// create the SVG writer
|
||||||
if( cmSvgWriterAlloc(ctx,&svgH) != kOkSvgRC )
|
if( cmSvgWriterAlloc(ctx,&svgH) != kOkSvgRC )
|
||||||
{
|
{
|
||||||
@ -2559,12 +2649,14 @@ cmXsRC_t _cmXsWriteMidiSvg( cmCtx_t* ctx, cmXScore_t* p, cmXsMidiFile_t* mf, con
|
|||||||
// for each MIDI file element
|
// for each MIDI file element
|
||||||
for(; e!=NULL && rc==kOkXsRC; e=e->link)
|
for(; e!=NULL && rc==kOkXsRC; e=e->link)
|
||||||
{
|
{
|
||||||
|
switch( e->flags & (kOnsetXsFl|kBarXsFl|kDampDnXsFl|kDampUpDnXsFl|kSostDnXsFl))
|
||||||
|
{
|
||||||
|
|
||||||
// if this is a note
|
// if this is a note
|
||||||
if( cmIsFlag(e->flags,kOnsetXsFl) )
|
case kOnsetXsFl:
|
||||||
{
|
{
|
||||||
const cmChar_t* classLabel = "note";
|
const cmChar_t* classLabel = "note";
|
||||||
|
|
||||||
|
|
||||||
t0 = cmTsPrintfP(t0,"note_%i%s",e->voice, cmIsFlag(e->flags,kGraceXsFl) ? "_g":"");
|
t0 = cmTsPrintfP(t0,"note_%i%s",e->voice, cmIsFlag(e->flags,kGraceXsFl) ? "_g":"");
|
||||||
|
|
||||||
if( cmIsFlag(e->flags,kGraceXsFl) )
|
if( cmIsFlag(e->flags,kGraceXsFl) )
|
||||||
@ -2576,9 +2668,10 @@ cmXsRC_t _cmXsWriteMidiSvg( cmCtx_t* ctx, cmXScore_t* p, cmXsMidiFile_t* mf, con
|
|||||||
if( cmSvgWriterText(svgH, e->tick + e->durTicks/2, e->d0 * noteHeight + noteHeight/2, cmMidiToSciPitch( e->d0, NULL, 0), "pitch") != kOkSvgRC )
|
if( cmSvgWriterText(svgH, e->tick + e->durTicks/2, e->d0 * noteHeight + noteHeight/2, cmMidiToSciPitch( e->d0, NULL, 0), "pitch") != kOkSvgRC )
|
||||||
rc = kSvgFailXsRC;
|
rc = kSvgFailXsRC;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
// if this is a bar
|
// if this is a bar
|
||||||
if( cmIsFlag(e->flags,kBarXsFl) )
|
case kBarXsFl:
|
||||||
{
|
{
|
||||||
if( cmSvgWriterLine(svgH, e->tick, 0, e->tick, 127*noteHeight, "bar") != kOkSvgRC )
|
if( cmSvgWriterLine(svgH, e->tick, 0, e->tick, 127*noteHeight, "bar") != kOkSvgRC )
|
||||||
rc = kSvgFailXsRC;
|
rc = kSvgFailXsRC;
|
||||||
@ -2588,6 +2681,19 @@ cmXsRC_t _cmXsWriteMidiSvg( cmCtx_t* ctx, cmXScore_t* p, cmXsMidiFile_t* mf, con
|
|||||||
rc = kSvgFailXsRC;
|
rc = kSvgFailXsRC;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// if this is a pedal event
|
||||||
|
case kDampDnXsFl:
|
||||||
|
case kDampUpDnXsFl:
|
||||||
|
case kSostDnXsFl:
|
||||||
|
{
|
||||||
|
const cmChar_t* classLabel = cmIsFlag(e->flags,kSostDnXsFl) ? "sost" : "damp";
|
||||||
|
unsigned y = (128 + cmIsFlag(e->flags,kSostDnXsFl)?1:0) * noteHeight;
|
||||||
|
cmSvgWriterRect(svgH, e->tick, y, e->durTicks, noteHeight-1, classLabel);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( rc != kOkXsRC )
|
if( rc != kOkXsRC )
|
||||||
@ -2606,6 +2712,102 @@ cmXsRC_t _cmXsWriteMidiSvg( cmCtx_t* ctx, cmXScore_t* p, cmXsMidiFile_t* mf, con
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXScore_t* p, cmXsMidiFile_t* mf, const cmChar_t* dir, const cmChar_t* fn )
|
||||||
|
{
|
||||||
|
cmXsRC_t rc = kOkXsRC;
|
||||||
|
|
||||||
|
if( p->partL==NULL || p->partL->measL == NULL )
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
cmMidiFileH_t mfH = cmMidiFileNullHandle;
|
||||||
|
unsigned trkN = 2;
|
||||||
|
unsigned ticksPerQN = p->partL->measL->divisions;
|
||||||
|
const cmChar_t* outFn = cmFsMakeFn(dir,fn,"mid",NULL);
|
||||||
|
|
||||||
|
if( cmMidiFileCreate( ctx, &mfH, trkN, ticksPerQN ) != kOkMfRC )
|
||||||
|
return cmErrMsg(&p->err,kMidiFailXsRC,"Unable to create the MIDI file object.");
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
cmXsNote_t* np = mp->noteL;
|
||||||
|
|
||||||
|
if( mp->divisions != ticksPerQN )
|
||||||
|
cmErrWarnMsg(&p->err,kMidiFailXsRC,"The 'tick per quarter note' (divisions) field in measure %i does not match the value in the first measure (%i).",mp->divisions,ticksPerQN);
|
||||||
|
|
||||||
|
// for each note in this measure
|
||||||
|
for(; np!=NULL; np=np->slink)
|
||||||
|
{
|
||||||
|
switch( np->flags & (kOnsetXsFl|kMetronomeXsFl|kDampDnXsFl|kDampUpDnXsFl|kSostDnXsFl) )
|
||||||
|
{
|
||||||
|
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 )
|
||||||
|
{
|
||||||
|
rc = kMidiFailXsRC;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kDampDnXsFl:
|
||||||
|
case kDampUpDnXsFl:
|
||||||
|
case kSostDnXsFl:
|
||||||
|
{
|
||||||
|
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 ) )
|
||||||
|
{
|
||||||
|
rc = kMidiFailXsRC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kMetronomeXsFl:
|
||||||
|
if( cmMidFileInsertTrackTempoMsg(mfH, 0, np->tick, np->duration ) != kOkMfRC )
|
||||||
|
rc = kMidiFailXsRC;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
{ assert(0); }
|
||||||
|
}
|
||||||
|
|
||||||
|
if( rc != kOkXsRC )
|
||||||
|
{
|
||||||
|
rc = cmErrMsg(&p->err,rc,"MIDI message insert failed on '%s'.",cmStringNullGuard(outFn));
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( cmMidiFileWrite(mfH,outFn) != kOkMfRC )
|
||||||
|
{
|
||||||
|
rc = cmErrMsg(&p->err,kMidiFailXsRC,"MIDI file write failed on '%s'.",cmStringNullGuard(outFn));
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
cmFsFreeFn(outFn);
|
||||||
|
if( cmMidiFileClose(&mfH) != kOkMfRC )
|
||||||
|
{
|
||||||
|
rc = cmErrMsg(&p->err,kMidiFailXsRC,"Unable to create the MIDI file object.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void _cmXsPushMidiEvent( cmXScore_t* p, cmXsMidiFile_t* mf, unsigned flags, unsigned tick, unsigned durTick, unsigned voice, unsigned d0, unsigned d1 )
|
void _cmXsPushMidiEvent( cmXScore_t* p, cmXsMidiFile_t* mf, unsigned flags, unsigned tick, unsigned durTick, unsigned voice, unsigned d0, unsigned d1 )
|
||||||
{
|
{
|
||||||
cmXsMidiEvt_t* e = cmLhAllocZ(p->lhH,cmXsMidiEvt_t,1);
|
cmXsMidiEvt_t* e = cmLhAllocZ(p->lhH,cmXsMidiEvt_t,1);
|
||||||
@ -2613,7 +2815,7 @@ void _cmXsPushMidiEvent( cmXScore_t* p, cmXsMidiFile_t* mf, unsigned flags, unsi
|
|||||||
e->tick = tick;
|
e->tick = tick;
|
||||||
e->durTicks = durTick;
|
e->durTicks = durTick;
|
||||||
e->voice = voice;
|
e->voice = voice;
|
||||||
e->d0 = d0;
|
e->d0 = d0; // note=pitch bar=number pedal=ctl# metronome=BPM
|
||||||
e->d1 = d1;
|
e->d1 = d1;
|
||||||
if( mf->eol != NULL )
|
if( mf->eol != NULL )
|
||||||
mf->eol->link = e;
|
mf->eol->link = e;
|
||||||
@ -2630,7 +2832,7 @@ void _cmXsPushMidiEvent( cmXScore_t* p, cmXsMidiFile_t* mf, unsigned flags, unsi
|
|||||||
mf->eol = e;
|
mf->eol = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmXsRC_t _cmXScoreWriteMidi( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const cmChar_t* fn )
|
cmXsRC_t _cmXScoreGenMidi( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const cmChar_t* fn )
|
||||||
{
|
{
|
||||||
cmXScore_t* p = _cmXScoreHandleToPtr(h);
|
cmXScore_t* p = _cmXScoreHandleToPtr(h);
|
||||||
cmXsPart_t* pp = p->partL;
|
cmXsPart_t* pp = p->partL;
|
||||||
@ -2638,6 +2840,9 @@ cmXsRC_t _cmXScoreWriteMidi( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
|
|||||||
cmXsMidiFile_t mf;
|
cmXsMidiFile_t mf;
|
||||||
memset(&mf,0,sizeof(mf));
|
memset(&mf,0,sizeof(mf));
|
||||||
|
|
||||||
|
// assign durations to pedal down events
|
||||||
|
_cmXScoreProcessPedals(p);
|
||||||
|
|
||||||
for(; pp!=NULL; pp=pp->link)
|
for(; pp!=NULL; pp=pp->link)
|
||||||
{
|
{
|
||||||
const cmXsMeas_t* meas = pp->measL;
|
const cmXsMeas_t* meas = pp->measL;
|
||||||
@ -2647,6 +2852,15 @@ cmXsRC_t _cmXScoreWriteMidi( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
|
|||||||
const cmXsNote_t* note = meas->noteL;
|
const cmXsNote_t* note = meas->noteL;
|
||||||
for(; note!=NULL; note=note->slink)
|
for(; note!=NULL; note=note->slink)
|
||||||
{
|
{
|
||||||
|
// if this is a metronome marker
|
||||||
|
if( cmIsFlag(note->flags,kMetronomeXsFl) )
|
||||||
|
{
|
||||||
|
// set BPM as d0
|
||||||
|
_cmXsPushMidiEvent(p,&mf,note->flags,note->tick,0,0,note->duration,0);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// if this is a sounding note
|
// if this is a sounding note
|
||||||
if( cmIsFlag(note->flags,kOnsetXsFl) )
|
if( cmIsFlag(note->flags,kOnsetXsFl) )
|
||||||
{
|
{
|
||||||
@ -2669,10 +2883,20 @@ cmXsRC_t _cmXScoreWriteMidi( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if this is a pedal event
|
||||||
|
if( cmIsFlag(note->flags,kDampDnXsFl|kDampUpDnXsFl|kSostDnXsFl) )
|
||||||
|
{
|
||||||
|
unsigned d0 = cmIsFlag(note->flags,kSostDnXsFl) ? kSostenutoCtlMdId : kSustainCtlMdId;
|
||||||
|
_cmXsPushMidiEvent(p,&mf,note->flags,note->tick,note->duration,0,d0,127);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_cmXsWriteMidiFile( ctx, p, &mf, dir, fn );
|
||||||
|
|
||||||
return _cmXsWriteMidiSvg( ctx, p, &mf, dir, fn );
|
return _cmXsWriteMidiSvg( ctx, p, &mf, dir, fn );
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -2719,13 +2943,13 @@ cmXsRC_t cmXScoreTest(
|
|||||||
{
|
{
|
||||||
cmFileSysPathPart_t* pp = cmFsPathParts(midiOutFn);
|
cmFileSysPathPart_t* pp = cmFsPathParts(midiOutFn);
|
||||||
|
|
||||||
_cmXScoreWriteMidi( ctx, h, pp->dirStr, pp->fnStr );
|
_cmXScoreGenMidi( ctx, h, pp->dirStr, pp->fnStr );
|
||||||
|
|
||||||
cmFsFreePathParts(pp);
|
cmFsFreePathParts(pp);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//cmXScoreReport(h,&ctx->rpt,true);
|
//cmXScoreReport(h,&ctx->rpt,false);
|
||||||
|
|
||||||
return cmXScoreFinalize(&h);
|
return cmXScoreFinalize(&h);
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ extern "C" {
|
|||||||
kUnterminatedTieXsRC,
|
kUnterminatedTieXsRC,
|
||||||
kUnterminatedSlurXsRC,
|
kUnterminatedSlurXsRC,
|
||||||
kUnterminatedOctaveShiftXsrRC,
|
kUnterminatedOctaveShiftXsrRC,
|
||||||
|
kPedalStateErrorXsRc,
|
||||||
kMidiFailXsRC,
|
kMidiFailXsRC,
|
||||||
kFileFailXsRC,
|
kFileFailXsRC,
|
||||||
kSvgFailXsRC
|
kSvgFailXsRC
|
||||||
|
Loading…
Reference in New Issue
Block a user