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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2611 - (hide annotations) (download)
Mon Jun 9 19:20:37 2014 UTC (9 years, 9 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 schoenebeck 2594 /*
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 schoenebeck 2600 #include "../../common/global_private.h"
13 schoenebeck 2611 #include "AbstractInstrumentManager.h"
14 schoenebeck 2594
15     namespace LinuxSampler {
16    
17 schoenebeck 2611 ///////////////////////////////////////////////////////////////////////
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 schoenebeck 2596 InstrumentScriptVM::InstrumentScriptVM() :
126 schoenebeck 2600 m_event(NULL), m_fnPlayNote(this), m_fnSetController(this),
127     m_fnIgnoreEvent(this), m_fnIgnoreController(this)
128 schoenebeck 2596 {
129 schoenebeck 2595 m_CC.size = _MEMBER_SIZEOF(AbstractEngineChannel, ControllerTable);
130 schoenebeck 2598 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 schoenebeck 2594 }
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 schoenebeck 2598 m_event = event;
142 schoenebeck 2594 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 schoenebeck 2598 switch (event->cause.Type) {
150 schoenebeck 2594 case Event::type_control_change:
151 schoenebeck 2598 pEngineChannel->ControllerTable[event->cause.Param.CC.Controller] =
152     event->cause.Param.CC.Value;
153 schoenebeck 2594 break;
154     case Event::type_channel_pressure:
155     pEngineChannel->ControllerTable[CTRL_TABLE_IDX_AFTERTOUCH] =
156 schoenebeck 2598 event->cause.Param.ChannelPressure.Value;
157 schoenebeck 2594 break;
158     case Event::type_pitchbend:
159     pEngineChannel->ControllerTable[CTRL_TABLE_IDX_PITCHBEND] =
160 schoenebeck 2598 event->cause.Param.Pitch.Pitch;
161 schoenebeck 2594 break;
162     }
163     }
164    
165     // run the script handler(s)
166     VMExecStatus_t res = VM_EXEC_NOT_RUNNING;
167 schoenebeck 2596 for ( ; event->handlers[event->currentHandler]; event->currentHandler++) {
168 schoenebeck 2594 res = ScriptVM::exec(
169 schoenebeck 2596 parserCtx, event->execCtx, event->handlers[event->currentHandler]
170 schoenebeck 2594 );
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 schoenebeck 2598 m["$EVENT_ID"] = &m_EVENT_ID;
185 schoenebeck 2594 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 schoenebeck 2596 VMFunction* InstrumentScriptVM::functionByName(const String& name) {
215     // built-in script functions of this class
216 schoenebeck 2598 if (name == "play_note") return &m_fnPlayNote;
217 schoenebeck 2600 else if (name == "set_controller") return &m_fnSetController;
218 schoenebeck 2598 else if (name == "ignore_event") return &m_fnIgnoreEvent;
219     else if (name == "ignore_controller") return &m_fnIgnoreController;
220 schoenebeck 2596
221     // built-in script functions of derived VM class
222     return ScriptVM::functionByName(name);
223     }
224    
225 schoenebeck 2594 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC