/[svn]/linuxsampler/trunk/src/engines/common/InstrumentScriptVM.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/src/engines/common/InstrumentScriptVM.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2612 - (show annotations) (download)
Tue Jun 10 13:32:16 2014 UTC (9 years, 10 months ago) by schoenebeck
File size: 9440 byte(s)
* Fixed crashes when exiting the sampler.
* Bumped version (1.0.0.svn47).

1 /*
2 * Copyright (c) 2014 Christian Schoenebeck
3 *
4 * http://www.linuxsampler.org
5 *
6 * This file is part of LinuxSampler and released under the same terms.
7 * See README file for details.
8 */
9
10 #include "InstrumentScriptVM.h"
11 #include "../AbstractEngineChannel.h"
12 #include "../../common/global_private.h"
13 #include "AbstractInstrumentManager.h"
14
15 namespace LinuxSampler {
16
17 ///////////////////////////////////////////////////////////////////////
18 // class 'InstrumentScript'
19
20 /** @brief Load real-time instrument script.
21 *
22 * Loads the real-time instrument script given by @a text on the engine
23 * channel this InstrumentScript object belongs to (defined by
24 * pEngineChannel member variable). The sampler engine's resource manager is
25 * used to allocate and share equivalent scripts on multiple engine
26 * channels.
27 *
28 * @param text - source code of script
29 */
30 void InstrumentScript::load(const String& text) {
31 dmsg(1,("Loading real-time instrument script ... "));
32
33 // hand back old script reference and VM execution contexts
34 // (if not done already)
35 unload();
36
37 code = text;
38
39 AbstractInstrumentManager* pManager =
40 dynamic_cast<AbstractInstrumentManager*>(pEngineChannel->pEngine->GetInstrumentManager());
41
42 // get new script reference
43 parserContext = pManager->scripts.Borrow(text, pEngineChannel);
44 if (!parserContext->errors().empty()) {
45 std::vector<ParserIssue> errors = parserContext->errors();
46 std::cerr << "[ScriptVM] Could not load instrument script, there were "
47 << errors.size() << " parser errors:\n";
48 for (int i = 0; i < errors.size(); ++i)
49 errors[i].dump();
50 return; // stop here if there were any parser errors
51 }
52
53 handlerInit = parserContext->eventHandlerByName("init");
54 handlerNote = parserContext->eventHandlerByName("note");
55 handlerRelease = parserContext->eventHandlerByName("release");
56 handlerController = parserContext->eventHandlerByName("controller");
57 bHasValidScript =
58 handlerInit || handlerNote || handlerRelease || handlerController;
59
60 // amount of script handlers each script event has to execute
61 int handlerExecCount = 0;
62 if (handlerNote || handlerRelease || handlerController) // only one of these are executed after "init" handler
63 handlerExecCount++;
64
65 // create script event pool (if it doesn't exist already)
66 if (!pEvents)
67 pEvents = new Pool<ScriptEvent>(CONFIG_MAX_EVENTS_PER_FRAGMENT);
68
69 // create new VM execution contexts for new script
70 while (!pEvents->poolIsEmpty()) {
71 RTList<ScriptEvent>::Iterator it = pEvents->allocAppend();
72 it->execCtx = pEngineChannel->pEngine->pScriptVM->createExecContext(
73 parserContext
74 );
75 it->handlers = new VMEventHandler*[handlerExecCount+1];
76 }
77 pEvents->clear();
78
79 dmsg(1,("Done\n"));
80 }
81
82 /** @brief Unload real-time instrument script.
83 *
84 * Unloads the currently used real-time instrument script and frees all
85 * resources allocated for that script. The sampler engine's resource manager
86 * is used to share equivalent scripts among multiple sampler channels, and
87 * to deallocate the parsed script once not used on any engine channel
88 * anymore.
89 *
90 * Calling thid method will however not clear the @c code member variable.
91 * Thus, the script can be parsed again afterwards.
92 */
93 void InstrumentScript::unload() {
94 if (parserContext)
95 dmsg(1,("Unloading current instrument script.\n"));
96
97 // free allocated VM execution contexts
98 if (pEvents) {
99 pEvents->clear();
100 while (!pEvents->poolIsEmpty()) {
101 RTList<ScriptEvent>::Iterator it = pEvents->allocAppend();
102 if (it->execCtx) {
103 // free VM execution context object
104 delete it->execCtx;
105 it->execCtx = NULL;
106 // free C array of handler pointers
107 delete [] it->handlers;
108 }
109 }
110 pEvents->clear();
111 }
112 // hand back VM representation of script
113 if (parserContext) {
114 AbstractInstrumentManager* pManager =
115 dynamic_cast<AbstractInstrumentManager*>(pEngineChannel->pEngine->GetInstrumentManager());
116
117 pManager->scripts.HandBack(parserContext, pEngineChannel);
118 parserContext = NULL;
119 handlerInit = NULL;
120 handlerNote = NULL;
121 handlerRelease = NULL;
122 handlerController = NULL;
123 }
124 bHasValidScript = false;
125 }
126
127 /**
128 * Same as unload(), but this one also empties the @c code member variable
129 * to an empty string.
130 */
131 void InstrumentScript::resetAll() {
132 unload();
133 code.clear();
134 }
135
136 ///////////////////////////////////////////////////////////////////////
137 // class 'InstrumentScriptVM'
138
139 InstrumentScriptVM::InstrumentScriptVM() :
140 m_event(NULL), m_fnPlayNote(this), m_fnSetController(this),
141 m_fnIgnoreEvent(this), m_fnIgnoreController(this)
142 {
143 m_CC.size = _MEMBER_SIZEOF(AbstractEngineChannel, ControllerTable);
144 m_CC_NUM = DECLARE_VMINT(m_event, class ScriptEvent, cause.Param.CC.Controller);
145 m_EVENT_ID = DECLARE_VMINT(m_event, class ScriptEvent, id);
146 m_EVENT_NOTE = DECLARE_VMINT(m_event, class ScriptEvent, cause.Param.Note.Key);
147 m_EVENT_VELOCITY = DECLARE_VMINT(m_event, class ScriptEvent, cause.Param.Note.Velocity);
148 }
149
150 VMExecStatus_t InstrumentScriptVM::exec(VMParserContext* parserCtx, ScriptEvent* event) {
151 AbstractEngineChannel* pEngineChannel =
152 static_cast<AbstractEngineChannel*>(event->cause.pEngineChannel);
153
154 // prepare built-in script variables for script execution
155 m_event = event;
156 m_CC.data = (int8_t*) &pEngineChannel->ControllerTable[0];
157
158 // if script is in start condition, then do mandatory MIDI event
159 // preprocessing tasks, which essentially means updating i.e. controller
160 // table with new CC value in case of a controller event, because the
161 // script might access the new CC value
162 if (!event->executionSlices) {
163 switch (event->cause.Type) {
164 case Event::type_control_change:
165 pEngineChannel->ControllerTable[event->cause.Param.CC.Controller] =
166 event->cause.Param.CC.Value;
167 break;
168 case Event::type_channel_pressure:
169 pEngineChannel->ControllerTable[CTRL_TABLE_IDX_AFTERTOUCH] =
170 event->cause.Param.ChannelPressure.Value;
171 break;
172 case Event::type_pitchbend:
173 pEngineChannel->ControllerTable[CTRL_TABLE_IDX_PITCHBEND] =
174 event->cause.Param.Pitch.Pitch;
175 break;
176 }
177 }
178
179 // run the script handler(s)
180 VMExecStatus_t res = VM_EXEC_NOT_RUNNING;
181 for ( ; event->handlers[event->currentHandler]; event->currentHandler++) {
182 res = ScriptVM::exec(
183 parserCtx, event->execCtx, event->handlers[event->currentHandler]
184 );
185 event->executionSlices++;
186 if (res & VM_EXEC_SUSPENDED || res & VM_EXEC_ERROR) return res;
187 }
188
189 return res;
190 }
191
192 std::map<String,VMIntRelPtr*> InstrumentScriptVM::builtInIntVariables() {
193 // first get buil-in integer variables of derived VM class
194 std::map<String,VMIntRelPtr*> m = ScriptVM::builtInIntVariables();
195
196 // now add own built-in variables
197 m["$CC_NUM"] = &m_CC_NUM;
198 m["$EVENT_ID"] = &m_EVENT_ID;
199 m["$EVENT_NOTE"] = &m_EVENT_NOTE;
200 m["$EVENT_VELOCITY"] = &m_EVENT_VELOCITY;
201 // m["$POLY_AT_NUM"] = &m_POLY_AT_NUM;
202
203 return m;
204 }
205
206 std::map<String,VMInt8Array*> InstrumentScriptVM::builtInIntArrayVariables() {
207 // first get buil-in integer array variables of derived VM class
208 std::map<String,VMInt8Array*> m = ScriptVM::builtInIntArrayVariables();
209
210 // now add own built-in variables
211 m["%CC"] = &m_CC;
212 //m["%KEY_DOWN"] = &m_KEY_DOWN;
213 //m["%POLY_AT"] = &m_POLY_AT;
214
215 return m;
216 }
217
218 std::map<String,int> InstrumentScriptVM::builtInConstIntVariables() {
219 // first get buil-in integer variables of derived VM class
220 std::map<String,int> m = ScriptVM::builtInConstIntVariables();
221
222 m["$VCC_MONO_AT"] = CTRL_TABLE_IDX_AFTERTOUCH;
223 m["$VCC_PITCH_BEND"] = CTRL_TABLE_IDX_PITCHBEND;
224
225 return m;
226 }
227
228 VMFunction* InstrumentScriptVM::functionByName(const String& name) {
229 // built-in script functions of this class
230 if (name == "play_note") return &m_fnPlayNote;
231 else if (name == "set_controller") return &m_fnSetController;
232 else if (name == "ignore_event") return &m_fnIgnoreEvent;
233 else if (name == "ignore_controller") return &m_fnIgnoreController;
234
235 // built-in script functions of derived VM class
236 return ScriptVM::functionByName(name);
237 }
238
239 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC