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 proprietary 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 |
NKSP 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. |
28 |
|
|
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 id="rpn_event">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> |
355 |
|
|
356 |
<h3>Variable Types</h3> |
<h3>Variable Types</h3> |
357 |
<p> |
<p> |
358 |
There are currently three different variable types, which you can easily |
There are currently five different variable types, which you can easily |
359 |
recognize upon their first character. |
recognize upon their first character. |
360 |
</p> |
</p> |
361 |
<table> |
<table> |
369 |
<td><code>%??variable-name??</code></td> <td>Integer Array</td> <td>Stores a certain amount of integer number values.</td> |
<td><code>%??variable-name??</code></td> <td>Integer Array</td> <td>Stores a certain amount of integer number values.</td> |
370 |
</tr> |
</tr> |
371 |
<tr> |
<tr> |
372 |
|
<td><code>~??variable-name??</code></td> <td>Real Number Scalar</td> <td>Stores one single real (floating point) number value.</td> |
373 |
|
</tr> |
374 |
|
<tr> |
375 |
|
<td><code>???variable-name??</code></td> <td>Real Number Array</td> <td>Stores a certain amount of real (floating point) number values.</td> |
376 |
|
</tr> |
377 |
|
<tr> |
378 |
<td><code>@??variable-name??</code></td> <td>String</td> <td>Stores one text string.</td> |
<td><code>@??variable-name??</code></td> <td>String</td> <td>Stores one text string.</td> |
379 |
</tr> |
</tr> |
380 |
</table> |
</table> |
475 |
</p> |
</p> |
476 |
<p> |
<p> |
477 |
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 |
478 |
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 |
479 |
that automatically triggers several new notes for each note being |
that automatically triggers several new notes for each note being |
480 |
triggered on a MIDI keyboard. The following example demonstrates how that |
triggered on a MIDI keyboard. The following example demonstrates how that |
481 |
could be achieved. |
could be achieved. |
534 |
happening when executing that script exactly: Each time you play a note |
happening when executing that script exactly: Each time you play a note |
535 |
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 |
536 |
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 |
537 |
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 |
538 |
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 |
539 |
by calling the <code>wait()</code> function, the respective handler |
by calling the <code>wait()</code> function, the respective handler |
540 |
execution instance is paused for a while and in total each handler |
execution instance is paused for a while and in total each handler |
543 |
you play multiple, successive notes on your keyboard in short time, you |
you play multiple, successive notes on your keyboard in short time, you |
544 |
will have several instances of the <code>note</code> event handler running |
will have several instances of the <code>note</code> event handler running |
545 |
simultaniously. And that's where the problem starts. Because by default, |
simultaniously. And that's where the problem starts. Because by default, |
546 |
as said, all variables are global variables. So the handler instances |
as said, all variables are global variables. So the event handler instances |
547 |
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 |
548 |
data. Thus the individual handler instances will modify the |
data. Thus the individual event handler instances will modify the |
549 |
<code>$i</code> and <code>$velocity</code> variables of each other, causing |
<code>$i</code> and <code>$velocity</code> variables of each other, causing |
550 |
an undesired misbehavior. |
an undesired misbehavior. |
551 |
</p> |
</p> |
623 |
</p> |
</p> |
624 |
<p> |
<p> |
625 |
Please note that the <i>polyphonic</i> qualifier only exists for integer |
Please note that the <i>polyphonic</i> qualifier only exists for integer |
626 |
variables. So you cannot declare polyphonic string variables, nor can you |
variables and real number variables (scalars). |
627 |
|
So you cannot declare polyphonic string variables, nor can you |
628 |
declare polyphonic array variables. Like in the previous explanation, |
declare polyphonic array variables. Like in the previous explanation, |
629 |
this is due to the fact that it would consume a huge amount of memory |
this is due to the fact that it would consume a huge amount of memory |
630 |
for such variables. And with string variables and array variables, the |
for such variables. And with string variables and array variables, the |
631 |
required amount of memory would be much higher than with simple integer |
required amount of memory would be much higher than with simple integer or |
632 |
variables. |
real number variables. |
633 |
</p> |
</p> |
634 |
<p> |
<p> |
635 |
As summary, the following are guideline rules describing when you should |
As summary, the following are guideline rules describing when you should |
1038 |
execution of the script instance by calling <code>exit()</code>. The latter |
execution of the script instance by calling <code>exit()</code>. The latter |
1039 |
is important in this example, because otherwise the script execution instances would |
is important in this example, because otherwise the script execution instances would |
1040 |
continue to run in this endless loop forever, even after the respectives |
continue to run in this endless loop forever, even after the respectives |
1041 |
notes are gone. Which would let your CPU usage to increase with every new note |
notes are gone. Which would let your CPU usage increase with every new note |
1042 |
and would never decrease again. |
and would never decrease again. |
1043 |
This behavior of the sampler is not a bug, it is intended, since there may |
This behavior of the sampler is not a bug, it is intended, since there may |
1044 |
also be cases where you want to do certain things by script even after the |
also be cases where you want to do certain things by script even after the |
1197 |
<p> |
<p> |
1198 |
If you are already familiar with some programming languages, then you |
If you are already familiar with some programming languages, then you |
1199 |
might already have seen such synchronized code block concepts |
might already have seen such synchronized code block concepts |
1200 |
in languages like i.e. Java. This technique really provides an easy way |
in languages like e.g. Java. This technique really provides an easy way |
1201 |
to protect certain sections of your script against concurrency issues. |
to protect certain sections of your script against concurrency issues. |
1202 |
</p> |
</p> |
1203 |
<note class="important"> |
<note class="important"> |
1300 |
</code> |
</code> |
1301 |
<p> |
<p> |
1302 |
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 |
1303 |
be 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. |
1304 |
</p> |
</p> |
1305 |
|
|
1306 |
<h3>String Operators</h3> |
<h3>String Operators</h3> |
1388 |
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 |
1389 |
with <code>SET_CONDITION(??condition-name??)</code> before. Trying to |
with <code>SET_CONDITION(??condition-name??)</code> before. Trying to |
1390 |
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 |
1391 |
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, |
1392 |
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. |
1393 |
</p> |
</p> |
1394 |
|
|
1565 |
previous example just to disable messages. There is actually a built-in |
previous example just to disable messages. There is actually a built-in |
1566 |
preprocessor condition dedicated to perform that task much more conveniently for you. |
preprocessor condition dedicated to perform that task much more conveniently for you. |
1567 |
To disable all messages in your script, simply add <code>SET_CONDITION(NKSP_NO_MESSAGE)</code> |
To disable all messages in your script, simply add <code>SET_CONDITION(NKSP_NO_MESSAGE)</code> |
1568 |
i.e. at the very beginning of your script. |
e.g. at the very beginning of your script. |
1569 |
So the previous example can be simplified like this: |
So the previous example can be simplified to this: |
1570 |
</p> |
</p> |
1571 |
<code> |
<code> |
1572 |
{ Enable debug mode, so show all debug messages. } |
{ Enable debug mode, so show all debug messages. } |