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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 2595 by schoenebeck, Thu Jun 5 12:14:53 2014 UTC revision 2612 by schoenebeck, Tue Jun 10 13:32:16 2014 UTC
# Line 9  Line 9 
9    
10  #include "InstrumentScriptVM.h"  #include "InstrumentScriptVM.h"
11  #include "../AbstractEngineChannel.h"  #include "../AbstractEngineChannel.h"
12    #include "../../common/global_private.h"
13    #include "AbstractInstrumentManager.h"
14    
15  namespace LinuxSampler {  namespace LinuxSampler {
16    
17      // circumvents a bug in GCC 4.x which causes a sizeof() expression applied      ///////////////////////////////////////////////////////////////////////
18      // on a class member to throw a compiler error, i.e. with GCC 4.4:      // class 'InstrumentScript'
     // "object missing in reference to 'LinuxSampler::AbstractEngineChannel::ControllerTable'")  
     // or with GCC 4.0:  
     // "invalid use of non-static data member 'LinuxSampler::AbstractEngineChannel::ControllerTable'"  
     #define _MEMBER_SIZEOF(T_Class, Member) sizeof(((T_Class*)NULL)->Member)  
19    
20      InstrumentScriptVM::InstrumentScriptVM() : m_event(NULL) {      /** @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);          m_CC.size = _MEMBER_SIZEOF(AbstractEngineChannel, ControllerTable);
144          m_CC_NUM = DECLARE_VMINT(m_cause, class Event, Param.CC.Controller);          m_CC_NUM = DECLARE_VMINT(m_event, class ScriptEvent, cause.Param.CC.Controller);
145          m_EVENT_NOTE = DECLARE_VMINT(m_cause, class Event, Param.Note.Key);          m_EVENT_ID = DECLARE_VMINT(m_event, class ScriptEvent, id);
146          m_EVENT_VELOCITY = DECLARE_VMINT(m_cause, class Event, Param.Note.Velocity);          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) {      VMExecStatus_t InstrumentScriptVM::exec(VMParserContext* parserCtx, ScriptEvent* event) {
# Line 31  namespace LinuxSampler { Line 152  namespace LinuxSampler {
152              static_cast<AbstractEngineChannel*>(event->cause.pEngineChannel);              static_cast<AbstractEngineChannel*>(event->cause.pEngineChannel);
153    
154          // prepare built-in script variables for script execution          // prepare built-in script variables for script execution
155          m_cause = &event->cause;          m_event = event;
156          m_CC.data = (int8_t*) &pEngineChannel->ControllerTable[0];          m_CC.data = (int8_t*) &pEngineChannel->ControllerTable[0];
157    
158          // if script is in start condition, then do mandatory MIDI event          // if script is in start condition, then do mandatory MIDI event
# Line 39  namespace LinuxSampler { Line 160  namespace LinuxSampler {
160          // table with new CC value in case of a controller event, because the          // table with new CC value in case of a controller event, because the
161          // script might access the new CC value          // script might access the new CC value
162          if (!event->executionSlices) {          if (!event->executionSlices) {
163              switch (m_cause->Type) {              switch (event->cause.Type) {
164                  case Event::type_control_change:                  case Event::type_control_change:
165                      pEngineChannel->ControllerTable[m_cause->Param.CC.Controller] =                      pEngineChannel->ControllerTable[event->cause.Param.CC.Controller] =
166                          m_cause->Param.CC.Value;                          event->cause.Param.CC.Value;
167                      break;                      break;
168                  case Event::type_channel_pressure:                  case Event::type_channel_pressure:
169                      pEngineChannel->ControllerTable[CTRL_TABLE_IDX_AFTERTOUCH] =                      pEngineChannel->ControllerTable[CTRL_TABLE_IDX_AFTERTOUCH] =
170                          m_cause->Param.ChannelPressure.Value;                          event->cause.Param.ChannelPressure.Value;
171                      break;                      break;
172                  case Event::type_pitchbend:                  case Event::type_pitchbend:
173                      pEngineChannel->ControllerTable[CTRL_TABLE_IDX_PITCHBEND] =                      pEngineChannel->ControllerTable[CTRL_TABLE_IDX_PITCHBEND] =
174                          m_cause->Param.Pitch.Pitch;                          event->cause.Param.Pitch.Pitch;
175                      break;                      break;
176              }              }
177          }          }
178    
179          // run the script handler(s)          // run the script handler(s)
180          VMExecStatus_t res = VM_EXEC_NOT_RUNNING;          VMExecStatus_t res = VM_EXEC_NOT_RUNNING;
181          while (event->handlers[event->currentHandler]) {          for ( ; event->handlers[event->currentHandler]; event->currentHandler++) {
182              res = ScriptVM::exec(              res = ScriptVM::exec(
183                  parserCtx, event->execCtx, event->handlers[event->currentHandler++]                  parserCtx, event->execCtx, event->handlers[event->currentHandler]
184              );              );
185              event->executionSlices++;              event->executionSlices++;
186              if (res & VM_EXEC_SUSPENDED || res & VM_EXEC_ERROR) return res;              if (res & VM_EXEC_SUSPENDED || res & VM_EXEC_ERROR) return res;
# Line 74  namespace LinuxSampler { Line 195  namespace LinuxSampler {
195    
196          // now add own built-in variables          // now add own built-in variables
197          m["$CC_NUM"] = &m_CC_NUM;          m["$CC_NUM"] = &m_CC_NUM;
198            m["$EVENT_ID"] = &m_EVENT_ID;
199          m["$EVENT_NOTE"] = &m_EVENT_NOTE;          m["$EVENT_NOTE"] = &m_EVENT_NOTE;
200          m["$EVENT_VELOCITY"] = &m_EVENT_VELOCITY;          m["$EVENT_VELOCITY"] = &m_EVENT_VELOCITY;
201  //         m["$POLY_AT_NUM"] = &m_POLY_AT_NUM;  //         m["$POLY_AT_NUM"] = &m_POLY_AT_NUM;
# Line 103  namespace LinuxSampler { Line 225  namespace LinuxSampler {
225          return m;          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  } // namespace LinuxSampler

Legend:
Removed from v.2595  
changed lines
  Added in v.2612

  ViewVC Help
Powered by ViewVC