cmMidiFile.h/c : Added cmMidiFileInsertMsg() Also rearranged code to isolate
cmMidiTrackMsg_t allocation. These changes are not yet tested.
This commit is contained in:
parent
21d13a94fd
commit
5cde332add
249
cmMidiFile.c
249
cmMidiFile.c
@ -19,8 +19,6 @@
|
|||||||
#define mfSwap32(v) cmSwap32(v)
|
#define mfSwap32(v) cmSwap32(v)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
unsigned cnt; // count of track records
|
unsigned cnt; // count of track records
|
||||||
@ -160,10 +158,25 @@ cmMfRC_t _cmMidiFileReadVarLen( _cmMidiFile_t* mfp, unsigned* p )
|
|||||||
return kOkMfRC;
|
return kOkMfRC;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmMfRC_t _cmMidiFileAppendTrackMsg( _cmMidiFile_t* mfp, unsigned short trkIdx, unsigned dtick, cmMidiByte_t status, cmMidiTrackMsg_t** trkMsgPtrPtr )
|
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 = (cmMidiTrackMsg_t*)_cmMidiFileMalloc(mfp, sizeof(cmMidiTrackMsg_t) );
|
||||||
|
|
||||||
|
// set the generic track record fields
|
||||||
|
tmp->dtick = dtick;
|
||||||
|
tmp->status = status;
|
||||||
|
tmp->metaId = kInvalidMetaMdId;
|
||||||
|
tmp->trkIdx = trkIdx;
|
||||||
|
tmp->byteCnt = 0;
|
||||||
|
tmp->uid = mfp->nextUid++;
|
||||||
|
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmMfRC_t _cmMidiFileAppendTrackMsg( _cmMidiFile_t* mfp, unsigned short trkIdx, unsigned dtick, cmMidiByte_t status, cmMidiTrackMsg_t** trkMsgPtrPtr )
|
||||||
|
{
|
||||||
|
cmMidiTrackMsg_t* tmp = _cmMidiFileAllocMsg( mfp, trkIdx, dtick, status );
|
||||||
|
|
||||||
// link new record onto track record chain
|
// link new record onto track record chain
|
||||||
if( mfp->trkV[trkIdx].base == NULL )
|
if( mfp->trkV[trkIdx].base == NULL )
|
||||||
mfp->trkV[trkIdx].base = tmp;
|
mfp->trkV[trkIdx].base = tmp;
|
||||||
@ -174,12 +187,6 @@ cmMfRC_t _cmMidiFileAppendTrackMsg( _cmMidiFile_t* mfp, unsigned short trkIdx, u
|
|||||||
mfp->trkV[trkIdx].cnt++;
|
mfp->trkV[trkIdx].cnt++;
|
||||||
|
|
||||||
|
|
||||||
// set the generic track record fields
|
|
||||||
tmp->dtick = dtick;
|
|
||||||
tmp->status = status;
|
|
||||||
tmp->metaId = kInvalidMetaMdId;
|
|
||||||
tmp->trkIdx = trkIdx;
|
|
||||||
tmp->byteCnt = 0;
|
|
||||||
*trkMsgPtrPtr = tmp;
|
*trkMsgPtrPtr = tmp;
|
||||||
|
|
||||||
return kOkMfRC;
|
return kOkMfRC;
|
||||||
@ -521,6 +528,43 @@ cmMfRC_t _cmMidiFileClose( _cmMidiFile_t* mfp )
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _cmMidiFileLinearize( _cmMidiFile_t* mfp )
|
||||||
|
{
|
||||||
|
unsigned trkIdx,i,j;
|
||||||
|
|
||||||
|
// get the total trk msg count
|
||||||
|
mfp->msgN = 0;
|
||||||
|
for(trkIdx=0; trkIdx<mfp->trkN; ++trkIdx)
|
||||||
|
mfp->msgN += mfp->trkV[ trkIdx ].cnt;
|
||||||
|
|
||||||
|
// allocate the trk msg index vector: msgV[]
|
||||||
|
mfp->msgV = cmMemResizeZ(cmMidiTrackMsg_t*, mfp->msgV, mfp->msgN);
|
||||||
|
|
||||||
|
// store a pointer to every trk msg in msgV[]
|
||||||
|
for(i=0,j=0; i<mfp->trkN; ++i)
|
||||||
|
{
|
||||||
|
cmMidiTrackMsg_t* m = mfp->trkV[i].base;
|
||||||
|
|
||||||
|
for(; m!=NULL; m=m->link)
|
||||||
|
{
|
||||||
|
assert( j < mfp->msgN );
|
||||||
|
|
||||||
|
mfp->msgV[j++] = m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// set the atick value in each msg
|
||||||
|
_cmMidiFileSetAccumulateTicks(mfp);
|
||||||
|
|
||||||
|
// sort msgV[] in ascending order on atick
|
||||||
|
qsort( mfp->msgV, mfp->msgN, sizeof(cmMidiTrackMsg_t*), _cmMidiFileSortFunc );
|
||||||
|
|
||||||
|
// set the amicro value in each msg
|
||||||
|
_cmMidiFileSetAbsoluteTime(mfp);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
cmMfRC_t cmMidiFileOpen( cmCtx_t* ctx, cmMidiFileH_t* hPtr, const char* fn )
|
cmMfRC_t cmMidiFileOpen( cmCtx_t* ctx, cmMidiFileH_t* hPtr, const char* fn )
|
||||||
{
|
{
|
||||||
@ -528,7 +572,6 @@ cmMfRC_t cmMidiFileOpen( cmCtx_t* ctx, cmMidiFileH_t* hPtr, const char* fn )
|
|||||||
_cmMidiFile_t* mfp = NULL;
|
_cmMidiFile_t* mfp = NULL;
|
||||||
unsigned short trkIdx = 0;
|
unsigned short trkIdx = 0;
|
||||||
cmErr_t err;
|
cmErr_t err;
|
||||||
unsigned i,j;
|
|
||||||
|
|
||||||
if( cmMidiFileIsValid(*hPtr) )
|
if( cmMidiFileIsValid(*hPtr) )
|
||||||
if((rc = _cmMidiFileClose(_cmMidiFileHandleToPtr(*hPtr))) != kOkMfRC )
|
if((rc = _cmMidiFileClose(_cmMidiFileHandleToPtr(*hPtr))) != kOkMfRC )
|
||||||
@ -538,7 +581,7 @@ cmMfRC_t cmMidiFileOpen( cmCtx_t* ctx, cmMidiFileH_t* hPtr, const char* fn )
|
|||||||
|
|
||||||
// allocate the midi file object
|
// allocate the midi file object
|
||||||
if(( mfp = cmMemAllocZ( _cmMidiFile_t, 1)) == NULL )
|
if(( mfp = cmMemAllocZ( _cmMidiFile_t, 1)) == NULL )
|
||||||
return rc = cmErrMsg(&err,kMemAllocFailMfRC,"MIDI file memory allocation failed.");
|
return rc = cmErrMsg(&err,kMemAllocFailMfRC,"MIDI file memory allocation failed.");
|
||||||
|
|
||||||
cmErrClone(&mfp->err,&err);
|
cmErrClone(&mfp->err,&err);
|
||||||
|
|
||||||
@ -562,7 +605,7 @@ cmMfRC_t cmMidiFileOpen( cmCtx_t* ctx, cmMidiFileH_t* hPtr, const char* fn )
|
|||||||
|
|
||||||
while( !cmFileEof(mfp->fh) && trkIdx < mfp->trkN )
|
while( !cmFileEof(mfp->fh) && trkIdx < mfp->trkN )
|
||||||
{
|
{
|
||||||
unsigned chkId=0,chkN=0;
|
unsigned chkId = 0,chkN=0;
|
||||||
|
|
||||||
// read the chunk id
|
// read the chunk id
|
||||||
if((rc = _cmMidiFileRead32(mfp,&chkId)) != kOkMfRC )
|
if((rc = _cmMidiFileRead32(mfp,&chkId)) != kOkMfRC )
|
||||||
@ -591,43 +634,12 @@ cmMfRC_t cmMidiFileOpen( cmCtx_t* ctx, cmMidiFileH_t* hPtr, const char* fn )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the total trk msg count
|
// store the file name
|
||||||
mfp->msgN = 0;
|
mfp->fn = _cmMidiFileMalloc(mfp,strlen(fn)+1);
|
||||||
for(trkIdx=0; trkIdx<mfp->trkN; ++trkIdx)
|
|
||||||
mfp->msgN += mfp->trkV[ trkIdx ].cnt;
|
|
||||||
|
|
||||||
// allocate the trk msg index vector: msgV[]
|
|
||||||
mfp->msgV = cmMemAllocZ(cmMidiTrackMsg_t*, mfp->msgN);
|
|
||||||
|
|
||||||
mfp->nextUid = 0;
|
|
||||||
|
|
||||||
// store a pointer to every trk msg in msgV[] and set 'uid'
|
|
||||||
for(i=0,j=0; i<mfp->trkN; ++i)
|
|
||||||
{
|
|
||||||
cmMidiTrackMsg_t* m = mfp->trkV[i].base;
|
|
||||||
|
|
||||||
for(; m!=NULL; m=m->link)
|
|
||||||
{
|
|
||||||
assert( j < mfp->msgN );
|
|
||||||
|
|
||||||
mfp->msgV[j++] = m;
|
|
||||||
m->uid = mfp->nextUid++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mfp->fn = _cmMidiFileMalloc(mfp,strlen(fn)+1);
|
|
||||||
assert( mfp->fn != NULL );
|
assert( mfp->fn != NULL );
|
||||||
strcpy(mfp->fn,fn);
|
strcpy(mfp->fn,fn);
|
||||||
|
|
||||||
|
_cmMidiFileLinearize(mfp);
|
||||||
// set the atick value in each msg
|
|
||||||
_cmMidiFileSetAccumulateTicks(mfp);
|
|
||||||
|
|
||||||
// sort msgV[] in ascending order on atick
|
|
||||||
qsort( mfp->msgV, mfp->msgN, sizeof(cmMidiTrackMsg_t*), _cmMidiFileSortFunc );
|
|
||||||
|
|
||||||
// set the amicro value in each msg
|
|
||||||
_cmMidiFileSetAbsoluteTime(mfp);
|
|
||||||
|
|
||||||
hPtr->h = mfp;
|
hPtr->h = mfp;
|
||||||
|
|
||||||
@ -682,11 +694,11 @@ cmMfRC_t _cmMidiFileWrite16( _cmMidiFile_t* mfp, unsigned short v )
|
|||||||
|
|
||||||
cmMfRC_t _cmMidiFileWrite24( _cmMidiFile_t* mfp, unsigned v )
|
cmMfRC_t _cmMidiFileWrite24( _cmMidiFile_t* mfp, unsigned v )
|
||||||
{
|
{
|
||||||
cmMfRC_t rc = kOkMfRC;
|
cmMfRC_t rc = kOkMfRC;
|
||||||
unsigned mask = 0xff0000;
|
unsigned mask = 0xff0000;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i=2; i>=0; --i)
|
for(i = 2; i>=0; --i)
|
||||||
{
|
{
|
||||||
unsigned char c = (v & mask) >> (i*8);
|
unsigned char c = (v & mask) >> (i*8);
|
||||||
mask >>= 8;
|
mask >>= 8;
|
||||||
@ -727,7 +739,7 @@ cmMfRC_t _cmMidiFileWriteRecd( _cmMidiFile_t* mfp, const void* v, unsigned byteC
|
|||||||
|
|
||||||
cmMfRC_t _cmMidiFileWriteVarLen( _cmMidiFile_t* mfp, unsigned v )
|
cmMfRC_t _cmMidiFileWriteVarLen( _cmMidiFile_t* mfp, unsigned v )
|
||||||
{
|
{
|
||||||
cmMfRC_t rc = kOkMfRC;
|
cmMfRC_t rc = kOkMfRC;
|
||||||
unsigned buf = v & 0x7f;
|
unsigned buf = v & 0x7f;
|
||||||
|
|
||||||
while((v >>= 7) > 0 )
|
while((v >>= 7) > 0 )
|
||||||
@ -786,7 +798,7 @@ cmMfRC_t _cmMidiFileWriteHdr( _cmMidiFile_t* mfp )
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// ... otherwise the division field was given in smpte
|
// ... otherwise the division field was given in smpte
|
||||||
v = mfp->smpteFmtId << 8;
|
v = mfp->smpteFmtId << 8;
|
||||||
v += mfp->smpteTicksPerFrame;
|
v += mfp->smpteTicksPerFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -800,7 +812,7 @@ cmMfRC_t _cmMidiFileWriteHdr( _cmMidiFile_t* mfp )
|
|||||||
|
|
||||||
cmMfRC_t _cmMidiFileWriteSysEx( _cmMidiFile_t* mfp, cmMidiTrackMsg_t* tmp )
|
cmMfRC_t _cmMidiFileWriteSysEx( _cmMidiFile_t* mfp, cmMidiTrackMsg_t* tmp )
|
||||||
{
|
{
|
||||||
cmMfRC_t rc = kOkMfRC;
|
cmMfRC_t rc = kOkMfRC;
|
||||||
|
|
||||||
if((rc = _cmMidiFileWrite8(mfp,kSysExMdId)) != kOkMfRC )
|
if((rc = _cmMidiFileWrite8(mfp,kSysExMdId)) != kOkMfRC )
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
@ -814,8 +826,8 @@ cmMfRC_t _cmMidiFileWriteSysEx( _cmMidiFile_t* mfp, cmMidiTrackMsg_t* tmp )
|
|||||||
|
|
||||||
cmMfRC_t _cmMidiFileWriteChannelMsg( _cmMidiFile_t* mfp, const cmMidiTrackMsg_t* tmp, cmMidiByte_t* runStatus )
|
cmMfRC_t _cmMidiFileWriteChannelMsg( _cmMidiFile_t* mfp, const cmMidiTrackMsg_t* tmp, cmMidiByte_t* runStatus )
|
||||||
{
|
{
|
||||||
cmMfRC_t rc = kOkMfRC;
|
cmMfRC_t rc = kOkMfRC;
|
||||||
unsigned byteN = cmMidiStatusToByteCount(tmp->status);
|
unsigned byteN = cmMidiStatusToByteCount(tmp->status);
|
||||||
cmMidiByte_t status = tmp->status + tmp->u.chMsgPtr->ch;
|
cmMidiByte_t status = tmp->status + tmp->u.chMsgPtr->ch;
|
||||||
|
|
||||||
if( status != *runStatus )
|
if( status != *runStatus )
|
||||||
@ -839,7 +851,7 @@ cmMfRC_t _cmMidiFileWriteChannelMsg( _cmMidiFile_t* mfp, const cmMidiTrackMsg_t*
|
|||||||
|
|
||||||
cmMfRC_t _cmMidiFileWriteMetaMsg( _cmMidiFile_t* mfp, const cmMidiTrackMsg_t* tmp )
|
cmMfRC_t _cmMidiFileWriteMetaMsg( _cmMidiFile_t* mfp, const cmMidiTrackMsg_t* tmp )
|
||||||
{
|
{
|
||||||
cmMfRC_t rc;
|
cmMfRC_t rc;
|
||||||
|
|
||||||
if((rc = _cmMidiFileWrite8(mfp,kMetaStId)) != kOkMfRC )
|
if((rc = _cmMidiFileWrite8(mfp,kMetaStId)) != kOkMfRC )
|
||||||
return rc;
|
return rc;
|
||||||
@ -852,7 +864,7 @@ cmMfRC_t _cmMidiFileWriteMetaMsg( _cmMidiFile_t* mfp, const cmMidiTrackMsg_t* tm
|
|||||||
{
|
{
|
||||||
case kSeqNumbMdId:
|
case kSeqNumbMdId:
|
||||||
if((rc = _cmMidiFileWrite8(mfp,sizeof(tmp->u.sVal))) == kOkMfRC )
|
if((rc = _cmMidiFileWrite8(mfp,sizeof(tmp->u.sVal))) == kOkMfRC )
|
||||||
rc = _cmMidiFileWrite16(mfp,tmp->u.sVal);
|
rc = _cmMidiFileWrite16(mfp,tmp->u.sVal);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kTempoMdId:
|
case kTempoMdId:
|
||||||
@ -862,27 +874,27 @@ cmMfRC_t _cmMidiFileWriteMetaMsg( _cmMidiFile_t* mfp, const cmMidiTrackMsg_t* tm
|
|||||||
|
|
||||||
case kSmpteMdId:
|
case kSmpteMdId:
|
||||||
if((rc = _cmMidiFileWrite8(mfp,sizeof(cmMidiSmpte_t))) == kOkMfRC )
|
if((rc = _cmMidiFileWrite8(mfp,sizeof(cmMidiSmpte_t))) == kOkMfRC )
|
||||||
rc = _cmMidiFileWriteRecd(mfp,tmp->u.smptePtr,sizeof(cmMidiSmpte_t));
|
rc = _cmMidiFileWriteRecd(mfp,tmp->u.smptePtr,sizeof(cmMidiSmpte_t));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kTimeSigMdId:
|
case kTimeSigMdId:
|
||||||
if((rc = _cmMidiFileWrite8(mfp,sizeof(cmMidiTimeSig_t))) == kOkMfRC )
|
if((rc = _cmMidiFileWrite8(mfp,sizeof(cmMidiTimeSig_t))) == kOkMfRC )
|
||||||
rc = _cmMidiFileWriteRecd(mfp,tmp->u.timeSigPtr,sizeof(cmMidiTimeSig_t));
|
rc = _cmMidiFileWriteRecd(mfp,tmp->u.timeSigPtr,sizeof(cmMidiTimeSig_t));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kKeySigMdId:
|
case kKeySigMdId:
|
||||||
if((rc = _cmMidiFileWrite8(mfp,sizeof(cmMidiKeySig_t))) == kOkMfRC )
|
if((rc = _cmMidiFileWrite8(mfp,sizeof(cmMidiKeySig_t))) == kOkMfRC )
|
||||||
rc = _cmMidiFileWriteRecd(mfp,tmp->u.keySigPtr,sizeof(cmMidiKeySig_t));
|
rc = _cmMidiFileWriteRecd(mfp,tmp->u.keySigPtr,sizeof(cmMidiKeySig_t));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kSeqSpecMdId:
|
case kSeqSpecMdId:
|
||||||
if((rc = _cmMidiFileWriteVarLen(mfp,sizeof(tmp->byteCnt))) == kOkMfRC )
|
if((rc = _cmMidiFileWriteVarLen(mfp,sizeof(tmp->byteCnt))) == kOkMfRC )
|
||||||
rc = _cmMidiFileWriteRecd(mfp,tmp->u.sysExPtr,tmp->byteCnt);
|
rc = _cmMidiFileWriteRecd(mfp,tmp->u.sysExPtr,tmp->byteCnt);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kMidiChMdId:
|
case kMidiChMdId:
|
||||||
if((rc = _cmMidiFileWrite8(mfp,sizeof(tmp->u.bVal))) == kOkMfRC )
|
if((rc = _cmMidiFileWrite8(mfp,sizeof(tmp->u.bVal))) == kOkMfRC )
|
||||||
rc = _cmMidiFileWrite8(mfp,tmp->u.bVal);
|
rc = _cmMidiFileWrite8(mfp,tmp->u.bVal);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kEndOfTrkMdId:
|
case kEndOfTrkMdId:
|
||||||
@ -898,8 +910,8 @@ cmMfRC_t _cmMidiFileWriteMetaMsg( _cmMidiFile_t* mfp, const cmMidiTrackMsg_t* tm
|
|||||||
case kCuePointMdId:
|
case kCuePointMdId:
|
||||||
{
|
{
|
||||||
unsigned n = tmp->u.text==NULL ? 0 : strlen(tmp->u.text);
|
unsigned n = tmp->u.text==NULL ? 0 : strlen(tmp->u.text);
|
||||||
if((rc = _cmMidiFileWriteVarLen(mfp,n)) == kOkMfRC && n>0 )
|
if((rc = _cmMidiFileWriteVarLen(mfp,n)) == kOkMfRC && n>0 )
|
||||||
rc = _cmMidiFileWriteRecd(mfp,tmp->u.text,n);
|
rc = _cmMidiFileWriteRecd(mfp,tmp->u.text,n);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -915,11 +927,11 @@ cmMfRC_t _cmMidiFileWriteMetaMsg( _cmMidiFile_t* mfp, const cmMidiTrackMsg_t* tm
|
|||||||
|
|
||||||
cmMfRC_t _cmMidiFileWriteTrack( _cmMidiFile_t* mfp, unsigned trkIdx )
|
cmMfRC_t _cmMidiFileWriteTrack( _cmMidiFile_t* mfp, unsigned trkIdx )
|
||||||
{
|
{
|
||||||
cmMfRC_t rc = kOkMfRC;
|
cmMfRC_t rc = kOkMfRC;
|
||||||
cmMidiTrackMsg_t* tmp = mfp->trkV[trkIdx].base;
|
cmMidiTrackMsg_t* tmp = mfp->trkV[trkIdx].base;
|
||||||
cmMidiByte_t runStatus = 0;
|
cmMidiByte_t runStatus = 0;
|
||||||
|
|
||||||
for(; tmp!=NULL; tmp=tmp->link)
|
for(; tmp != NULL; tmp=tmp->link)
|
||||||
{
|
{
|
||||||
// write the msg tick count
|
// write the msg tick count
|
||||||
if((rc = _cmMidiFileWriteVarLen(mfp,tmp->dtick)) != kOkMfRC )
|
if((rc = _cmMidiFileWriteVarLen(mfp,tmp->dtick)) != kOkMfRC )
|
||||||
@ -968,8 +980,8 @@ cmMfRC_t cmMidiFileWrite( cmMidiFileH_t h, const char* fn )
|
|||||||
|
|
||||||
for(i=0; i < mfp->trkN; ++i )
|
for(i=0; i < mfp->trkN; ++i )
|
||||||
{
|
{
|
||||||
unsigned chkId='MTrk';
|
unsigned chkId = 'MTrk';
|
||||||
long offs0,offs1;
|
long offs0,offs1;
|
||||||
|
|
||||||
// write the track chunk id ('MTrk')
|
// write the track chunk id ('MTrk')
|
||||||
if((rc = _cmMidiFileWrite32(mfp,chkId)) != kOkMfRC )
|
if((rc = _cmMidiFileWrite32(mfp,chkId)) != kOkMfRC )
|
||||||
@ -1124,14 +1136,14 @@ cmMidiTrackMsg_t* _cmMidiFileUidToMsg( _cmMidiFile_t* mfp, unsigned uid )
|
|||||||
cmMfRC_t cmMidiFileSetVelocity( cmMidiFileH_t h, unsigned uid, cmMidiByte_t vel )
|
cmMfRC_t cmMidiFileSetVelocity( cmMidiFileH_t h, unsigned uid, cmMidiByte_t vel )
|
||||||
{
|
{
|
||||||
cmMidiTrackMsg_t* r;
|
cmMidiTrackMsg_t* r;
|
||||||
_cmMidiFile_t* mfp = _cmMidiFileHandleToPtr(h);
|
_cmMidiFile_t* mfp = _cmMidiFileHandleToPtr(h);
|
||||||
|
|
||||||
assert( mfp != NULL );
|
assert( mfp != NULL );
|
||||||
|
|
||||||
if((r = _cmMidiFileUidToMsg(mfp,uid)) == NULL )
|
if((r = _cmMidiFileUidToMsg(mfp,uid)) == NULL )
|
||||||
return cmErrMsg(&mfp->err,kUidNotFoundMfRC,"The MIDI file uid %i could not be found.",uid);
|
return cmErrMsg(&mfp->err,kUidNotFoundMfRC,"The MIDI file uid %i could not be found.",uid);
|
||||||
|
|
||||||
if( cmMidiIsNoteOn(r->status)==false && cmMidiIsNoteOff(r->status,0)==false )
|
if( cmMidiIsNoteOn(r->status) == false && cmMidiIsNoteOff(r->status,0)==false )
|
||||||
return cmErrMsg(&mfp->err,kUidNotANoteMsgMfRC,"Cannot set velocity on a non-Note-On/Off msg.");
|
return cmErrMsg(&mfp->err,kUidNotANoteMsgMfRC,"Cannot set velocity on a non-Note-On/Off msg.");
|
||||||
|
|
||||||
cmMidiChMsg_t* chm = (cmMidiChMsg_t*)r->u.chMsgPtr;
|
cmMidiChMsg_t* chm = (cmMidiChMsg_t*)r->u.chMsgPtr;
|
||||||
@ -1141,6 +1153,103 @@ cmMfRC_t cmMidiFileSetVelocity( cmMidiFileH_t h, unsigned uid, cmMidiByte_t vel
|
|||||||
return kOkMfRC;
|
return kOkMfRC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns NULL if uid is not found or if it the first msg on the track.
|
||||||
|
cmMidiTrackMsg_t* _cmMidiFileMsgBeforeUid( _cmMidiFile_t* p, unsigned uid )
|
||||||
|
{
|
||||||
|
cmMidiTrackMsg_t* m;
|
||||||
|
|
||||||
|
if((m = _cmMidiFileUidToMsg(p,uid)) == NULL )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
assert( m->trkIdx < p->trkN );
|
||||||
|
|
||||||
|
cmMidiTrackMsg_t* m0 = NULL;
|
||||||
|
cmMidiTrackMsg_t* m1 = p->trkV[ m->trkIdx ].base;
|
||||||
|
for(; m1!=NULL; m1 = m1->link)
|
||||||
|
{
|
||||||
|
if( m1->uid == uid )
|
||||||
|
break;
|
||||||
|
m0 = m1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned _cmMidiFileIsMsgFirstOnTrack( _cmMidiFile_t* p, unsigned uid )
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
for(i=0; i<p->trkN; ++i)
|
||||||
|
if( p->trkV[i].base!=NULL && p->trkV[i].base->uid == uid )
|
||||||
|
return i;
|
||||||
|
|
||||||
|
return cmInvalidIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cmMfRC_t cmMidiFileInsertMsg( cmMidiFileH_t h, unsigned uid, int dtick, cmMidiByte_t ch, cmMidiByte_t status, cmMidiByte_t d0, cmMidiByte_t d1 )
|
||||||
|
{
|
||||||
|
_cmMidiFile_t* mfp = _cmMidiFileHandleToPtr(h);
|
||||||
|
assert( mfp != NULL );
|
||||||
|
cmMidiTrackMsg_t* ref = NULL;
|
||||||
|
unsigned trkIdx = cmInvalidIdx;
|
||||||
|
|
||||||
|
// if dtick is positive ...
|
||||||
|
if( dtick >= 0 )
|
||||||
|
{
|
||||||
|
ref = _cmMidiFileUidToMsg(mfp,uid); // ... then get the ref. msg.
|
||||||
|
trkIdx = ref->trkIdx;
|
||||||
|
}
|
||||||
|
else // if dtick is negative ...
|
||||||
|
{
|
||||||
|
// ... get get the msg before the ref. msg.
|
||||||
|
if((ref = _cmMidiFileMsgBeforeUid(mfp,uid)) == NULL )
|
||||||
|
{
|
||||||
|
// ... the ref. msg was first in the track so there is no msg before it
|
||||||
|
trkIdx = _cmMidiFileIsMsgFirstOnTrack(mfp,uid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify that the reference msg was found
|
||||||
|
if( trkIdx == cmInvalidIdx )
|
||||||
|
return cmErrMsg(&mfp->err,kUidNotFoundMfRC,"The UID (%i) reference note could not be located.",uid);
|
||||||
|
|
||||||
|
assert( trkIdx < mfp->trkN );
|
||||||
|
|
||||||
|
// complete the msg setup
|
||||||
|
_cmMidiTrack_t* trk = mfp->trkV + trkIdx;
|
||||||
|
cmMidiTrackMsg_t* m = _cmMidiFileAllocMsg(mfp, trkIdx, abs(dtick), status );
|
||||||
|
cmMidiChMsg_t* c = (cmMidiChMsg_t*)m->u.chMsgPtr; // cast away const
|
||||||
|
c->ch = ch;
|
||||||
|
c->d0 = d0;
|
||||||
|
c->d1 = d1;
|
||||||
|
|
||||||
|
// if 'm' is prior to the first msg in the track
|
||||||
|
if( ref == NULL )
|
||||||
|
{
|
||||||
|
// ... then make 'm' the first msg in the first msg
|
||||||
|
m->link = trk->base;
|
||||||
|
trk->base = m;
|
||||||
|
// 'm' is before ref and the track cannot be empty (because ref is in it) 'm'
|
||||||
|
// can never be the last msg in the list
|
||||||
|
}
|
||||||
|
else // ref is the msg before 'm'
|
||||||
|
{
|
||||||
|
m->link = ref->link;
|
||||||
|
ref->link = m;
|
||||||
|
|
||||||
|
// if ref was the last msg in the trk ...
|
||||||
|
if( trk->last == ref )
|
||||||
|
trk->last = m; //... then 'm' is now the last msg in the trk
|
||||||
|
}
|
||||||
|
|
||||||
|
trk->cnt += 1;
|
||||||
|
|
||||||
|
_cmMidiFileLinearize(mfp);
|
||||||
|
|
||||||
|
return kOkMfRC;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
unsigned cmMidiFileSeekUsecs( cmMidiFileH_t h, unsigned long long offsUSecs, unsigned* msgUsecsPtr, unsigned* microsPerTickPtr )
|
unsigned cmMidiFileSeekUsecs( cmMidiFileH_t h, unsigned long long offsUSecs, unsigned* msgUsecsPtr, unsigned* microsPerTickPtr )
|
||||||
{
|
{
|
||||||
_cmMidiFile_t* p;
|
_cmMidiFile_t* p;
|
||||||
|
@ -161,6 +161,10 @@ 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'.
|
||||||
|
// 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 );
|
||||||
|
|
||||||
// Return a pointer to the first msg at or after 'usecsOffs' or kInvalidIdx if no
|
// 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
|
// msg exists after 'usecsOffs'. Note that 'usecOffs' is an offset from the beginning
|
||||||
// of the file.
|
// of the file.
|
||||||
|
Loading…
Reference in New Issue
Block a user