/[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 2611 - (show annotations) (download)
Mon Jun 9 19:20:37 2014 UTC (9 years, 10 months ago) by schoenebeck
File size: 9063 byte(s)
* Fixed crash when loading an instrument script.
* Fixed "init" script handler only to be executed once:
  when the script was loaded.
* Fixed aftertouch script event which always had value zero
  and controller number was set to aftertouch value instead.
* gig Engine: Fixed handling of "smartmidi" dimension, which
  was recognized as "unknown" dimension.
* Fixed script function gig_set_dim_zone(): was accessing
  wrong event.
* ls_instr_script command line tool: is now not limited to
  core language scripts, but can now also parse sampler format
  dependent instrument scripts, with the respective specific
  built-in script variables and functions.
* ScriptVM: Fixed runtime behavior of "and" and "or" binary
  script expressions, which also evaluated the right hand side
  of the expression even if the left hand side already failed
  the overall expression semantic to become true.
* Bumped version (1.0.0.svn46).

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

  ViewVC Help
Powered by ViewVC