aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorWohlstand <admin@wohlnet.ru>2017-11-09 22:50:32 +0300
committerWohlstand <admin@wohlnet.ru>2017-11-09 22:50:32 +0300
commit0be25a41ca793c3c03814f529890492adfac8ad5 (patch)
treea099d0025109b689bb0d6847e83b9890e34d5d35 /src
parent265ae7a37afb087b9e16f4ddd0eaef28a21826de (diff)
downloadlibADLMIDI-0be25a41ca793c3c03814f529890492adfac8ad5.tar.gz
libADLMIDI-0be25a41ca793c3c03814f529890492adfac8ad5.tar.bz2
libADLMIDI-0be25a41ca793c3c03814f529890492adfac8ad5.zip
Resolve weird crash caused by Tetris inside ADLMIDI2 and other changes
- Move most of inline classes methods into own CC file - Move Input into own header with own CC file to share it with the puzzle game - Created virtual destructors and resolved weak vtable trouble between of Tetris's classes - Remove static declarisons of Tetris class. Instead, let it be member of UserInterface - Fixed forgot note-offs while sorting events row with zero length notes - Fixed crash caused by unsafe access by reference to element of array that was modified/reallocated one or multiple times - Stabilize dealing with zero-length notes
Diffstat (limited to 'src')
-rw-r--r--src/adlmidi_midiplay.cpp60
-rw-r--r--src/adlmidi_private.hpp4
2 files changed, 44 insertions, 20 deletions
diff --git a/src/adlmidi_midiplay.cpp b/src/adlmidi_midiplay.cpp
index 220b18c..83517db 100644
--- a/src/adlmidi_midiplay.cpp
+++ b/src/adlmidi_midiplay.cpp
@@ -193,38 +193,59 @@ void MIDIplay::MidiTrackRow::sortEvents(bool *noteStates)
}
/*
- * If Note-Off and it's Note-On is on the same row - move this danmed note off down!
+ * If Note-Off and it's Note-On is on the same row - move this damned note off down!
*/
if(noteStates)
{
+ std::set<size_t> markAsOn;
for(size_t i = 0; i < anyOther.size(); i++)
{
- MidiEvent &e = anyOther[i];
+ const MidiEvent e = anyOther[i];
if(e.type == MidiEvent::T_NOTEON)
{
- size_t note_i = (e.channel * 255) + e.data[0];
+ const size_t note_i = (e.channel * 255) + (e.data[0] & 0x7F);
//Check, was previously note is on or off
bool wasOn = noteStates[note_i];
- bool keepOn = true;
+ markAsOn.insert(note_i);
+ // Detect zero-length notes are following previously pressed note
+ int noteOffsOnSameNote = 0;
for(EvtArr::iterator j = noteOffs.begin(); j != noteOffs.end();)
{
//If note was off, and note-off on same row with note-on - move it down!
if(
((*j).channel == e.channel) &&
- ((*j).data[0] == e.data[0]) &&
- !wasOn // Also check, is this note already OFF!!!
+ ((*j).data[0] == e.data[0])
)
{
- anyOther.push_back(*j);
- j = noteOffs.erase(j);
- keepOn = false;
- continue;
+ //If note is already off OR more than one note-off on same row and same note
+ if(!wasOn || (noteOffsOnSameNote != 0))
+ {
+ anyOther.push_back(*j);
+ j = noteOffs.erase(j);
+ markAsOn.erase(note_i);
+ continue;
+ } else {
+ //When same row has many note-offs on same row
+ //that means a zero-length note follows previous note
+ //it must be shuted down
+ noteOffsOnSameNote++;
+ }
}
j++;
}
- if(keepOn) noteStates[note_i] = true;
}
}
+
+ //Mark other notes as released
+ for(EvtArr::iterator j = noteOffs.begin(); j != noteOffs.end(); j++)
+ {
+ size_t note_i = (j->channel * 255) + (j->data[0] & 0x7F);
+ noteStates[note_i] = false;
+ }
+
+ for(std::set<size_t>::iterator j = markAsOn.begin(); j != markAsOn.end(); j++)
+ noteStates[*j] = true;
+
}
/***********************************************************************************/
@@ -1543,10 +1564,17 @@ bool MIDIplay::ProcessEventsNew(bool isSeek)
PositionNew::TrackInfo &track = CurrentPositionNew.track[tk];
if((track.status >= 0) && (track.delay <= 0))
{
+ //Check is an end of track has been reached
+ if(track.pos == trackDataNew[tk].end())
+ {
+ track.status = -1;
+ break;
+ }
+
// Handle event
for(size_t i = 0; i < track.pos->events.size(); i++)
{
- MidiEvent &evt = track.pos->events[i];
+ const MidiEvent &evt = track.pos->events[i];
#ifdef ENABLE_BEGIN_SILENCE_SKIPPING
if(!CurrentPositionNew.began && (evt.type == MidiEvent::T_NOTEON))
CurrentPositionNew.began = true;
@@ -1562,11 +1590,7 @@ bool MIDIplay::ProcessEventsNew(bool isSeek)
if(maxTime < track.pos->time)
maxTime = track.pos->time;
#endif
-
// Read next event time (unless the track just ended)
- if(track.pos == trackDataNew[tk].end())
- track.status = -1;
-
if(track.status >= 0)
{
track.delay += track.pos->delay;
@@ -1847,7 +1871,7 @@ void MIDIplay::setErrorString(const std::string &err)
}
-void MIDIplay::HandleEvent(size_t tk, MIDIplay::MidiEvent &evt, int &status)
+void MIDIplay::HandleEvent(size_t tk, const MIDIplay::MidiEvent &evt, int &status)
{
if(hooks.onEvent)
{
@@ -2575,7 +2599,7 @@ ADLMIDI_EXPORT bool AdlInstrumentTester::HandleInputChar(char ch)
default:
const char *p = strchr(notes, ch);
if(p && *p)
- DoNote((p - notes) - 12);
+ DoNote((int)(p - notes) - 12);
}
return true;
}
diff --git a/src/adlmidi_private.hpp b/src/adlmidi_private.hpp
index 37e0d25..58b4e10 100644
--- a/src/adlmidi_private.hpp
+++ b/src/adlmidi_private.hpp
@@ -257,7 +257,7 @@ struct MIDIEventHooks
onDebugMessage_userData(NULL)
{}
//! Raw MIDI event hook
- typedef void (*RawEventHook)(void *userdata, uint8_t type, uint8_t subtype, uint8_t channel, uint8_t *data, size_t len);
+ typedef void (*RawEventHook)(void *userdata, uint8_t type, uint8_t subtype, uint8_t channel, const uint8_t *data, size_t len);
RawEventHook onEvent;
void *onEvent_userData;
@@ -886,7 +886,7 @@ private:
bool ProcessEvents();
bool ProcessEventsNew(bool isSeek = false);
void HandleEvent(size_t tk);
- void HandleEvent(size_t tk, MidiEvent &evt, int &status);
+ void HandleEvent(size_t tk, const MidiEvent &evt, int &status);
// Determine how good a candidate this adlchannel
// would be for playing a note from this instrument.