cmMidiFile.h/c : Added a the unique msg id 'uid' to cmMidiTrackMsg_t.

Changed the dtick to seconds/samples conversions to use doubles
instead of integers to avoid round off error.
This commit is contained in:
kpl 2013-09-25 23:43:59 -07:00
parent 63e3713c84
commit bec5f199b4
2 changed files with 37 additions and 41 deletions

View File

@ -41,7 +41,7 @@ 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
unsigned nextUid; // next available msg uid
} _cmMidiFile_t; } _cmMidiFile_t;
@ -524,6 +524,7 @@ cmMfRC_t cmMidiFileOpen( const char* fn, cmMidiFileH_t* hPtr, cmCtx_t* ctx )
// store a pointer to every trk msg in msgV[] // store a pointer to every trk msg in msgV[]
// and convert tick to absolute tick // and convert tick to absolute tick
mfp->nextUid = 0;
unsigned i = 0; unsigned i = 0;
for(trkIdx=0; trkIdx<mfp->trkN; ++trkIdx) for(trkIdx=0; trkIdx<mfp->trkN; ++trkIdx)
{ {
@ -534,15 +535,16 @@ cmMfRC_t cmMidiFileOpen( const char* fn, cmMidiFileH_t* hPtr, cmCtx_t* ctx )
{ {
assert( i < mfp->msgN); assert( i < mfp->msgN);
tick += tmp->dtick; // convert delta-ticks to absolute ticks tick += tmp->dtick; // convert delta-ticks to absolute ticks
tmp->atick = tick; tmp->atick = tick;
tmp->uid = mfp->nextUid++; // assign the msg uid
mfp->msgV[i] = tmp; mfp->msgV[i] = tmp;
tmp = tmp->link; tmp = tmp->link;
++i; ++i;
} }
} }
// sort msgV[] in ascending order on dtick // sort msgV[] in ascending order on atick
qsort( mfp->msgV, mfp->msgN, sizeof(cmMidiTrackMsg_t*), _cmMidiFileSortFunc ); qsort( mfp->msgV, mfp->msgN, sizeof(cmMidiTrackMsg_t*), _cmMidiFileSortFunc );
//for(i=0; i<25; ++i) //for(i=0; i<25; ++i)
@ -552,24 +554,6 @@ cmMfRC_t cmMidiFileOpen( const char* fn, cmMidiFileH_t* hPtr, cmCtx_t* ctx )
assert( mfp->fn != NULL ); assert( mfp->fn != NULL );
strcpy(mfp->fn,fn); strcpy(mfp->fn,fn);
//
// calculate the total duration of the MIDI file and convert absolute ticks back to delta ticks
//
/*
unsigned mi;
unsigned prvTick = 0;
for(mi=0; mi<mfp->msgN; ++mi)
{
cmMidiTrackMsg_t* mp = mfp->msgV[mi];
// convert absolute ticks back to delta ticks
unsigned dtick = mp->dtick - prvTick;
prvTick = mp->dtick;
mp->dtick = dtick;
}
*/
hPtr->h = mfp; hPtr->h = mfp;
@ -1062,9 +1046,9 @@ unsigned cmMidiFileSeekUsecs( cmMidiFileH_t h, unsigned offsUSecs, unsigned* ms
return cmInvalidIdx; return cmInvalidIdx;
unsigned mi; unsigned mi;
unsigned microsPerQN = 60000000/120; double microsPerQN = 60000000.0/120.0;
unsigned microsPerTick = microsPerQN / p->ticksPerQN; double microsPerTick = microsPerQN / p->ticksPerQN;
unsigned accUSecs = 0; double accUSecs = 0;
for(mi=0; mi<p->msgN; ++mi) for(mi=0; mi<p->msgN; ++mi)
{ {
@ -1084,10 +1068,10 @@ unsigned cmMidiFileSeekUsecs( cmMidiFileH_t h, unsigned offsUSecs, unsigned* ms
return cmInvalidIdx; return cmInvalidIdx;
if( msgUsecsPtr != NULL ) if( msgUsecsPtr != NULL )
*msgUsecsPtr = accUSecs - offsUSecs; *msgUsecsPtr = round(accUSecs - offsUSecs);
if( microsPerTickPtr != NULL ) if( microsPerTickPtr != NULL )
*microsPerTickPtr = microsPerTick; *microsPerTickPtr = round(microsPerTick);
return mi; return mi;
} }
@ -1097,15 +1081,16 @@ double cmMidiFileDurSecs( cmMidiFileH_t h )
_cmMidiFile_t* mfp = _cmMidiFileHandleToPtr(h); _cmMidiFile_t* mfp = _cmMidiFileHandleToPtr(h);
unsigned mi; unsigned mi;
double durSecs = 0; double durSecs = 0;
unsigned microsPerQN = 60000000/120; double r = 1.0; //1000.0/(1000-.8);
unsigned microsPerTick = microsPerQN / mfp->ticksPerQN; double microsPerQN = r*60000000.0/120.0;
double microsPerTick = microsPerQN / mfp->ticksPerQN;
for(mi=0; mi<mfp->msgN; ++mi) for(mi=0; mi<mfp->msgN; ++mi)
{ {
cmMidiTrackMsg_t* mp = mfp->msgV[mi]; cmMidiTrackMsg_t* mp = mfp->msgV[mi];
if( mp->status == kMetaStId && mp->metaId == kTempoMdId ) if( mp->status == kMetaStId && mp->metaId == kTempoMdId )
microsPerTick = mp->u.iVal / mfp->ticksPerQN; microsPerTick = r*mp->u.iVal / mfp->ticksPerQN;
// update the accumulated seconds // update the accumulated seconds
durSecs += (mp->dtick * microsPerTick) / 1000000.0; durSecs += (mp->dtick * microsPerTick) / 1000000.0;
@ -1126,17 +1111,18 @@ void cmMidiFileTickToMicros( cmMidiFileH_t h )
return; return;
unsigned mi; unsigned mi;
unsigned microsPerQN = 60000000/120; // default tempo double r = 1.0; //1000.0/(1000-.8);
unsigned microsPerTick = microsPerQN / p->ticksPerQN; double microsPerQN = r*60000000/120; // default tempo
double microsPerTick = microsPerQN / p->ticksPerQN;
for(mi=0; mi<p->msgN; ++mi) for(mi=0; mi<p->msgN; ++mi)
{ {
cmMidiTrackMsg_t* mp = p->msgV[mi]; cmMidiTrackMsg_t* mp = p->msgV[mi];
if( mp->status == kMetaStId && mp->metaId == kTempoMdId ) if( mp->status == kMetaStId && mp->metaId == kTempoMdId )
microsPerTick = mp->u.iVal / p->ticksPerQN; microsPerTick = r*mp->u.iVal / p->ticksPerQN;
mp->dtick *= microsPerTick; mp->dtick = round(microsPerTick*mp->dtick);
} }
} }
@ -1144,28 +1130,37 @@ void cmMidiFileTickToMicros( cmMidiFileH_t h )
void cmMidiFileTickToSamples( cmMidiFileH_t h, double srate, bool absFl ) void cmMidiFileTickToSamples( cmMidiFileH_t h, double srate, bool absFl )
{ {
_cmMidiFile_t* p; _cmMidiFile_t* p;
unsigned mi;
//bool fl = true;
if((p = _cmMidiFileHandleToPtr(h)) == NULL ) if((p = _cmMidiFileHandleToPtr(h)) == NULL )
return; return;
cmMidiFileTickToMicros(h); if( p->msgN == 0 )
return;
unsigned absSmp = 0; unsigned mi;
double r = 1.0; //1000.0/(1000-.8);
double microsPerQN = r*60000000/120; // default tempo
double microsPerTick = microsPerQN / p->ticksPerQN;
double absSmp = 0;
for(mi=0; mi<p->msgN; ++mi) for(mi=0; mi<p->msgN; ++mi)
{ {
cmMidiTrackMsg_t* mp = p->msgV[mi]; cmMidiTrackMsg_t* mp = p->msgV[mi];
unsigned delta = floor((mp->dtick*srate)/1000000.0);
absSmp += delta; if( mp->status == kMetaStId && mp->metaId == kTempoMdId )
microsPerTick = r*mp->u.iVal / p->ticksPerQN;
mp->dtick = absFl ? absSmp : delta; double delta = microsPerTick*mp->dtick*srate/1000000.0;
absSmp += delta;
mp->dtick = round(absFl ? absSmp : delta);
} }
} }
typedef struct _cmMidiVoice_str typedef struct _cmMidiVoice_str
{ {
const cmMidiTrackMsg_t* mp; const cmMidiTrackMsg_t* mp;

View File

@ -62,6 +62,7 @@ extern "C" {
typedef struct cmMidiTrackMsg_str typedef struct cmMidiTrackMsg_str
{ {
unsigned uid; // uid's are unique among all msg's in the file
unsigned dtick; // delta ticks unsigned dtick; // delta ticks
unsigned atick; unsigned atick;
cmMidiByte_t status; // ch msg's have the channel value removed (it is stored in u.chMsgPtr->ch) cmMidiByte_t status; // ch msg's have the channel value removed (it is stored in u.chMsgPtr->ch)