ViewVC logotype

Annotation of /doc/docbase/instrument_scripts/nksp/real_unit_final/01_nksp_real_unit_final.html

Parent Directory Parent Directory | Revision Log Revision Log

Revision 3605 - (hide annotations) (download) (as text)
Tue Sep 17 19:44:02 2019 UTC (22 months, 2 weeks ago) by schoenebeck
File MIME type: text/html
File size: 51579 byte(s)
- Minor fixes regarding real numbers, unit and finalness.

1 schoenebeck 3599 <html>
2     <head>
3     <meta name="author" content="Christian Schoenebeck">
4     <title>Real Numbers, Units and Finalness</title>
5     <urlpath>Real_Numbers_Units_and_Finalness</urlpath>
6 schoenebeck 3605 <meta name="description" content="New NKSP Core Language Features: Support for real numbers, standard measuring units and finalness.">
7 schoenebeck 3599 <link rel="stylesheet" href="http://doc.linuxsampler.org/css/preview.css">
8     <script type="text/javascript" src="http://doc.linuxsampler.org/js/preview.js"></script>
9     </head>
10     <body>
11     <p>
12     As you might have seen from our change log, I've been recently working on
13     a bunch of new core features for our <a href="01_nksp.html">NKSP</a>
14     real-time instrument script engine, with the goal to make instrument
15     scripting more intuitive and less error prone, especially from a
16     musician's point of view.
17     </p>
18     <p>
19     The changes are quite substantial, so here is
20     a more detailed description of what's new, how to use those new
21     features, what's the motivation behind them, and also a discourse
22     about some of the associated language design (and implementation) aspects.
23     </p>
24     <note class="important">
25     Features described in this article refer to LinuxSampler version <b>2.1.1.svn16</b> (or higher).
26     So these features are not available in older versions of the sampler.
27     And since these are new development features, they still might be subject to change.
28     </note>
30 schoenebeck 3603 <h2 id="64bit">64-Bit Integers</h2>
31 schoenebeck 3599 <p>
32     First of all, integers, i.e. integer number literals (as e.g. <code lang="nksp">4294967295</code>), integer
33     variables (like <code lang="nksp">declare $foo := 4294967295</code>), or
34     integer array variables (like <code>declare %bar[3] := ( 1, 2, 3 ) </code>),
35     and all their arithmetics like
36     <code lang="nksp">($foo + 1024) / 24</code> and all built-in functions (as e.g.
37     <code>min()</code>), are now all 64 bit with <a href="01_nksp.html">NKSP</a>.<br>
38     <br>
39     I hear your "<i>Yaaawn</i>" at this point. You might be surprised though about the amount of
40     <a href="https://en.wikipedia.org/wiki/Diff">diff</a> involved
41     and how often people stumbled over undesired 32-bit truncation with their
42     scripts before. So that change alone reduced error-proneness tremendously.
43     But let's get on.
44     </p>
46 schoenebeck 3603 <h2 id="real_numbers">Real Numbers</h2>
47 schoenebeck 3599 <p>
48     You are finally no longer limited to integer math with <a href="01_nksp.html">NKSP</a>.
49     You can now also use floating point arithmetics which will make calculations,
50     that is mathematical formulas in your scripts much easier than before.
51     Sounds a bit more interesting, doesn't it?<br>
52     </p>
54 schoenebeck 3603 <h3 id="real_variables">Variables</h3>
55 schoenebeck 3599 <p>
56     We call those floating point numbers
57     <i title="One of the most important classes of numbers in mathematics where each <b>real number</b> represents a continous quantity qualified for reflecting a distance on a line, and hence real numbers are commonly used for the numerical value of measurements of physical quantities like e.g. length, temperature, mass, velocity.">
58     real numbers
59     </i> from now on and you can
60     write them like you probably already expected; in simple dotted notation like
61     <code>2.98</code>. Likewise there are new variable types for real numbers as well.
62     The syntax to declare a real number variable is:
63     </p>
64     <p>
65     <code lang="nksp">
66     declare ~??real-variable-name?? := ??initial-value??
67     </code>
68     </p>
69     <p>
70     Like e.g.:
71     </p>
72     <p>
73     <code lang="nksp">
74     declare ~foo := 3.14159265
75     </code>
76     </p>
77     <p>
78     So it looks pretty much the same as with integer variables, just that you use
79     "~" as prefix in front of the variable name instead of "$" that you would
80     use for integer variables <b>and</b> the values <b>must always</b> contain a dot so that the parser
81     can distinguish them clearly from integer numbers.
82     Moreover there is now also a real number array variable type which you can
83     declare like this:
84     </p>
85     <p>
86     <code lang="nksp">
87     declare ???real-array-variable-name??[??amount-of-elements??] := ( ??initial-values?? )
88     </code>
89     </p>
90     <p>
91     Like e.g.:
92     </p>
93     <p>
94     <code lang="nksp">
95     declare ?foo[4] := ( 0.1, 2.0, 46.238, 104.97 )
96     </code>
97     </p>
98     <p>
99     Once again, the only differences to integer array variables are that you use
100     "?" as prefix in front of the array variable name instead of "%" that you
101     would use for integer array variables, <b>and</b> that you <b>must always</b> use a
102     dot for each value being assigned.
103     And as with integer variables, if you omit to assign initial value(s) for
104     your real number variables or real array variables then they are automatically
105     initialized with zero value(s) (that is <code>0.0</code> actually).
106     </p>
107     <note class="remark">
108 schoenebeck 3605 I actually already had plans for implementing floating point support in
109     <i title="NKSP stands for 'is <b>N</b>ot <b>KSP</b>', which denotes its distinction to an existing proprietary language called <i>KSP</i>. NSKP is a script language specifically designed to write real-time capable software extensions to LinuxSampler's sampler engines that can be bundled individually with sounds by sound designers themselves.">NKSP</i>
110 schoenebeck 3599 much earlier, but I somehow had the feeling that <i>KSP</i> would add it as well.
111     And I though before "inventing" again some kind of new syntax set for this feature
112     and then having to somehow merge and maintain cross-compatibility between <i>KSP</i> syntax
113     and <i>NKSP</i> syntax, I decided to wait a bit, and it
114     eventually appeared now on <i>KSP</i> side, so it was a good point to finally fill
115     this gap in <i>NKSP</i>.
116     </note>
118 schoenebeck 3603 <h3 id="type_casting">Type Casting</h3>
119 schoenebeck 3599 <p>
120     Like <i>KSP</i> we are (currently) quite strict about your obligation to distinguish
121     clearly between integer numbers and real numbers with <i>NKSP</i>. That means blindly
122     mixing integers and real numbers e.g. in formulas, will currently cause a parser error
123     like in this example:
124     </p>
125     <p>
126     <code>~foo := (~bar + 1.9) / 24 { WRONG! }</code>
127     </p>
128     <p>
129     In this example you would simply use <code>24.0</code> instead of <code>24</code> to
130     fix the parser error:
131     </p>
132     <p>
133     <code>~foo := (~bar + 1.9) / 24.0 { correct }</code>
134     </p>
135     <p>
136     That's because, when you are mixing integer numbers and real numbers in mathematical
137     operations, like the division in the latter example, what was your intended data type that you
138     expected of the result of that division; a real number or an integer result? Because it
139     would not only mean a different data type, it might certainly also mean a completely
140     different result value accordingly.
141     </p>
142     <p>
143     That does not mean you were not allowed to mix real numbers with integers, it is just
144     that you have to make your point clear to the parser what your intention is. For that
145     purpose there are now 2 new built-in functions <code>int_to_real()</code> and
146     <code>real_to_int()</code> which you may use for required type casts (data type conversions).
147     So let's say you have a mathematical formula where you want to mix that formula with
148     a real number variable and an integer variable, then you might e.g. type cast the
149     integer variable like this:
150     </p>
151     <p>
152     <code>~bla := ~foo / int_to_real($bar)</code>
153     </p>
154     <p>
155     And since this is a very common thing to do, we also have 2 short-hand forms of these
156     2 built-in functions in <i>NKSP</i> which are simply <code>real()</code> and <code>int()</code>:
157     </p>
158     <p>
159     <code>~bla := ~foo / real($bar) { same as above, just shorter } </code>
160     </p>
161     <note>
162     The short-hand functions <code>real()</code> and <code>int()</code> only exist in
163     <i>NKSP</i>. They don't exist with <i>KSP</i>.
164     </note>
165     <note class="remark">
166     In future we might certainly lift this data type strictness and do it like many other
167     programming languages handle this: just showing a parser warning (not an error) on mixed
168     integer vs. real number expressions, and at the same time performing always an implied type cast
169     of the respective integer to a real number type automatically by the compiler.
170     </note>
172     <h3>Built-in Functions</h3>
173     <p>
174     What about real numbers and existing built-in functions? When you check our latest reference
175     documentation of <a href="01_nksp_reference.html">NKSP built-in functions</a>,
176     you will notice that most of them accept now both, integers and real numbers as arguments
177     to their function calls. You should be aware though that the precise acceptance of data
178     types and the resulting behaviour change, varies between the individual built-in functions,
179     which is due to the difference in purpose of all those numerous built-in functions.
180     </p>
181     <p>
182     For instance the data type of the result returned by <code>min()</code> and <code>max()</code>
183     function calls depends now on the data type being passed to those functions. That is
184     if you pass real numbers to those 2 functions then you'll get a real number as result;
185     if you pass integers instead then you'll get an integer as result instead.
186     </p>
187     <p>
188 schoenebeck 3605 Then there are functions, like e.g. the new math functions <code>sin()</code>, <code>cos()</code>,
189 schoenebeck 3599 <code>tan()</code>, <code>sqrt()</code>, which only accept real numbers as arguments (and
190     always return a real number as result). Trying to pass integers will cause a parser error,
191     because those particular functions are not really useful on integers at all.
192     </p>
193     <p>
194     Likewise the previously already existing functions <code>fade_in()</code> and <code>fade_out()</code>
195     accept now both integers and real numbers for their 2nd argument (<code>??duration-us??</code>),
196     but do not allow real numbers for their 1st argument (<code>??note-id??</code>), because for
197     a duration real numbers make sense, whereas for a <code>??note-id??</code>
198     real numbers would not make any sense and such an attempt is usually a result of some
199     programming error, hence you will get a parser error when trying to pass a real number
200     to the 1st argument of those 2 built-in functions.
201     </p>
202     <p>
203     There might also be differences how built-in functions handle mixed usage of integers
204     and real numbers as arguments, simultaniously for the same function call that is.
205     For instance
206     the <code>min()</code> and <code>max()</code> functions are very permissive and allow you to mix
207     an integer argument with a real number argument. In such mixed cases those 2 functions
208     will simply handle the integer argument as if it was a real number and hence the
209     result's data type would be a real number. So this would be Ok:
210     </p>
211     <p>
212     <code>
213     min(0.3, 300) { OK for this function: mixed real and integer arguments }
214     </code>
215     </p>
216     <p>
218     Yet other functions,
219     like the <code>search()</code>
220     function, are very strict regarding data type. So if you are passing an integer array as 1st argument to
221     the <code>search()</code> function then it only accepts an integer (scalar) as
222     2nd argument, and likewise if you are passing a real number array as 1st argument
223     then it only accepts a real number (scalar) as 2nd argument. Attempts passing
224     different types, or in a different way to that function, will cause a parser error.
225     </p>
226     <note>
227     Use common sense! The accepted data types of arguments and correspending
228     result's data type of built-in functions usually match with your intuition,
229     and if it does not for some reason, then
230     you always get a clear parser error message immediately when trying to pass a wrong data
231     type while typing your scripts (e.g. in Gigedit's script editor). And on doubt you can
232     always refer to the <a href="01_nksp_reference.html">reference documentation</a> for
233     details of course.
234     </note>
236     <h3>Comparing for Equalness</h3>
237     <p>
238     If you are also writing <i>KSP</i> scripts, then you probably already knew most of the things that I
239     described above about real numbers. But here comes an important difference that we
240     have when dealing with real numbers in <i>NKSP</i>: real number value comparison for equalness and unequalness.
241     </p>
242     <p>
243 schoenebeck 3601 In our automated
244     <a href="http://svn.linuxsampler.org/cgi-bin/viewvc.cgi/linuxsampler/trunk/src/scriptvm/tests/NKSPCoreLangTest.cpp?view=markup">NKSP core language test cases</a>
245     you find an example that looks
246 schoenebeck 3599 like this (slightly changed here for simplicity):
247     </p>
248     <p>
249     <code>
250     on init
251     declare ~a := 0.165
252     declare ~b := 0.185
253     declare ~x := 0.1
254     declare ~y := 0.25
256     if (~a + ~b = ~x + ~y)
257     message("Test succeeded")
258     else
259     message("Test failed")
260     end if
262     end on
263     </code>
264     </p>
265     <p>
266     When you add the values of those variables from this example in your head, you will see that the actual
267     test in that example theoretically boils down to comparing <code>if (0.35 = 0.35)</code>.
268     Hence this test should always succeed. At least
269     that's what one would expect if one would do the calculations above manually by humans
270     in the real world.
271     In practice though, when this script is executed on a computer, the numbers on both sides would
272     slightly deviate from <code>0.35</code>. These differences to the expected value are
273     actually extremely little, that is very tiny fractions of several digits behind the decimal point,
274     but the final consequence would still be nevertheless different values on both sides and this test "would" hence fail.
275     These small errors are due to the technical way
276     <a href="https://en.wikipedia.org/wiki/Floating-point_arithmetic">floating point numbers are encoded</a>
277     on any modern <i>CPU</i> which causes small calculation errors with these summations for instance.
278     Due to that very well known circumstance of floating point arithmetics on
279     CPUs, it is commonly discouraged with system programming languages like C/C++
280     to directly compare floating point numbers for equalness, nor for unequalness for that exact reason.
281     </p>
282     <p>
283     However the use case for the NKSP language is completely different from
284     system level programming languages like C/C++. We don't need to be so
285     conservative in many aspects those languages need to be. The musical context of
286     <i>NKSP</i> simply has different requirements. Simplicity and high level
287     handling is more important for <i>NKSP</i> than revealing bit by bit
288     of the actual CPU registers bare-bone directly to users of instrument scripts.
289     So I decided to implement
290     real number equal (<code>=</code> operator) and unequal comparison
291     (<code>#</code> operator) to automatically take the expected floating
292     point tolerances of the underlying CPU into account.
293     </p>
294     <p>
295     So in short: the
296     <u>test case example above does <b>not</b> fail with our <i>NKSP</i> implementation</u>!
297     </p>
298     <p>
299     That does not mean you can simply switch off your head when doing
300     real number arithmetics and subsequent comparisons of those calculations.
301     Because with every calculation you do, the total amount of calculation
302     error (caused by the utilized floating point processing hardware) increases,
303     so after a certain amount of subsequent calculations
304     our equal/unequal comparisons would fail as well after a certain point.
305     But most of the time you will have formulas which end up with a very
306     limited amount of floating point calculations before you eventually
307     do your comparisons, so in most cases you should just be fine. But keep
308     this issue in mind when doing e.g. numeric (large amount of subsequent)
309     calculations e.g. in <code>while</code> loops.
310     </p>
311     <p>
312     What about the other comparison operators like <code>&lt;</code>,
313     <code>&gt;</code>, <code>&lt;=</code>, <code>&gt;=</code>? Well,
314 schoenebeck 3605 those other comparison operators all behave like with system level
315 schoenebeck 3599 programming languages. So these comparison operators currently
316     do <b>not</b> take the mentioned floating point tolerances into
317     account and hence they behave differently than the <code>=</code>
318     and <code>#</code> operators with <i>NKSP</i>.
319     The idea was that those other
320     comparison operators are typically used for what mathematicians
321     call "transitivity". So they are used e.g. for sorting tasks
322     where there should always be a clear determinism of the
323     comparison results, and where execution speed is an issue as well.
324     Because the truth is also that our floating point tolerance
325     aware "equal" / "unequal" comparisons come with the price of
326     requiring execution of additional calculations on the underlying CPU.
327     </p>
329     <note class="remark">
330     You might wonder now, isn't this still sort of a hack? Wouldn't
331     there be a better way to implement real numbers in <i>NKSP</i> so that
332     all calculations would behave exactly as we would expect them from
333     theoretical math? The short answer is both <b>yes</b> and <b>no</b>.<br>
334     <br>
335     <b>Yes</b>, we could implement support for real numbers as so called
336     <a href="https://en.wikipedia.org/wiki/Computer_algebra_system">algebraic system</a>,
337     which would accomplish that real number calculations would always exactly
338     result as you would expect them to do from traditional mathematics,
339     like certain mathematical software applications use to do it
340     (e.g. <a href="https://en.wikipedia.org/wiki/Maple_(software)">Maple</a>).
341     However to achieve that we could no longer utilize hardware acceleration
342     of the CPU's floating point unit, because it is limited to floating point
343     values of fixed precision (e.g. either 32 bit and/or 64 bit).
344     Hence we would need to execute a huge amount of instructions on the CPU
345     instead for every single real number calculation in scripts, so there would
346     be a severe performance penalty.<br>
347     <br>
348     And <b>no</b>, we actually cannot do that in <i>NKSP</i> at all, because this kind of
349     complex real number implementation would require memory allocations at
350     runtime, which in turn would violate a key feature of <i>NKSP</i>
351     scripting: its guaranteed real-time stability and runtime determinism.
352     </note>
354 schoenebeck 3603 <h2 id="units">Standard Measuring Units</h2>
355 schoenebeck 3599 <p>
356     If you are coming from <i>KSP</i> then you are eventually going to think next
357     "WTF? What is this all about?". But hang with me, no matter how often you
358     wrote instrument scripts before, you will most
359     certainly regularly come into a situation like described next and we
360     have a convenient fix for that.
361     <p>
363 schoenebeck 3603 <h3 id="unit_literals">Unit Literals</h3>
364 schoenebeck 3599 <p>
365     Let's consider you wanted to pause your script at a certain point for let's say
366     1 second. Ok, you remember from the back of your head that you need to use the
367     built-in <code>wait()</code> function for that, but which value do you need to
368     pass exactly to achieve that 1 second break?
369     Would it be <code>wait(1000)</code>
370     or probably <code>wait(1000000)</code>? Of course now you reach out for the
371     reference documentation at this point and eventually find out that it
372     would actually be <code>wait(1000000)</code>. Not very intuitive. And
373     the large amount of zeros required does not help to make your code necessarily
374     more readable either, right?
375     </p>
376     <p>
377     So what about actually writing what we had in mind at first place:
378     </p>
379     <p>
380     <code>
381     wait(1s)
382     </code>
383     </p>
384     <p>
385     It couldn't be much clearer.
386     </p>
387     <p>
388     Or you want a break of 23 milliseconds instead? Then let's just write that!
389     </p>
390     <p>
391     <code>
392     wait(23ms)
393     </code>
394     </p>
395     <p>
396     Now let's consider another example: Say you wanted to reduce volume of some voices by 3.5 decibel.
397     You remember that was something like <code>change_vol(??note??, ??volume??)</code>,
398     but what would <code>??volume??</code> be exactly? Digging out the docs yet again you
399     find out the correct call was <code>change_vol($EVENT_ID, -3500)</code>.<br>
400     <br>
401     We can do better than that:
402     </p>
403     <p>
404     <code>
405     change_vol($EVENT_ID, -3.5dB)
406     </code>
407     </p>
408     <p>
409     You rather want a slight volume increase by just 56 milli dB instead?
410     </p>
411     <p>
412     <code>
413     change_vol($EVENT_ID, +56mdB)
414     </code>
415     </p>
416     <p>
417     Or let's lower the tuning of a note by -24 Cents:
418     </p>
419     <p>
420     <code>
421     change_tune($EVENT_ID, -24c)
422     </code>
423     </p>
424     <p>
425     I'm sure you got the point. We are naturally using standard measuring
426     units in our daily life without noticing their importance, but they actually help us a
427     lot to give some otherwise purely abstract numbers an intuitive meaning to us.
428     Hence it just made sense to add measuring units as core feature of the NKSP
429     language, their built-in functions, variables and whatever you do with them.
430     </p>
432     <h3>Calculating with Units</h3>
433     <p>
434 schoenebeck 3605 Having said that, these examples above were just meant as warm up appetizer.
435 schoenebeck 3599 Of course you can do much more with this feature than just passing them
436     literally to some built-in function call as we did above so far.
437     You can assign them to variables, too, like:
438     </p>
439     <p>
440     <code>
441     declare ~pitchLfoFrequency := 1.2kHz
442     </code>
443     </p>
444     <p>
445     You can use them in combinations with integers or real numbers, and of course
446     you can do all mathematical calculations and comparisons that you would
447     naturally be able to do in real life. For instance the following example
448     </p>
449     <code>
450     on init
451     declare $a := 1s
452     declare $b := 12ms
453     declare $result := $a - $b
454     message("Result of calculation is " &amp; $result)
455     end on
456     </code>
457     </p>
458     <p>
459     would print the text <code>"Result of calculation is 988ms"</code> to the terminal
460     (notice that <code>$a</code> and <code>$b</code> actually used different units here).<br>
461     <br>
462     Or the following example
463     </p>
464     <code>
465     on init
466     declare ~a := 2.0mdB
467     declare ~b := 3.2mdB
468     message( 4.0 * ( ~a + ~b ) / 2.0 + 0.1mdB )
469     end on
470     </code>
471     </p>
472     <p>
473     would print the text <code>"10.5mdB"</code> to the terminal.<br>
474     <br>
475     Or let's make this little value comparison check:
476     </p>
477     <p>
478     <code>
479     on init
480     declare ~foo := 999ms
481     declare ~bar := 1s
482     if (~foo &lt; ~bar)
483     message("Test succeeded")
484     else
485     message("Test failed")
486     end fi
487     end on
488     </code>
489     </p>
490     <p>
491     which will succeed of course
492     (notice again that <code>~foo</code> and <code>~bar</code> used different units here as well).<br>
493     <br>
494     So as you can see the units are not just eye candy for your code, they
495     are actually interpreted actively by the script engine appropriately such that all your
496     calculations, comparisons and function calls behave as
497     you would expect them to do from your real-life experience.
498     </p>
500     <h3>Unit Components</h3>
501     <p>
502     In the examples above you might have noticed that the units' components
503     were shown in different colors. That's not a glitch of the website,
504     that's intentional and in fact NKSP code on this website is in general,
505     automatically displayed in the same way as with e.g. Gigedit's instrument
506     script editor. So what's the deal?
507     </p>
508     <p>
509     If you take the value <code>6.8mdB</code> as an example, you have in front
510     the <code>??numeric component?? = 6.8</code> of course, followed
511     by the <code>??metric prefix?? = <span class="up">md</span></code> for
512     "milli deci" (which is always simply some kind of multiplication factor)
513     and finally the fundamental <code>??unit type?? = <span class="ut">B</span></code> for "Bel" (which actually gives the number its final meaning).
514     </p>
515     <p>
516     So here's where language design comes into play. From language point of view both
517     the <code>??numeric component??</code> and the optional <code>??metric prefix??</code>
518     are runtime features which may change at any time,
519     whereas the optional <code>??unit type??</code> is always
520     a constant, "sticky", parse-time feature that you may never change at runtime.
521     That means if you define a variable like e.g. <code>declare $foo := 1s</code>
522     that variable <code>$foo</code> is now firmly tied to the unit type "seconds" for your entire script.
523     You may change the variable's numeric component and metric prefix later on at any time like e.g.
524     <code>$foo := 8ms</code>, but you must not change the variable ever to a different
525     unit type later on like <code>$foo := 8Hz</code>. Trying to switch
526     the variable to a different unit type that way will cause a parser error.
527 schoenebeck 3605 Changing the fundamental unit type of a variable is not allowed, because it
528     would change the semantical meaning of the variable.
529 schoenebeck 3599 </p>
530     <note class="remark">
531     What may look like a lousy limitation of the technical implementation
532     is in fact an intentional language design decision and is actually a feature,
533     called <i>determinism</i>.
534     The price of this limitation of forcing unit types to be a constant parse time
535     feature of variables and expressions comes with the profit of buying substantial
536     error checks at parse time, and that in turn helps you to write more
537     reliable instrument scripts in a shorter amount of time. For instance no
538     matter how complex your mathematical formulas are in your scripts, the parser
539     will always be able to check already at parse-time whether the
540     final, evaluated results of your formulas and overall code that you pass to
541     built-in functions, will finally be of correct unit type expected by the
542     respective function that you are going to call with them as function arguments.
543     Or in other words: the parser is able to check the correct meaning of your formulas at parse-time.
544     So the parser will stop you immediately
545     from doing such and similar mistakes by raising a parser error immediately while you are typing
546     your script code. So you neither
547     have to load the script into the sampler, nor do you have to run and test the
548     code just to spot such kind of mistakes. You will always see them instantly
549 schoenebeck 3605 in the code editor while you are typing your code.
550 schoenebeck 3599 </note>
551     <p>
552     So getting back and proceed with an early example, this code would be fine:
553     </p>
554     <p>
555     <code>
556     on note
557     declare ~reduction := -3.5dB { correct unit type }
558     change_vol($EVENT_ID, ~reduction)
559     end note
560     </code>
561     </p>
562     <p>
563 schoenebeck 3605 That's Ok because the built-in function <code>change_vol()</code>
564     optionally accepts the unit <code>B</code> for its 2nd argument.
565 schoenebeck 3599 Whereas the following would immediately raise a parser error:
566     </p>
567     <p>
568     <code>
569     on note
570     declare ~reduction := -3.5kHz { WRONG unit type for change_vol() call! }
571     change_vol($EVENT_ID, ~reduction)
572     end note
573     </code>
574     </p>
575     <p>
576     That's because using the unit type Hertz for changing volume with the
577     built-in function <code>change_vol()</code> does not make any sense,
578     that built-in function expects a unit type suitable for volume changes,
579     not a unit type for frequencies, and hence it is clearly a
580     programming mistake. So getting this error in
581     practice, you may have simply picked a wrong variable by accident for
582     a certain function call for instance and the parser will immediately
583     point you on that undesired circumstance.
584     </p>
585     <p>
586     As another example, you may now also use units with the built-in random number
587     generating function like e.g. <code>random(100Hz, 5kHz)</code>. The function
588     would then return an arbitrary value between <code>100Hz</code> and <code>5kHz</code>
589     each time you call it that way, so that makes sense. But trying e.g. <code>random(100Hz, 5s)</code>
590     would not make any sense and consequently you would immediately get a parser
591     error that you are attempting to pass two different unit types to the <code>random()</code> function,
592     which is not accepted by this particular built-in function.
593     And these kinds of parse-time errors are always detected,
594     no matter whether you are literally passing constant
595     values like in the simple example here, but also through every other means like
596     variables and complex mathematical expressions.
597     </p>
598     <p>
599     The following tables list the unit types and metric prefixes currently supported by <i>NKSP</i>.
600     </p>
601     <p>
602     <table>
603     <tr>
604     <th>Unit Type</th> <th>Description</th> <th>Purpose</th>
605     </tr>
606     <tr>
607     <td><code>s</code></td>
608     <td>short for "seconds"</td>
609     <td>May be used for time durations.</td>
610     </tr>
611     <tr>
612     <td><code>Hz</code></td>
613     <td>short for "Hertz"</td>
614     <td>May be used for frequencies.</td>
615     </tr>
616     <tr>
617     <td><code>B</code></td>
618     <td>short for "Bel"</td>
619 schoenebeck 3605 <td>May be used for volume changes and other kinds of relative changes
620     (e.g. depth of envelope generators).</td>
621 schoenebeck 3599 </tr>
622     </table>
624     <table>
625     <tr>
626     <th>Metric Prefix</th> <th>Description</th> <th>Equivalent Factor</th>
627     </tr>
628     <tr>
629     <td><code>u</code></td>
630     <td>short for "micro"</td>
631     <td>10<sup>-6</sup>&nbsp;&nbsp;=&nbsp;&nbsp;0.000001</td>
632     </tr>
633     <tr>
634     <td><code>m</code></td>
635     <td>short for "milli"</td>
636     <td>10<sup>-3</sup>&nbsp;&nbsp;=&nbsp;&nbsp;0.001</td>
637     </tr>
638     <tr>
639     <td><code>c</code></td>
640     <td>short for "centi"</td>
641     <td>10<sup>-2</sup>&nbsp;&nbsp;=&nbsp;&nbsp;0.01</td>
642     </tr>
643     <tr>
644     <td><code>d</code></td>
645     <td>short for "deci"</td>
646     <td>10<sup>-1</sup>&nbsp;&nbsp;=&nbsp;&nbsp;0.1</td>
647     </tr>
648     <tr>
649     <td><code>da</code></td>
650     <td>short for "deca"</td>
651     <td>10<sup>1</sup>&nbsp;&nbsp;=&nbsp;&nbsp;10</td>
652     </tr>
653     <tr>
654     <td><code>h</code></td>
655     <td>short for "hecto"</td>
656     <td>10<sup>2</sup>&nbsp;&nbsp;=&nbsp;&nbsp;100</td>
657     </tr>
658     <tr>
659     <td><code>k</code></td>
660     <td>short for "kilo"</td>
661     <td>10<sup>3</sup>&nbsp;&nbsp;=&nbsp;&nbsp;1000</td>
662     </tr>
663     </table>
664     </p>
665     <p>
666     Of course there are much more standard unit types and metric prefixes than
667     those, but currently we only support those listed above. Simply because
668     I found these listed ones to be actually useful for instrument scripts.
669     </p>
670     <note class="important">
671     When changing tuning, which is commonly expected by musicians in "Cents",
672     like e.g.: <code>change_tune($EVENT_ID, -24c)</code>, you might have noticed
673     already from the markup color here, that this is actually not handled as a unit
674     type by the <i>NKSP</i> language and that's why it is not listed as
675     a unit type in the table above. So tuning changes in "Cents" is actually just a value
676     with metric prefix "centi" and without any unit type, since tuning changes
677     in "Cents" is really just a relative multiplication factor for changing the pitch of
678     a note depending on the current base frequency of the note.<br>
679     <br>
680     This might look a bit odd to you, it is semantically however absolutely correct
681     to handle tuning changes in "Cents" that way by the language. You can still also use expressions like
682     "milli Cents", e.g.: <code>change_tune($EVENT_ID, +324mc)</code>, which is also
683     valid since we (currently) allow a combination of up to 2 metric prefixes with <i>NKSP</i>.<br>
684     <br>
685     The obvious advantage of not making "Cents" a dedicated unit type is that we can
686     just use the character "c" in scripts both for tuning changes, as well as for conventional
687     "centi" metric usage like <code>1cs</code> ("one centi second").
688     The downside of this design decision (that is "Cents" being defined as metric prefix) on the other hand
689     means that we loose the previously described parse-time stickyness feature that we
690     would have with "real" unit types, and hence also loose some of the described
691     error detection mechanisms that we have with "real" unit types at parse time.<br>
692     <br>
693     <u>In practice that means:</u> you need to be a bit more cautious when doing calculations
694     with tuning values in "Cents" compared to other tasks like volume changes, because with every
695     calculation you do in your scripts, you might accidentally drop the "Cents" from your unit, which
696     eventually will cause e.g. the <code>change_tune()</code> function to
697     behave completely differently (since a value without any metric prefix
698     will then be interpreted by <code>change_tune()</code> to be a value in "milli cents",
699     exactly like this function did before introduction of units feature in <i>NKSP</i>).
700     </note>
702 schoenebeck 3603 <h3 id="unit_conversion">Unit Conversion</h3>
703 schoenebeck 3599 <p>
704     Even though you are not allowed to change the unit type of a variable itself
705     by assignment at runtime, that does not mean there was no way to get rid of
706     units or that you were unable to convert values from one unit type to a
707     different unit type. You can do that very easily actually with <i>NKSP</i>,
708     exactly as you learned in school; i.e. by multiplications and divisions.
709     </p>
710     <p>
711     Let's say you have a variable <code>$someFrequency</code> that you
712     use for controlling some LFO's frequency by script, and for some reason you really
713     want to use the same value of that variable (for what reason ever)
714     to change some volume with <code>change_vol()</code>, then all you have
715     to do is dividing the existing unit type away, and multiplying it
716     with the new unit type:
717     </p>
718     <p>
719     <code>
720     on note
721     declare $someFrequency := 100Hz
722     change_vol($EVENT_ID, $someFrequency / 1Hz * 1mdB)
723     end note
724     </code>
725     </p>
726     <p>
727     Which would convert the variable's original value <code>100Hz</code>
728     to <code>100mdB</code> before passing it to the <code>change_vol()</code>
729     function. So this actually did 3 things:
730     </p>
731     <p>
732     <ol>
733     <li>the divsion (by <code>/ 1Hz</code>) dropped the old unit type (Hertz),</li>
734     <li>the multiplication (by <code>* 1mdB</code>) added the new unit type (Bel)</li>
735     <li>and that multiplication also changed the metric prefix (to milli deci) before the result is finally passed to the <code>change_vol()</code> function.</li>
736     </ol>
737     </p>
738     <p>
739     And since <code>change_vol()</code> would now receive the value
740     in correct unit type, this overall solution is hence legal and accepted by the parser without any complaint.
741     And this type of unit conversion does not break any parse-time determinism
742     and error detection features either, since it is not touching the variable's
743     unit type directly (only the temporary value eventually being passed to the <code>change_vol()</code> function here),
744     and so the result of the unit conversion expressions above
745     can always reliably be evaluated by the parser at parse-time.
746     </p>
747     <note class="important">
748     There are some intended limitations when performing unit type conversions though.
749     For instance you are never allowed to multiply some unit type with another unit type
750     in <i>NKSP</i>, neither different unit types like e.g. <code>100Hz * 1B</code>, nor
751     with the same unit type like e.g. <code>4s * 8s</code>. That's because we don't have
752     any practical usage for e.g. "square seconds" or other kinds of mixed unit types
753     in instrument scripts.
754     So trying to create a number or variable with more than one unit type will always
755     raise a parser error. So keep that in mind and use common sense when writing
756     calculations with units. And like always: the parser will always point you on
757     misusage immediately.
758     </note>
760     <h3>Array Variables</h3>
761     <p>
762     And as we are at limitations regarding units:
763     Currently <b>unit types</b> are not accepted for array variables yet. <b>Metric prefixes</b>
764     are allowed though!
765     </p>
766     <p>
767     <code>
768     declare %foo[4] := ( 800, 1m, 14c, 43) { OK - metric prefixes, but no unit types }
769     declare %bar[4] := ( 800s, 1ms, 14kHz, 43mdB) { WRONG - unit types not allowed for arrays yet }
770     </code>
771     </p>
772     <p>
773     Main reason for that current limitation is that unlike with scalar variables,
774     accessing array variables at runtime with an index by yet another (runtime changeable)
775     variable might break the previously described parse-time determinism of unit types.
776     That means if we just take the array variable <code>%bar[]</code> declared above
777     and would access it in our scripts with another variable like:
778     </p>
779     <p>
780     <code>
781     %bar[$someVar]
782     </code>
783     </p>
784     <p>
785     then what would that unit type of that array access be? Notice that the array variable
786     <code>%bar[]</code> was initialized with 3 different unit types for its individual elements.
787     So the unit type of the array access would obviously depend on the precise
788     value of variable <code>$someVar</code>, which most probably will change at runtime and
789     hence the compiler would not know at parse-time yet.
790     </p>
791     <note class="remark">
792     This limitation will most probably be lifted later on by allowing exactly one unit type
793     for an array variable, so that the array would be initialized with exactly the same unit
794     type for all its elements to retain the parse-time determinism that we were talking about.
795     </note>
797 schoenebeck 3603 <h2 id="finalness">Finalness</h2>
798 schoenebeck 3599 <p>
799     Here comes another new core language feature of <i>NKSP</i> that you certainly don't
800     know from <i>KSP</i> (as it does not exist there), and which definitely requires an
801     elaborate explanation of what it is about: "finalizing" some value.
802     </p>
804     <h3>Default Relativity</h3>
805     <p>
806     When changing synthesis parameters, these are commonly <i>relative</i> changes, depending
807     on other modulation sources. For instance let's say you are using <code>change_vol()</code>
808     in your script to change the volume of voices of a note, then the actual, final volume
809     value being applied to the voices is not just the value that you passed to <code>change_vol()</code>,
810     but rather a combination of that value and values of other modulation sources of volume
811 schoenebeck 3605 like a constant gain setting stored with the instrument patch, as well as a continuously
812 schoenebeck 3599 changing value coming from an amplitude LFO
813     that you might be using in your instrument patch, and you might most certainly also use
814     an amplitude envelope generator which will also have its impact on the final volume of course.
815 schoenebeck 3605 All these individual volume values are multiplied with each other in real-time by the sampler's engine core
816 schoenebeck 3599 to eventually calculate the actual, final volume to be applied to the voices, like illustrated in the following
817     schematic figure.
818     </p>
819     <img src="nksp_multi_mods_rel.png" caption="Relative Modulation (Default Behaviour)">
820     <p>
821     This <i>relative</i> handling of synthesis parameters is a good thing, because multiple
822     modulation sources combined make up a vivid sound. However there are situations where this
823     combined behaviour for synthesis parameters is not what you want. Sometimes you want to be
824     able to just say in your script e.g. "Make the volume of those voices exactly -6dB. Period. I mean it!".
825     And that's exactly what the newly introduced "final" operator <code>!</code> does.
826     </p>
828     <h3>Final Operator</h3>
829     <p>
830     <code>
831     on note
832     declare $volume := -6dB
833     change_vol($EVENT_ID, !$volume) { '!' makes value read from variable $volume to become 'final' }
834     end note
835     </code>
836     </p>
837     <p>
838     By prepending an exclamation mark <code>!</code> in front of an expression as shown in the code above,
839     you mark that value of that expression to be "final",
840     wich means the value will bypass the values of all other modulation sources, so the
841     sampler will ignore all other modulation sources that may exist, and
842     will simply use your script's value exclusively for that synthesis parameter,
843     as illustrated in the following figure:
844     </p>
845     <img src="nksp_multi_mods_fin.png" caption="Force 'Finalness' by Script">
846     <p>
847     You can of course revert back at any time to let the sampler process that synthesis parameter
848     relatively again by calling <code>change_vol()</code> and just passing
849     a value for volume without "finalness" (i.e. without <code>!</code> operator) this time.
850     </p>
851     <p>
852     In the previous code example, the "finalness" was applied to the temporary value
853     being passed to the <code>change_vol()</code> function, it did not change
854     the information stored in variable <code>$volume</code> at all though. So this is different
855     from:
856     </p>
857     <p>
858     <code>
859     on note
860     declare $volume := !-6dB { store 'finalness' directly to variable $volume }
861     change_vol($EVENT_ID, $volume)
862     end note
863     </code>
864     </p>
865     <p>
866     In the latter code example the actual "finalness" is stored directly now
867     to the <code>$volume</code> variable instead. Both approaches
868     make sense depending on the actual use case. For instance if you only
869     need "finalness" in rare situations, then you might use the prior
870     solution by using the "final" operator just with the respective function call,
871     whereas in use cases where you would always apply the
872     <code>$volume</code> "finally" and probably need to pass it to several
873     <code>change_vol()</code> function calls at several places in your script,
874 schoenebeck 3605 then you might store the "finalness" information directly to the variable instead.
875 schoenebeck 3599 </p>
876     <note class="remark">
877     <i>KSP</i> is also using the exclamation mark in front of variable names of string arrays.
878     Our usage of the exclamation mark character for this "finalness" feature
879     does not cause a language conflict with
880     that aspect though, because variable names (i.e. containing exclamation mark) are
881     resolved by the language before our unary <code>!</code> "final" operator is resolved in
882     expressions.
883     </note>
885     <h3>Mixed Finalness</h3>
886     <p>
887     Like with the other new language features described previously above, we also
888     have some potential ambiguities that we need to deal with when applying "finalness".
889     For instance consider this code:
890     </p>
891     <p>
892     <code>
893     on note
894     declare $volume := !-6dB { store 'finalness' directly to variable $volume }
895     change_vol($EVENT_ID, $volume + 2dB) { raises parser warning here ! }
896     end note
897     </code>
898     </p>
899     <p>
900     Should the resulting, expected volume change of <code>-4dB</code> be applied as
901     "final" value or as <i>relative</i> value instead?
902     Because the problem here is that <code>!-6dB</code> obviously means "final",
903     whereas </code>+ 2dB</code> is actually a <i>relative</i> value to be added.
904     </p>
905     <p>
906     In the current version of the sampler the value to be applied in this case would be "final", so you will not get a parser error,
907     however you will get a parser warning to make you aware about this ambiguity.
908     So to fix the example above, that is to to get rid of that parser warning, you can simply add an exclamation
909     mark in front of the other number as well like:
910     </p>
911     <p>
912     <code>
913     on note
914     declare $volume := !-6dB { store 'finalness' directly to variable $volume }
915     change_vol($EVENT_ID, $volume + !2dB) { '!' fixes parser warning }
916     end note
917     </code>
918     </p>
919     <p>
920     Also built-in functions will behave similarly as described above. Certain built-in functions
921     accept <i>finalness</i> for all of their arguments, some functions accept <i>finalness</i> for only certain
922     arguments and some functions won't accept <i>finalness</i> at all. Like with the other new core language
923     features always use common sense and quickly think about whether it would make sense if a
924     certain function would accept <i>finalness</i> for its argument(s). Most of the time your guess will be
925     right, and if not, then the parser will tell you immediately with either an error or warning, and the
926     <a href="01_nksp_reference.html">NKSP built-in functions reference</a> will help you out with
927     details in such rare cases where things might not be clear to you immediately.
928     </p>
930     <h3>Implied Finalness</h3>
931     <p>
932     Here comes the point where the feature circle of this article closes: the unit type "Bel" used
933     in the examples for the "final" operator above is somewhat special, since the unit type "Bel" is
934     in general used for <i>relative</i> quantities like i.e. volume changes. Tuning changes (i.e. in "Cents") are
935     also relative quantities.
936     </p>
937     <p>
938     However other unit types like "seconds" or "Hertz" are <i>absolute</i>
939     quantities. That means if you are using unit types "Hertz" or "seconds" in your scripts, then their
940     values are automatically applied as <i>implied</i> "final" values, as if you were using the <code>!</code>
941     operator for them in your code. The parser will raise a parser warning though to point you on that
942     circumstance.
943     </p>
944     <p>
945     The following table outlines this issue for the currently supported unit types.
946     </p>
947     <p>
948     <table>
949     <tr>
950 schoenebeck 3605 <th>Unit&nbsp;Type</th> <th>Relative</th> <th>Final</th> <th>Reason</th>
951 schoenebeck 3599 </tr>
952     <tr>
953     <td>None</td>
954     <td>Yes, by default.</td>
955     <td>Yes, if <code>!</code> is used.</td>
956     <td>If no unit type is used (which includes if <b>only</b> a metric prefix is used like e.g. <code>change_tune($EVENT_ID, -23c)</code>) then such values can be used both for relative, as well as for 'final' changes.</td>
957     </tr>
958     <tr>
959     <td><code>s</code></td>
960     <td>No, never.</td>
961     <td>Yes, always.</td>
962     <td>This unit type is naturally for absolute values only, which implies its value to be always 'final'.</td>
963     </tr>
964     <tr>
965     <td><code>Hz</code></td>
966     <td>No, never.</td>
967     <td>Yes, always.</td>
968     <td>This unit type is naturally for absolute values only, which implies its value to be always 'final'.</td>
969     </tr>
970     <tr>
971     <td><code>B</code></td>
972     <td>Yes, by default.</td>
973     <td>Yes, if <code>!</code> is used.</td>
974     <td>This unit type is naturally for relative changes. So this unit type can be used both for relative, as well as for 'final' changes.</td>
975     </tr>
976     </table>
977     </p>
978     <note class="remark">
979     Since unit types like <i>seconds</i> and <i>Hertz</i> are naturally always used for absolute values
980     in real life,
981     it might be considerable to drop the mentioned parser warnings which currently occur
982     if those units are used in scripts without having used the <code>!</code> operator.
983     </note>
985     <h3>Array Variables</h3>
986     <p>
987     As with unit types, the same current restriction applies to "finalness" in conjunction with
988     array variables at the moment: you may currently <b>not</b> apply "finalness" to the elements of array variables yet.
989     </p>
990     <p>
991     <code>
992     declare %foo[3] := ( !-6dB, -8dB, !2dB ) { WRONG - finalness not allowed for arrays (yet) ! }
993     </code>
994     </p>
995     <p>
996     The reason is also exactly the same, because <i>finalness</i> is a parse-time required information
997 schoenebeck 3605 and an array access by using yet another variable like e.g. <code>%foo[$someVar]</code> might
998 schoenebeck 3599 break that parse-time awareness of "finalness" for the compiler.
999     </p>
1000     <note class="remark">
1001     Likewise we might certainly lift that restriction later on by
1002     allowing <i>finalness</i> to be applied to arrays by initializing <b>all</b> members of an array to be all "final".
1003     </note>
1005     <h2>Backward Compatibility</h2>
1006     <p>
1007 schoenebeck 3605 You might be asking, what do all those new features mean to your existing instrument scripts,
1008 schoenebeck 3599 do they break your old scripts?
1009     </p>
1010     <p>
1011     The clear and short answer is:&nbsp;&nbsp;&nbsp;<b>No</b>, of course <u>they do <b>not</b> break your existing scripts</u>!
1012     </p>
1013     <p>
1014     Our goal was always to preserve constant behaviour for existing sounds,
1015     so that even ancient sound files in GigaSampler v1 format still would sound
1016 schoenebeck 3605 exactly as you heard them originally for the 1st time many, many years ago
1017     (probably with GigaSampler at that time).
1018 schoenebeck 3599 And that means the same policy applies to instrument scripts as well of course.
1019     </p>
1020     <p>
1021     You can also arbitrarily mix your existing instrument scripts by just partly using the new
1022     features described in this article at some sections of your scripts, while
1023 schoenebeck 3605 at the same time preserving your old code at other code sections. So these features
1024 schoenebeck 3599 are designed that they won't break anything existing, and that they always
1025 schoenebeck 3605 collaborate correctly in an arbitrary, mixed way with old <i>NKSP</i> code.
1026 schoenebeck 3599 </p>
1028     <h2>Status Quo</h2>
1029     <p>
1030 schoenebeck 3605 That's it!&nbsp;&nbsp;For now ...
1031 schoenebeck 3599 </p>
1032     <p>
1033     This is the current development state regarding these new <a href="01_nksp.html">NKSP</a>
1034     core language features. It might not be the final word though. I am aware certain
1035     aspects that I decided can be argued about (or maybe even entire features).
1036     And that's actually one of the reasons why I decided to write this (even for my habits)
1037 schoenebeck 3605 quite long and detailed article, which also explained the reasons for individual language design
1038 schoenebeck 3599 decisions that I took.
1039     </p>
1040     <p>
1041     You can however share your thoughts and arguments about these new features with us
1042     on the <a href="https://sourceforge.net/projects/linuxsampler/lists/linuxsampler-devel">mailing list</a>
1043     of course!
1044     </p>
1045     <note class="important">
1046     Keep in mind, the earlier you come up with suggestions for changes, the higher the chance
1047     that it might actually become changed and vice versa!&nbsp;&nbsp;&nbsp;(See "Backward Compatibility" above)
1048     </note>
1049     </body>
1050     </html>

  ViewVC Help
Powered by ViewVC