cmMidiFile.h/c,cmMidiFilePlay.c : Added cmMidiFileCreate(), cmMidiFileInsertTrack???Msg(). Removed cmMidiFileIsNull() and _cmMidiFileMalloc().

This commit is contained in:
kevin 2016-07-20 19:17:44 -04:00
parent 9036de70ba
commit bf8f641d22
3 changed files with 196 additions and 72 deletions

View File

@ -54,10 +54,6 @@ _cmMidiFile_t* _cmMidiFileHandleToPtr( cmMidiFileH_t h )
return p;
}
void* _cmMidiFileMalloc( _cmMidiFile_t* mfp, unsigned byteN )
{ return cmLHeapAllocZ(mfp->lhH,byteN); }
cmMfRC_t _cmMidiFileRead8( _cmMidiFile_t* mfp, cmMidiByte_t* p )
{
if( cmFileReadUChar(mfp->fh,p,1) != kOkFileRC )
@ -107,7 +103,7 @@ cmMfRC_t _cmMidiFileReadText( _cmMidiFile_t* mfp, cmMidiTrackMsg_t* tmp, unsigne
if( byteN == 0 )
return kOkMfRC;
char* t = (char*)_cmMidiFileMalloc(mfp,byteN+1);
char* t = cmLhAllocZ(mfp->lhH,char,byteN+1);
t[byteN] = 0;
if( cmFileReadChar(mfp->fh,t,byteN) != kOkFileRC )
@ -120,7 +116,7 @@ cmMfRC_t _cmMidiFileReadText( _cmMidiFile_t* mfp, cmMidiTrackMsg_t* tmp, unsigne
cmMfRC_t _cmMidiFileReadRecd( _cmMidiFile_t* mfp, cmMidiTrackMsg_t* tmp, unsigned byteN )
{
char* t = (char*)_cmMidiFileMalloc(mfp,byteN);
char* t = cmLhAllocZ(mfp->lhH,char,byteN);
if( cmFileReadChar(mfp->fh,t,byteN) != kOkFileRC )
return cmErrMsg(&mfp->err,kFileFailMfRC,"MIDI read record failed.");
@ -160,7 +156,7 @@ cmMfRC_t _cmMidiFileReadVarLen( _cmMidiFile_t* mfp, unsigned* p )
cmMidiTrackMsg_t* _cmMidiFileAllocMsg( _cmMidiFile_t* mfp, unsigned short trkIdx, unsigned dtick, cmMidiByte_t status )
{
cmMidiTrackMsg_t* tmp = (cmMidiTrackMsg_t*)_cmMidiFileMalloc(mfp, sizeof(cmMidiTrackMsg_t) );
cmMidiTrackMsg_t* tmp = cmLhAllocZ(mfp->lhH,cmMidiTrackMsg_t, 1 );
// set the generic track record fields
tmp->dtick = dtick;
@ -226,7 +222,7 @@ cmMfRC_t _cmMidiFileReadSysEx( _cmMidiFile_t* mfp, cmMidiTrackMsg_t* tmp, unsign
}
// allocate memory to hold the sys-ex msg
cmMidiByte_t* mp = (cmMidiByte_t *)_cmMidiFileMalloc(mfp, byteN );
cmMidiByte_t* mp = cmLhAllocZ(mfp->lhH,cmMidiByte_t, byteN );
// read the sys-ex msg from the file into msg memory
if( cmFileReadUChar(mfp->fh,mp,byteN) != kOkFileRC )
@ -241,7 +237,7 @@ cmMfRC_t _cmMidiFileReadSysEx( _cmMidiFile_t* mfp, cmMidiTrackMsg_t* tmp, unsign
cmMfRC_t _cmMidiFileReadChannelMsg( _cmMidiFile_t* mfp, cmMidiByte_t* rsPtr, cmMidiByte_t status, cmMidiTrackMsg_t* tmp )
{
cmMfRC_t rc = kOkMfRC;
cmMidiChMsg_t* p = (cmMidiChMsg_t*)_cmMidiFileMalloc(mfp,sizeof(cmMidiChMsg_t));
cmMidiChMsg_t* p = cmLhAllocZ(mfp->lhH,cmMidiChMsg_t,1);
unsigned useRsFl = status <= 0x7f;
cmMidiByte_t statusCh = useRsFl ? *rsPtr : status;
@ -416,7 +412,7 @@ cmMfRC_t _cmMidiFileReadHdr( _cmMidiFile_t* mfp )
// allocate and zero the track array
if( mfp->trkN )
mfp->trkV = _cmMidiFileMalloc( mfp, sizeof(_cmMidiTrack_t)*mfp->trkN);
mfp->trkV = cmLhAllocZ(mfp->lhH, _cmMidiTrack_t, mfp->trkN);
return rc;
}
@ -565,69 +561,79 @@ void _cmMidiFileLinearize( _cmMidiFile_t* mfp )
}
cmMfRC_t cmMidiFileOpen( cmCtx_t* ctx, cmMidiFileH_t* hPtr, const char* fn )
cmMfRC_t _cmMidiFileCreate( cmCtx_t* ctx, cmMidiFileH_t* hp )
{
cmMfRC_t rc = kOkMfRC;
_cmMidiFile_t* mfp = NULL;
unsigned short trkIdx = 0;
cmErr_t err;
_cmMidiFile_t* p = NULL;
if( cmMidiFileIsValid(*hPtr) )
if((rc = _cmMidiFileClose(_cmMidiFileHandleToPtr(*hPtr))) != kOkMfRC )
if((rc = cmMidiFileClose(hp)) != kOkMfRC )
return rc;
cmErrSetup(&err,&ctx->rpt,"MIDI File");
// allocate the midi file object
if(( mfp = cmMemAllocZ( _cmMidiFile_t, 1)) == NULL )
return rc = cmErrMsg(&err,kMemAllocFailMfRC,"MIDI file memory allocation failed.");
if(( p = cmMemAllocZ( _cmMidiFile_t, 1)) == NULL )
return rc = cmErrMsg(&ctx->err,kMemAllocFailMfRC,"MIDI file memory allocation failed.");
cmErrClone(&mfp->err,&err);
cmErrSetup(&p->err,&ctx->rpt,"MIDI File");
// allocate the linked heap
if( cmLHeapIsValid( mfp->lhH = cmLHeapCreate( 1024, ctx )) == false )
{
rc = cmErrMsg(&err,kMemAllocFailMfRC,"MIDI heap allocation failed.");
goto errLabel;
}
if( cmLHeapIsValid( p->lhH = cmLHeapCreate( 1024, ctx )) == false )
rc = cmErrMsg(&p->err,kMemAllocFailMfRC,"MIDI heap allocation failed.");
if( rc != kOkMfRC )
_cmMidiFileClose(p);
else
hp->h = p;
return rc;
}
cmMfRC_t cmMidiFileOpen( cmCtx_t* ctx, cmMidiFileH_t* hp, const char* fn )
{
cmMfRC_t rc = kOkMfRC;
unsigned short trkIdx = 0;
if((rc = _cmMidiFileCreate(ctx,hp)) != kOkMfRC )
return rc;
_cmMidiFile_t* p = _cmMidiFileHandleToPtr(*hp);
// open the file
if(cmFileOpen(&mfp->fh,fn,kReadFileFl | kBinaryFileFl,mfp->err.rpt) != kOkFileRC )
if(cmFileOpen(&p->fh,fn,kReadFileFl | kBinaryFileFl,p->err.rpt) != kOkFileRC )
{
rc = cmErrMsg(&mfp->err,kFileFailMfRC,"MIDI file open failed.");
rc = cmErrMsg(&p->err,kFileFailMfRC,"MIDI file open failed.");
goto errLabel;
}
// read header and setup track array
if(( rc = _cmMidiFileReadHdr(mfp)) != kOkMfRC )
if(( rc = _cmMidiFileReadHdr(p)) != kOkMfRC )
goto errLabel;
while( !cmFileEof(mfp->fh) && trkIdx < mfp->trkN )
while( !cmFileEof(p->fh) && trkIdx < p->trkN )
{
unsigned chkId = 0,chkN=0;
// read the chunk id
if((rc = _cmMidiFileRead32(mfp,&chkId)) != kOkMfRC )
if((rc = _cmMidiFileRead32(p,&chkId)) != kOkMfRC )
goto errLabel;
// read the chunk size
if((rc = _cmMidiFileRead32(mfp,&chkN)) != kOkMfRC )
if((rc = _cmMidiFileRead32(p,&chkN)) != kOkMfRC )
goto errLabel;
// if this is not a trk chunk then skip it
if( chkId != (unsigned)'MTrk')
{
//if( fseek( mfp->fp, chkN, SEEK_CUR) != 0 )
if( cmFileSeek(mfp->fh,kCurFileFl,chkN) != kOkFileRC )
//if( fseek( p->fp, chkN, SEEK_CUR) != 0 )
if( cmFileSeek(p->fh,kCurFileFl,chkN) != kOkFileRC )
{
rc = cmErrMsg(&mfp->err,kFileFailMfRC,"MIDI file seek failed.");
rc = cmErrMsg(&p->err,kFileFailMfRC,"MIDI file seek failed.");
goto errLabel;
}
}
else
{
if((rc = _cmMidiFileReadTrack(mfp,trkIdx)) != kOkMfRC )
if((rc = _cmMidiFileReadTrack(p,trkIdx)) != kOkMfRC )
goto errLabel;
++trkIdx;
@ -635,38 +641,55 @@ cmMfRC_t cmMidiFileOpen( cmCtx_t* ctx, cmMidiFileH_t* hPtr, const char* fn )
}
// store the file name
mfp->fn = _cmMidiFileMalloc(mfp,strlen(fn)+1);
assert( mfp->fn != NULL );
strcpy(mfp->fn,fn);
p->fn = cmLhAllocZ(p->lhH,char,strlen(fn)+1);
assert( p->fn != NULL );
strcpy(p->fn,fn);
_cmMidiFileLinearize(mfp);
_cmMidiFileLinearize(p);
hPtr->h = mfp;
errLabel:
if( cmFileClose(&mfp->fh) != kOkFileRC )
rc = cmErrMsg(&mfp->err,kFileFailMfRC,"MIDI file close failed.");
if( cmFileClose(&p->fh) != kOkFileRC )
rc = cmErrMsg(&p->err,kFileFailMfRC,"MIDI file close failed.");
if( rc != kOkMfRC )
_cmMidiFileClose(mfp);
_cmMidiFileClose(p);
return rc;
}
cmMfRC_t cmMidiFileCreate( cmCtx_t* ctx, cmMidiFileH_t* hp, unsigned trkN, unsigned ticksPerQN )
{
cmMfRC_t rc = kOkMfRC;
if((rc = _cmMidiFileCreate(ctx,hp)) != kOkMfRC )
return rc;
_cmMidiFile_t* p = _cmMidiFileHandleToPtr(*hp);
p->ticksPerQN = ticksPerQN;
p->fmtId = 1;
p->trkN = trkN;
p->trkV = cmLhAllocZ(p->lhH, _cmMidiTrack_t, p->trkN);
return rc;
}
cmMfRC_t cmMidiFileClose( cmMidiFileH_t* h )
cmMfRC_t cmMidiFileClose( cmMidiFileH_t* hp )
{
cmMfRC_t rc;
cmMfRC_t rc = kOkMfRC;
if( cmMidiFileIsNull(*h) )
if( hp==NULL || cmMidiFileIsValid(*hp)==false )
return kOkMfRC;
if((rc = _cmMidiFileClose(_cmMidiFileHandleToPtr(*h))) == kOkMfRC )
_cmMidiFile_t* p = _cmMidiFileHandleToPtr(*hp);
if((rc = _cmMidiFileClose(p)) != kOkMfRC )
return rc;
h->h = NULL;
hp->h = NULL;
return rc;
}
@ -1013,7 +1036,7 @@ cmMfRC_t cmMidiFileWrite( cmMidiFileH_t h, const char* fn )
bool cmMidiFileIsValid( cmMidiFileH_t h )
{ return !cmMidiFileIsNull(h); }
{ return h.h != NULL; }
unsigned cmMidiFileTrackCount( cmMidiFileH_t h )
{
@ -1220,7 +1243,7 @@ cmMfRC_t cmMidiFileInsertMsg( cmMidiFileH_t h, unsigned uid, int dtick, cmMidiBy
// complete the msg setup
_cmMidiTrack_t* trk = mfp->trkV + trkIdx;
cmMidiTrackMsg_t* m = _cmMidiFileAllocMsg(mfp, trkIdx, abs(dtick), status );
cmMidiChMsg_t* c = (cmMidiChMsg_t*)_cmMidiFileMalloc(mfp,sizeof(cmMidiChMsg_t));
cmMidiChMsg_t* c = cmLhAllocZ(mfp->lhH,cmMidiChMsg_t,1);
m->u.chMsgPtr = c;
@ -1255,6 +1278,105 @@ cmMfRC_t cmMidiFileInsertMsg( cmMidiFileH_t h, unsigned uid, int dtick, cmMidiBy
}
// Only set
// atick - used to position the msg in the track
// status - this field is always set (Note that channel information must stripped from the status byte and included in the channel msg data)
// metaId - this field is optional depending on the msg type
// byteCnt - used to allocate storage for the data element in 'cmMidiTrackMsg_t.u'
// u - the message data
cmMfRC_t cmMidiFileInsertTrackMsg( cmMidiFileH_t h, unsigned trkIdx, const cmMidiTrackMsg_t* msg )
{
_cmMidiFile_t* p = _cmMidiFileHandleToPtr(h);
// validate the track index
if( trkIdx >= p->trkN )
return cmErrMsg(&p->err,kInvalidTrkIndexMfRC,"The track index (%i) is invalid.",trkIdx);
// allocate a new track record
cmMidiTrackMsg_t* m = (cmMidiTrackMsg_t*)cmLhAllocZ(p->lhH,char,sizeof(cmMidiTrackMsg_t)+msg->byteCnt);
// fill the track record
m->uid = p->nextUid++;
m->atick = msg->atick;
m->status = msg->status;
m->metaId = msg->metaId;
m->trkIdx = trkIdx;
m->byteCnt = msg->byteCnt;
memcpy(&m->u,&msg->u,sizeof(msg->u));
// copy the exernal data
if( msg->byteCnt > 0 )
{
m->u.voidPtr = (m+1);
memcpy((void*)m->u.voidPtr,msg->u.voidPtr,msg->byteCnt);
}
cmMidiTrackMsg_t* m0 = NULL;
cmMidiTrackMsg_t* m1 = p->trkV[trkIdx].base;
// locate the track record before and after the new msg
for(; m1!=NULL; m1=m1->link)
if( m1->atick > m->atick )
{
if( m0 == NULL )
p->trkV[trkIdx].base = m;
else
m0->link = m;
m->link = m1;
break;
}
// the new track record is the last msg
if( m1 == NULL )
{
m1 = p->trkV[trkIdx].last;
m1->link = m;
p->trkV[trkIdx].last = m;
if( p->trkV[trkIdx].base == NULL )
p->trkV[trkIdx].base = m;
}
return kOkMfRC;
}
cmMfRC_t cmMidiFileInsertTrackChMsg( cmMidiFileH_t h, unsigned trkIdx, unsigned atick, cmMidiByte_t status, cmMidiByte_t d0, cmMidiByte_t d1 )
{
cmMidiTrackMsg_t m;
cmMidiChMsg_t cm;
memset(&m,0,sizeof(m));
memset(&cm,0,sizeof(cm));
cm.ch = status & 0x0f;
cm.d0 = d0;
cm.d1 = d1;
m.atick = atick;
m.status = status & 0xf0;
m.byteCnt = sizeof(cm);
m.u.chMsgPtr = &cm;
return cmMidiFileInsertTrackMsg(h,trkIdx,&m);
}
cmMfRC_t cmMidFileInsertTrackTempoMsg( cmMidiFileH_t h, unsigned trkIdx, unsigned atick, unsigned bpm )
{
cmMidiTrackMsg_t m;
memset(&m,0,sizeof(m));
m.atick = atick;
m.status = kMetaStId;
m.metaId = kTempoMdId;
m.u.iVal = 60000000/bpm; // convert BPM to microsPerQN
return cmMidiFileInsertTrackMsg(h,trkIdx,&m);
}
unsigned cmMidiFileSeekUsecs( cmMidiFileH_t h, unsigned long long offsUSecs, unsigned* msgUsecsPtr, unsigned* microsPerTickPtr )
{
_cmMidiFile_t* p;
@ -1657,9 +1779,6 @@ void cmMidiFilePrintTracks( cmMidiFileH_t h, unsigned trkIdx, cmRpt_t* rpt )
}
}
bool cmMidiFileIsNull( cmMidiFileH_t h )
{ return (_cmMidiFile_t*)h.h == NULL; }
void cmMidiFileTestPrint( void* printDataPtr, const char* fmt, va_list vl )
{ vprintf(fmt,vl); }

View File

@ -116,12 +116,14 @@ extern "C" {
kSostenutoPedalMfRC, // 11
kLargeDeltaTickMfRC, // 12 (a large delta tick value was filtered)
kUidNotFoundMfRC, // 13
kUidNotANoteMsgMfRC // 14
kUidNotANoteMsgMfRC, // 14
kInvalidTrkIndexMfRC // 15
};
extern cmMidiFileH_t cmMidiFileNullHandle;
cmMfRC_t cmMidiFileOpen( cmCtx_t* ctx, cmMidiFileH_t* hPtr, const char* fn );
cmMfRC_t cmMidiFileOpen( cmCtx_t* ctx, cmMidiFileH_t* h, const char* fn );
cmMfRC_t cmMidiFileCreate( cmCtx_t* ctx, cmMidiFileH_t* hp, unsigned trkN, unsigned ticksPerQN );
cmMfRC_t cmMidiFileClose( cmMidiFileH_t* hp );
cmMfRC_t cmMidiFileWrite( cmMidiFileH_t h, const char* fn );
@ -168,6 +170,10 @@ extern "C" {
// 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 cmMidiFileInsertTrackMsg( cmMidiFileH_t h, unsigned trkIdx, const cmMidiTrackMsg_t* msg );
cmMfRC_t cmMidiFileInsertTrackChMsg( cmMidiFileH_t h, unsigned trkIdx, unsigned atick, cmMidiByte_t status, cmMidiByte_t d0, cmMidiByte_t d1 );
cmMfRC_t cmMidFileInsertTrackTempoMsg( cmMidiFileH_t h, unsigned trkIdx, unsigned atick, unsigned bpm );
// Return a pointer to the first msg at or after 'usecsOffs' or kInvalidIdx if no
// msg exists after 'usecsOffs'. Note that 'usecOffs' is an offset from the beginning
// of the file.
@ -191,7 +197,6 @@ extern "C" {
void cmMidiFilePrintMsgs( cmMidiFileH_t h, cmRpt_t* rpt );
void cmMidiFilePrintTrack( cmMidiFileH_t h, unsigned trkIdx, cmRpt_t* rpt );
bool cmMidiFileIsNull( cmMidiFileH_t h );
void cmMidiFileTest( const char* fn, cmCtx_t* ctx );
// Generate a piano-roll plot description file which can be displayed with cmXScore.m

View File

@ -88,7 +88,7 @@ cmMfpRC_t cmMfpDestroy( cmMfpH_t* hp )
{
cmMfp_t* p = _cmMfpHandleToPtr(*hp);
if( cmMidiFileIsNull(p->mfH)==false && p->closeFileFl==true )
if( cmMidiFileIsValid(p->mfH)==false && p->closeFileFl==true )
cmMidiFileClose(&p->mfH);
cmMemFree(p);
@ -121,7 +121,7 @@ cmMfpRC_t cmMfpLoadHandle( cmMfpH_t h, cmMidiFileH_t mfH )
cmMfp_t* p = _cmMfpHandleToPtr(h);
// if a file has already been assigned to this player
if( (cmMidiFileIsNull(p->mfH) == false) && p->closeFileFl)
if( (cmMidiFileIsValid(p->mfH) == false) && p->closeFileFl)
{
// close the existing file
cmMidiFileClose(&p->mfH);