1 /*
2  * Copyright (c) 2014-2020 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(0LL),
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(1LL),
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 enum {
79     CALLBACK_STATUS_TERMINATED = 0,
80     CALLBACK_STATUS_QUEUE = 1,
81     CALLBACK_STATUS_RUNNING = (1 << 1)
82 };
83 
84 namespace LinuxSampler {
85 
86     class AbstractEngineChannel;
87     struct InstrumentScript;
88 
89     /** @brief Convert IDs between script scope and engine internal scope.
90      *
91      * This class is used to translate unique IDs of events between script
92      * scope and sampler engine internal scope, that is:
93      * @code
94      * int (script scope) -> event_id_t (engine internal scope)
95      * int (script scope) -> note_id_t (engine internal scope)
96      * @endcode
97      * and vice versa:
98      * @code
99      * event_id_t (engine internal scope) -> int (script scope)
100      * note_id_t (engine internal scope)  -> int (script scope)
101      * @endcode
102      * This is required because engine internally i.e. notes and regular events
103      * are using their own, separate ID generating pool, and their ID number
104      * set may thus overlap and historically there were built-in script
105      * functions in KSP which allow to pass both regular MIDI event IDs, as well
106      * as Note IDs. So we must be able to distinguish between them in our
107      * built-in script function implementations.
108      *
109      * @see INSTR_SCRIPT_EVENT_ID_RESERVED_BITS
110      */
111     class ScriptID {
112     public:
113         enum type_t {
114             EVENT, ///< ID is actually an event ID
115             NOTE, ///< ID is actually a note ID
116         };
117 
118         /**
119          * Construct a ScriptID object with an ID from script scope.
120          */
ScriptID(vmint id)121         ScriptID(vmint id) : m_id(id) {}
122 
123         /**
124          * Returns a ScriptID object constructed with an event ID from engine
125          * internal scope.
126          */
fromEventID(event_id_t id)127         inline static ScriptID fromEventID(event_id_t id) {
128             return ScriptID(INSTR_SCRIPT_EVENT_ID_FLAG | id);
129         }
130 
131         /**
132          * Returns a ScriptID object constructed with a note ID from engine
133          * internal scope.
134          */
fromNoteID(note_id_t id)135         inline static ScriptID fromNoteID(note_id_t id) {
136             return ScriptID(INSTR_SCRIPT_NOTE_ID_FLAG | id);
137         }
138 
139         /**
140          * Whether the ID reflected by this ScriptID object is actually a note
141          * ID or rather an event ID.
142          */
type()143         inline type_t type() const {
144             return (m_id & INSTR_SCRIPT_NOTE_ID_FLAG) ? NOTE : EVENT;
145         }
146 
isNoteID()147         inline bool isNoteID() const {
148             return type() == NOTE;
149         }
150 
isEventID()151         inline bool isEventID() const {
152             return type() == EVENT;
153         }
154 
155         /**
156          * Returns event ID (for engine internal scope) of the ID reflected by
157          * this ScriptID object, it returns 0 (being an invalid ID) if the ID
158          * reflected by this ScriptID object is not an event ID.
159          */
eventID()160         inline event_id_t eventID() const {
161             switch (type()) {
162                 case EVENT: return m_id;
163                 default:    return 0; // not an event id, return invalid ID
164             }
165         }
166 
167         /**
168          * Returns note ID (for engine internal scope) of the ID reflected by
169          * this ScriptID object, it returns 0 (being an invalid ID) if the ID
170          * reflected by this ScriptID object is not a note ID.
171          */
noteID()172         inline note_id_t noteID() const {
173             switch (type()) {
174                 case NOTE: return ~INSTR_SCRIPT_NOTE_ID_FLAG & m_id;
175                 default:   return 0; // not a note id, return invalid ID
176             }
177         }
178 
179         /**
180          * Integer cast operator, which returns an ID number of this ScripID
181          * object intended for script scope.
182          */
vmint()183         inline operator vmint() const {
184             return m_id;
185         }
186 
187     private:
188         vmint m_id;
189     };
190 
191     /** @brief List of Event IDs.
192      *
193      * Used for built-in script functions:
194      *     by_marks(), set_event_mark(), delete_event_mark()
195      */
196     class EventGroup : protected ConstCapacityArray<vmint> {
197     public:
EventGroup()198         EventGroup() : ConstCapacityArray<vmint>(CONFIG_MAX_EVENTS_PER_FRAGMENT), m_script(NULL) {}
199         void insert(vmint eventID);
200         void erase(vmint eventID);
setScript(InstrumentScript * pScript)201         void setScript(InstrumentScript* pScript) { m_script = pScript; }
size()202         inline size_t size() const { return ConstCapacityArray<vmint>::size(); }
clear()203         inline void clear() { ConstCapacityArray<vmint>::clear(); }
204         inline vmint& operator[](ssize_t index) { return ConstCapacityArray<vmint>::operator[](index); }
205         inline const vmint& operator[](ssize_t index) const { return ConstCapacityArray<vmint>::operator[](index); }
206     protected:
207         InstrumentScript* m_script;
208     };
209 
210     /** @brief Real-time instrument script VM representation.
211      *
212      * Holds the VM representation of all event handlers of the currently loaded
213      * script, ready to be executed by the sampler engine.
214      *
215      * Even thought scripts (or to be more specific their event handler objects)
216      * are shared between sampler engine channels, the InstrumentScript struct
217      * instances though are not shared. Each sampler engine channel has its own
218      * instance of a InstrumentScript struct. That's important, because this
219      * struct also holds engine channel local informations, for example the
220      * events that occured on the respective engine channel.
221      */
222     struct InstrumentScript {
223         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!
224         bool                  bHasValidScript; ///< True in case there is a valid script currently loaded, false if script processing shall be skipped.
225         VMEventHandler*       handlerInit; ///< VM representation of script's initilization callback or NULL if current script did not define such an init handler.
226         VMEventHandler*       handlerNote; ///< VM representation of script's MIDI note on callback or NULL if current script did not define such an event handler.
227         VMEventHandler*       handlerRelease; ///< VM representation of script's MIDI note off callback or NULL if current script did not define such an event handler.
228         VMEventHandler*       handlerController; ///< VM representation of script's MIDI controller callback or NULL if current script did not define such an event handler.
229         VMEventHandler*       handlerRpn; ///< VM representation of script's MIDI RPN event callback or NULL if current script did not define such an event handler.
230         VMEventHandler*       handlerNrpn; ///< VM representation of script's MIDI NRPN event callback or NULL if current script did not define such an event handler.
231         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).
232         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.
233         RTAVLTree<ScriptEvent> suspendedEvents; ///< Contains pointers to all suspended events, sorted by time when those script events are to be resumed next.
234         AbstractEngineChannel* pEngineChannel;
235         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.
236         EventGroup            eventGroups[INSTR_SCRIPT_EVENT_GROUPS]; ///< Used for built-in script functions: by_event_marks(), set_event_mark(), delete_event_mark().
237 
238         InstrumentScript(AbstractEngineChannel* pEngineChannel);
239         ~InstrumentScript();
240 
241         void load(const String& text, const std::map<String,String>& patchVars);
242         void unload();
243         void resetAll();
244         void resetEvents();
245     };
246 
247     /** @brief Real-time instrument script virtual machine.
248      *
249      * Extends the core ScriptVM implementation with MIDI specific built-in
250      * script functions and MIDI specific built-in script variables required
251      * for MIDI processing by instrument script for all sampler engine
252      * implementations (sampler formats) of this sampler.
253      *
254      * Note that this class is currently re-entrant safe, but @b not thread
255      * safe! See also comments of base class ScriptVM regarding this issue.
256      */
257     class InstrumentScriptVM : public ScriptVM {
258     public:
259         InstrumentScriptVM();
260         VMExecStatus_t exec(VMParserContext* parserCtx, ScriptEvent* event);
261         VMFunction* functionByName(const String& name) OVERRIDE;
262         std::map<String,VMIntPtr*> builtInIntVariables() OVERRIDE;
263         std::map<String,VMInt8Array*> builtInIntArrayVariables() OVERRIDE;
264         std::map<String,vmint> builtInConstIntVariables() OVERRIDE;
265         std::map<String,VMDynVar*> builtInDynamicVariables() OVERRIDE;
266     protected:
267         ScriptEvent* m_event; ///< The event currently executed by exec().
268 
269         // built-in script variables
270         VMInt8Array m_CC;
271         VMInt8RelPtr m_CC_NUM;
272         VMIntRelPtr  m_EVENT_ID;
273         VMInt8RelPtr m_EVENT_NOTE;
274         VMInt8RelPtr m_EVENT_VELOCITY;
275         VMInt8Array  m_KEY_DOWN;
276         VMInt16RelPtr m_RPN_ADDRESS; // used for both RPN and NRPN events
277         VMInt16RelPtr m_RPN_VALUE;   // used for both RPN and NRPN events
278         //VMIntArray m_POLY_AT; //TODO: ...
279         //int m_POLY_AT_NUM; //TODO: ...
280         VMInt32RelPtr m_NI_CALLBACK_TYPE;
281         VMInt8RelPtr m_NKSP_IGNORE_WAIT;
282         VMIntRelPtr  m_NKSP_CALLBACK_PARENT_ID;
283 
284         // built-in script functions
285         InstrumentScriptVMFunction_play_note m_fnPlayNote;
286         InstrumentScriptVMFunction_set_controller m_fnSetController;
287         InstrumentScriptVMFunction_set_rpn m_fnSetRpn;
288         InstrumentScriptVMFunction_set_nrpn m_fnSetNrpn;
289         InstrumentScriptVMFunction_ignore_event m_fnIgnoreEvent;
290         InstrumentScriptVMFunction_ignore_controller m_fnIgnoreController;
291         InstrumentScriptVMFunction_note_off m_fnNoteOff;
292         InstrumentScriptVMFunction_set_event_mark m_fnSetEventMark;
293         InstrumentScriptVMFunction_delete_event_mark m_fnDeleteEventMark;
294         InstrumentScriptVMFunction_by_marks m_fnByMarks;
295         InstrumentScriptVMFunction_change_vol m_fnChangeVol;
296         InstrumentScriptVMFunction_change_vol_time m_fnChangeVolTime;
297         InstrumentScriptVMFunction_change_tune m_fnChangeTune;
298         InstrumentScriptVMFunction_change_tune_time m_fnChangeTuneTime;
299         InstrumentScriptVMFunction_change_pan m_fnChangePan;
300         InstrumentScriptVMFunction_change_pan_time m_fnChangePanTime;
301         InstrumentScriptVMFunction_change_pan_curve m_fnChangePanCurve;
302         InstrumentScriptVMFunction_change_cutoff m_fnChangeCutoff;
303         InstrumentScriptVMFunction_change_reso m_fnChangeReso;
304         InstrumentScriptVMFunction_change_attack m_fnChangeAttack;
305         InstrumentScriptVMFunction_change_decay m_fnChangeDecay;
306         InstrumentScriptVMFunction_change_sustain m_fnChangeSustain;
307         InstrumentScriptVMFunction_change_release m_fnChangeRelease;
308         InstrumentScriptVMFunction_change_cutoff_attack m_fnChangeCutoffAttack;
309         InstrumentScriptVMFunction_change_cutoff_decay m_fnChangeCutoffDecay;
310         InstrumentScriptVMFunction_change_cutoff_sustain m_fnChangeCutoffSustain;
311         InstrumentScriptVMFunction_change_cutoff_release m_fnChangeCutoffRelease;
312         InstrumentScriptVMFunction_change_amp_lfo_depth m_fnChangeAmpLFODepth;
313         InstrumentScriptVMFunction_change_amp_lfo_freq m_fnChangeAmpLFOFreq;
314         InstrumentScriptVMFunction_change_cutoff_lfo_depth m_fnChangeCutoffLFODepth;
315         InstrumentScriptVMFunction_change_cutoff_lfo_freq m_fnChangeCutoffLFOFreq;
316         InstrumentScriptVMFunction_change_pitch_lfo_depth m_fnChangePitchLFODepth;
317         InstrumentScriptVMFunction_change_pitch_lfo_freq m_fnChangePitchLFOFreq;
318         InstrumentScriptVMFunction_change_note m_fnChangeNote;
319         InstrumentScriptVMFunction_change_velo m_fnChangeVelo;
320         InstrumentScriptVMFunction_fork m_fnFork;
321         InstrumentScriptVMFunction_event_status m_fnEventStatus;
322         InstrumentScriptVMFunction_wait m_fnWait2;
323         InstrumentScriptVMFunction_stop_wait m_fnStopWait;
324         InstrumentScriptVMFunction_abort m_fnAbort;
325         InstrumentScriptVMFunction_fade_in m_fnFadeIn;
326         InstrumentScriptVMFunction_fade_out m_fnFadeOut;
327         InstrumentScriptVMFunction_change_vol_curve m_fnChangeVolCurve;
328         InstrumentScriptVMFunction_change_tune_curve m_fnChangeTuneCurve;
329         InstrumentScriptVMFunction_get_event_par m_fnGetEventPar;
330         InstrumentScriptVMFunction_set_event_par m_fnSetEventPar;
331         InstrumentScriptVMFunction_change_play_pos m_fnChangePlayPos;
332         InstrumentScriptVMFunction_callback_status m_fnCallbackStatus;
333         InstrumentScriptVMDynVar_ENGINE_UPTIME m_varEngineUptime;
334         InstrumentScriptVMDynVar_NI_CALLBACK_ID m_varCallbackID;
335         InstrumentScriptVMDynVar_ALL_EVENTS m_varAllEvents;
336         InstrumentScriptVMDynVar_NKSP_CALLBACK_CHILD_ID m_varCallbackChildID;
337 
338         friend class InstrumentScriptVMFunction_play_note;
339         friend class InstrumentScriptVMFunction_set_controller;
340         friend class InstrumentScriptVMFunction_set_rpn;
341         friend class InstrumentScriptVMFunction_set_nrpn;
342         friend class InstrumentScriptVMFunction_ignore_event;
343         friend class InstrumentScriptVMFunction_ignore_controller;
344         friend class InstrumentScriptVMFunction_note_off;
345         friend class InstrumentScriptVMFunction_set_event_mark;
346         friend class InstrumentScriptVMFunction_delete_event_mark;
347         friend class InstrumentScriptVMFunction_by_marks;
348         friend class InstrumentScriptVMFunction_change_vol;
349         friend class InstrumentScriptVMFunction_change_vol_time;
350         friend class InstrumentScriptVMFunction_change_tune;
351         friend class InstrumentScriptVMFunction_change_tune_time;
352         friend class InstrumentScriptVMFunction_change_pan;
353         friend class InstrumentScriptVMFunction_change_pan_time;
354         friend class InstrumentScriptVMFunction_change_pan_curve;
355         friend class InstrumentScriptVMFunction_change_cutoff;
356         friend class InstrumentScriptVMFunction_change_reso;
357         friend class InstrumentScriptVMFunction_change_attack;
358         friend class InstrumentScriptVMFunction_change_decay;
359         friend class InstrumentScriptVMFunction_change_release;
360         friend class InstrumentScriptVMFunction_change_sustain;
361         friend class InstrumentScriptVMFunction_change_cutoff_attack;
362         friend class InstrumentScriptVMFunction_change_cutoff_decay;
363         friend class InstrumentScriptVMFunction_change_cutoff_release;
364         friend class InstrumentScriptVMFunction_change_cutoff_sustain;
365         friend class VMChangeSynthParamFunction;
366         friend class InstrumentScriptVMFunction_change_amp_lfo_depth;
367         friend class InstrumentScriptVMFunction_change_amp_lfo_freq;
368         friend class InstrumentScriptVMFunction_change_cutoff_lfo_depth;
369         friend class InstrumentScriptVMFunction_change_cutoff_lfo_freq;
370         friend class InstrumentScriptVMFunction_change_pitch_lfo_depth;
371         friend class InstrumentScriptVMFunction_change_pitch_lfo_freq;
372         friend class VMChangeFadeCurveFunction;
373         friend class InstrumentScriptVMFunction_fade_in;
374         friend class InstrumentScriptVMFunction_fade_out;
375         friend class InstrumentScriptVMFunction_get_event_par;
376         friend class InstrumentScriptVMFunction_set_event_par;
377         friend class InstrumentScriptVMFunction_change_note;
378         friend class InstrumentScriptVMFunction_change_velo;
379         friend class InstrumentScriptVMFunction_change_play_pos;
380         friend class InstrumentScriptVMFunction_event_status;
381         friend class InstrumentScriptVMFunction_wait;
382         friend class InstrumentScriptVMFunction_stop_wait;
383         friend class InstrumentScriptVMFunction_abort;
384         friend class InstrumentScriptVMFunction_fork;
385         friend class InstrumentScriptVMFunction_callback_status;
386         friend class InstrumentScriptVMDynVar_ENGINE_UPTIME;
387         friend class InstrumentScriptVMDynVar_NI_CALLBACK_ID;
388         friend class InstrumentScriptVMDynVar_ALL_EVENTS;
389         friend class InstrumentScriptVMDynVar_NKSP_CALLBACK_CHILD_ID;
390     };
391 
392 } // namespace LinuxSampler
393 
394 #endif // LS_INSTRUMENT_SCRIPT_VM_H
395