cmMidiFile.h/c : Completed cmMidiFileInsertTrackMsg() and added _cmMidiFile_t.msgVDirtyFl and associated processing.
This commit is contained in:
parent
198aa41b98
commit
49943bd43e
110
cmMidiFile.c
110
cmMidiFile.c
@ -40,12 +40,14 @@ typedef struct
|
|||||||
char* fn; // file name or NULL if this object did not originate from a file
|
char* fn; // file name or NULL if this object did not originate from a file
|
||||||
unsigned msgN; // count of msg's in msgV[]
|
unsigned msgN; // count of msg's in msgV[]
|
||||||
cmMidiTrackMsg_t** msgV; // sorted msg list
|
cmMidiTrackMsg_t** msgV; // sorted msg list
|
||||||
|
bool msgVDirtyFl; // msgV[] needs to be refreshed from trkV[] because new msg's were inserted.
|
||||||
unsigned nextUid; // next available msg uid
|
unsigned nextUid; // next available msg uid
|
||||||
} _cmMidiFile_t;
|
} _cmMidiFile_t;
|
||||||
|
|
||||||
|
|
||||||
cmMidiFileH_t cmMidiFileNullHandle = cmSTATIC_NULL_HANDLE;
|
cmMidiFileH_t cmMidiFileNullHandle = cmSTATIC_NULL_HANDLE;
|
||||||
|
|
||||||
|
const cmMidiTrackMsg_t** _cmMidiFileMsgArray( _cmMidiFile_t* p );
|
||||||
|
|
||||||
_cmMidiFile_t* _cmMidiFileHandleToPtr( cmMidiFileH_t h )
|
_cmMidiFile_t* _cmMidiFileHandleToPtr( cmMidiFileH_t h )
|
||||||
{
|
{
|
||||||
@ -435,7 +437,7 @@ void _cmMidiFileSetAccumulateTicks( _cmMidiFile_t* p )
|
|||||||
unsigned i;
|
unsigned i;
|
||||||
bool fl = true;
|
bool fl = true;
|
||||||
|
|
||||||
// iniitalize nextTrkTick[] and nextTrkMsg[].
|
// iniitalize nextTrkTick[] and nextTrkMsg[] to the first msg in each track
|
||||||
for(i=0; i<p->trkN; ++i)
|
for(i=0; i<p->trkN; ++i)
|
||||||
if((nextTrkMsg[i] = p->trkV[i].base) != NULL )
|
if((nextTrkMsg[i] = p->trkV[i].base) != NULL )
|
||||||
nextTrkMsg[i]->atick = nextTrkMsg[i]->dtick;
|
nextTrkMsg[i]->atick = nextTrkMsg[i]->dtick;
|
||||||
@ -474,21 +476,23 @@ void _cmMidiFileSetAccumulateTicks( _cmMidiFile_t* p )
|
|||||||
|
|
||||||
void _cmMidiFileSetAbsoluteTime( _cmMidiFile_t* mfp )
|
void _cmMidiFileSetAbsoluteTime( _cmMidiFile_t* mfp )
|
||||||
{
|
{
|
||||||
|
const cmMidiTrackMsg_t** msgV = _cmMidiFileMsgArray(mfp);
|
||||||
double microsPerQN = 60000000/120; // default tempo;
|
double microsPerQN = 60000000/120; // default tempo;
|
||||||
double microsPerTick = microsPerQN / mfp->ticksPerQN;
|
double microsPerTick = microsPerQN / mfp->ticksPerQN;
|
||||||
unsigned long long amicro = 0;
|
unsigned long long amicro = 0;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
|
||||||
|
|
||||||
for(i=0; i<mfp->msgN; ++i)
|
for(i=0; i<mfp->msgN; ++i)
|
||||||
{
|
{
|
||||||
cmMidiTrackMsg_t* mp = mfp->msgV[i];
|
cmMidiTrackMsg_t* mp = (cmMidiTrackMsg_t*)msgV[i]; // cast away const
|
||||||
unsigned dtick = 0;
|
unsigned dtick = 0;
|
||||||
|
|
||||||
if( i > 0 )
|
if( i > 0 )
|
||||||
{
|
{
|
||||||
// atick must have already been set and sorted
|
// atick must have already been set and sorted
|
||||||
assert( mp->atick >= mfp->msgV[i-1]->atick );
|
assert( mp->atick >= msgV[i-1]->atick );
|
||||||
dtick = mp->atick - mfp->msgV[i-1]->atick;
|
dtick = mp->atick - msgV[i-1]->atick;
|
||||||
}
|
}
|
||||||
|
|
||||||
amicro += microsPerTick * dtick;
|
amicro += microsPerTick * dtick;
|
||||||
@ -524,10 +528,14 @@ cmMfRC_t _cmMidiFileClose( _cmMidiFile_t* mfp )
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void _cmMidiFileLinearize( _cmMidiFile_t* mfp )
|
void _cmMidiFileLinearize( _cmMidiFile_t* mfp )
|
||||||
{
|
{
|
||||||
unsigned trkIdx,i,j;
|
unsigned trkIdx,i,j;
|
||||||
|
|
||||||
|
if( mfp->msgVDirtyFl == false )
|
||||||
|
return;
|
||||||
|
|
||||||
// get the total trk msg count
|
// get the total trk msg count
|
||||||
mfp->msgN = 0;
|
mfp->msgN = 0;
|
||||||
for(trkIdx=0; trkIdx<mfp->trkN; ++trkIdx)
|
for(trkIdx=0; trkIdx<mfp->trkN; ++trkIdx)
|
||||||
@ -559,6 +567,20 @@ void _cmMidiFileLinearize( _cmMidiFile_t* mfp )
|
|||||||
// set the amicro value in each msg
|
// set the amicro value in each msg
|
||||||
_cmMidiFileSetAbsoluteTime(mfp);
|
_cmMidiFileSetAbsoluteTime(mfp);
|
||||||
|
|
||||||
|
mfp->msgVDirtyFl = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note that p->msgV[] should always be accessed through this function
|
||||||
|
// to guarantee that the p->msgVDirtyFl is checked and msgV[] is updated
|
||||||
|
// in case msgV[] is out of sync (due to inserted msgs (see cmMidiFileInsertTrackMsg())
|
||||||
|
// with trkV[].
|
||||||
|
const cmMidiTrackMsg_t** _cmMidiFileMsgArray( _cmMidiFile_t* p )
|
||||||
|
{
|
||||||
|
_cmMidiFileLinearize(p);
|
||||||
|
|
||||||
|
// this cast is needed to eliminate an apparently needless 'incompatible type' warning
|
||||||
|
return (const cmMidiTrackMsg_t**)p->msgV;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmMfRC_t _cmMidiFileCreate( cmCtx_t* ctx, cmMidiFileH_t* hp )
|
cmMfRC_t _cmMidiFileCreate( cmCtx_t* ctx, cmMidiFileH_t* hp )
|
||||||
@ -645,9 +667,9 @@ cmMfRC_t cmMidiFileOpen( cmCtx_t* ctx, cmMidiFileH_t* hp, const char* fn )
|
|||||||
assert( p->fn != NULL );
|
assert( p->fn != NULL );
|
||||||
strcpy(p->fn,fn);
|
strcpy(p->fn,fn);
|
||||||
|
|
||||||
|
p->msgVDirtyFl = true;
|
||||||
_cmMidiFileLinearize(p);
|
_cmMidiFileLinearize(p);
|
||||||
|
|
||||||
|
|
||||||
errLabel:
|
errLabel:
|
||||||
|
|
||||||
if( cmFileClose(&p->fh) != kOkFileRC )
|
if( cmFileClose(&p->fh) != kOkFileRC )
|
||||||
@ -1133,6 +1155,7 @@ unsigned cmMidiFileMsgCount( cmMidiFileH_t h )
|
|||||||
return mfp->msgN;
|
return mfp->msgN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const cmMidiTrackMsg_t** cmMidiFileMsgArray( cmMidiFileH_t h )
|
const cmMidiTrackMsg_t** cmMidiFileMsgArray( cmMidiFileH_t h )
|
||||||
{
|
{
|
||||||
_cmMidiFile_t* mfp;
|
_cmMidiFile_t* mfp;
|
||||||
@ -1140,18 +1163,18 @@ const cmMidiTrackMsg_t** cmMidiFileMsgArray( cmMidiFileH_t h )
|
|||||||
if((mfp = _cmMidiFileHandleToPtr(h)) == NULL )
|
if((mfp = _cmMidiFileHandleToPtr(h)) == NULL )
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
// this cast is needed to eliminate an apparently needless 'incompatible type' warning
|
return _cmMidiFileMsgArray(mfp);
|
||||||
return (const cmMidiTrackMsg_t**)mfp->msgV;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
cmMidiTrackMsg_t* _cmMidiFileUidToMsg( _cmMidiFile_t* mfp, unsigned uid )
|
cmMidiTrackMsg_t* _cmMidiFileUidToMsg( _cmMidiFile_t* mfp, unsigned uid )
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
const cmMidiTrackMsg_t** msgV = _cmMidiFileMsgArray(mfp);
|
||||||
|
|
||||||
for(i=0; i<mfp->msgN; ++i)
|
for(i=0; i<mfp->msgN; ++i)
|
||||||
if( mfp->msgV[i]->uid == uid )
|
if( msgV[i]->uid == uid )
|
||||||
return mfp->msgV[i];
|
return (cmMidiTrackMsg_t*)msgV[i];
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -1272,18 +1295,12 @@ cmMfRC_t cmMidiFileInsertMsg( cmMidiFileH_t h, unsigned uid, int dtick, cmMidiBy
|
|||||||
|
|
||||||
trk->cnt += 1;
|
trk->cnt += 1;
|
||||||
|
|
||||||
_cmMidiFileLinearize(mfp);
|
mfp->msgVDirtyFl = true;
|
||||||
|
|
||||||
return kOkMfRC;
|
return kOkMfRC;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 )
|
cmMfRC_t cmMidiFileInsertTrackMsg( cmMidiFileH_t h, unsigned trkIdx, const cmMidiTrackMsg_t* msg )
|
||||||
{
|
{
|
||||||
_cmMidiFile_t* p = _cmMidiFileHandleToPtr(h);
|
_cmMidiFile_t* p = _cmMidiFileHandleToPtr(h);
|
||||||
@ -1311,11 +1328,12 @@ cmMfRC_t cmMidiFileInsertTrackMsg( cmMidiFileH_t h, unsigned trkIdx, const cmMi
|
|||||||
memcpy((void*)m->u.voidPtr,msg->u.voidPtr,msg->byteCnt);
|
memcpy((void*)m->u.voidPtr,msg->u.voidPtr,msg->byteCnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
cmMidiTrackMsg_t* m0 = NULL;
|
cmMidiTrackMsg_t* m0 = NULL; // msg before insertion
|
||||||
cmMidiTrackMsg_t* m1 = p->trkV[trkIdx].base;
|
cmMidiTrackMsg_t* m1 = p->trkV[trkIdx].base; // msg after insertion
|
||||||
|
|
||||||
// locate the track record before and after the new msg
|
// locate the track record before and after the new msg based on 'atick' value
|
||||||
for(; m1!=NULL; m1=m1->link)
|
for(; m1!=NULL; m1=m1->link)
|
||||||
|
{
|
||||||
if( m1->atick > m->atick )
|
if( m1->atick > m->atick )
|
||||||
{
|
{
|
||||||
if( m0 == NULL )
|
if( m0 == NULL )
|
||||||
@ -1327,16 +1345,41 @@ cmMfRC_t cmMidiFileInsertTrackMsg( cmMidiFileH_t h, unsigned trkIdx, const cmMi
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// the new track record is the last msg
|
m0 = m1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the new track record was not inserted then it is the last msg
|
||||||
if( m1 == NULL )
|
if( m1 == NULL )
|
||||||
{
|
{
|
||||||
m1 = p->trkV[trkIdx].last;
|
assert(m0 == p->trkV[trkIdx].last);
|
||||||
m1->link = m;
|
|
||||||
|
// link in the new msg
|
||||||
|
if( m0 != NULL )
|
||||||
|
m0->link = m;
|
||||||
|
|
||||||
|
// the new msg always becomes the last msg
|
||||||
p->trkV[trkIdx].last = m;
|
p->trkV[trkIdx].last = m;
|
||||||
|
|
||||||
|
// if the new msg is the first msg inserted in this track
|
||||||
if( p->trkV[trkIdx].base == NULL )
|
if( p->trkV[trkIdx].base == NULL )
|
||||||
p->trkV[trkIdx].base = m;
|
p->trkV[trkIdx].base = m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set the dtick field of the new msg
|
||||||
|
if( m0 != NULL )
|
||||||
|
{
|
||||||
|
assert( m->atick >= m0->atick );
|
||||||
|
m->dtick = m->atick - m0->atick;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the dtick field of the msg following the new msg
|
||||||
|
if( m1 != NULL )
|
||||||
|
{
|
||||||
|
assert( m1->atick >= m->atick );
|
||||||
|
m1->dtick = m1->atick - m->atick;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->msgVDirtyFl = true;
|
||||||
|
|
||||||
return kOkMfRC;
|
return kOkMfRC;
|
||||||
|
|
||||||
@ -1391,10 +1434,11 @@ unsigned cmMidiFileSeekUsecs( cmMidiFileH_t h, unsigned long long offsUSecs, un
|
|||||||
double microsPerQN = 60000000.0/120.0;
|
double microsPerQN = 60000000.0/120.0;
|
||||||
double microsPerTick = microsPerQN / p->ticksPerQN;
|
double microsPerTick = microsPerQN / p->ticksPerQN;
|
||||||
double accUSecs = 0;
|
double accUSecs = 0;
|
||||||
|
const cmMidiTrackMsg_t** msgV = _cmMidiFileMsgArray(p);
|
||||||
|
|
||||||
for(mi=0; mi<p->msgN; ++mi)
|
for(mi=0; mi<p->msgN; ++mi)
|
||||||
{
|
{
|
||||||
const cmMidiTrackMsg_t* mp = p->msgV[mi];
|
const cmMidiTrackMsg_t* mp = msgV[mi];
|
||||||
|
|
||||||
if( mp->amicro >= offsUSecs )
|
if( mp->amicro >= offsUSecs )
|
||||||
break;
|
break;
|
||||||
@ -1419,7 +1463,9 @@ double cmMidiFileDurSecs( cmMidiFileH_t h )
|
|||||||
if( mfp->msgN == 0 )
|
if( mfp->msgN == 0 )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return mfp->msgV[ mfp->msgN-1 ]->amicro / 1000000.0;
|
const cmMidiTrackMsg_t** msgV = _cmMidiFileMsgArray(mfp);
|
||||||
|
|
||||||
|
return msgV[ mfp->msgN-1 ]->amicro / 1000000.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct _cmMidiVoice_str
|
typedef struct _cmMidiVoice_str
|
||||||
@ -1472,6 +1518,8 @@ void cmMidiFileCalcNoteDurations( cmMidiFileH_t h )
|
|||||||
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;
|
||||||
|
|
||||||
|
const cmMidiTrackMsg_t** msgV = _cmMidiFileMsgArray(p);
|
||||||
|
|
||||||
// initialize the state tracking variables
|
// initialize the state tracking variables
|
||||||
for(i=0; i<kMidiChCnt; ++i)
|
for(i=0; i<kMidiChCnt; ++i)
|
||||||
{
|
{
|
||||||
@ -1492,10 +1540,10 @@ void cmMidiFileCalcNoteDurations( cmMidiFileH_t h )
|
|||||||
// for each midi event
|
// for each midi event
|
||||||
for(mi=0; mi<p->msgN; ++mi)
|
for(mi=0; mi<p->msgN; ++mi)
|
||||||
{
|
{
|
||||||
cmMidiTrackMsg_t* m = p->msgV[mi];
|
cmMidiTrackMsg_t* m = (cmMidiTrackMsg_t*)msgV[mi]; // cast away const
|
||||||
|
|
||||||
// verify that time is also incrementing
|
// verify that time is also incrementing
|
||||||
assert( mi==0 || (mi>0 && m->amicro >= p->msgV[mi-1]->amicro) );
|
assert( mi==0 || (mi>0 && m->amicro >= msgV[mi-1]->amicro) );
|
||||||
|
|
||||||
// ignore all non-channel messages
|
// ignore all non-channel messages
|
||||||
if( !cmMidiIsChStatus( m->status ) )
|
if( !cmMidiIsChStatus( m->status ) )
|
||||||
@ -1656,12 +1704,14 @@ void cmMidiFileSetDelay( cmMidiFileH_t h, unsigned ticks )
|
|||||||
if((p = _cmMidiFileHandleToPtr(h)) == NULL )
|
if((p = _cmMidiFileHandleToPtr(h)) == NULL )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
const cmMidiTrackMsg_t** msgV = _cmMidiFileMsgArray(p);
|
||||||
|
|
||||||
if( p->msgN == 0 )
|
if( p->msgN == 0 )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for(mi=0; mi<p->msgN; ++mi)
|
for(mi=0; mi<p->msgN; ++mi)
|
||||||
{
|
{
|
||||||
cmMidiTrackMsg_t* mp = p->msgV[mi];
|
cmMidiTrackMsg_t* mp = (cmMidiTrackMsg_t*)msgV[mi]; // cast away const
|
||||||
|
|
||||||
// locate the first msg which has a non-zero delta tick
|
// locate the first msg which has a non-zero delta tick
|
||||||
if( mp->dtick > 0 )
|
if( mp->dtick > 0 )
|
||||||
@ -1742,14 +1792,16 @@ void _cmMidiFilePrintMsg( cmRpt_t* rpt, const cmMidiTrackMsg_t* tmp )
|
|||||||
|
|
||||||
void cmMidiFilePrintMsgs( cmMidiFileH_t h, cmRpt_t* rpt )
|
void cmMidiFilePrintMsgs( cmMidiFileH_t h, cmRpt_t* rpt )
|
||||||
{
|
{
|
||||||
const _cmMidiFile_t* p = _cmMidiFileHandleToPtr(h);
|
_cmMidiFile_t* p = _cmMidiFileHandleToPtr(h);
|
||||||
unsigned mi;
|
unsigned mi;
|
||||||
|
|
||||||
_cmMidiFilePrintHdr(p,rpt);
|
_cmMidiFilePrintHdr(p,rpt);
|
||||||
|
|
||||||
|
const cmMidiTrackMsg_t** msgV = _cmMidiFileMsgArray(p);
|
||||||
|
|
||||||
for(mi=0; mi<p->msgN; ++mi)
|
for(mi=0; mi<p->msgN; ++mi)
|
||||||
{
|
{
|
||||||
cmMidiTrackMsg_t* mp = p->msgV[mi];
|
const cmMidiTrackMsg_t* mp = msgV[mi];
|
||||||
|
|
||||||
if( mp != NULL )
|
if( mp != NULL )
|
||||||
_cmMidiFilePrintMsg(rpt,mp);
|
_cmMidiFilePrintMsg(rpt,mp);
|
||||||
|
25
cmMidiFile.h
25
cmMidiFile.h
@ -136,17 +136,20 @@ extern "C" {
|
|||||||
// Return midi file format id (0,1,2) or kInvalidId if 'h' is invalid.
|
// Return midi file format id (0,1,2) or kInvalidId if 'h' is invalid.
|
||||||
unsigned cmMidiFileType( cmMidiFileH_t h );
|
unsigned cmMidiFileType( cmMidiFileH_t h );
|
||||||
|
|
||||||
// Returns ticks per quarter note or kInvalidMidiByte if 'h' is invalid or 0 if file uses SMPTE ticks per frame time base.
|
// Returns ticks per quarter note or kInvalidMidiByte if 'h' is
|
||||||
|
// invalid or 0 if file uses SMPTE ticks per frame time base.
|
||||||
unsigned cmMidiFileTicksPerQN( cmMidiFileH_t h );
|
unsigned cmMidiFileTicksPerQN( cmMidiFileH_t h );
|
||||||
|
|
||||||
// The file name used in an earlier call to midiFileOpen() or NULL if this
|
// The file name used in an earlier call to midiFileOpen() or NULL if this
|
||||||
// midi file did not originate from an actual file.
|
// midi file did not originate from an actual file.
|
||||||
const char* cmMidiFileName( cmMidiFileH_t h );
|
const char* cmMidiFileName( cmMidiFileH_t h );
|
||||||
|
|
||||||
// Returns SMPTE ticks per frame or kInvalidMidiByte if 'h' is invalid or 0 if file uses ticks per quarter note time base.
|
// Returns SMPTE ticks per frame or kInvalidMidiByte if 'h' is
|
||||||
|
// invalid or 0 if file uses ticks per quarter note time base.
|
||||||
cmMidiByte_t cmMidiFileTicksPerSmpteFrame( cmMidiFileH_t h );
|
cmMidiByte_t cmMidiFileTicksPerSmpteFrame( cmMidiFileH_t h );
|
||||||
|
|
||||||
// Returns SMPTE format or kInvalidMidiByte if 'h' is invalid or 0 if file uses ticks per quarter note time base.
|
// Returns SMPTE format or kInvalidMidiByte if 'h' is invalid or 0
|
||||||
|
// if file uses ticks per quarter note time base.
|
||||||
cmMidiByte_t cmMidiFileSmpteFormatId( cmMidiFileH_t h );
|
cmMidiByte_t cmMidiFileSmpteFormatId( cmMidiFileH_t h );
|
||||||
|
|
||||||
// Returns count of records in track 'trackIdx' or kInvalidCnt if 'h' is invalid.
|
// Returns count of records in track 'trackIdx' or kInvalidCnt if 'h' is invalid.
|
||||||
@ -155,11 +158,13 @@ extern "C" {
|
|||||||
// Returns base of record chain from track 'trackIdx' or NULL if 'h' is invalid.
|
// Returns base of record chain from track 'trackIdx' or NULL if 'h' is invalid.
|
||||||
const cmMidiTrackMsg_t* cmMidiFileTrackMsg( cmMidiFileH_t h, unsigned trackIdx );
|
const cmMidiTrackMsg_t* cmMidiFileTrackMsg( cmMidiFileH_t h, unsigned trackIdx );
|
||||||
|
|
||||||
// Returns the total count of records in the midi file and the number in the array returned by cmMidiFileMsgArray().
|
// Returns the total count of records in the midi file and the
|
||||||
|
// number in the array returned by cmMidiFileMsgArray().
|
||||||
// Return kInvalidCnt if 'h' is invalid.
|
// Return kInvalidCnt if 'h' is invalid.
|
||||||
unsigned cmMidiFileMsgCount( cmMidiFileH_t h );
|
unsigned cmMidiFileMsgCount( cmMidiFileH_t h );
|
||||||
|
|
||||||
// Returns a pointer to the base of an array of pointers to each record in the file sorted in ascending time order.
|
// Returns a pointer to the base of an array of pointers to all records
|
||||||
|
// in the file sorted in ascending time order.
|
||||||
// Returns NULL if 'h' is invalid.
|
// Returns NULL if 'h' is invalid.
|
||||||
const cmMidiTrackMsg_t** cmMidiFileMsgArray( cmMidiFileH_t h );
|
const cmMidiTrackMsg_t** cmMidiFileMsgArray( cmMidiFileH_t h );
|
||||||
|
|
||||||
@ -170,6 +175,16 @@ extern "C" {
|
|||||||
// 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 );
|
||||||
|
|
||||||
|
//
|
||||||
|
// Insert a new cmMidiTrackMsg_t into the MIDI file on the specified track.
|
||||||
|
//
|
||||||
|
// Only the following fields need be set in 'msg'.
|
||||||
|
// 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 );
|
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 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 );
|
cmMfRC_t cmMidFileInsertTrackTempoMsg( cmMidiFileH_t h, unsigned trkIdx, unsigned atick, unsigned bpm );
|
||||||
|
Loading…
Reference in New Issue
Block a user