Merge branch 'develop' of gitea.larke.org:klarke/libcm into develop
This commit is contained in:
commit
8848b03412
@ -149,6 +149,7 @@ unsigned _cmMsf_WriteMatchFileLine( cmFileH_t fH, cmScH_t scH, const cmScMatcher
|
|||||||
return scUid;
|
return scUid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is the score follower callback function
|
||||||
void _cmMsf_ScoreFollowCb( struct cmScMatcher_str* p, void* arg, cmScMatcherResult_t* rp )
|
void _cmMsf_ScoreFollowCb( struct cmScMatcher_str* p, void* arg, cmScMatcherResult_t* rp )
|
||||||
{
|
{
|
||||||
_cmMsf_ScoreFollow_t* r = (_cmMsf_ScoreFollow_t*)arg;
|
_cmMsf_ScoreFollow_t* r = (_cmMsf_ScoreFollow_t*)arg;
|
||||||
@ -193,7 +194,7 @@ cmMsfRC_t cmMidiScoreFollowMain(
|
|||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup the callback record
|
// setup the callback record with an array that has twice as many records as there are score events
|
||||||
if((sfr.rAllocN = cmScoreEvtCount( scH )*2) == 0)
|
if((sfr.rAllocN = cmScoreEvtCount( scH )*2) == 0)
|
||||||
{
|
{
|
||||||
rc = cmErrMsg(&err,kFailMsfRC,"The score %s appears to be empty.",cmStringNullGuard(scoreCsvFn));
|
rc = cmErrMsg(&err,kFailMsfRC,"The score %s appears to be empty.",cmStringNullGuard(scoreCsvFn));
|
||||||
|
@ -960,7 +960,7 @@ cmTsbRC_t cmTakeSeqBldrLoadTake( cmTakeSeqBldrH_t h, unsigned tlMarkUid, bool ov
|
|||||||
//cmMidiFileTickToSamples( mfH, cmTimeLineSampleRate(p->tlH), false );
|
//cmMidiFileTickToSamples( mfH, cmTimeLineSampleRate(p->tlH), false );
|
||||||
|
|
||||||
// calculate MIDI note and pedal durations (see cmMidiChMsg_t.durTicks)
|
// calculate MIDI note and pedal durations (see cmMidiChMsg_t.durTicks)
|
||||||
cmMidiFileCalcNoteDurations( mfH );
|
cmMidiFileCalcNoteDurations( mfH, 0 );
|
||||||
|
|
||||||
unsigned i = 0;
|
unsigned i = 0;
|
||||||
unsigned n = cmMidiFileMsgCount(mfH);
|
unsigned n = cmMidiFileMsgCount(mfH);
|
||||||
|
@ -733,7 +733,7 @@ cmTlRC_t _cmTlAllocMidiFileRecd( _cmTl_t* p, const cmChar_t* nameStr, const cmCh
|
|||||||
//cmMidiFileTickToSamples(mfH,p->srate,false);
|
//cmMidiFileTickToSamples(mfH,p->srate,false);
|
||||||
|
|
||||||
// assign note durations to all note-on msg's
|
// assign note durations to all note-on msg's
|
||||||
cmMidiFileCalcNoteDurations(mfH);
|
cmMidiFileCalcNoteDurations(mfH,0);
|
||||||
|
|
||||||
unsigned recdByteCnt = sizeof(cmTlMidiFile_t) + strlen(fn) + 1;
|
unsigned recdByteCnt = sizeof(cmTlMidiFile_t) + strlen(fn) + 1;
|
||||||
|
|
||||||
|
@ -681,12 +681,13 @@ cmXsRC_t _cmXScoreParseNote(cmXScore_t* p, cmXsMeas_t* meas, const cmXmlNode_t*
|
|||||||
return _cmXScorePushNote(p, meas, voiceId, note );
|
return _cmXScorePushNote(p, meas, voiceId, note );
|
||||||
}
|
}
|
||||||
|
|
||||||
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 )
|
cmXsRC_t _cmXScorePushNonNote( cmXScore_t* p, cmXsMeas_t* meas, const cmXmlNode_t* noteXmlNode, unsigned tick, unsigned duration, unsigned staff, double rvalue, const cmChar_t* tvalue, unsigned flags )
|
||||||
{
|
{
|
||||||
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->tick = tick;
|
note->tick = tick;
|
||||||
|
note->staff = staff;
|
||||||
note->flags = flags;
|
note->flags = flags;
|
||||||
note->rvalue = rvalue;
|
note->rvalue = rvalue;
|
||||||
note->tvalue = tvalue;
|
note->tvalue = tvalue;
|
||||||
@ -822,7 +823,7 @@ cmXsRC_t _cmXScoreParseDirection(cmXScore_t* p, cmXsMeas_t* meas, const cmXmlNo
|
|||||||
}
|
}
|
||||||
|
|
||||||
if( pushFl )
|
if( pushFl )
|
||||||
rc = _cmXScorePushNonNote(p,meas,dnp,tick+offset,duration,rvalue,tvalue,flags);
|
rc = _cmXScorePushNonNote(p,meas,dnp,tick+offset,duration,staff,rvalue,tvalue,flags);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -868,7 +869,7 @@ cmXsRC_t _cmXScoreParseMeasure(cmXScore_t* p, cmXsPart_t* pp, const cmXmlNode_t*
|
|||||||
}
|
}
|
||||||
|
|
||||||
// store the bar line
|
// store the bar line
|
||||||
if((rc = _cmXScorePushNonNote(p,meas,mnp,tick,0,0,NULL,kBarXsFl)) != kOkXsRC )
|
if((rc = _cmXScorePushNonNote(p,meas,mnp,tick,0,0,0,NULL,kBarXsFl)) != kOkXsRC )
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
np = mnp->children;
|
np = mnp->children;
|
||||||
@ -1562,7 +1563,7 @@ void _cmXScoreFixBarLines( cmXScore_t* p )
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Assign pedal down durations to pedal down events.
|
// Assign pedal down durations to pedal down events.
|
||||||
cmXsRC_t _cmXScoreProcessPedals( cmXScore_t* p )
|
cmXsRC_t _cmXScoreProcessPedals( cmXScore_t* p, bool reportFl )
|
||||||
{
|
{
|
||||||
cmXsRC_t rc = kOkXsRC;
|
cmXsRC_t rc = kOkXsRC;
|
||||||
cmXsPart_t* pp = p->partL;
|
cmXsPart_t* pp = p->partL;
|
||||||
@ -1584,11 +1585,14 @@ cmXsRC_t _cmXScoreProcessPedals( cmXScore_t* p )
|
|||||||
case 0:
|
case 0:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kDampDnXsFl:
|
case kDampDnXsFl:
|
||||||
if( dnp != NULL )
|
if( dnp != NULL )
|
||||||
cmErrWarnMsg(&p->err,kPedalStateErrorXsRc,"Damper down not preceded by damper up in measure:%i.",mp->number);
|
cmErrWarnMsg(&p->err,kPedalStateErrorXsRc,"Damper down not preceded by damper up in measure:%i.",mp->number);
|
||||||
else
|
else
|
||||||
dnp = np;
|
dnp = np;
|
||||||
|
|
||||||
|
if( reportFl )
|
||||||
|
cmRptPrintf(p->err.rpt,"Damp Down : staff:%i meas:%i tick:%i\n", np->staff, mp->number, np->tick);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kDampUpXsFl:
|
case kDampUpXsFl:
|
||||||
@ -1599,6 +1603,10 @@ cmXsRC_t _cmXScoreProcessPedals( cmXScore_t* p )
|
|||||||
dnp->duration = np->tick - dnp->tick;
|
dnp->duration = np->tick - dnp->tick;
|
||||||
dnp = NULL;
|
dnp = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( reportFl )
|
||||||
|
cmRptPrintf(p->err.rpt,"Damp Up : staff:%i meas:%i tick:%i\n", np->staff, mp->number, np->tick);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kDampUpDnXsFl:
|
case kDampUpDnXsFl:
|
||||||
@ -1609,13 +1617,19 @@ cmXsRC_t _cmXScoreProcessPedals( cmXScore_t* p )
|
|||||||
dnp->duration = np->tick - dnp->tick;
|
dnp->duration = np->tick - dnp->tick;
|
||||||
dnp = np;
|
dnp = np;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( reportFl )
|
||||||
|
cmRptPrintf(p->err.rpt,"Damp UpDn : staff:%i meas:%i tick:%i\n", np->staff, mp->number, np->tick);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kSostDnXsFl:
|
case kSostDnXsFl:
|
||||||
if( snp != NULL )
|
if( snp != NULL )
|
||||||
cmErrWarnMsg(&p->err,kPedalStateErrorXsRc,"Sostenuto down not preceded by sostenuto up in measure:%i.",mp->number);
|
cmErrWarnMsg(&p->err,kPedalStateErrorXsRc,"Sostenuto down not preceded by sostenuto up in measure:%i.",mp->number);
|
||||||
else
|
else
|
||||||
snp = np;
|
snp = np;
|
||||||
|
|
||||||
|
if( reportFl )
|
||||||
|
cmRptPrintf(p->err.rpt,"Sost Down : staff:%i meas:%i tick:%i\n", np->staff, mp->number, np->tick);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kSostUpXsFl:
|
case kSostUpXsFl:
|
||||||
@ -1626,6 +1640,8 @@ cmXsRC_t _cmXScoreProcessPedals( cmXScore_t* p )
|
|||||||
snp->duration = np->tick - snp->tick;
|
snp->duration = np->tick - snp->tick;
|
||||||
snp = NULL;
|
snp = NULL;
|
||||||
}
|
}
|
||||||
|
if( reportFl )
|
||||||
|
cmRptPrintf(p->err.rpt,"Sost Up : staff:%i meas:%i tick:%i\n", np->staff, mp->number, np->tick);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -2706,7 +2722,7 @@ cmXsRC_t _cmXsApplyEditFile( cmXScore_t* p, const cmChar_t* fn )
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn, const cmChar_t* editFn )
|
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;
|
||||||
|
|
||||||
@ -2771,7 +2787,7 @@ cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn, c
|
|||||||
}
|
}
|
||||||
|
|
||||||
// assign durations to pedal down events
|
// assign durations to pedal down events
|
||||||
_cmXScoreProcessPedals(p);
|
_cmXScoreProcessPedals(p,damperRptFl);
|
||||||
|
|
||||||
// remove some notes which share a pitch and are overlapped or embedded within another note.
|
// remove some notes which share a pitch and are overlapped or embedded within another note.
|
||||||
_cmXScoreProcessOverlappingNotes(p);
|
_cmXScoreProcessOverlappingNotes(p);
|
||||||
@ -3408,7 +3424,7 @@ void _cmXScoreGenEditFileWrite( void* arg, const cmChar_t* text )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cmXsRC_t cmXScoreGenEditFile( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* outFn )
|
cmXsRC_t cmXScoreGenEditFile( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* outFn, bool damperRptFl )
|
||||||
{
|
{
|
||||||
cmXsH_t xsH = cmXsNullHandle;
|
cmXsH_t xsH = cmXsNullHandle;
|
||||||
cmFileH_t fH = cmFileNullHandle;
|
cmFileH_t fH = cmFileNullHandle;
|
||||||
@ -3419,7 +3435,7 @@ cmXsRC_t cmXScoreGenEditFile( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_
|
|||||||
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)) != kOkXsRC )
|
if((rc = cmXScoreInitialize(ctx,&xsH,xmlFn,NULL,damperRptFl)) != kOkXsRC )
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
if( cmFileOpen(&fH,outFn,kWriteFileFl,&ctx->rpt) != kOkFileRC )
|
if( cmFileOpen(&fH,outFn,kWriteFileFl,&ctx->rpt) != kOkFileRC )
|
||||||
@ -4077,21 +4093,22 @@ cmXsRC_t cmXScoreTest(
|
|||||||
int beginMeasNumb,
|
int beginMeasNumb,
|
||||||
int beginBPM,
|
int beginBPM,
|
||||||
bool standAloneFl,
|
bool standAloneFl,
|
||||||
bool panZoomFl )
|
bool panZoomFl,
|
||||||
|
bool damperRptFl)
|
||||||
{
|
{
|
||||||
cmXsRC_t rc;
|
cmXsRC_t rc;
|
||||||
cmXsH_t h = cmXsNullHandle;
|
cmXsH_t h = cmXsNullHandle;
|
||||||
|
|
||||||
if( editFn!=NULL && !cmFsIsFile(editFn) )
|
if( editFn!=NULL && !cmFsIsFile(editFn) )
|
||||||
{
|
{
|
||||||
cmRptPrintf(&ctx->rpt,"The edit file %s does not exist. A new edit file will be created.",editFn);
|
cmRptPrintf(&ctx->rpt,"The edit file %s does not exist. A new edit file will be created.\n",editFn);
|
||||||
cmXScoreGenEditFile(ctx,xmlFn,editFn);
|
cmXScoreGenEditFile(ctx,xmlFn,editFn,damperRptFl);
|
||||||
editFn = NULL;
|
editFn = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Parse the XML file and apply the changes in editFn.
|
// Parse the XML file and apply the changes in editFn.
|
||||||
if((rc = cmXScoreInitialize( ctx, &h, xmlFn,editFn)) != kOkXsRC )
|
if((rc = cmXScoreInitialize( ctx, &h, xmlFn,editFn, damperRptFl )) != kOkXsRC )
|
||||||
return cmErrMsg(&ctx->err,rc,"XScore alloc failed.");
|
return cmErrMsg(&ctx->err,rc,"XScore alloc failed.");
|
||||||
|
|
||||||
if( csvOutFn != NULL )
|
if( csvOutFn != NULL )
|
||||||
@ -4101,14 +4118,14 @@ cmXsRC_t cmXScoreTest(
|
|||||||
|
|
||||||
_cmXsIsCsvValid(ctx,h,csvOutFn);
|
_cmXsIsCsvValid(ctx,h,csvOutFn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// measure the score complexity
|
||||||
|
double wndSecs = 1.0;
|
||||||
|
|
||||||
|
_cmXsMeasComplexity(h,wndSecs);
|
||||||
|
|
||||||
if( midiOutFn != NULL )
|
if( midiOutFn != NULL )
|
||||||
{
|
{
|
||||||
// measure the score complexity
|
|
||||||
double wndSecs = 1.0;
|
|
||||||
|
|
||||||
_cmXsMeasComplexity(h,wndSecs);
|
|
||||||
|
|
||||||
cmFileSysPathPart_t* pp = cmFsPathParts(midiOutFn);
|
cmFileSysPathPart_t* pp = cmFsPathParts(midiOutFn);
|
||||||
|
|
||||||
_cmXsWriteMidiFile(ctx, h, beginMeasNumb, beginBPM, pp->dirStr, pp->fnStr );
|
_cmXsWriteMidiFile(ctx, h, beginMeasNumb, beginBPM, pp->dirStr, pp->fnStr );
|
||||||
|
@ -47,7 +47,7 @@ extern "C" {
|
|||||||
// Initialize an cmXScore object from a Sibelius generated MusicXML file.
|
// Initialize an cmXScore object from a Sibelius generated MusicXML file.
|
||||||
// 'editFn' is used to add additional information to the score.
|
// 'editFn' is used to add additional information to the score.
|
||||||
// See cmXScoreGenEditFile()
|
// See cmXScoreGenEditFile()
|
||||||
cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn, const cmChar_t* editFn );
|
cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn, const cmChar_t* editFn, bool damperRptFl );
|
||||||
cmXsRC_t cmXScoreFinalize( cmXsH_t* hp );
|
cmXsRC_t cmXScoreFinalize( cmXsH_t* hp );
|
||||||
|
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ extern "C" {
|
|||||||
// Generate a template 'edit file'. This file can be edited by hand to included additional
|
// Generate a template 'edit file'. This file can be edited by hand to included additional
|
||||||
// information in the score. See the 'editFn' argument to cmXScoreInitialize() for where
|
// information in the score. See the 'editFn' argument to cmXScoreInitialize() for where
|
||||||
// this file is used.
|
// this file is used.
|
||||||
cmXsRC_t cmXScoreGenEditFile( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* outFn );
|
cmXsRC_t cmXScoreGenEditFile( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* outFn, bool damperRptFl );
|
||||||
|
|
||||||
// Generate the CSV file suitable for use by cmScore.
|
// Generate the CSV file suitable for use by cmScore.
|
||||||
//
|
//
|
||||||
@ -72,7 +72,7 @@ extern "C" {
|
|||||||
// Set reportFl to true to print a report of the score following processing.
|
// Set reportFl to true to print a report of the score following processing.
|
||||||
// Set begMeasNumb to the first measure the to be written to the output csv, MIDI and SVG files.
|
// Set begMeasNumb to the first measure the to be written to the output csv, MIDI and SVG files.
|
||||||
// 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 );
|
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 );
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -150,7 +150,7 @@ void _cmDListIndexFree( cmDList_t* p, cmDListIndex_t* x )
|
|||||||
// x is the first index
|
// x is the first index
|
||||||
if( x0 == NULL )
|
if( x0 == NULL )
|
||||||
{
|
{
|
||||||
assert( x1 = p->indexes );
|
assert( x1 == p->indexes );
|
||||||
p->indexes = x->link;
|
p->indexes = x->link;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -88,9 +88,9 @@ extern "C" {
|
|||||||
#define cmMidiIsStatus( s ) (kNoteOffMdId <= (s) /*&& ((unsigned)(s)) <= kSysRtResetMdId*/ )
|
#define cmMidiIsStatus( s ) (kNoteOffMdId <= (s) /*&& ((unsigned)(s)) <= kSysRtResetMdId*/ )
|
||||||
#define cmMidiIsChStatus( s ) (kNoteOffMdId <= (s) && (s) < kSysExMdId)
|
#define cmMidiIsChStatus( s ) (kNoteOffMdId <= (s) && (s) < kSysExMdId)
|
||||||
|
|
||||||
#define cmMidiIsNoteOn( s ) ( kNoteOnMdId <= (s) && (s) <= (kNoteOnMdId + kMidiChCnt) )
|
#define cmMidiIsNoteOn( s ) ( kNoteOnMdId <= (s) && (s) < (kNoteOnMdId + kMidiChCnt) )
|
||||||
#define cmMidiIsNoteOff( s, d1 ) ( (cmMidiIsNoteOn(s) && (d1)==0) || (kNoteOffMdId <= (s) && (s) <= (kNoteOffMdId + kMidiChCnt)) )
|
#define cmMidiIsNoteOff( s, d1 ) ( (cmMidiIsNoteOn(s) && (d1)==0) || (kNoteOffMdId <= (s) && (s) < (kNoteOffMdId + kMidiChCnt)) )
|
||||||
#define cmMidiIsCtl( s ) ( kCtlMdId <= (s) && (s) <= (kCtlMdId + kMidiChCnt) )
|
#define cmMidiIsCtl( s ) ( kCtlMdId <= (s) && (s) < (kCtlMdId + kMidiChCnt) )
|
||||||
|
|
||||||
#define cmMidiIsSustainPedal( s, d0 ) ( kCtlMdId <= (s) && (s) <= (kCtlMdId + kMidiChCnt) && (d0)== kSustainCtlMdId )
|
#define cmMidiIsSustainPedal( s, d0 ) ( kCtlMdId <= (s) && (s) <= (kCtlMdId + kMidiChCnt) && (d0)== kSustainCtlMdId )
|
||||||
#define cmMidiIsSustainPedalDown( s, d0, d1) ( cmMidiIsSustainPedal(s,d0) && (d1)>=64 )
|
#define cmMidiIsSustainPedalDown( s, d0, d1) ( cmMidiIsSustainPedal(s,d0) && (d1)>=64 )
|
||||||
|
156
src/cmMidiFile.c
156
src/cmMidiFile.c
@ -423,6 +423,34 @@ cmMfRC_t _cmMidiFileReadHdr( _cmMidiFile_t* mfp )
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _cmMidiFileDrop( _cmMidiFile_t* p )
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
unsigned n = 0;
|
||||||
|
for(i=0; i<p->trkN; ++i)
|
||||||
|
{
|
||||||
|
_cmMidiTrack_t* trk = p->trkV + i;
|
||||||
|
cmMidiTrackMsg_t* m0 = NULL;
|
||||||
|
cmMidiTrackMsg_t* m = trk->base;
|
||||||
|
|
||||||
|
for(; m!=NULL; m=m->link)
|
||||||
|
{
|
||||||
|
if( cmIsFlag(m->flags,kDropTrkMsgFl) )
|
||||||
|
{
|
||||||
|
++n;
|
||||||
|
if( m0 == NULL )
|
||||||
|
trk->base = m->link;
|
||||||
|
else
|
||||||
|
m0->link = m->link;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m0 = m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int _cmMidiFileSortFunc( const void *p0, const void* p1 )
|
int _cmMidiFileSortFunc( const void *p0, const void* p1 )
|
||||||
{
|
{
|
||||||
if( (*(cmMidiTrackMsg_t**)p0)->atick == (*(cmMidiTrackMsg_t**)p1)->atick )
|
if( (*(cmMidiTrackMsg_t**)p0)->atick == (*(cmMidiTrackMsg_t**)p1)->atick )
|
||||||
@ -1369,7 +1397,6 @@ cmMfRC_t cmMidiFileInsertMsg( cmMidiFileH_t h, unsigned uid, int dtick, cmMidiBy
|
|||||||
mfp->msgVDirtyFl = true;
|
mfp->msgVDirtyFl = true;
|
||||||
|
|
||||||
return kOkMfRC;
|
return kOkMfRC;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cmMfRC_t cmMidiFileInsertTrackMsg( cmMidiFileH_t h, unsigned trkIdx, const cmMidiTrackMsg_t* msg )
|
cmMfRC_t cmMidiFileInsertTrackMsg( cmMidiFileH_t h, unsigned trkIdx, const cmMidiTrackMsg_t* msg )
|
||||||
@ -1532,6 +1559,38 @@ unsigned cmMidiFileSeekUsecs( cmMidiFileH_t h, unsigned long long offsUSecs, un
|
|||||||
return mi;
|
return mi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
1.Move closest previous tempo msg to begin.
|
||||||
|
2.The first msg in each track must be the first msg >= begin.time
|
||||||
|
3.Remove all msgs > end.time - except the 'endMsg' for each note/pedal that is active at end time.
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
unsigned _cmMidiFileIsEndMsg( cmMidiTrackMsg_t* m, cmMidiTrackMsg_t** endMsgArray, unsigned n )
|
||||||
|
{
|
||||||
|
unsigned i = 0;
|
||||||
|
for(; i<n; ++i)
|
||||||
|
if( endMsgArray[i] == m )
|
||||||
|
return i;
|
||||||
|
|
||||||
|
return cmInvalidIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _cmMidiFileAllEndMsgFound( cmMidiTrackMsg_t** noteMsgArray, unsigned n0, cmMidiTrackMsg_t** pedalMsgArray, unsigned n1 )
|
||||||
|
{
|
||||||
|
unsigned i=0;
|
||||||
|
for(; i<n0; ++i)
|
||||||
|
if( noteMsgArray[i] != NULL )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for(i=0; i<n1; ++i)
|
||||||
|
if( pedalMsgArray[i] != NULL )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
double cmMidiFileDurSecs( cmMidiFileH_t h )
|
double cmMidiFileDurSecs( cmMidiFileH_t h )
|
||||||
{
|
{
|
||||||
_cmMidiFile_t* mfp = _cmMidiFileHandleToPtr(h);
|
_cmMidiFile_t* mfp = _cmMidiFileHandleToPtr(h);
|
||||||
@ -1544,14 +1603,6 @@ double cmMidiFileDurSecs( cmMidiFileH_t h )
|
|||||||
return msgV[ mfp->msgN-1 ]->amicro / 1000000.0;
|
return msgV[ mfp->msgN-1 ]->amicro / 1000000.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct _cmMidiVoice_str
|
|
||||||
{
|
|
||||||
const cmMidiTrackMsg_t* mp;
|
|
||||||
unsigned durMicros;
|
|
||||||
bool sustainFl;
|
|
||||||
struct _cmMidiVoice_str* link;
|
|
||||||
} _cmMidiVoice_t;
|
|
||||||
|
|
||||||
|
|
||||||
void _cmMidiFileSetDur( cmMidiTrackMsg_t* m0, cmMidiTrackMsg_t* m1 )
|
void _cmMidiFileSetDur( cmMidiTrackMsg_t* m0, cmMidiTrackMsg_t* m1 )
|
||||||
{
|
{
|
||||||
@ -1574,10 +1625,11 @@ bool _cmMidiFileCalcNoteDur( cmMidiTrackMsg_t* m0, cmMidiTrackMsg_t* m1, int not
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmMidiFileCalcNoteDurations( cmMidiFileH_t h )
|
void cmMidiFileCalcNoteDurations( cmMidiFileH_t h, unsigned flags )
|
||||||
{
|
{
|
||||||
_cmMidiFile_t* p;
|
_cmMidiFile_t* p;
|
||||||
|
bool warningFl = cmIsFlag(flags,kWarningsMfFl);
|
||||||
|
|
||||||
if((p = _cmMidiFileHandleToPtr(h)) == NULL )
|
if((p = _cmMidiFileHandleToPtr(h)) == NULL )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -1586,13 +1638,14 @@ void cmMidiFileCalcNoteDurations( cmMidiFileH_t h )
|
|||||||
|
|
||||||
unsigned mi = cmInvalidId;
|
unsigned mi = cmInvalidId;
|
||||||
cmMidiTrackMsg_t* noteM[ kMidiNoteCnt * kMidiChCnt ]; // ptr to note-on or NULL if the note is not sounding
|
cmMidiTrackMsg_t* noteM[ kMidiNoteCnt * kMidiChCnt ]; // ptr to note-on or NULL if the note is not sounding
|
||||||
cmMidiTrackMsg_t* sustV[ kMidiChCnt ];
|
cmMidiTrackMsg_t* sustV[ kMidiChCnt ]; // ptr to last sustain pedal down msg or NULL if susteain pedal is not down
|
||||||
cmMidiTrackMsg_t* sostV[ kMidiChCnt ];
|
cmMidiTrackMsg_t* sostV[ kMidiChCnt ]; // ptr to last sost. pedal down msg or NULL if sost. pedal is not down
|
||||||
int noteGateM[ kMidiNoteCnt * kMidiChCnt ]; // true if the associated note key is depressed
|
int noteGateM[ kMidiNoteCnt * kMidiChCnt ]; // true if the associated note key is depressed
|
||||||
bool sostGateM[ kMidiNoteCnt * kMidiChCnt ]; // true if the associated note was active when the sost. pedal went down
|
bool sostGateM[ kMidiNoteCnt * kMidiChCnt ]; // true if the associated note was active when the sost. pedal went down
|
||||||
int sustGateV[ kMidiChCnt]; // true if the associated sustain pedal is down
|
int sustGateV[ kMidiChCnt]; // true if the associated sustain pedal is down
|
||||||
int sostGateV[ kMidiChCnt]; // true if the associated sostenuto pedal is down
|
int sostGateV[ kMidiChCnt]; // true if the associated sostenuto pedal is down
|
||||||
unsigned i,j;
|
unsigned i,j;
|
||||||
|
unsigned n = 0;
|
||||||
|
|
||||||
const cmMidiTrackMsg_t** msgV = _cmMidiFileMsgArray(p);
|
const cmMidiTrackMsg_t** msgV = _cmMidiFileMsgArray(p);
|
||||||
|
|
||||||
@ -1634,12 +1687,22 @@ void cmMidiFileCalcNoteDurations( cmMidiFileH_t h )
|
|||||||
unsigned k = ch*kMidiNoteCnt + d0;
|
unsigned k = ch*kMidiNoteCnt + d0;
|
||||||
|
|
||||||
// there should be no existing sounding note instance for this pitch
|
// there should be no existing sounding note instance for this pitch
|
||||||
//if( noteGateM[k] == 0 && noteM[k] != NULL )
|
if( noteGateM[k] == 0 && noteM[k] != NULL )
|
||||||
// cmErrWarnMsg(&p->err,kMissingNoteOffMfRC,"%i : Missing note-off instance for note on:%s",m->uid,cmMidiToSciPitch(d0,NULL,0));
|
{
|
||||||
|
if( warningFl )
|
||||||
|
cmErrWarnMsg(&p->err,kMissingNoteOffMfRC,"%i : Missing note-off instance for note on:%s",m->uid,cmMidiToSciPitch(d0,NULL,0));
|
||||||
|
|
||||||
|
if( cmIsFlag(flags,kDropReattacksMfFl) )
|
||||||
|
{
|
||||||
|
m->flags |= kDropTrkMsgFl;
|
||||||
|
n += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// if this is a re-attack
|
||||||
if( noteM[k] != NULL )
|
if( noteM[k] != NULL )
|
||||||
noteGateM[k] += 1;
|
noteGateM[k] += 1;
|
||||||
else
|
else // this is a new attack
|
||||||
{
|
{
|
||||||
noteM[k] = m;
|
noteM[k] = m;
|
||||||
noteGateM[k] = 1;
|
noteGateM[k] = 1;
|
||||||
@ -1676,8 +1739,8 @@ void cmMidiFileCalcNoteDurations( cmMidiFileH_t h )
|
|||||||
if( cmMidiFileIsSustainPedalDown(m) )
|
if( cmMidiFileIsSustainPedalDown(m) )
|
||||||
{
|
{
|
||||||
// if the sustain channel is already down
|
// if the sustain channel is already down
|
||||||
//if( sustGateV[ch] )
|
if( warningFl && sustGateV[ch] )
|
||||||
// cmErrWarnMsg(&p->err,kSustainPedalMfRC,"%i : The sustain pedal went down twice with no intervening release.",m->uid);
|
cmErrWarnMsg(&p->err,kSustainPedalMfRC,"%i : The sustain pedal went down twice with no intervening release.",m->uid);
|
||||||
|
|
||||||
sustGateV[ch] += 1;
|
sustGateV[ch] += 1;
|
||||||
|
|
||||||
@ -1722,8 +1785,8 @@ void cmMidiFileCalcNoteDurations( cmMidiFileH_t h )
|
|||||||
if( cmMidiFileIsSostenutoPedalDown(m) )
|
if( cmMidiFileIsSostenutoPedalDown(m) )
|
||||||
{
|
{
|
||||||
// if the sustain channel is already down
|
// if the sustain channel is already down
|
||||||
//if( sostGateV[ch] )
|
if( warningFl && sostGateV[ch] )
|
||||||
// cmErrWarnMsg(&p->err,kSostenutoPedalMfRC,"%i : The sostenuto pedal went down twice with no intervening release.",m->uid);
|
cmErrWarnMsg(&p->err,kSostenutoPedalMfRC,"%i : The sostenuto pedal went down twice with no intervening release.",m->uid);
|
||||||
|
|
||||||
// record the notes that are active when the sostenuto pedal went down
|
// record the notes that are active when the sostenuto pedal went down
|
||||||
unsigned k = ch * kMidiNoteCnt;
|
unsigned k = ch * kMidiNoteCnt;
|
||||||
@ -1770,6 +1833,46 @@ void cmMidiFileCalcNoteDurations( cmMidiFileH_t h )
|
|||||||
}
|
}
|
||||||
|
|
||||||
} // for each midi file event
|
} // for each midi file event
|
||||||
|
|
||||||
|
|
||||||
|
if( warningFl )
|
||||||
|
{
|
||||||
|
unsigned sustChN = 0; // count of channels where the sustain pedal was left on at the end of the file
|
||||||
|
unsigned sostChN = 0; // sostenuto
|
||||||
|
unsigned sustInstN = 0; // count of sustain on with no previous sustain off
|
||||||
|
unsigned sostInstN = 0; // sostenuto on
|
||||||
|
unsigned noteN = 0; // count of notes left on at the end of the file
|
||||||
|
unsigned noteInstN = 0; // count of reattacks
|
||||||
|
|
||||||
|
// initialize the state tracking variables
|
||||||
|
for(i=0; i<kMidiChCnt; ++i)
|
||||||
|
{
|
||||||
|
if( sustV[i]!=NULL )
|
||||||
|
sustChN += 1;
|
||||||
|
|
||||||
|
sustInstN += sustGateV[i];
|
||||||
|
|
||||||
|
if( sostV[i] != NULL )
|
||||||
|
sostChN += 1;
|
||||||
|
|
||||||
|
sostInstN += sostGateV[i] = 0;
|
||||||
|
|
||||||
|
for(j=0; j<kMidiNoteCnt; ++j)
|
||||||
|
{
|
||||||
|
noteN += noteM[ i*kMidiNoteCnt + j ] != NULL;
|
||||||
|
noteInstN += noteGateM[ i*kMidiNoteCnt + j ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cmErrWarnMsg(&p->err,kEventTerminationMfRC,"note:%i inst:%i sustain: %i inst: %i sost: %i inst: %i",noteN,noteInstN,sustChN,sustInstN,sostChN,sostInstN);
|
||||||
|
}
|
||||||
|
|
||||||
|
// drop
|
||||||
|
if( cmIsFlag(flags,kDropReattacksMfFl) )
|
||||||
|
_cmMidiFileDrop(p);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmMidiFileSetDelay( cmMidiFileH_t h, unsigned ticks )
|
void cmMidiFileSetDelay( cmMidiFileH_t h, unsigned ticks )
|
||||||
@ -1833,15 +1936,16 @@ void _cmMidiFilePrintHdr( const _cmMidiFile_t* mfp, cmRpt_t* rpt )
|
|||||||
|
|
||||||
cmRptPrintf(rpt,"fmt:%i ticksPerQN:%i tracks:%i\n",mfp->fmtId,mfp->ticksPerQN,mfp->trkN);
|
cmRptPrintf(rpt,"fmt:%i ticksPerQN:%i tracks:%i\n",mfp->fmtId,mfp->ticksPerQN,mfp->trkN);
|
||||||
|
|
||||||
cmRptPrintf(rpt," UID dtick atick amicro type ch D0 D1\n");
|
cmRptPrintf(rpt," UID trk dtick atick amicro type ch D0 D1\n");
|
||||||
cmRptPrintf(rpt,"----- ---------- ---------- ---------- : ---- --- --- ---\n");
|
cmRptPrintf(rpt,"----- --- ---------- ---------- ---------- : ---- --- --- ---\n");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _cmMidiFilePrintMsg( cmRpt_t* rpt, const cmMidiTrackMsg_t* tmp )
|
void _cmMidiFilePrintMsg( cmRpt_t* rpt, const cmMidiTrackMsg_t* tmp )
|
||||||
{
|
{
|
||||||
cmRptPrintf(rpt,"%5i %10u %10llu %10llu : ",
|
cmRptPrintf(rpt,"%5i %3i %10u %10llu %10llu : ",
|
||||||
tmp->uid,
|
tmp->uid,
|
||||||
|
tmp->trkIdx,
|
||||||
tmp->dtick,
|
tmp->dtick,
|
||||||
tmp->atick,
|
tmp->atick,
|
||||||
tmp->amicro );
|
tmp->amicro );
|
||||||
@ -1980,7 +2084,7 @@ cmMfRC_t cmMidiFileGenPlotFile( cmCtx_t* ctx, const cmChar_t* midiFn, const cmCh
|
|||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmMidiFileCalcNoteDurations( mfH );
|
cmMidiFileCalcNoteDurations( mfH, 0 );
|
||||||
|
|
||||||
if( cmFileOpen(&fH,outFn,kWriteFileFl,p->err.rpt) != kOkFileRC )
|
if( cmFileOpen(&fH,outFn,kWriteFileFl,p->err.rpt) != kOkFileRC )
|
||||||
return cmErrMsg(&p->err,kFileFailMfRC,"Unable to create the file '%s'.",cmStringNullGuard(outFn));
|
return cmErrMsg(&p->err,kFileFailMfRC,"Unable to create the file '%s'.",cmStringNullGuard(outFn));
|
||||||
@ -2013,7 +2117,7 @@ cmMfRC_t cmMidiFileGenSvgFile( cmCtx_t* ctx, const cmChar_t* midiFn, const cmCha
|
|||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmMidiFileCalcNoteDurations( mfH );
|
cmMidiFileCalcNoteDurations( mfH, 0 );
|
||||||
|
|
||||||
msgN = cmMidiFileMsgCount(mfH);
|
msgN = cmMidiFileMsgCount(mfH);
|
||||||
msgs = cmMidiFileMsgArray(mfH);
|
msgs = cmMidiFileMsgArray(mfH);
|
||||||
@ -2159,7 +2263,7 @@ void cmMidiFileTest( const char* fn, cmCtx_t* ctx )
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmMidiFileCalcNoteDurations( h );
|
cmMidiFileCalcNoteDurations( h, 0 );
|
||||||
|
|
||||||
if( 1 )
|
if( 1 )
|
||||||
{
|
{
|
||||||
|
@ -63,11 +63,16 @@ extern "C" {
|
|||||||
struct cmMidiTrackMsg_str* end; // note-off or pedal-up message
|
struct cmMidiTrackMsg_str* end; // note-off or pedal-up message
|
||||||
} cmMidiChMsg_t;
|
} cmMidiChMsg_t;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
kDropTrkMsgFl = 0x01
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct cmMidiTrackMsg_str
|
typedef struct cmMidiTrackMsg_str
|
||||||
{
|
{
|
||||||
|
unsigned flags; // see k???TrkMsgFl
|
||||||
unsigned uid; // uid's are unique among all msg's in the file
|
unsigned uid; // uid's are unique among all msg's in the file
|
||||||
unsigned dtick; // delta ticks between events on this track
|
unsigned dtick; // delta ticks between events on this track (ticks between this event and the previous event on this track)
|
||||||
unsigned long long atick; // global (all tracks interleaved) accumulated ticks
|
unsigned long long atick; // global (all tracks interleaved) accumulated ticks
|
||||||
unsigned long long amicro; // global (all tracks interleaved) accumulated microseconds adjusted for tempo changes
|
unsigned long long amicro; // global (all tracks interleaved) accumulated microseconds adjusted for tempo changes
|
||||||
cmMidiByte_t status; // ch msg's have the channel value removed (it is stored in u.chMsgPtr->ch)
|
cmMidiByte_t status; // ch msg's have the channel value removed (it is stored in u.chMsgPtr->ch)
|
||||||
@ -91,9 +96,12 @@ extern "C" {
|
|||||||
} u;
|
} u;
|
||||||
} cmMidiTrackMsg_t;
|
} cmMidiTrackMsg_t;
|
||||||
|
|
||||||
#define cmMidiFileIsNoteOn(m) (cmMidiIsNoteOn((m)->status) && (m)->u.chMsgPtr->d1>0)
|
#define cmMidiFileIsNoteOn(m) (cmMidiIsNoteOn((m)->status) && ((m)->u.chMsgPtr->d1>0))
|
||||||
#define cmMidiFileIsNoteOff(m) (cmMidiIsNoteOff((m)->status,(m)->u.chMsgPtr->d1))
|
#define cmMidiFileIsNoteOff(m) (cmMidiIsNoteOff((m)->status,(m)->u.chMsgPtr->d1))
|
||||||
|
|
||||||
|
#define cmMidiFileIsPedalUp(m) (cmMidiIsPedalUp( (m)->status, (m)->u.chMsgPtr->d0, (m)->u.chMsgPtr->d1) )
|
||||||
|
#define cmMidiFileIsPedalDown(m) (cmMidiIsPedalDown( (m)->status, (m)->u.chMsgPtr->d0, (m)->u.chMsgPtr->d1) )
|
||||||
|
|
||||||
#define cmMidiFileIsSustainPedalUp(m) (cmMidiIsSustainPedalUp( (m)->status,(m)->u.chMsgPtr->d0,(m)->u.chMsgPtr->d1))
|
#define cmMidiFileIsSustainPedalUp(m) (cmMidiIsSustainPedalUp( (m)->status,(m)->u.chMsgPtr->d0,(m)->u.chMsgPtr->d1))
|
||||||
#define cmMidiFileIsSustainPedalDown(m) (cmMidiIsSustainPedalDown( (m)->status,(m)->u.chMsgPtr->d0,(m)->u.chMsgPtr->d1))
|
#define cmMidiFileIsSustainPedalDown(m) (cmMidiIsSustainPedalDown( (m)->status,(m)->u.chMsgPtr->d0,(m)->u.chMsgPtr->d1))
|
||||||
|
|
||||||
@ -118,7 +126,9 @@ extern "C" {
|
|||||||
kUidNotFoundMfRC, // 13
|
kUidNotFoundMfRC, // 13
|
||||||
kUidNotANoteMsgMfRC, // 14
|
kUidNotANoteMsgMfRC, // 14
|
||||||
kInvalidTrkIndexMfRC,// 15
|
kInvalidTrkIndexMfRC,// 15
|
||||||
kSvgFailMfRC // 16
|
kSvgFailMfRC, // 16
|
||||||
|
kMsgNotFoundMfRC, // 17
|
||||||
|
kEventTerminationMfRC // 18
|
||||||
};
|
};
|
||||||
|
|
||||||
extern cmMidiFileH_t cmMidiFileNullHandle;
|
extern cmMidiFileH_t cmMidiFileNullHandle;
|
||||||
@ -172,6 +182,7 @@ extern "C" {
|
|||||||
// Set the velocity of a note-on/off msg identified by 'uid'.
|
// Set the velocity of a note-on/off msg identified by 'uid'.
|
||||||
cmMfRC_t cmMidiFileSetVelocity( cmMidiFileH_t h, unsigned uid, cmMidiByte_t vel );
|
cmMfRC_t cmMidiFileSetVelocity( cmMidiFileH_t h, unsigned uid, cmMidiByte_t vel );
|
||||||
|
|
||||||
|
|
||||||
// Insert a MIDI message relative to the reference msg identified by 'uid'.
|
// Insert a MIDI message relative to the reference msg identified by 'uid'.
|
||||||
// If dtick is positive/negative then the new msg is inserted after/before the reference msg.
|
// If dtick is positive/negative then the new msg is inserted after/before the reference msg.
|
||||||
cmMfRC_t cmMidiFileInsertMsg( cmMidiFileH_t h, unsigned uid, int dtick, cmMidiByte_t ch, cmMidiByte_t status, cmMidiByte_t d0, cmMidiByte_t d1 );
|
cmMfRC_t cmMidiFileInsertMsg( cmMidiFileH_t h, unsigned uid, int dtick, cmMidiByte_t ch, cmMidiByte_t status, cmMidiByte_t d0, cmMidiByte_t d1 );
|
||||||
@ -199,8 +210,9 @@ extern "C" {
|
|||||||
|
|
||||||
double cmMidiFileDurSecs( cmMidiFileH_t h );
|
double cmMidiFileDurSecs( cmMidiFileH_t h );
|
||||||
|
|
||||||
// Calculate Note Duration
|
// Calculate Note Duration
|
||||||
void cmMidiFileCalcNoteDurations( cmMidiFileH_t h );
|
enum { kWarningsMfFl=0x01, kDropReattacksMfFl=0x02 };
|
||||||
|
void cmMidiFileCalcNoteDurations( cmMidiFileH_t h, unsigned flags );
|
||||||
|
|
||||||
// Set the delay prior to the first non-zero msg.
|
// Set the delay prior to the first non-zero msg.
|
||||||
void cmMidiFileSetDelay( cmMidiFileH_t h, unsigned ticks );
|
void cmMidiFileSetDelay( cmMidiFileH_t h, unsigned ticks );
|
||||||
@ -218,8 +230,7 @@ extern "C" {
|
|||||||
{
|
{
|
||||||
unsigned uid;
|
unsigned uid;
|
||||||
unsigned long long amicro;
|
unsigned long long amicro;
|
||||||
unsigned density;
|
unsigned density;
|
||||||
|
|
||||||
} cmMidiFileDensity_t;
|
} cmMidiFileDensity_t;
|
||||||
|
|
||||||
// Generate the note onset density measure for each note in the MIDI file.
|
// Generate the note onset density measure for each note in the MIDI file.
|
||||||
|
@ -650,6 +650,9 @@ cmXmlRC_t _cmXmlReadNode( cmXml_t* p, cmXmlNode_t* parent )
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( np==NULL && p->stack==NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
// if an end-tag was just read or node was created but closed then pop the stack
|
// if an end-tag was just read or node was created but closed then pop the stack
|
||||||
if( np==NULL || (np==p->stack && cmIsFlag(np->flags,kClosedXmlFl)) )
|
if( np==NULL || (np==p->stack && cmIsFlag(np->flags,kClosedXmlFl)) )
|
||||||
p->stack = p->stack->parent;
|
p->stack = p->stack->parent;
|
||||||
|
Loading…
Reference in New Issue
Block a user