--- linuxsampler/trunk/src/engines/common/InstrumentScriptVM.cpp 2014/06/12 18:25:11 2629 +++ linuxsampler/trunk/src/engines/common/InstrumentScriptVM.cpp 2016/07/10 14:24:13 2935 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Christian Schoenebeck + * Copyright (c) 2014 - 2016 Christian Schoenebeck * * http://www.linuxsampler.org * @@ -16,8 +16,65 @@ namespace LinuxSampler { /////////////////////////////////////////////////////////////////////// + // class 'EventGroup' + + void EventGroup::insert(int eventID) { + if (contains(eventID)) return; + + AbstractEngine* pEngine = m_script->pEngineChannel->pEngine; + + // before adding the new event ID, check if there are any dead events + // and remove them in that case, before otherwise we might run in danger + // to run out of free space on this group for event IDs if a lot of + // events die before being removed explicitly from the group by script + // + // NOTE: or should we do this "dead ones" check only once in a while? + int firstDead = -1; + for (int i = 0; i < size(); ++i) { + if (firstDead >= 0) { + if (pEngine->EventByID(eventID)) { + remove(firstDead, i - firstDead); + firstDead = -1; + } + } else { + if (!pEngine->EventByID(eventID)) firstDead = i; + } + } + + append(eventID); + } + + void EventGroup::erase(int eventID) { + int index = find(eventID); + remove(index); + } + + /////////////////////////////////////////////////////////////////////// // class 'InstrumentScript' + InstrumentScript::InstrumentScript(AbstractEngineChannel* pEngineChannel) { + parserContext = NULL; + bHasValidScript = false; + handlerInit = NULL; + handlerNote = NULL; + handlerRelease = NULL; + handlerController = NULL; + pEvents = NULL; + for (int i = 0; i < 128; ++i) + pKeyEvents[i] = NULL; + this->pEngineChannel = pEngineChannel; + for (int i = 0; i < INSTR_SCRIPT_EVENT_GROUPS; ++i) + eventGroups[i].setScript(this); + } + + InstrumentScript::~InstrumentScript() { + resetAll(); + if (pEvents) { + for (int i = 0; i < 128; ++i) delete pKeyEvents[i]; + delete pEvents; + } + } + /** @brief Load real-time instrument script. * * Loads the real-time instrument script given by @a text on the engine @@ -64,8 +121,11 @@ handlerExecCount++; // create script event pool (if it doesn't exist already) - if (!pEvents) + if (!pEvents) { pEvents = new Pool(CONFIG_MAX_EVENTS_PER_FRAGMENT); + for (int i = 0; i < 128; ++i) + pKeyEvents[i] = new RTList(pEvents); + } // create new VM execution contexts for new script while (!pEvents->poolIsEmpty()) { @@ -97,6 +157,8 @@ if (parserContext) dmsg(1,("Unloading current instrument script.\n")); + resetEvents(); + // free allocated VM execution contexts if (pEvents) { pEvents->clear(); @@ -135,13 +197,33 @@ unload(); code.clear(); } + + /** + * Clears all currently active script events. This should be called + * whenever the engine or engine channel was reset for some reason. + */ + void InstrumentScript::resetEvents() { + for (int i = 0; i < INSTR_SCRIPT_EVENT_GROUPS; ++i) + eventGroups[i].clear(); + + for (int i = 0; i < 128; ++i) + if (pKeyEvents[i]) + pKeyEvents[i]->clear(); + + suspendedEvents.clear(); + + if (pEvents) pEvents->clear(); + } /////////////////////////////////////////////////////////////////////// // class 'InstrumentScriptVM' InstrumentScriptVM::InstrumentScriptVM() : m_event(NULL), m_fnPlayNote(this), m_fnSetController(this), - m_fnIgnoreEvent(this), m_fnIgnoreController(this), m_fnNoteOff(this) + m_fnIgnoreEvent(this), m_fnIgnoreController(this), m_fnNoteOff(this), + m_fnSetEventMark(this), m_fnDeleteEventMark(this), m_fnByMarks(this), + m_fnChangeVol(this), m_fnChangeTune(this), m_fnChangePan(this), + m_fnChangeCutoff(this), m_fnChangeReso(this), m_fnEventStatus(this) { m_CC.size = _MEMBER_SIZEOF(AbstractEngineChannel, ControllerTable); m_CC_NUM = DECLARE_VMINT(m_event, class ScriptEvent, cause.Param.CC.Controller); @@ -224,8 +306,13 @@ // first get buil-in integer variables of derived VM class std::map m = ScriptVM::builtInConstIntVariables(); + m["$EVENT_STATUS_INACTIVE"] = EVENT_STATUS_INACTIVE; + m["$EVENT_STATUS_NOTE_QUEUE"] = EVENT_STATUS_NOTE_QUEUE; m["$VCC_MONO_AT"] = CTRL_TABLE_IDX_AFTERTOUCH; m["$VCC_PITCH_BEND"] = CTRL_TABLE_IDX_PITCHBEND; + for (int i = 0; i < INSTR_SCRIPT_EVENT_GROUPS; ++i) { + m["$MARK_" + ToString(i+1)] = i; + } return m; } @@ -237,6 +324,15 @@ else if (name == "ignore_event") return &m_fnIgnoreEvent; else if (name == "ignore_controller") return &m_fnIgnoreController; else if (name == "note_off") return &m_fnNoteOff; + else if (name == "set_event_mark") return &m_fnSetEventMark; + else if (name == "delete_event_mark") return &m_fnDeleteEventMark; + else if (name == "by_marks") return &m_fnByMarks; + else if (name == "change_vol") return &m_fnChangeVol; + else if (name == "change_tune") return &m_fnChangeTune; + else if (name == "change_pan") return &m_fnChangePan; + else if (name == "change_cutoff") return &m_fnChangeCutoff; + else if (name == "change_reso") return &m_fnChangeReso; + else if (name == "event_status") return &m_fnEventStatus; // built-in script functions of derived VM class return ScriptVM::functionByName(name);