ViewVC logotype

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

Parent Directory Parent Directory | Revision Log Revision Log

Revision 3603 - (show annotations) (download) (as text)
Tue Sep 17 17:21:13 2019 UTC (13 months ago) by schoenebeck
File MIME type: text/html
File size: 50745 byte(s)
Introducing first auto links.

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

  ViewVC Help
Powered by ViewVC