/[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 2612 - (hide 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 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 schoenebeck 2612 unload();
36 schoenebeck 2611
37 schoenebeck 2612 code = text;
38    
39 schoenebeck 2611 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 schoenebeck 2612 *
90     * Calling thid method will however not clear the @c code member variable.
91     * Thus, the script can be parsed again afterwards.
92 schoenebeck 2611 */
93 schoenebeck 2612 void InstrumentScript::unload() {
94 schoenebeck 2611 if (parserContext)
95 schoenebeck 2612 dmsg(1,("Unloading current instrument script.\n"));
96 schoenebeck 2611
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 schoenebeck 2612 /**
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 schoenebeck 2611 ///////////////////////////////////////////////////////////////////////
137     // class 'InstrumentScriptVM'
138    
139 schoenebeck 2596 InstrumentScriptVM::InstrumentScriptVM() :
140 schoenebeck 2600 m_event(NULL), m_fnPlayNote(this), m_fnSetController(this),
141     m_fnIgnoreEvent(this), m_fnIgnoreController(this)
142 schoenebeck 2596 {
143 schoenebeck 2595 m_CC.size = _MEMBER_SIZEOF(AbstractEngineChannel, ControllerTable);
144 schoenebeck 2598 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 schoenebeck 2594 }
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 schoenebeck 2598 m_event = event;
156 schoenebeck 2594 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 schoenebeck 2598 switch (event->cause.Type) {
164 schoenebeck 2594 case Event::type_control_change:
165 schoenebeck 2598 pEngineChannel->ControllerTable[event->cause.Param.CC.Controller] =
166     event->cause.Param.CC.Value;
167 schoenebeck 2594 break;
168     case Event::type_channel_pressure:
169     pEngineChannel->ControllerTable[CTRL_TABLE_IDX_AFTERTOUCH] =
170 schoenebeck 2598 event->cause.Param.ChannelPressure.Value;
171 schoenebeck 2594 break;
172     case Event::type_pitchbend:
173     pEngineChannel->ControllerTable[CTRL_TABLE_IDX_PITCHBEND] =
174 schoenebeck 2598 event->cause.Param.Pitch.Pitch;
175 schoenebeck 2594 break;
176     }
177     }
178    
179     // run the script handler(s)
180     VMExecStatus_t res = VM_EXEC_NOT_RUNNING;
181 schoenebeck 2596 for ( ; event->handlers[event->currentHandler]; event->currentHandler++) {
182 schoenebeck 2594 res = ScriptVM::exec(
183 schoenebeck 2596 parserCtx, event->execCtx, event->handlers[event->currentHandler]
184 schoenebeck 2594 );
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 schoenebeck 2598 m["$EVENT_ID"] = &m_EVENT_ID;
199 schoenebeck 2594 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 schoenebeck 2596 VMFunction* InstrumentScriptVM::functionByName(const String& name) {
229     // built-in script functions of this class
230 schoenebeck 2598 if (name == "play_note") return &m_fnPlayNote;
231 schoenebeck 2600 else if (name == "set_controller") return &m_fnSetController;
232 schoenebeck 2598 else if (name == "ignore_event") return &m_fnIgnoreEvent;
233     else if (name == "ignore_controller") return &m_fnIgnoreController;
234 schoenebeck 2596
235     // built-in script functions of derived VM class
236     return ScriptVM::functionByName(name);
237     }
238    
239 schoenebeck 2594 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC