11 |
your own instrument scripts in short time. It concentrates on describing |
your own instrument scripts in short time. It concentrates on describing |
12 |
the script language. If you rather want to learn how to modify and |
the script language. If you rather want to learn how to modify and |
13 |
attach scripts to your sounds, then please refer to the gigedit manual for |
attach scripts to your sounds, then please refer to the gigedit manual for |
14 |
<a href="gigedit_scripts.html">how to manage instrument scripts with gigedit</a>. |
<a href="gigedit_scripts.html">how to manage instrument scripts with gigedit</a> |
15 |
|
for Gigasampler/GigaStudio format sounds, or refer to the SFZ opcode |
16 |
|
<code lang="sfz">script</code> for attaching NKSP scripts with |
17 |
|
SFZ format sounds. |
18 |
</p> |
</p> |
19 |
|
|
20 |
<h3>At a Glance</h3> |
<h3>At a Glance</h3> |
21 |
<p> |
<p> |
22 |
<img src="nksp_file.png" style="height:111px; margin-right:12px;"> |
<img src="nksp_file.png" style="height:111px; margin-right:12px;"> |
23 |
NKSP stands for "is <b>N</b>ot <b>KSP</b>", which denotes its distinction |
NKSP stands for "is <b>N</b>ot <b>KSP</b>", which denotes its distinction |
24 |
to an existing proprieatary language called <i>KSP</i>. |
to an existing proprietary language called <i>KSP</i>. |
25 |
NSKP is a script language specifically designed to write real-time capable |
NSKP is a script language specifically designed to write real-time capable |
26 |
software extensions to LinuxSampler's sampler engines that can be bundled |
software extensions to LinuxSampler's sampler engines that can be bundled |
27 |
individually with sounds by sound designers themselves. |
individually with sounds by sound designers themselves. |
67 |
end on |
end on |
68 |
</code> |
</code> |
69 |
<p> |
<p> |
70 |
There are currently four events available: |
There are currently six events available: |
71 |
</p> |
</p> |
72 |
<table> |
<table> |
73 |
<tr> |
<tr> |
77 |
<td><code>on note</code></td> <td>This event handler is executed when a new note was triggered, i.e. when hitting a key on a MIDI keyboard.</td> |
<td><code>on note</code></td> <td>This event handler is executed when a new note was triggered, i.e. when hitting a key on a MIDI keyboard.</td> |
78 |
</tr> |
</tr> |
79 |
<tr> |
<tr> |
80 |
<td><code>on release</code></td> <td>This event handler is executed when a new note was released, i.e. when releasing a key on a MIDI keyboard.</td> |
<td><code>on release</code></td> <td>This event handler is executed when a note was released, i.e. when releasing a key on a MIDI keyboard.</td> |
81 |
</tr> |
</tr> |
82 |
<tr> |
<tr> |
83 |
<td><code>on controller</code></td> <td>This event handler is executed when a MIDI control change event occurred. For instance when turning the modulation wheel at a MIDI keyboard.</td> |
<td><code>on controller</code></td> <td>This event handler is executed when a MIDI control change event occurred. For instance when turning the modulation wheel at a MIDI keyboard.</td> |
84 |
</tr> |
</tr> |
85 |
<tr> |
<tr> |
86 |
|
<td><code>on rpn</code></td> <td>This event handler is executed when a MIDI <i>RPN</i> event occurred.</td> |
87 |
|
</tr> |
88 |
|
<tr> |
89 |
|
<td><code>on nrpn</code></td> <td>This event handler is executed when a MIDI <i>NRPN</i> event occurred.</td> |
90 |
|
</tr> |
91 |
|
<tr> |
92 |
<td><code>on init</code></td> <td>Executed only once, as very first event handler, right after the script had been loaded. This code block is usually used to initialize variables in your script with some initial, useful data.</td> |
<td><code>on init</code></td> <td>Executed only once, as very first event handler, right after the script had been loaded. This code block is usually used to initialize variables in your script with some initial, useful data.</td> |
93 |
</tr> |
</tr> |
94 |
</table> |
</table> |
153 |
Please note that you can hardly find MIDI keyboards which support release |
Please note that you can hardly find MIDI keyboards which support release |
154 |
velocity. So with most keyboards this value will be 127. |
velocity. So with most keyboards this value will be 127. |
155 |
</p> |
</p> |
156 |
|
|
157 |
<h3>Controller Events</h3> |
<h3>Controller Events</h3> |
158 |
<p> |
<p> |
159 |
Now let's extend the first script to not only show note-on and note-off |
Now let's extend the first script to not only show note-on and note-off |
186 |
</p> |
</p> |
187 |
<p> |
<p> |
188 |
There is some special aspect you need to be aware about: in contrast to the MIDI standard, |
There is some special aspect you need to be aware about: in contrast to the MIDI standard, |
189 |
monophonic aftertouch (a.k.a. channel pressure) and pitch beend wheel are |
monophonic aftertouch (a.k.a. channel pressure) and pitch bend wheel are |
190 |
handled by NKSP as if they were regular MIDI controllers. So a value change |
handled by NKSP as if they were regular MIDI controllers. So a value change |
191 |
of one of those two triggers a regular <code>controller</code> event handler |
of one of those two triggers a regular <code>controller</code> event handler |
192 |
to be executed. To obtain the current aftertouch value you can use |
to be executed. To obtain the current aftertouch value you can use |
193 |
<code>%CC[$VCC_MONO_AT]</code>, and to get the current pitch bend wheel |
<code>%CC[$VCC_MONO_AT]</code>, and to get the current pitch bend wheel |
194 |
value use <code>%CC[$VCC_PITCH_BEND]</code>. |
value use <code>%CC[$VCC_PITCH_BEND]</code>. |
195 |
</p> |
</p> |
196 |
|
|
197 |
|
<h3>RPN / NRPN Events</h3> |
198 |
|
<p> |
199 |
|
There are also dedicated event handlers for |
200 |
|
MIDI <i title="Registered Parameter Number">RPN</i> and |
201 |
|
<i title="Non-Registered Parameter Number">NRPN</i> |
202 |
|
events: |
203 |
|
</p> |
204 |
|
<code> |
205 |
|
on rpn |
206 |
|
message("RPN address msb=" & msb($RPN_ADDRESS) & ",lsb=" & lsb($RPN_ADDRESS) & |
207 |
|
"-> value msb=" & msb($RPN_VALUE) & ",lsb=" & lsb($RPN_VALUE)) |
208 |
|
if ($RPN_ADDRESS = 2) |
209 |
|
message("Standard Coarse Tuning RPN received") |
210 |
|
end if |
211 |
|
end on |
212 |
|
|
213 |
|
on nrpn |
214 |
|
message("NRPN address msb=" & msb($RPN_ADDRESS) & ",lsb=" & lsb($RPN_ADDRESS) & |
215 |
|
"-> value msb=" & msb($RPN_VALUE) & ",lsb=" & lsb($RPN_VALUE)) |
216 |
|
end on |
217 |
|
</code> |
218 |
|
<p> |
219 |
|
Since MIDI RPN and NRPN events are actually MIDI controller events, |
220 |
|
you might as well handle these with the previous |
221 |
|
<code>controller</code> event handler. But since RPN and NRPN messages |
222 |
|
are not just one MIDI message, but rather always handled by a set of |
223 |
|
individual MIDI messages, and since the |
224 |
|
precise set and sequence of actual MIDI commands sent varies between |
225 |
|
vendors and even among individual of their products, it highly makes sense to |
226 |
|
use these two specialized event handlers for these instead, because the |
227 |
|
sampler will already relief you from that burden to deal with all those |
228 |
|
low-level MIDI event processing issues and all their wrinkles involved |
229 |
|
when handling RPNs and NRPNs. |
230 |
|
</p> |
231 |
|
<note> |
232 |
|
Even though there are two separate, dedicated event handlers for RPN and NRPN events, |
233 |
|
they both share the same built-in variable names as you can see in the |
234 |
|
example above. |
235 |
|
</note> |
236 |
|
<p> |
237 |
|
So by reading <code>$RPN_ADDRESS</code> you get the RPN / NRPN parameter |
238 |
|
number that had been changed, and <code>$RPN_VALUE</code> represents the |
239 |
|
new value of that RPN / NRPN parameter. Note that these two built-in |
240 |
|
variables are a 14-bit representation of the parameter number and new |
241 |
|
value. So their possible value range is <code>0 .. 16383</code>. If you |
242 |
|
rather want to use their (in MIDI world) more common separated two 7 bit |
243 |
|
values instead, then you can easily do that by wrapping them into either |
244 |
|
<code>msb()</code> or <code>lsb()</code> calls like also demonstrated above. |
245 |
|
</p> |
246 |
|
|
247 |
<h3>Script Load Event</h3> |
<h3>Script Load Event</h3> |
248 |
<p> |
<p> |
249 |
As the last one of the four event types available with NKSP, the following |
As the last one of the six event types available with NKSP, the following |
250 |
is an example of an <code>init</code> event handler. |
is an example of an <code>init</code> event handler. |
251 |
</p> |
</p> |
252 |
<code> |
<code> |
270 |
had in mind when you wrote a certain script three years ago, and also if |
had in mind when you wrote a certain script three years ago, and also if |
271 |
some other developer might need to continue working on your scripts one |
some other developer might need to continue working on your scripts one |
272 |
day, you should place as many comments into your scripts as possible. A |
day, you should place as many comments into your scripts as possible. A |
273 |
comment in NKSP is everything that is nested into a an opening and closing |
comment in NKSP is everything that is nested into an opening and closing |
274 |
pair of curly braces. |
pair of curly braces. |
275 |
</p> |
</p> |
276 |
<code>{ This is a comment. }</code> |
<code>{ This is a comment. }</code> |
310 |
<p> |
<p> |
311 |
The left hand side's <code>??variable-name??</code> is an arbitrary name |
The left hand side's <code>??variable-name??</code> is an arbitrary name |
312 |
you can chose for your variable. That name might consist of English |
you can chose for your variable. That name might consist of English |
313 |
letters A to Z (lower and upper case) and the underscore character "<code>_</code>". |
letters A to Z (lower and upper case), digits (<code>0</code> to <code>9</code>), |
314 |
|
and the underscore character "<code>_</code>". |
315 |
Variable names must be unique. So you can neither declare several variables |
Variable names must be unique. So you can neither declare several variables |
316 |
with the same name, nor can you use a name for your variable that is |
with the same name, nor can you use a name for your variable that is |
317 |
already been reserved by <i>built-in variables</i>. |
already been reserved by <i>built-in variables</i>. |
469 |
</p> |
</p> |
470 |
<p> |
<p> |
471 |
Let's assume you wanted to write an instrument script that shall resemble |
Let's assume you wanted to write an instrument script that shall resemble |
472 |
a simple delay effect. You could do that by writing an note event handler |
a simple delay effect. You could do that by writing a note event handler |
473 |
that automatically triggers several new notes for each note being |
that automatically triggers several new notes for each note being |
474 |
triggered on a MIDI keyboard. The following example demonstrates how that |
triggered on a MIDI keyboard. The following example demonstrates how that |
475 |
could be achieved. |
could be achieved. |
476 |
</p> |
</p> |
|
<note class="important"> |
|
|
The following example does not fully work with LinuxSampler yet. That's |
|
|
because the used <code>wait()</code> function is not fully implemented |
|
|
yet. Currently a <code>wait()</code> function call suspends execution, |
|
|
but since the respective scheduler code is yet missing, the script |
|
|
will automatically be resumed with the next audio fragment cycle. So |
|
|
effectively a <code>wait()</code> call will pause your script for a few |
|
|
miliseconds with LinuxSampler right now, no matter which function argument |
|
|
you provided. Hopefully this will be implemented soon though. |
|
|
</note> |
|
477 |
<code> |
<code> |
478 |
on init |
on init |
479 |
{ The amount of notes to play } |
{ The amount of notes to play } |
528 |
happening when executing that script exactly: Each time you play a note |
happening when executing that script exactly: Each time you play a note |
529 |
on your keyboard, a new instance of the <code>note</code> event handler |
on your keyboard, a new instance of the <code>note</code> event handler |
530 |
will be spawned and executed by the sampler. In all our examples so far |
will be spawned and executed by the sampler. In all our examples so far |
531 |
our scripts were so simple, that in practice only one handler instance |
our scripts were so simple, that in practice only one event handler instance |
532 |
was executed at a time. This is different in this case though. Because |
was executed at a time. This is different in this case though. Because |
533 |
by calling the <code>wait()</code> function, the respective handler |
by calling the <code>wait()</code> function, the respective handler |
534 |
execution instance is paused for a while and in total each handler |
execution instance is paused for a while and in total each handler |
537 |
you play multiple, successive notes on your keyboard in short time, you |
you play multiple, successive notes on your keyboard in short time, you |
538 |
will have several instances of the <code>note</code> event handler running |
will have several instances of the <code>note</code> event handler running |
539 |
simultaniously. And that's where the problem starts. Because by default, |
simultaniously. And that's where the problem starts. Because by default, |
540 |
as said, all variables are global variables. So the handler instances |
as said, all variables are global variables. So the event handler instances |
541 |
which are now running in parallel, are all reading and modifying the same |
which are now running in parallel, are all reading and modifying the same |
542 |
data. Thus the individual handler instances will modify the |
data. Thus the individual event handler instances will modify the |
543 |
<code>$i</code> and <code>$velocity</code> variables of each other, causing |
<code>$i</code> and <code>$velocity</code> variables of each other, causing |
544 |
an undesired misbehavior. |
an undesired misbehavior. |
545 |
</p> |
</p> |
822 |
@postfix := "nd" |
@postfix := "nd" |
823 |
case 3 |
case 3 |
824 |
@postfix := "rd" |
@postfix := "rd" |
825 |
end if |
end select |
826 |
|
|
827 |
message("This is the " & $numberOfNotes & @postfix & " note triggered so far.") |
message("This is the " & $numberOfNotes & @postfix & " note triggered so far.") |
828 |
end on |
end on |
863 |
case 3 |
case 3 |
864 |
message("Third note was triggered!") { Will never be printed ! } |
message("Third note was triggered!") { Will never be printed ! } |
865 |
exit |
exit |
866 |
end if |
end select |
867 |
|
|
868 |
message("Wow, already the " & $numberOfNotes & "th note triggered.") |
message("Wow, already the " & $numberOfNotes & "th note triggered.") |
869 |
end on |
end on |
902 |
case 1 to 99 |
case 1 to 99 |
903 |
message("Less than 100 notes triggered so far") |
message("Less than 100 notes triggered so far") |
904 |
exit |
exit |
905 |
end if |
end select |
906 |
|
|
907 |
message("Wow, already the " & $numberOfNotes & "th note triggered.") |
message("Wow, already the " & $numberOfNotes & "th note triggered.") |
908 |
end on |
end on |
982 |
loop is thus left at that point and the text message was printed |
loop is thus left at that point and the text message was printed |
983 |
three times in total. |
three times in total. |
984 |
</p> |
</p> |
985 |
|
|
986 |
|
<h3>User Functions</h3> |
987 |
|
<p> |
988 |
|
We already came across various built-in functions, which you may call |
989 |
|
by your scripts to perform certain tasks or behavior which is already |
990 |
|
provided for you by the sampler. NKSP also allows you to write your |
991 |
|
own functions, which you then may call from various places of your |
992 |
|
script. |
993 |
|
<p> |
994 |
|
</p> |
995 |
|
When working on larger scripts, you |
996 |
|
may notice that you easily get to the point where you may have to |
997 |
|
duplicate portions of your script code, since there are certain things |
998 |
|
that you may have to do again and again in different parts of your script. |
999 |
|
Software developers usually try to avoid such code duplications to |
1000 |
|
keep the overall amount of code as small as possible, since the |
1001 |
|
overall amount of code would bloat quickly and would |
1002 |
|
make the software very hard to maintain. One way for you to avoid such |
1003 |
|
script code duplications with NKSP is to write so called <i>User Functions</s>. |
1004 |
|
</p> |
1005 |
|
<p> |
1006 |
|
Let's assume you wanted to create a simple stuttering effect. You may do so |
1007 |
|
like in the following example. |
1008 |
|
</p> |
1009 |
|
<code> |
1010 |
|
on note |
1011 |
|
while (1) |
1012 |
|
wait(200000) |
1013 |
|
if (not (event_status($EVENT_ID) .and. $EVENT_STATUS_NOTE_QUEUE)) |
1014 |
|
exit() |
1015 |
|
end if |
1016 |
|
change_vol($EVENT_ID, -20000) { Reduce volume by 20 dB. } |
1017 |
|
wait(200000) |
1018 |
|
if (not (event_status($EVENT_ID) .and. $EVENT_STATUS_NOTE_QUEUE)) |
1019 |
|
exit() |
1020 |
|
end if |
1021 |
|
change_vol($EVENT_ID, 0) { Increase volume to 0 dB. } |
1022 |
|
end while |
1023 |
|
end on |
1024 |
|
</code> |
1025 |
|
<p> |
1026 |
|
This script will run an endless loop for each note being triggered. |
1027 |
|
Every <code lang="none">200ms</code> it will turn the volume alternatingly down and |
1028 |
|
up to create the audible stuttering effect. After each <code lang="nksp">wait()</code> |
1029 |
|
call it calls <code>event_status($EVENT_ID)</code> to check whether |
1030 |
|
this note is still alive, and as soon as the note died, it will stop |
1031 |
|
execution of the script instance by calling <code>exit()</code>. The latter |
1032 |
|
is important in this example, because otherwise the script execution instances would |
1033 |
|
continue to run in this endless loop forever, even after the respectives |
1034 |
|
notes are gone. Which would let your CPU usage increase with every new note |
1035 |
|
and would never decrease again. |
1036 |
|
This behavior of the sampler is not a bug, it is intended, since there may |
1037 |
|
also be cases where you want to do certain things by script even after the |
1038 |
|
respective notes are dead and gone. However as you can see, that script is |
1039 |
|
using the same portions of script code twice. To avoid that, you could also |
1040 |
|
write the same script with a user function like this: |
1041 |
|
</p> |
1042 |
|
<code> |
1043 |
|
function pauseMyScript |
1044 |
|
wait(200000) |
1045 |
|
if (not (event_status($EVENT_ID) .and. $EVENT_STATUS_NOTE_QUEUE)) |
1046 |
|
exit() |
1047 |
|
end if |
1048 |
|
end function |
1049 |
|
|
1050 |
|
on note |
1051 |
|
while (1) |
1052 |
|
call pauseMyScript |
1053 |
|
change_vol($EVENT_ID, -20000) { Reduce volume by 20 dB. } |
1054 |
|
call pauseMyScript |
1055 |
|
change_vol($EVENT_ID, 0) { Increase volume back to 0 dB. } |
1056 |
|
end while |
1057 |
|
end on |
1058 |
|
</code> |
1059 |
|
<p> |
1060 |
|
The script became in this simple example only slightly smaller, but it also |
1061 |
|
became easier to read and behaves identically to the previous solution. |
1062 |
|
And in practice, with a more complex script, you can |
1063 |
|
reduce the overall amount of script code a lot this way. You can choose any |
1064 |
|
name for your own user functions, as long as the name is not already |
1065 |
|
reserved by a built-in function. Note that for calling a user function, |
1066 |
|
you must always precede the actual user function name with the |
1067 |
|
<code>call</code> keyword. Likewise you may however not use the |
1068 |
|
<code>call</code> keyword for calling any built-in function. So that |
1069 |
|
substantially differs calling built-in functions from calling user functions. |
1070 |
|
</p> |
1071 |
|
|
1072 |
|
<h3>Synchronized Blocks</h3> |
1073 |
|
<p> |
1074 |
|
When we introduced the <a href="#polyphonic_variables">polyphonic keyword</a> |
1075 |
|
previously, we learned that a script may automatically be suspended by |
1076 |
|
the sampler at any time and then your script is thus sleeping for an |
1077 |
|
arbitrary while. The sampler must do such auto suspensions under certain |
1078 |
|
situations in cases where an instrument script may become a hazard for the |
1079 |
|
sampler's overall real-time stability. If the sampler would not do so, then |
1080 |
|
instrument scripts might easily cause audio dropouts, or at worst, buggy |
1081 |
|
instrument scripts might even lock up the entire sampler in an endless |
1082 |
|
loop. So auto suspension is an essential feature of the sampler's real-time |
1083 |
|
instrument script engine. |
1084 |
|
</p> |
1085 |
|
<p> |
1086 |
|
Now the problem as a script author is that you don't really know beforehand |
1087 |
|
why and when your script might get auto suspended by the sampler. And when |
1088 |
|
you are working on more complex, sophisticated scripts, you will notice |
1089 |
|
that this might indeed be a big problem in certain sections of your scripts. |
1090 |
|
Because in practice, a sophisticated script often has at least one certain |
1091 |
|
consecutive portion of statements which must be executed in strict consecutive order |
1092 |
|
by the sampler, which might otherwise cause concurrency issues and thus |
1093 |
|
misbehavior of your script if that sensible code section was auto suspended |
1094 |
|
in between. A typical example of such concurrency sensible code sections are |
1095 |
|
statements which are reading and conditionally modifying global variables. |
1096 |
|
If your script gets auto suspended in such a code section, another |
1097 |
|
script handler instance might then interfere and change those global |
1098 |
|
variables in between. |
1099 |
|
</p> |
1100 |
|
<p> |
1101 |
|
To avoid that, you can place such a sensible code section at the very beginning |
1102 |
|
of your event handler. For example consider you might be writing a custom |
1103 |
|
<i title="A consecutive pitch glide from one note to another note.">glissando</i> |
1104 |
|
script starting like this: |
1105 |
|
</p> |
1106 |
|
<code> |
1107 |
|
on init |
1108 |
|
declare $keysDown |
1109 |
|
declare $firstNoteID |
1110 |
|
declare $firstNoteNr |
1111 |
|
declare $firstVelocity |
1112 |
|
end on |
1113 |
|
|
1114 |
|
on note |
1115 |
|
{ The concurrency sensible code section for the "first active" note. } |
1116 |
|
inc($keysDown) |
1117 |
|
if ($keysDown = 1 or event_status($firstNoteID) = $EVENT_STATUS_INACTIVE) |
1118 |
|
$firstNoteID = $EVENT_ID |
1119 |
|
$firstNoteNr = $EVENT_NOTE |
1120 |
|
$firstVelocity = $EVENT_VELOCITY |
1121 |
|
exit { return from event handler here } |
1122 |
|
end if |
1123 |
|
|
1124 |
|
{ The non-sensible code for all other subsequent notes would go here. } |
1125 |
|
end on |
1126 |
|
|
1127 |
|
on release |
1128 |
|
dec($keysDown) |
1129 |
|
end on |
1130 |
|
</code> |
1131 |
|
<p> |
1132 |
|
Because the earlier statements are executed in an event handler, the higher |
1133 |
|
the chance that they will never get auto suspended. And with those couple of |
1134 |
|
lines in the latter example you might even be lucky that it won't ever get |
1135 |
|
suspended in that sensible code section at least. However when it comes to live |
1136 |
|
concerts you don't really want to depend on luck, and in practice such a |
1137 |
|
sensible code section might be bigger than this one. |
1138 |
|
</p> |
1139 |
|
<p> |
1140 |
|
That's why we introduced <code>synchronized</code> code blocks for the |
1141 |
|
NKSP language, which have the following form: |
1142 |
|
</p> |
1143 |
|
<code> |
1144 |
|
synchronized |
1145 |
|
|
1146 |
|
??statements?? |
1147 |
|
|
1148 |
|
end synchronized |
1149 |
|
</code> |
1150 |
|
<p> |
1151 |
|
All <code>??statements??</code> which you put into such a synchronized |
1152 |
|
code block are guaranteed that they will never get auto suspended by |
1153 |
|
the sampler. |
1154 |
|
</p> |
1155 |
|
<note> |
1156 |
|
Such <code>synchronized</code> blocks are a language extension which |
1157 |
|
is only available with NKSP. KSP does not support <code>synchronized</code> blocks. |
1158 |
|
</note> |
1159 |
|
<p> |
1160 |
|
So to make our previous example concurrency safe, we would |
1161 |
|
change it like this: |
1162 |
|
</p> |
1163 |
|
<code> |
1164 |
|
on init |
1165 |
|
declare $keysDown |
1166 |
|
declare $firstNoteID |
1167 |
|
declare $firstNoteNr |
1168 |
|
declare $firstVelocity |
1169 |
|
end on |
1170 |
|
|
1171 |
|
on note |
1172 |
|
{ The concurrency sensible code section for the "first active" note. } |
1173 |
|
synchronized |
1174 |
|
inc($keysDown) |
1175 |
|
if ($keysDown = 1 or event_status($firstNoteID) = $EVENT_STATUS_INACTIVE) |
1176 |
|
$firstNoteID = $EVENT_ID |
1177 |
|
$firstNoteNr = $EVENT_NOTE |
1178 |
|
$firstVelocity = $EVENT_VELOCITY |
1179 |
|
exit { return from event handler here } |
1180 |
|
end if |
1181 |
|
end synchronized |
1182 |
|
|
1183 |
|
{ The non-sensible code for all other subsequent notes would go here. } |
1184 |
|
end on |
1185 |
|
|
1186 |
|
on release |
1187 |
|
dec($keysDown) |
1188 |
|
end on |
1189 |
|
</code> |
1190 |
|
<p> |
1191 |
|
If you are already familiar with some programming languages, then you |
1192 |
|
might already have seen such synchronized code block concepts |
1193 |
|
in languages like e.g. Java. This technique really provides an easy way |
1194 |
|
to protect certain sections of your script against concurrency issues. |
1195 |
|
</p> |
1196 |
|
<note class="important"> |
1197 |
|
You <b>must</b> use such <code>synchronized</code> code blocks only with great |
1198 |
|
care! If the amount of statements being executed in your synchronized block |
1199 |
|
is too large, then you will get audio dropouts. If you even use loops in |
1200 |
|
synchronized code blocks, then the entire sampler might even become |
1201 |
|
unresponsive in case your script is buggy! |
1202 |
|
</note> |
1203 |
|
|
1204 |
<h2>Operators</h2> |
<h2>Operators</h2> |
1205 |
<p> |
<p> |
1206 |
A programming language provides so called <i>operators</i> to perform |
A programming language provides so called <i>operators</i> to perform |
1230 |
<h3>Boolean Operators</h3> |
<h3>Boolean Operators</h3> |
1231 |
<p> |
<p> |
1232 |
To perform logical transformations of <i>boolean</i> data, you may use the |
To perform logical transformations of <i>boolean</i> data, you may use the |
1233 |
following boolean operators: |
following logical operators: |
1234 |
</p> |
</p> |
1235 |
<code> |
<code> |
1236 |
on init |
on init |
1243 |
end on |
end on |
1244 |
</code> |
</code> |
1245 |
<p> |
<p> |
1246 |
Remember that with boolean operations, all integer values other than <code>0</code> |
Keep in mind that with logical operators shown above, |
1247 |
|
all integer values other than <code>0</code> |
1248 |
are interpreted as boolean <i>true</i> while an integer value of |
are interpreted as boolean <i>true</i> while an integer value of |
1249 |
precisely <code>0</code> is interpreted of being boolean <i>false</i>. |
precisely <code>0</code> is interpreted as being boolean <i>false</i>. |
1250 |
|
</p> |
1251 |
|
<p> |
1252 |
|
So the logical operators shown above always look at numbers at a whole. |
1253 |
|
Sometimes however you might rather need to process numbers bit by bit. For |
1254 |
|
that purpose the following bitwise operators exist. |
1255 |
|
</p> |
1256 |
|
<code> |
1257 |
|
on init |
1258 |
|
message("1 .and. 1 is " & 1 .and. 1) { bitwise "and" } |
1259 |
|
message("1 .and. 0 is " & 1 .and. 0) { bitwise "and" } |
1260 |
|
message("1 .or. 1 is " & 1 .or. 1) { bitwise "or" } |
1261 |
|
message("1 .or. 0 is " & 1 .or. 0) { bitwise "or" } |
1262 |
|
message(".not. 1 is " & .not. 1) { bitwise "not" } |
1263 |
|
message(".not. 0 is " & .not. 0) { bitwise "not" } |
1264 |
|
end on |
1265 |
|
</code> |
1266 |
|
<p> |
1267 |
|
Bitwise operators work essentially like logical operators, with the |
1268 |
|
difference that bitwise operators compare each bit independently. |
1269 |
|
So a bitwise <code>.and.</code> operator for instance takes the 1st bit |
1270 |
|
of the left hand's side value, the 1st bit of the right hand's side value, |
1271 |
|
compares the two bits logically and then stores that result as 1st bit of |
1272 |
|
the final result value, then it takes the 2nd bit of the left hand's side value |
1273 |
|
and the 2nd bit of the right hand's side value, compares those two bits logically |
1274 |
|
and then stores that result as 2nd bit of the final result value, and so on. |
1275 |
</p> |
</p> |
1276 |
|
|
1277 |
|
|
1278 |
<h3>Comparison Operators</h3> |
<h3>Comparison Operators</h3> |
1279 |
<p> |
<p> |
1293 |
</code> |
</code> |
1294 |
<p> |
<p> |
1295 |
All these operations yield in a <i>boolean</i> result which could then |
All these operations yield in a <i>boolean</i> result which could then |
1296 |
by used i.e. with <code>if</code> or <code>while</code> loop statements. |
be used e.g. with <code>if</code> or <code>while</code> loop statements. |
1297 |
</p> |
</p> |
1298 |
|
|
1299 |
<h3>String Operators</h3> |
<h3>String Operators</h3> |
1381 |
You should only reset a preprocessor condition that way if you did set it |
You should only reset a preprocessor condition that way if you did set it |
1382 |
with <code>SET_CONDITION(??condition-name??)</code> before. Trying to |
with <code>SET_CONDITION(??condition-name??)</code> before. Trying to |
1383 |
reset a condition that has not been set before, or trying to reset a |
reset a condition that has not been set before, or trying to reset a |
1384 |
condition that has already been reset, will both be ignored by the samlper, |
condition that has already been reset, will both be ignored by the sampler, |
1385 |
but again you will get a warning, and you should take care about it. |
but again you will get a warning, and you should take care about it. |
1386 |
</p> |
</p> |
1387 |
|
|
1549 |
use the preprocessor instead for such things. And like stated above, |
use the preprocessor instead for such things. And like stated above, |
1550 |
there are certain things which you can only achieve with the preprocessor. |
there are certain things which you can only achieve with the preprocessor. |
1551 |
</p> |
</p> |
1552 |
|
|
1553 |
|
<h3>Disable Messages</h3> |
1554 |
|
<p> |
1555 |
|
Since it is quite common to switch a script between a development version |
1556 |
|
and a production version, you actually don't need to wrap all your |
1557 |
|
<code>message()</code> calls into preprocessor statements like in the |
1558 |
|
previous example just to disable messages. There is actually a built-in |
1559 |
|
preprocessor condition dedicated to perform that task much more conveniently for you. |
1560 |
|
To disable all messages in your script, simply add <code>SET_CONDITION(NKSP_NO_MESSAGE)</code> |
1561 |
|
e.g. at the very beginning of your script. |
1562 |
|
So the previous example can be simplified to this: |
1563 |
|
</p> |
1564 |
|
<code> |
1565 |
|
{ Enable debug mode, so show all debug messages. } |
1566 |
|
SET_CONDITION(DEBUG_MODE) |
1567 |
|
|
1568 |
|
{ If our user declared condition "DEBUG_MODE" is not set ... } |
1569 |
|
USE_CODE_IF_NOT(DEBUG_MODE) |
1570 |
|
{ ... then enable this built-in condition to disable all message() calls. } |
1571 |
|
SET_CONDITION(NKSP_NO_MESSAGE) |
1572 |
|
END_USE_CODE |
1573 |
|
|
1574 |
|
on init |
1575 |
|
declare const %primes[12] := ( 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37 ) |
1576 |
|
declare $i |
1577 |
|
|
1578 |
|
message("This script has just been loaded.") |
1579 |
|
|
1580 |
|
USE_CODE_IF(DEBUG_MODE) |
1581 |
|
$i := 0 |
1582 |
|
while ($i < num_elements(%primes)) |
1583 |
|
message("Prime " & $i & " is " & %primes[$i]) |
1584 |
|
$i := $i + 1 |
1585 |
|
end while |
1586 |
|
END_USE_CODE |
1587 |
|
end on |
1588 |
|
|
1589 |
|
on note |
1590 |
|
message("Note " & $EVENT_NOTE & " was triggered with velocity " & $EVENT_VELOCITY) |
1591 |
|
end on |
1592 |
|
|
1593 |
|
on release |
1594 |
|
message("Note " & $EVENT_NOTE & " was released with release velocity " & $EVENT_VELOCITY) |
1595 |
|
end on |
1596 |
|
|
1597 |
|
on controller |
1598 |
|
message("MIDI Controller " & $CC_NUM " changed its value to " & %CC[$CC_NUM]) |
1599 |
|
end on |
1600 |
|
</code> |
1601 |
|
<p> |
1602 |
|
You can then actually also add <code>RESET_CONDITION(NKSP_NO_MESSAGE)</code> |
1603 |
|
at another section of your script, which will cause all subsequent |
1604 |
|
<code>message()</code> calls to be processed again. So that way you can |
1605 |
|
easily enable and disable <code>message()</code> calls of entire individual |
1606 |
|
sections of your script, without having to wrap all <code>message()</code> |
1607 |
|
calls into preprocessor statements. |
1608 |
|
</p> |
1609 |
|
|
1610 |
<h2>What Next?</h2> |
<h2>What Next?</h2> |
1611 |
<p> |
<p> |
1612 |
You have completed the introduction of the NKSP real-time instrument |
You have completed the introduction of the NKSP real-time instrument |
1616 |
Which provides you an overview and quick access to the details of all |
Which provides you an overview and quick access to the details of all |
1617 |
built-in functions, built-in variables and more. |
built-in functions, built-in variables and more. |
1618 |
</p> |
</p> |
1619 |
|
<p> |
1620 |
|
You might also be interested to look at new <i>NKSP</i> core language |
1621 |
|
features being added to the latest development version of the sampler: |
1622 |
|
<a href="real_unit_final/01_nksp_real_unit_final.html"> |
1623 |
|
Real Numbers, Units and Finalness ... |
1624 |
|
</a> |
1625 |
|
</p> |
1626 |
|
|
1627 |
</body> |
</body> |
1628 |
</html> |
</html> |