--- linuxsampler/trunk/src/engines/EngineBase.h 2016/04/19 14:07:53 2879 +++ linuxsampler/trunk/src/engines/EngineBase.h 2016/06/30 16:44:46 2927 @@ -771,8 +771,12 @@ // // FIXME: it would probably be better to just schedule newly spawned script executions here and then execute them altogether with already suspended ones all at once in order of all their scheduled timing for (RTList::Iterator itEvent = pChannel->pEvents->first(), - end = pChannel->pEvents->end(); itEvent != end; ++itEvent) + end = pChannel->pEvents->end(); itEvent != end; ) { + //HACK: avoids iterator invalidation which might happen below since an instrument script might drop an event by direct raw pointer access (it would be considerable to extend the Iterator class to detect and circumvent this case by checking the "reincarnation" member variable). + RTList::Iterator itNext = itEvent; + ++itNext; + switch (itEvent->Type) { case Event::type_note_on: if (pChannel->pScript->handlerNote) @@ -792,6 +796,9 @@ //TODO: ... break; } + + // see HACK comment above + itEvent = itNext; } // this has to be run again, since the newly spawned scripts @@ -1780,16 +1787,8 @@ // if no solo mode (the usual case) or if solo mode and no other key pressed, then release voices on this key if needed if (bShouldRelease) { itNoteOffEventOnKeyList->Type = Event::type_release; // transform event type - // spawn release triggered voice(s) if needed - if (pKey->ReleaseTrigger && pChannel->pInstrument) { - // assign a new note to this release event - if (LaunchNewNote(pChannel, &*itNoteOffEventOnKeyList)) { - // allocate and trigger new release voice(s) - TriggerReleaseVoices(pChannel, itNoteOffEventOnKeyList); - } - pKey->ReleaseTrigger = false; - } + ProcessReleaseTrigger(pChannel, itNoteOffEventOnKeyList, pKey); } // if neither a voice was spawned or postponed on this key then remove note off event from key again @@ -1800,6 +1799,45 @@ } /** + * Called on sustain pedal up events to check and if required, + * launch release trigger voices on the respective active key. + * + * @param pEngineChannel - engine channel on which this event occurred on + * @param itEvent - release trigger event (contains note number) + */ + virtual void ProcessReleaseTrigger(EngineChannel* pEngineChannel, RTList::Iterator& itEvent) OVERRIDE { + EngineChannelBase* pChannel = static_cast*>(pEngineChannel); + + const int iKey = itEvent->Param.Note.Key; + if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range + + MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey]; + + ProcessReleaseTrigger(pChannel, itEvent, pKey); + } + + /** + * Called on note-off and sustain pedal up events to check and if + * required, launch release trigger voices on the respective active + * key. + * + * @param pEngineChannel - engine channel on which this event occurred on + * @param itEvent - note off event / release trigger event + * @param pKey - key on which the release trigger voices shall be spawned + */ + inline void ProcessReleaseTrigger(EngineChannelBase* pChannel, RTList::Iterator& itEvent, MidiKey* pKey) { + // spawn release triggered voice(s) if needed + if (pKey->ReleaseTrigger && pChannel->pInstrument) { + // assign a new note to this release event + if (LaunchNewNote(pChannel, &*itEvent)) { + // allocate and trigger new release voice(s) + TriggerReleaseVoices(pChannel, itEvent); + } + pKey->ReleaseTrigger = false; + } + } + + /** * Reset all voices and disk thread and clear input event queue and all * control and status variables. This method is protected by a mutex. */