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)
|
#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 )
|
||||||
@ -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;
|
|
||||||
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);
|
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;
|
||||||
|
|
||||||
@ -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