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
195
cmMidiFile.c
195
cmMidiFile.c
@ -19,8 +19,6 @@
|
||||
#define mfSwap32(v) cmSwap32(v)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned cnt; // count of track records
|
||||
@ -160,10 +158,25 @@ cmMfRC_t _cmMidiFileReadVarLen( _cmMidiFile_t* mfp, unsigned* p )
|
||||
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) );
|
||||
|
||||
// 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
|
||||
if( mfp->trkV[trkIdx].base == NULL )
|
||||
mfp->trkV[trkIdx].base = tmp;
|
||||
@ -174,12 +187,6 @@ cmMfRC_t _cmMidiFileAppendTrackMsg( _cmMidiFile_t* mfp, unsigned short trkIdx, u
|
||||
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;
|
||||
|
||||
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 )
|
||||
{
|
||||
@ -528,7 +572,6 @@ cmMfRC_t cmMidiFileOpen( cmCtx_t* ctx, cmMidiFileH_t* hPtr, const char* fn )
|
||||
_cmMidiFile_t* mfp = NULL;
|
||||
unsigned short trkIdx = 0;
|
||||
cmErr_t err;
|
||||
unsigned i,j;
|
||||
|
||||
if( cmMidiFileIsValid(*hPtr) )
|
||||
if((rc = _cmMidiFileClose(_cmMidiFileHandleToPtr(*hPtr))) != kOkMfRC )
|
||||
@ -591,43 +634,12 @@ cmMfRC_t cmMidiFileOpen( cmCtx_t* ctx, cmMidiFileH_t* hPtr, const char* fn )
|
||||
}
|
||||
}
|
||||
|
||||
// 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 = 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++;
|
||||
}
|
||||
}
|
||||
|
||||
// store the file name
|
||||
mfp->fn = _cmMidiFileMalloc(mfp,strlen(fn)+1);
|
||||
assert( mfp->fn != NULL );
|
||||
strcpy(mfp->fn,fn);
|
||||
|
||||
|
||||
// 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);
|
||||
_cmMidiFileLinearize(mfp);
|
||||
|
||||
hPtr->h = mfp;
|
||||
|
||||
@ -1141,6 +1153,103 @@ cmMfRC_t cmMidiFileSetVelocity( cmMidiFileH_t h, unsigned uid, cmMidiByte_t vel
|
||||
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 )
|
||||
{
|
||||
_cmMidiFile_t* p;
|
||||
|
@ -161,6 +161,10 @@ extern "C" {
|
||||
// Set the velocity of a note-on/off msg identified by 'uid'.
|
||||
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
|
||||
// msg exists after 'usecsOffs'. Note that 'usecOffs' is an offset from the beginning
|
||||
// of the file.
|
||||
|
Loading…
Reference in New Issue
Block a user