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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3193 - (show annotations) (download) (as text)
Sat May 20 12:28:57 2017 UTC (6 years, 10 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 16092 byte(s)
* NKSP: Added built-in script function "get_event_par()" and implemented
  some of its possible parameter selections.
* NKSP: Added built-in script function "set_event_par()" and implemented
  some of its possible parameter selections.
* NKSP: Fixed (removed) artificial value limit for duration argument of
  built-in script functions "change_vol_time()" and "change_tune_time()".
* Fixed compile error with pre-C++11 compilers.
* Bumped version (2.0.0.svn46).

1 /*
2 * Copyright (c) 2014-2017 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 #ifndef LS_INSTRUMENT_SCRIPT_VM_H
11 #define LS_INSTRUMENT_SCRIPT_VM_H
12
13 #include "../../common/global.h"
14 #include "../../common/ConstCapacityArray.h"
15 #include "../../scriptvm/ScriptVM.h"
16 #include "Event.h"
17 #include "../../common/Pool.h"
18 #include "InstrumentScriptVMFunctions.h"
19 #include "InstrumentScriptVMDynVars.h"
20
21 /**
22 * Amount of bits on the left hand side of all pool_element_id_t numbers (i.e.
23 * event_id_t, note_id_t) being reserved for script VM implementation internal
24 * purposes.
25 *
26 * Right now there is only one bit reserved, which allows the VM (and its
27 * built-in functions) to distinguish user supplied @c Event IDs (event_id_t)
28 * from @c Note IDs (note_id_t).
29 */
30 #define INSTR_SCRIPT_EVENT_ID_RESERVED_BITS 1
31
32 /**
33 * Used by InstrScriptIDType_T to initialize its constants at compile time.
34 *
35 * This macro is already ready to initialize additional members for
36 * InstrScriptIDType_T (that is more than the currently two enum constants).
37 * Just keep in mind that you also have to increase
38 * INSTR_SCRIPT_EVENT_ID_RESERVED_BITS when you add more!
39 *
40 * @param x - sequential consecutive number (starting with zero)
41 */
42 #define INSTR_SCRIPT_ID_TYPE_FLAG(x) \
43 (x << (sizeof(pool_element_id_t) * 8 - INSTR_SCRIPT_EVENT_ID_RESERVED_BITS))
44
45 /**
46 * These flags are used to distinguish the individual ID Types in script scope
47 * from each other. They are added as most left bit(s) to each ID in script
48 * scope.
49 */
50 enum InstrScriptIDType_T {
51 /**
52 * Used to mark IDs (in script scope) to actually be a MIDI event ID.
53 */
54 INSTR_SCRIPT_EVENT_ID_FLAG = INSTR_SCRIPT_ID_TYPE_FLAG(0),
55
56 /**
57 * Used to mark IDs (in script scope) to actually be a note ID.
58 */
59 INSTR_SCRIPT_NOTE_ID_FLAG = INSTR_SCRIPT_ID_TYPE_FLAG(1),
60 };
61
62 #define INSTR_SCRIPT_EVENT_GROUPS 28
63
64 #define EVENT_STATUS_INACTIVE 0
65 #define EVENT_STATUS_NOTE_QUEUE 1
66
67 enum {
68 EVENT_PAR_NOTE = 1,
69 EVENT_PAR_VELOCITY,
70 EVENT_PAR_VOLUME,
71 EVENT_PAR_TUNE,
72 EVENT_PAR_0 = 1024,
73 EVENT_PAR_1,
74 EVENT_PAR_2,
75 EVENT_PAR_3,
76 };
77
78 namespace LinuxSampler {
79
80 class AbstractEngineChannel;
81 struct InstrumentScript;
82
83 /** @brief Convert IDs between script scope and engine internal scope.
84 *
85 * This class is used to translate unique IDs of events between script
86 * scope and sampler engine internal scope, that is:
87 * @code
88 * int (script scope) -> event_id_t (engine internal scope)
89 * int (script scope) -> note_id_t (engine internal scope)
90 * @endcode
91 * and vice versa:
92 * @code
93 * event_id_t (engine internal scope) -> int (script scope)
94 * note_id_t (engine internal scope) -> int (script scope)
95 * @endcode
96 * This is required because engine internally i.e. notes and regular events
97 * are using their own, separate ID generating pool, and their ID number
98 * set may thus overlap and historically there were built-in script
99 * functions in KSP which allow to pass both regular MIDI event IDs, as well
100 * as Note IDs. So we must be able to distinguish between them in our
101 * built-in script function implementations.
102 *
103 * @see INSTR_SCRIPT_EVENT_ID_RESERVED_BITS
104 */
105 class ScriptID {
106 public:
107 enum type_t {
108 EVENT, ///< ID is actually an event ID
109 NOTE, ///< ID is actually a note ID
110 };
111
112 /**
113 * Construct a ScriptID object with an ID from script scope.
114 */
115 ScriptID(uint id) : m_id(id) {}
116
117 /**
118 * Returns a ScriptID object constructed with an event ID from engine
119 * internal scope.
120 */
121 inline static ScriptID fromEventID(event_id_t id) {
122 return ScriptID(INSTR_SCRIPT_EVENT_ID_FLAG | id);
123 }
124
125 /**
126 * Returns a ScriptID object constructed with a note ID from engine
127 * internal scope.
128 */
129 inline static ScriptID fromNoteID(note_id_t id) {
130 return ScriptID(INSTR_SCRIPT_NOTE_ID_FLAG | id);
131 }
132
133 /**
134 * Whether the ID reflected by this ScriptID object is actually a note
135 * ID or rather an event ID.
136 */
137 inline type_t type() const {
138 return (m_id & INSTR_SCRIPT_NOTE_ID_FLAG) ? NOTE : EVENT;
139 }
140
141 inline bool isNoteID() const {
142 return type() == NOTE;
143 }
144
145 inline bool isEventID() const {
146 return type() == EVENT;
147 }
148
149 /**
150 * Returns event ID (for engine internal scope) of the ID reflected by
151 * this ScriptID object, it returns 0 (being an invalid ID) if the ID
152 * reflected by this ScriptID object is not an event ID.
153 */
154 inline event_id_t eventID() const {
155 switch (type()) {
156 case EVENT: return m_id;
157 default: return 0; // not an event id, return invalid ID
158 }
159 }
160
161 /**
162 * Returns note ID (for engine internal scope) of the ID reflected by
163 * this ScriptID object, it returns 0 (being an invalid ID) if the ID
164 * reflected by this ScriptID object is not a note ID.
165 */
166 inline note_id_t noteID() const {
167 switch (type()) {
168 case NOTE: return ~INSTR_SCRIPT_NOTE_ID_FLAG & m_id;
169 default: return 0; // not a note id, return invalid ID
170 }
171 }
172
173 /**
174 * Integer cast operator, which returns an ID number of this ScripID
175 * object intended for script scope.
176 */
177 inline operator uint() const {
178 return m_id;
179 }
180
181 private:
182 uint m_id;
183 };
184
185 /** @brief List of Event IDs.
186 *
187 * Used for built-in script functions:
188 * by_marks(), set_event_mark(), delete_event_mark()
189 */
190 class EventGroup : protected ConstCapacityArray<int> {
191 public:
192 EventGroup() : ConstCapacityArray<int>(CONFIG_MAX_EVENTS_PER_FRAGMENT), m_script(NULL) {}
193 void insert(int eventID);
194 void erase(int eventID);
195 void setScript(InstrumentScript* pScript) { m_script = pScript; }
196 inline int size() const { return ConstCapacityArray<int>::size(); }
197 inline void clear() { ConstCapacityArray<int>::clear(); }
198 inline int& operator[](uint index) { return ConstCapacityArray<int>::operator[](index); }
199 inline const int& operator[](uint index) const { return ConstCapacityArray<int>::operator[](index); }
200 protected:
201 InstrumentScript* m_script;
202 };
203
204 /** @brief Real-time instrument script VM representation.
205 *
206 * Holds the VM representation of all event handlers of the currently loaded
207 * script, ready to be executed by the sampler engine.
208 *
209 * Even thought scripts (or to be more specific their event handler objects)
210 * are shared between sampler engine channels, the InstrumentScript struct
211 * instances though are not shared. Each sampler engine channel has its own
212 * instance of a InstrumentScript struct. That's important, because this
213 * struct also holds engine channel local informations, for example the
214 * events that occured on the respective engine channel.
215 */
216 struct InstrumentScript {
217 VMParserContext* parserContext; ///< VM represenation of the currently loaded script or NULL if not script was loaded. Note that it is also not NULL if parser errors occurred!
218 bool bHasValidScript; ///< True in case there is a valid script currently loaded, false if script processing shall be skipped.
219 VMEventHandler* handlerInit; ///< VM representation of script's initilization callback or NULL if current script did not define such an init handler.
220 VMEventHandler* handlerNote; ///< VM representation of script's MIDI note on callback or NULL if current script did not define such an event handler.
221 VMEventHandler* handlerRelease; ///< VM representation of script's MIDI note off callback or NULL if current script did not define such an event handler.
222 VMEventHandler* handlerController; ///< VM representation of script's MIDI controller callback or NULL if current script did not define such an event handler.
223 Pool<ScriptEvent>* pEvents; ///< Pool of all available script execution instances. ScriptEvents available to be allocated from the Pool are currently unused / not executiong, whereas the ScriptEvents allocated on the list are currently suspended / have not finished execution yet (@see pKeyEvents).
224 RTList<ScriptEvent>* pKeyEvents[128]; ///< Stores previously finished executed "note on" script events for the respective active note/key as long as the key/note is active. This is however only done if there is a "note" script event handler and a "release" script event handler defined in the script and both handlers use (reference) polyphonic variables. If that is not the case, then this list is not used at all. So the purpose of pKeyEvents is only to implement preserving/passing polyphonic variable data from "on note .. end on" script block to the respective "on release .. end on" script block.
225 RTAVLTree<ScriptEvent> suspendedEvents; ///< Contains pointers to all suspended events, sorted by time when those script events are to be resumed next.
226 AbstractEngineChannel* pEngineChannel;
227 String code; ///< Source code of the instrument script. Used in case the sampler engine is changed, in that case a new ScriptVM object is created for the engine and VMParserContext object for this script needs to be recreated as well. Thus the script is then parsed again by passing the source code to recreate the parser context.
228 EventGroup eventGroups[INSTR_SCRIPT_EVENT_GROUPS]; ///< Used for built-in script functions: by_event_marks(), set_event_mark(), delete_event_mark().
229
230 InstrumentScript(AbstractEngineChannel* pEngineChannel);
231 ~InstrumentScript();
232
233 void load(const String& text);
234 void unload();
235 void resetAll();
236 void resetEvents();
237 };
238
239 /** @brief Real-time instrument script virtual machine.
240 *
241 * Extends the core ScriptVM implementation with MIDI specific built-in
242 * script functions and MIDI specific built-in script variables required
243 * for MIDI processing by instrument script for all sampler engine
244 * implementations (sampler formats) of this sampler.
245 *
246 * Note that this class is currently re-entrant safe, but @b not thread
247 * safe! See also comments of base class ScriptVM regarding this issue.
248 */
249 class InstrumentScriptVM : public ScriptVM {
250 public:
251 InstrumentScriptVM();
252 VMExecStatus_t exec(VMParserContext* parserCtx, ScriptEvent* event);
253 VMFunction* functionByName(const String& name) OVERRIDE;
254 std::map<String,VMIntRelPtr*> builtInIntVariables() OVERRIDE;
255 std::map<String,VMInt8Array*> builtInIntArrayVariables() OVERRIDE;
256 std::map<String,int> builtInConstIntVariables() OVERRIDE;
257 std::map<String,VMDynVar*> builtInDynamicVariables() OVERRIDE;
258 protected:
259 ScriptEvent* m_event; ///< The event currently executed by exec().
260
261 // built-in script variables
262 VMInt8Array m_CC;
263 VMInt8RelPtr m_CC_NUM;
264 VMIntRelPtr m_EVENT_ID;
265 VMInt8RelPtr m_EVENT_NOTE;
266 VMInt8RelPtr m_EVENT_VELOCITY;
267 VMInt8Array m_KEY_DOWN;
268 //VMIntArray m_POLY_AT; //TODO: ...
269 //int m_POLY_AT_NUM; //TODO: ...
270 VMIntRelPtr m_NI_CALLBACK_TYPE;
271 VMIntRelPtr m_NKSP_IGNORE_WAIT;
272
273 // built-in script functions
274 InstrumentScriptVMFunction_play_note m_fnPlayNote;
275 InstrumentScriptVMFunction_set_controller m_fnSetController;
276 InstrumentScriptVMFunction_ignore_event m_fnIgnoreEvent;
277 InstrumentScriptVMFunction_ignore_controller m_fnIgnoreController;
278 InstrumentScriptVMFunction_note_off m_fnNoteOff;
279 InstrumentScriptVMFunction_set_event_mark m_fnSetEventMark;
280 InstrumentScriptVMFunction_delete_event_mark m_fnDeleteEventMark;
281 InstrumentScriptVMFunction_by_marks m_fnByMarks;
282 InstrumentScriptVMFunction_change_vol m_fnChangeVol;
283 InstrumentScriptVMFunction_change_vol_time m_fnChangeVolTime;
284 InstrumentScriptVMFunction_change_tune m_fnChangeTune;
285 InstrumentScriptVMFunction_change_tune_time m_fnChangeTuneTime;
286 InstrumentScriptVMFunction_change_pan m_fnChangePan;
287 InstrumentScriptVMFunction_change_cutoff m_fnChangeCutoff;
288 InstrumentScriptVMFunction_change_reso m_fnChangeReso;
289 InstrumentScriptVMFunction_change_attack m_fnChangeAttack;
290 InstrumentScriptVMFunction_change_decay m_fnChangeDecay;
291 InstrumentScriptVMFunction_change_release m_fnChangeRelease;
292 InstrumentScriptVMFunction_change_amp_lfo_depth m_fnChangeAmpLFODepth;
293 InstrumentScriptVMFunction_change_amp_lfo_freq m_fnChangeAmpLFOFreq;
294 InstrumentScriptVMFunction_change_pitch_lfo_depth m_fnChangePitchLFODepth;
295 InstrumentScriptVMFunction_change_pitch_lfo_freq m_fnChangePitchLFOFreq;
296 InstrumentScriptVMFunction_event_status m_fnEventStatus;
297 InstrumentScriptVMFunction_wait m_fnWait2;
298 InstrumentScriptVMFunction_stop_wait m_fnStopWait;
299 InstrumentScriptVMFunction_fade_in m_fnFadeIn;
300 InstrumentScriptVMFunction_fade_out m_fnFadeOut;
301 InstrumentScriptVMFunction_get_event_par m_fnGetEventPar;
302 InstrumentScriptVMFunction_set_event_par m_fnSetEventPar;
303 InstrumentScriptVMDynVar_ENGINE_UPTIME m_varEngineUptime;
304 InstrumentScriptVMDynVar_NI_CALLBACK_ID m_varCallbackID;
305 InstrumentScriptVMDynVar_ALL_EVENTS m_varAllEvents;
306
307 friend class InstrumentScriptVMFunction_play_note;
308 friend class InstrumentScriptVMFunction_set_controller;
309 friend class InstrumentScriptVMFunction_ignore_event;
310 friend class InstrumentScriptVMFunction_ignore_controller;
311 friend class InstrumentScriptVMFunction_note_off;
312 friend class InstrumentScriptVMFunction_set_event_mark;
313 friend class InstrumentScriptVMFunction_delete_event_mark;
314 friend class InstrumentScriptVMFunction_by_marks;
315 friend class InstrumentScriptVMFunction_change_vol;
316 friend class InstrumentScriptVMFunction_change_vol_time;
317 friend class InstrumentScriptVMFunction_change_tune;
318 friend class InstrumentScriptVMFunction_change_tune_time;
319 friend class InstrumentScriptVMFunction_change_pan;
320 friend class InstrumentScriptVMFunction_change_cutoff;
321 friend class InstrumentScriptVMFunction_change_reso;
322 friend class InstrumentScriptVMFunction_change_attack;
323 friend class InstrumentScriptVMFunction_change_decay;
324 friend class InstrumentScriptVMFunction_change_release;
325 friend class VMChangeSynthParamFunction;
326 friend class InstrumentScriptVMFunction_change_amp_lfo_depth;
327 friend class InstrumentScriptVMFunction_change_amp_lfo_freq;
328 friend class InstrumentScriptVMFunction_change_pitch_lfo_depth;
329 friend class InstrumentScriptVMFunction_change_pitch_lfo_freq;
330 friend class InstrumentScriptVMFunction_fade_in;
331 friend class InstrumentScriptVMFunction_fade_out;
332 friend class InstrumentScriptVMFunction_get_event_par;
333 friend class InstrumentScriptVMFunction_set_event_par;
334 friend class InstrumentScriptVMFunction_event_status;
335 friend class InstrumentScriptVMFunction_wait;
336 friend class InstrumentScriptVMFunction_stop_wait;
337 friend class InstrumentScriptVMDynVar_ENGINE_UPTIME;
338 friend class InstrumentScriptVMDynVar_NI_CALLBACK_ID;
339 friend class InstrumentScriptVMDynVar_ALL_EVENTS;
340 };
341
342 } // namespace LinuxSampler
343
344 #endif // LS_INSTRUMENT_SCRIPT_VM_H

  ViewVC Help
Powered by ViewVC