cmMidiFile.h/c : Added 'end' field to cmMidiChMsg_t and setting code. Not yet tested.
This commit is contained in:
parent
de1649b204
commit
2b01371684
181
cmMidiFile.c
181
cmMidiFile.c
@ -1304,182 +1304,13 @@ typedef struct _cmMidiVoice_str
|
|||||||
} _cmMidiVoice_t;
|
} _cmMidiVoice_t;
|
||||||
|
|
||||||
|
|
||||||
void _cmMidFileCalcNoteDurationReleaseNote( _cmMidiVoice_t** listPtrPtr, _cmMidiVoice_t* pp, _cmMidiVoice_t* vp )
|
|
||||||
{
|
|
||||||
assert( (pp==NULL && vp==*listPtrPtr) || pp->link==vp);
|
|
||||||
|
|
||||||
// store the duration of the note into the track msg
|
|
||||||
// assoc'd with the note-on msg
|
|
||||||
cmMidiChMsg_t* cmp = (cmMidiChMsg_t*)vp->mp->u.chMsgPtr; // cast away const
|
|
||||||
cmp->durMicros = vp->durMicros;
|
|
||||||
|
|
||||||
_cmMidiVoice_t* np = vp->link;
|
|
||||||
|
|
||||||
// release the voice msg
|
|
||||||
cmMemFree(vp);
|
|
||||||
|
|
||||||
// unlink the active voice msg
|
|
||||||
if( pp == NULL )
|
|
||||||
*listPtrPtr = np;
|
|
||||||
else
|
|
||||||
pp->link = np;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void _cmMidiFileCalcNoteDurationsAllocVoice( _cmMidiVoice_t** listPtrPtr, cmMidiTrackMsg_t* mp, bool sustainFl )
|
|
||||||
{
|
|
||||||
_cmMidiVoice_t* vp = cmMemAllocZ(_cmMidiVoice_t,1);
|
|
||||||
vp->mp = mp;
|
|
||||||
vp->sustainFl = sustainFl;
|
|
||||||
vp->link = *listPtrPtr;
|
|
||||||
*listPtrPtr = vp;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cmMidiFileCalcNoteDurations2( cmMidiFileH_t h )
|
|
||||||
{
|
|
||||||
_cmMidiFile_t* p;
|
|
||||||
|
|
||||||
if((p = _cmMidiFileHandleToPtr(h)) == NULL )
|
|
||||||
return;
|
|
||||||
|
|
||||||
if( p->msgN == 0 )
|
|
||||||
return;
|
|
||||||
|
|
||||||
unsigned mi = cmInvalidId;
|
|
||||||
_cmMidiVoice_t* list = NULL; // list of active voices
|
|
||||||
_cmMidiVoice_t* vp = NULL;
|
|
||||||
cmMidiTrackMsg_t* sustainPedalDownMsg = NULL;
|
|
||||||
bool sustainFlagV[ kMidiChCnt ];
|
|
||||||
|
|
||||||
// clear the sustain pedal flag
|
|
||||||
for(mi=0; mi<kMidiChCnt; ++mi)
|
|
||||||
sustainFlagV[mi]=false;
|
|
||||||
|
|
||||||
for(mi=0; mi<p->msgN; ++mi)
|
|
||||||
{
|
|
||||||
cmMidiTrackMsg_t* mp = p->msgV[mi];
|
|
||||||
|
|
||||||
unsigned d_amicro = 0;
|
|
||||||
if( mi > 0 )
|
|
||||||
{
|
|
||||||
assert( mp->amicro >= p->msgV[mi-1]->amicro );
|
|
||||||
d_amicro = mp->amicro - p->msgV[mi-1]->amicro;
|
|
||||||
}
|
|
||||||
|
|
||||||
// update the duration of the sounding notes
|
|
||||||
for(vp = list; vp!=NULL; vp=vp->link)
|
|
||||||
vp->durMicros += d_amicro;
|
|
||||||
|
|
||||||
// update the sustain pedal duration
|
|
||||||
if( sustainPedalDownMsg != NULL )
|
|
||||||
((cmMidiChMsg_t*)(sustainPedalDownMsg->u.chMsgPtr))->durMicros += d_amicro; // cast away const
|
|
||||||
|
|
||||||
//
|
|
||||||
// If this is sustain pedal msg
|
|
||||||
//
|
|
||||||
if( mp->status==kCtlMdId && mp->u.chMsgPtr->d0 == kSustainCtlMdId )
|
|
||||||
{
|
|
||||||
unsigned chIdx = mp->u.chMsgPtr->ch;
|
|
||||||
assert( chIdx < kMidiChCnt );
|
|
||||||
|
|
||||||
// set the state of the sustain pedal flags
|
|
||||||
sustainFlagV[chIdx] = mp->u.chMsgPtr->d1 >= 64;
|
|
||||||
|
|
||||||
// if the pedal went down ...
|
|
||||||
if( sustainFlagV[chIdx] )
|
|
||||||
{
|
|
||||||
|
|
||||||
if( sustainPedalDownMsg != NULL )
|
|
||||||
{
|
|
||||||
// TODO: the correct way to handle this is to maintain multiple sustain pedals
|
|
||||||
//cmErrMsg(&p->err,kSustainPedalMfRC,"Sustain pedal down with no intervening sustain pedal up.");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sustainPedalDownMsg = mp;
|
|
||||||
((cmMidiChMsg_t*)(sustainPedalDownMsg->u.chMsgPtr))->durMicros = 0; // cast away const
|
|
||||||
}
|
|
||||||
|
|
||||||
_cmMidiFileCalcNoteDurationsAllocVoice( &list, mp, true );
|
|
||||||
}
|
|
||||||
else // ... if the pedal went up
|
|
||||||
{
|
|
||||||
|
|
||||||
sustainPedalDownMsg = NULL;
|
|
||||||
|
|
||||||
// ... then release sustaining notes
|
|
||||||
_cmMidiVoice_t* pp = NULL;
|
|
||||||
for(vp=list; vp != NULL; )
|
|
||||||
{
|
|
||||||
_cmMidiVoice_t* np = vp->link;
|
|
||||||
if( vp->sustainFl && (vp->mp->u.chMsgPtr->ch == chIdx) )
|
|
||||||
_cmMidFileCalcNoteDurationReleaseNote(&list,pp,vp);
|
|
||||||
else
|
|
||||||
pp = vp;
|
|
||||||
|
|
||||||
vp = np;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// if this is a note-on msg
|
|
||||||
//
|
|
||||||
if( mp->status==kNoteOnMdId && mp->u.chMsgPtr->d1>0 )
|
|
||||||
{
|
|
||||||
_cmMidiFileCalcNoteDurationsAllocVoice( &list, mp, false );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
//
|
|
||||||
// if this is a note-off msg
|
|
||||||
//
|
|
||||||
if( (mp->status==kNoteOnMdId && mp->u.chMsgPtr->d1==0) || (mp->status==kNoteOffMdId) )
|
|
||||||
{
|
|
||||||
_cmMidiVoice_t* pp = NULL;
|
|
||||||
unsigned chIdx = mp->u.chMsgPtr->ch;
|
|
||||||
assert( chIdx < kMidiChCnt );
|
|
||||||
|
|
||||||
|
|
||||||
// for each active voice
|
|
||||||
for(vp=list; vp!=NULL; vp=vp->link )
|
|
||||||
{
|
|
||||||
// if this active voice ch/pitch matches the note-off msg ch pitch
|
|
||||||
if( (vp->mp->u.chMsgPtr->d0==mp->u.chMsgPtr->d0) && (vp->mp->u.chMsgPtr->ch==chIdx) )
|
|
||||||
{
|
|
||||||
// if the sustain pedal is down for this channel - then defer turning the note off
|
|
||||||
if( sustainFlagV[chIdx] )
|
|
||||||
vp->sustainFl = true;
|
|
||||||
else
|
|
||||||
_cmMidFileCalcNoteDurationReleaseNote(&list,pp,vp);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
pp = vp;
|
|
||||||
} // end for
|
|
||||||
} // end if
|
|
||||||
|
|
||||||
} // end-for
|
|
||||||
|
|
||||||
|
|
||||||
// check for hung notes
|
|
||||||
_cmMidiVoice_t* np = NULL;
|
|
||||||
vp = list;
|
|
||||||
while( vp != NULL )
|
|
||||||
{
|
|
||||||
np = vp->link;
|
|
||||||
|
|
||||||
if( cmMidiIsNoteOn(vp->mp->status) == false )
|
|
||||||
cmErrMsg(&p->err,kMissingNoteOffMfRC,"Missing note-off for note-on:%s",cmMidiToSciPitch(vp->mp->u.chMsgPtr->d0,NULL,0));
|
|
||||||
|
|
||||||
cmMemFree(vp);
|
|
||||||
vp = np;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _cmMidiFileSetDur( cmMidiTrackMsg_t* m0, cmMidiTrackMsg_t* m1 )
|
void _cmMidiFileSetDur( cmMidiTrackMsg_t* m0, cmMidiTrackMsg_t* m1 )
|
||||||
{
|
{
|
||||||
// calculate the duration of the sounding note
|
// calculate the duration of the sounding note
|
||||||
((cmMidiChMsg_t*)m0->u.chMsgPtr)->durMicros = m1->amicro - m0->amicro;
|
((cmMidiChMsg_t*)m0->u.chMsgPtr)->durMicros = m1->amicro - m0->amicro;
|
||||||
|
|
||||||
|
// set the note-off msg pointer
|
||||||
|
((cmMidiChMsg_t*)m0->u.chMsgPtr)->end = m1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _cmMidiFileCalcNoteDur( cmMidiTrackMsg_t* m0, cmMidiTrackMsg_t* m1, int noteGateFl, int sustainGateFl, bool sostGateFl )
|
bool _cmMidiFileCalcNoteDur( cmMidiTrackMsg_t* m0, cmMidiTrackMsg_t* m1, int noteGateFl, int sustainGateFl, bool sostGateFl )
|
||||||
@ -1628,6 +1459,7 @@ void cmMidiFileCalcNoteDurations( cmMidiFileH_t h )
|
|||||||
if( sustV[ch] != NULL )
|
if( sustV[ch] != NULL )
|
||||||
{
|
{
|
||||||
_cmMidiFileSetDur(sustV[ch],m);
|
_cmMidiFileSetDur(sustV[ch],m);
|
||||||
|
((cmMidiChMsg_t*)sustV[ch]->u.chMsgPtr)->end = m; // set the pedal-up msg ptr. in the pedal-down msg.
|
||||||
sustV[ch] = NULL;
|
sustV[ch] = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1635,7 +1467,7 @@ void cmMidiFileCalcNoteDurations( cmMidiFileH_t h )
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
||||||
// This is a sostenuto-pedal down msg
|
// This is a sostenuto pedal-down msg
|
||||||
if( cmMidiFileIsSostenutoPedalDown(m) )
|
if( cmMidiFileIsSostenutoPedalDown(m) )
|
||||||
{
|
{
|
||||||
// if the sustain channel is already down
|
// if the sustain channel is already down
|
||||||
@ -1651,7 +1483,7 @@ void cmMidiFileCalcNoteDurations( cmMidiFileH_t h )
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
||||||
// This is a sostenuto-pedal up msg
|
// This is a sostenuto pedal-up msg
|
||||||
if( cmMidiFileIsSostenutoPedalUp(m) )
|
if( cmMidiFileIsSostenutoPedalUp(m) )
|
||||||
{
|
{
|
||||||
// if the sustain channel is already up
|
// if the sustain channel is already up
|
||||||
@ -1678,6 +1510,7 @@ void cmMidiFileCalcNoteDurations( cmMidiFileH_t h )
|
|||||||
if( sostV[ch] != NULL )
|
if( sostV[ch] != NULL )
|
||||||
{
|
{
|
||||||
_cmMidiFileSetDur(sostV[ch],m);
|
_cmMidiFileSetDur(sostV[ch],m);
|
||||||
|
((cmMidiChMsg_t*)sostV[ch]->u.chMsgPtr)->end = m; // set the pedal-up msg ptr. in the pedal-down msg.
|
||||||
sostV[ch] = NULL;
|
sostV[ch] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,12 +52,15 @@ extern "C" {
|
|||||||
cmMidiByte_t scale;
|
cmMidiByte_t scale;
|
||||||
} cmMidiKeySig_t;
|
} cmMidiKeySig_t;
|
||||||
|
|
||||||
|
struct cmMidiTrackMsg_str;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
cmMidiByte_t ch;
|
cmMidiByte_t ch;
|
||||||
cmMidiByte_t d0;
|
cmMidiByte_t d0;
|
||||||
cmMidiByte_t d1;
|
cmMidiByte_t d1;
|
||||||
unsigned durMicros; // note duration in microseconds (corrected for tempo changes)
|
unsigned durMicros; // note duration in microseconds (corrected for tempo changes)
|
||||||
|
struct cmMidiTrackMsg_str* end; // note-off or pedal-up message
|
||||||
} cmMidiChMsg_t;
|
} cmMidiChMsg_t;
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user