/[svn]/linuxsampler/trunk/src/scriptvm/ScriptVM.h
ViewVC logotype

Contents of /linuxsampler/trunk/src/scriptvm/ScriptVM.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3733 - (show annotations) (download) (as text)
Sat Feb 1 18:11:20 2020 UTC (4 years, 2 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 19420 byte(s)
NKSP: Added support for 'patch' variables.

* NKSP language: Added support for 'patch' variable qualifier
  (as new dedicated keyword 'patch').

* NKSP parser: capture locations of 'patch' variable declarations
  in script's source code.

* ScriptVM: Allow patching 'patch' script variables by replacing
  their default assignment expression with a supplied replacement
  variable initialization expression by optional 2nd argument when
  calling loadScript().

* ScriptVM: Allow retrieval of default initialization expressions
  of all 'patch' variables by optional 3rd argument when calling
  loadScript() (i.e. for instrument editors).

* gig engine: Implemented support for loading real-time instrument
  scripts with 'patch' variables bundled with gig instruments.

* Bumped version (2.1.1.svn46).


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_SCRIPTVM_H
11 #define LS_SCRIPTVM_H
12
13 #include <iostream>
14 #include <vector>
15
16 #include "../common/global.h"
17 #include "common.h"
18
19 namespace LinuxSampler {
20
21 class ParserContext;
22 class ExecContext;
23
24 /** @brief Core virtual machine for real-time instrument scripts.
25 *
26 * This is the core of the virtual machine and main entry class, used for
27 * running real-time instrument scripts. This VM core encompasses the
28 * instrument script parser, generalized virtual machine and very generic
29 * built-in script functions. Thus this class only provides functionalities
30 * which are yet independent of the actual purpose the virtual machine is
31 * going to be used for.
32 *
33 * The actual use case specific functionalites (i.e. MIDI processing) is
34 * then implemented by sampler engines' VM classes which are derived from
35 * this generalized ScriptVM class.
36 *
37 * Typical usage of this class:
38 *
39 * - 1. Create an instance of this ScriptVM class (or of one of its deriving
40 * classes).
41 * - 2. Load a script by passing its source code to method loadScript(),
42 * which will return the parsed representation of the script.
43 * - 3. Create a VM execution context by calling createExecContext().
44 * - 4. Execute the script by calling method exec().
45 *
46 * This class is re-entrant safe, but not thread safe. So you can share one
47 * instance of this class between multiple (native) threads, but you @b must
48 * @b not execute methods of the same class instance simultaniously from
49 * different (native) threads. If you want to execute scripts simultaniously
50 * multi threaded, then create a separate ScriptVM instance for each
51 * (native) thread. Also note that one VMParserContext instance is tied to
52 * exactly one ScriptVM instance. So you @b must @b not create a
53 * VMParserContext with one ScriptVM instance and run it with a different
54 * ScriptVM instance!
55 */
56 class ScriptVM : public VMFunctionProvider {
57 public:
58 ScriptVM();
59 virtual ~ScriptVM();
60
61 /**
62 * Loads a script given by its source code (passed as argument @a s to
63 * this method) and returns the parsed representation of that script.
64 * After calling this method you must check the returned VMParserContext
65 * object whether there had been any parser errors. If there were no
66 * parser errors, you may pass the VMParserContext object to method
67 * exec() for actually executing the script.
68 *
69 * It is your responsibility to free the returned VMParserContext
70 * object once you don't need it anymore.
71 *
72 * The NKSP language supports so called 'patch' variables, which are
73 * declared by the dedicated keyword 'patch' (as variable qualifier) in
74 * real-time instrument scripts, like e.g.:
75 * @code
76 * on init
77 * declare patch ~foo := 0.435
78 * end on
79 * @endcode
80 * These 'patch' variables allow to override their initial value (i.e.
81 * on a per instrument basis). In the example above, the script variable
82 * @c ~foo would be initialized with value @c 0.435 by default. However
83 * by simply passing an appropriate key-value pair with argument
84 * @p patchVars when calling this method, the NKSP parser will replace
85 * that default initialization value by the passed replacement value.
86 * So key of the optional @p patchVars map argument is the ('patch')
87 * variable name to be patched, and value is the replacement
88 * initialization value for the respective variable. You can see this as
89 * kind of preprocessor mechanism of the NKSP parser, so you are not
90 * limited to simply replace a scalar value with a different scalar
91 * value, you can actually replace any complex default initialization
92 * expression with a new (potentially complex) replacement expression,
93 * e.g. including function calls, formulas, etc.
94 *
95 * The optional 3rd argument @p patchVarsDef allows you to retrieve the
96 * default initialization value(s) of all 'patch' variables declared in
97 * the passed script itself. This is useful for instrument editors.
98 *
99 * @param s - entire source code of the script to be loaded
100 * @param patchVars - (optional) replacement value for patch variables
101 * @param patchVarsDef - (optional) output of original values of patch
102 * variables
103 * @returns parsed representation of the script
104 */
105 VMParserContext* loadScript(const String& s,
106 const std::map<String,String>& patchVars =
107 std::map<String,String>(),
108 std::map<String,String>* patchVarsDef = NULL);
109
110 /**
111 * Same as above's loadScript() method, but this one reads the script's
112 * source code from an input stream object (i.e. stdin or a file).
113 *
114 * @param is - input stream from which the entire source code of the
115 * script is to be read and loaded from
116 * @param patchVars - (optional) replacement value for patch variables
117 * @param patchVarsDef - (optional) output of original values of patch
118 * variables
119 * @returns parsed representation of the script
120 */
121 VMParserContext* loadScript(std::istream* is,
122 const std::map<String,String>& patchVars =
123 std::map<String,String>(),
124 std::map<String,String>* patchVarsDef = NULL);
125
126 /**
127 * Parses a script's source code (passed as argument @a s to this
128 * method), splits that input up in its individual tokens (i.e.
129 * keyword, variable name, event name, etc.) and returns all those
130 * tokens, for the purpose that the caller can provide syntax syntax
131 * highlighting for the passed script.
132 *
133 * This method is actually not used by the sampler at all, it is rather
134 * provided for external script editor applications, to provide them a
135 * convenient backend for parsing scripts and providing syntax
136 * highlighting.
137 *
138 * @returns recognized tokens of passed script's source code
139 */
140 std::vector<VMSourceToken> syntaxHighlighting(const String& s);
141
142 /**
143 * Same as above's syntaxHighlighting() method, but this one reads the
144 * script's source code from an input stream object (i.e. stdin or a
145 * file).
146 *
147 * @param is - input stream from which the entire source code of the
148 * script is to be read and loaded from
149 * @returns recognized tokens of passed script's source code
150 */
151 std::vector<VMSourceToken> syntaxHighlighting(std::istream* is);
152
153 /**
154 * Dumps the translated tree of the already parsed script, given by
155 * argument @a context, to stdout. This method is for debugging purposes
156 * only.
157 *
158 * @param context - parsed representation of the script
159 * @see loadScript()
160 */
161 void dumpParsedScript(VMParserContext* context);
162
163 /**
164 * Creates a so called VM exceution context for a specific, already
165 * parsed script (provided by argument @a parserContext). Due to the
166 * general real-time design of this virtual machine, the VM execution
167 * context differs for every script. So you must (re)create the
168 * execution context for each script being loaded.
169 *
170 * @param parserContext - parsed representation of the script
171 * @see loadScript()
172 */
173 VMExecContext* createExecContext(VMParserContext* parserContext);
174
175 /**
176 * Execute a script by virtual machine. Since scripts are event-driven,
177 * you actually execute only one specific event handler block (i.e. a
178 * "on note ... end on" code block) by calling this method (not the
179 * entire script), and hence you must provide one precise handler of the
180 * script to be executed by this method.
181 *
182 * This method usually blocks until the entire script event handler
183 * block has been executed completely. It may however also return before
184 * completion if either a) a script runtime error occurred or b) the
185 * script was suspended by the VM (either because script execution
186 * exceeded a certain limit of time or the script called the built-in
187 * wait() function). You must check the return value of this method to
188 * find out which case applies.
189 *
190 * @param parserContext - parsed representation of the script (see loadScript())
191 * @param execContext - VM execution context (see createExecContext())
192 * @param handler - precise event handler (i.e. "on note ... end on"
193 * code block) to be executed
194 * (see VMParserContext::eventHandlerByName())
195 * @returns current status of the vitual machine (i.e. script succeeded,
196 * script runtime error occurred or script was suspended for
197 * some reason).
198 */
199 VMExecStatus_t exec(VMParserContext* parserContext, VMExecContext* execContext, VMEventHandler* handler);
200
201 /**
202 * Returns built-in script function for the given function @a name. To
203 * get the implementation of the built-in message() script function for
204 * example, you would pass "message" here).
205 *
206 * This method is re-implemented by deriving classes to add more use
207 * case specific built-in functions.
208 *
209 * @param name - name of the function to be retrieved (i.e. "wait" for the
210 * built-in wait() function).
211 */
212 VMFunction* functionByName(const String& name) OVERRIDE;
213
214 /**
215 * Whether the passed built-in function is disabled and should thus be
216 * ignored by the parser at the passed parser context (parser state
217 * where the built-in function call occurs).
218 *
219 * @param fn - built-in function to be checked
220 * @param ctx - parser context at the position where the built-in
221 * function call is located within the script
222 */
223 bool isFunctionDisabled(VMFunction* fn, VMParserContext* ctx) OVERRIDE;
224
225 /**
226 * Returns all built-in integer script variables. This method returns a
227 * STL map, where the map's key is the variable name and the map's value
228 * is the native pointer to the actual built-in variable.
229 *
230 * This method is re-implemented by deriving classes to add more use
231 * case specific built-in variables.
232 */
233 std::map<String,VMIntPtr*> builtInIntVariables() OVERRIDE;
234
235 /**
236 * Returns all built-in (8 bit) integer array script variables. This
237 * method returns a STL map, where the map's key is the array variable
238 * name and the map's value is the native pointer to the actual built-in
239 * array variable.
240 *
241 * This method is re-implemented by deriving classes to add more use
242 * case specific built-in array variables.
243 */
244 std::map<String,VMInt8Array*> builtInIntArrayVariables() OVERRIDE;
245
246 /**
247 * Returns all built-in constant integer script variables, which are
248 * constant and their final data is already available at parser time
249 * and won't change during runtime. Providing your built-in constants
250 * this way may lead to performance benefits compared to using other
251 * ways of providing built-in variables, because the script parser
252 * can perform optimizations when the script is refering to such
253 * constants.
254 *
255 * This type of built-in variable can only be read, but not be altered
256 * by scripts. This method returns a STL map, where the map's key is
257 * the variable name and the map's value is the final constant data.
258 *
259 * This method is re-implemented by deriving classes to add more use
260 * case specific built-in constant integers.
261 *
262 * @b Note: In case your built-in variable should be read-only but its
263 * value is not already available at parser time (i.e. because its
264 * value may change at runtime), then you should add it to
265 * builtInIntVariables() instead and use the macro
266 * DECLARE_VMINT_READONLY() to define the variable for read-only
267 * access by scripts.
268 */
269 std::map<String,vmint> builtInConstIntVariables() OVERRIDE;
270
271 /**
272 * Returns all built-in constant real number (floating point) script
273 * variables, which are constant and their final data is already
274 * available at parser time and won't change during runtime. Providing
275 * your built-in constants this way may lead to performance benefits
276 * compared to using other ways of providing built-in variables, because
277 * the script parser can perform optimizations when the script is
278 * refering to such constants.
279 *
280 * This type of built-in variable can only be read, but not be altered
281 * by scripts. This method returns a STL map, where the map's key is
282 * the variable name and the map's value is the final constant data.
283 *
284 * This method is re-implemented by deriving classes to add more use
285 * case specific built-in constant real numbers.
286 */
287 std::map<String,vmfloat> builtInConstRealVariables() OVERRIDE;
288
289 /**
290 * Returns all built-in dynamic variables. This method returns a STL
291 * map, where the map's key is the dynamic variable's name and the
292 * map's value is the pointer to the actual object implementing the
293 * behavior which is actually generating the content of the dynamic
294 * variable.
295 *
296 * This method is re-implemented by deriving classes to add more use
297 * case specific built-in dynamic variables.
298 */
299 std::map<String,VMDynVar*> builtInDynamicVariables() OVERRIDE;
300
301 /**
302 * Enables or disables automatic suspension of scripts by the VM.
303 * If automatic suspension is enabled then scripts are monitored
304 * regarding their execution time and in case they are execution
305 * for too long, then they are automatically suspended by the VM for
306 * a certain amount of time in order to avoid any RT instablity
307 * issues caused by bugs in the script, i.e. endless while() loops
308 * or very large scripts.
309 *
310 * Automatic suspension is enabled by default due to the aimed
311 * real-time context of this virtual machine.
312 *
313 * @param b - true: enable auto suspension [default],
314 * false: disable auto suspension
315 */
316 void setAutoSuspendEnabled(bool b = true);
317
318 /**
319 * Returns true in case automatic suspension of scripts by the VM is
320 * enabled. See setAutoSuspendEnabled() for details.
321 *
322 * Automatic suspension is enabled by default due to the aimed
323 * real-time context of this virtual machine.
324 */
325 bool isAutoSuspendEnabled() const;
326
327 /**
328 * By default (i.e. in production use) the built-in exit() function
329 * prohibits any arguments to be passed to its function by scripts. So
330 * by default, scripts trying to pass any arguments to the built-in
331 * exit() function will yield in a parser error.
332 *
333 * By calling this method the built-in exit() function will optionally
334 * accept one argument to be passed to its function call by scripts. The
335 * value of that function argument will become available by calling
336 * VMExecContext::exitResult() after execution of the script.
337 *
338 * @see VMExecContext::exitResult()
339 */
340 void setExitResultEnabled(bool b = true);
341
342 /**
343 * Returns @c true if the built-in exit() function optionally accepts
344 * a function argument by scripts.
345 *
346 * @see setExitResultEnabled()
347 */
348 bool isExitResultEnabled() const;
349
350 VMEventHandler* currentVMEventHandler(); //TODO: should be protected (only usable during exec() calls, intended only for VMFunctions)
351 VMParserContext* currentVMParserContext(); //TODO: should be protected (only usable during exec() calls, intended only for VMFunctions)
352 VMExecContext* currentVMExecContext(); //TODO: should be protected (only usable during exec() calls, intended only for VMFunctions)
353
354 private:
355 VMParserContext* loadScriptOnePass(const String& s);
356 protected:
357 VMEventHandler* m_eventHandler;
358 ParserContext* m_parserContext;
359 bool m_autoSuspend;
360 bool m_acceptExitRes;
361 class CoreVMFunction_message* m_fnMessage;
362 class CoreVMFunction_exit* m_fnExit;
363 class CoreVMFunction_wait* m_fnWait;
364 class CoreVMFunction_abs* m_fnAbs;
365 class CoreVMFunction_random* m_fnRandom;
366 class CoreVMFunction_num_elements* m_fnNumElements;
367 class CoreVMFunction_inc* m_fnInc;
368 class CoreVMFunction_dec* m_fnDec;
369 class CoreVMFunction_in_range* m_fnInRange;
370 class CoreVMFunction_sh_left* m_fnShLeft;
371 class CoreVMFunction_sh_right* m_fnShRight;
372 class CoreVMFunction_msb* m_fnMsb;
373 class CoreVMFunction_lsb* m_fnLsb;
374 class CoreVMFunction_min* m_fnMin;
375 class CoreVMFunction_max* m_fnMax;
376 class CoreVMFunction_array_equal* m_fnArrayEqual;
377 class CoreVMFunction_search* m_fnSearch;
378 class CoreVMFunction_sort* m_fnSort;
379 class CoreVMFunction_int_to_real* m_fnIntToReal;
380 class CoreVMFunction_real_to_int* m_fnRealToInt;
381 class CoreVMFunction_round* m_fnRound;
382 class CoreVMFunction_ceil* m_fnCeil;
383 class CoreVMFunction_floor* m_fnFloor;
384 class CoreVMFunction_sqrt* m_fnSqrt;
385 class CoreVMFunction_log* m_fnLog;
386 class CoreVMFunction_log2* m_fnLog2;
387 class CoreVMFunction_log10* m_fnLog10;
388 class CoreVMFunction_exp* m_fnExp;
389 class CoreVMFunction_pow* m_fnPow;
390 class CoreVMFunction_sin* m_fnSin;
391 class CoreVMFunction_cos* m_fnCos;
392 class CoreVMFunction_tan* m_fnTan;
393 class CoreVMFunction_asin* m_fnAsin;
394 class CoreVMFunction_acos* m_fnAcos;
395 class CoreVMFunction_atan* m_fnAtan;
396 class CoreVMDynVar_NKSP_REAL_TIMER* m_varRealTimer;
397 class CoreVMDynVar_NKSP_PERF_TIMER* m_varPerfTimer;
398 };
399
400 } // namespace LinuxSampler
401
402 #endif // LS_INSTRUMENTSCRIPTVM_H

  ViewVC Help
Powered by ViewVC