handle "velocity==0 means note-off". Makes for better handling of the case where notes overlap
This commit is contained in:
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
* MIDI event info is explained here: http://www.sonicspot.com/guide/midifiles.html
|
* MIDI event info is explained here: http://www.sonicspot.com/guide/midifiles.html
|
||||||
|
|
||||||
* Explanation of MIDI "running status" here: http://www.borg.com/~jglatt/tech/midispec/run.htm
|
* Explanation of MIDI "running status" and note-on velocity==0 meaning: http://www.borg.com/~jglatt/tech/midispec/run.htm
|
||||||
|
|
||||||
* Guitar track mappings are explained here: http://www.scorehero.com/forum/viewtopic.php?t=1179
|
* Guitar track mappings are explained here: http://www.scorehero.com/forum/viewtopic.php?t=1179
|
||||||
|
|
||||||
@@ -650,9 +650,9 @@ static bool LoadFromMidi( const RString &sPath, Song &songOut )
|
|||||||
while( event.size() )
|
while( event.size() )
|
||||||
{
|
{
|
||||||
MidiEventType midiEventType = (MidiEventType)(event[0] >> 4);
|
MidiEventType midiEventType = (MidiEventType)(event[0] >> 4);
|
||||||
//uint8_t uMidiChannel = event[0] & 0xF; // currently unused
|
uint8_t uMidiChannel = event[0] & 0xF; // currently unused
|
||||||
uint8_t uParam1 = event[1]; // meaning is MidiEventType-specific
|
uint8_t uParam1 = event[1]; // meaning is MidiEventType-specific
|
||||||
//uint8_t uParam2 = event[2]; // currently unused, meaning is MidiEventType-specific
|
uint8_t uParam2 = event[2]; // currently unused, meaning is MidiEventType-specific
|
||||||
|
|
||||||
switch( midiEventType )
|
switch( midiEventType )
|
||||||
{
|
{
|
||||||
@@ -660,7 +660,11 @@ static bool LoadFromMidi( const RString &sPath, Song &songOut )
|
|||||||
case note_on:
|
case note_on:
|
||||||
{
|
{
|
||||||
const uint8_t &uNoteNumber = uParam1;
|
const uint8_t &uNoteNumber = uParam1;
|
||||||
//const uint8_t &uVelocity = uParam2; // currently unused
|
const uint8_t &uVelocity = uParam2;
|
||||||
|
|
||||||
|
// velocity == 0, by convention, means note-off
|
||||||
|
if( uVelocity == 0 )
|
||||||
|
midiEventType = note_off;
|
||||||
|
|
||||||
GuitarDifficulty gd;
|
GuitarDifficulty gd;
|
||||||
NoteNumberType nnt;
|
NoteNumberType nnt;
|
||||||
@@ -693,7 +697,7 @@ static bool LoadFromMidi( const RString &sPath, Song &songOut )
|
|||||||
if( nnt >= NUM_FRETS )
|
if( nnt >= NUM_FRETS )
|
||||||
continue; // data other than the frets is not handled yet
|
continue; // data other than the frets is not handled yet
|
||||||
|
|
||||||
bool bTrackIsOn = false;
|
bool bNonTerminatedNote = false;
|
||||||
long countOfLastNote = 0;
|
long countOfLastNote = 0;
|
||||||
FOREACH_CONST( MidiEvent, vMidiEvent[gd][nnt], iter )
|
FOREACH_CONST( MidiEvent, vMidiEvent[gd][nnt], iter )
|
||||||
{
|
{
|
||||||
@@ -722,67 +726,69 @@ static bool LoadFromMidi( const RString &sPath, Song &songOut )
|
|||||||
long count = iter->count;
|
long count = iter->count;
|
||||||
float fBeat = NoteRowToBeat( MidiCountToNoteRow(count) );
|
float fBeat = NoteRowToBeat( MidiCountToNoteRow(count) );
|
||||||
bool bNoteHandled = false;
|
bool bNoteHandled = false;
|
||||||
if( bTrackIsOn )
|
long length = count - countOfLastNote;
|
||||||
{
|
|
||||||
if( midiEventType == note_off || midiEventType == note_on )
|
|
||||||
{
|
|
||||||
// end this track
|
|
||||||
long length = count - countOfLastNote;
|
|
||||||
|
|
||||||
|
|
||||||
|
// Check for termination of a sustain note
|
||||||
|
switch( midiEventType )
|
||||||
|
{
|
||||||
|
case note_off:
|
||||||
|
case note_on:
|
||||||
|
if( bNonTerminatedNote )
|
||||||
|
{
|
||||||
if( length >= 240 )
|
if( length >= 240 )
|
||||||
{
|
{
|
||||||
TapNote tn = TAP_ORIGINAL_HOLD_HEAD;
|
TapNote tn = TAP_ORIGINAL_HOLD_HEAD;
|
||||||
tn.iDuration = MidiCountToNoteRow( length );
|
tn.iDuration = MidiCountToNoteRow( length );
|
||||||
noteData.SetTapNote( nnt, MidiCountToNoteRow(countOfLastNote), tn );
|
noteData.SetTapNote( nnt, MidiCountToNoteRow(countOfLastNote), tn );
|
||||||
|
|
||||||
if( gd == expert && fBeat >= 9*4-2 && nnt == yellow )
|
// if( gd == expert && fBeat >= 27*4-2 && nnt == green )
|
||||||
LOG->Trace( "Added hold at %f", fBeat );
|
// LOG->Trace( "Added hold at %f, length %d", fBeat, length );
|
||||||
}
|
}
|
||||||
|
|
||||||
bTrackIsOn = false;
|
bNonTerminatedNote = false;
|
||||||
countOfLastNote = 0;
|
|
||||||
bNoteHandled = true;
|
bNoteHandled = true;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
|
||||||
|
switch( midiEventType )
|
||||||
{
|
{
|
||||||
if( midiEventType == note_on )
|
case note_on:
|
||||||
{
|
{
|
||||||
// start this track
|
|
||||||
TapNote tn = TAP_ORIGINAL_TAP;
|
TapNote tn = TAP_ORIGINAL_TAP;
|
||||||
|
|
||||||
// We're about to add a tap note. If the previous note was a sustain note that ended
|
// We're about to add a tap note. If the previous note was a sustain note that ended
|
||||||
// on this row, then make the sustain note one row shorter so that it doesn't end on
|
// on this row, then make the sustain note shorter so that it doesn't end on
|
||||||
// the same row as the tap note we're about to add. NoteData cannot handle a
|
// the same row as the tap note we're about to add. NoteData cannot handle a
|
||||||
// hold note ending on the same row as a tap note.
|
// hold note ending on the same row as a tap note.
|
||||||
NoteData::iterator begin, end;
|
NoteData::iterator begin, end;
|
||||||
noteData.GetTapNoteRangeInclusive( nnt, MidiCountToNoteRow(count), MidiCountToNoteRow(count), begin, end, true );
|
noteData.GetTapNoteRangeInclusive( nnt, MidiCountToNoteRow(count), MidiCountToNoteRow(count), begin, end, true );
|
||||||
for( NoteData::iterator iter = begin; iter != end; iter++ )
|
for( NoteData::iterator iter = begin; iter != end; iter++ )
|
||||||
{
|
{
|
||||||
if( gd == expert && fBeat >= 9*4-2 && nnt == yellow )
|
// if( gd == expert && fBeat >= 27*4-2 && nnt == green )
|
||||||
LOG->Trace( "shortening hold at %f", fBeat );
|
// LOG->Trace( "shortening hold at %f, length %d", fBeat, length );
|
||||||
|
|
||||||
ASSERT( iter->second.type == TapNote::hold_head );
|
ASSERT( iter->second.type == TapNote::hold_head );
|
||||||
ASSERT( iter->first + iter->second.iDuration == MidiCountToNoteRow(count) );
|
iter->second.iDuration = MidiCountToNoteRow(count) - iter->first - 2;
|
||||||
iter->second.iDuration -= 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
noteData.SetTapNote( nnt, MidiCountToNoteRow(count), tn );
|
noteData.SetTapNote( nnt, MidiCountToNoteRow(count), tn );
|
||||||
|
|
||||||
|
|
||||||
if( gd == expert && fBeat >= 9*4-2 && nnt == yellow )
|
// if( gd == expert && fBeat >= 27*4-2 && nnt == green )
|
||||||
LOG->Trace( "Added tap at %f", fBeat );
|
// LOG->Trace( "Added tap at %f, length %d", fBeat, length );
|
||||||
|
|
||||||
bTrackIsOn = true;
|
bNonTerminatedNote = true;
|
||||||
countOfLastNote = count;
|
|
||||||
bNoteHandled = true;
|
bNoteHandled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
countOfLastNote = count;
|
||||||
|
|
||||||
if( !bNoteHandled )
|
if( !bNoteHandled )
|
||||||
{
|
LOG->Warn( "Unexpected MIDI event type %X at count %ld", midiEventType, count );
|
||||||
LOG->Trace( "Unexpected MIDI event type %X at count %ld", midiEventType, count );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user