Dive into Kontakt Scripting: A Gentle Introduction, plus Script Downloads
When I look back at the Kontakt features we’ve done here at Noisepages, I notice that one feature of the software that keeps coming up is scripting. We’ve used scripts to:
- sequence and re-tune music box samples
- create a constrain-to-scale MIDI insert effect for Kore and other hosts
- Latch incoming notes, and dynamically pan voices in stereo
As well, we’ve looked at the creative potential of the scripts that ship with Kontakt. I’ve also pointed readers towards some fine scripting resources for Kontakt users. With one exception - stereo panning - these have all been stock factory scripts, prewritten scripts from third parties, or very slightly modified versions. Now that everyone’s toes are wet it’s time to dive in and splash around with some scripting from scratch. The water’s warm and we won’t venture too deep. I guarantee there are no sharks.
First, a few words about what Kontakt scripting is and isn’t. It doesn’t work on an audio or DSP level. If you’re familiar with Reaktor, a good comparison is the event handling in that program. Kontakt scripts respond to events, like MIDI notes, MIDI CCs, button presses, GUI knob tweaks and (in the case of sequencer scripts) clock signals. The output of a script could be note on and off signals or automation for Kontakt’s internal parameters like panning. Speaking of panning, I’ll give you an example drawn from the first Kontakt feature at noisepages.
on init
declare $PanPos := 700
end on
on note
change_pan($EVENT_ID,$PanPos,0)
$PanPos := ($PanPos * -1)
end on
I’ll go through it step by step for the benefit of readers with zero programming experience. Those of you who are old hands at scripting and programming, try not to scoff, and pay attention because there are some essential Kontakt ideas in here.
on init tells Kontakt to do something when the script is first loaded into an instrument, or when an instrument containing this script is loaded. This is used to set up required elements of the script - things that generally only happen once and absolutely must happen for everything else to proceed. end on tells Kontakt that this series of setup instructions has ended.
What this particular initialization sequence does is to declare - that is, create – a variable and assign it an initial value. What’s a variable? It’s a container that can hold various values. Variable names in Kontakt scripts start with a $ symbol, so they’re easy to recognize. The := symbol assigns a value to the variable.
The next chunk of the script is called a callback. It’s a chunk of code that responds to some event – in this case, a note. It’s also bracketed by on and end on statements to show where the callback begins and ends.
The callback is where the action happens. change_pan() is a built in function that changes the position of a note in the stereo mix. There are three parameters, or bits of data, that change_pan() needs to work its magic. $EVENT_ID represents the ID of the incoming note that triggered the on note callback. $PanPos is the variable we defined in the on init section; the maximum panning can be –1000 (fully left) or 1000 (fully right). The third variable is called the relative-bit, and can be either zero or one. It determines whether the panning is applied relative to the initial panning of the note or the current panning, if panning has already been applied. The relative bit doesn’t matter much in this script but it has to be there or else Kontakt complains when you click on apply to initialize the script after editing.
The above image shows you what it looks like when the Kontakt script interpreter finds something it doesn’t like – in this case, it’s the missing one or zero that represents the relative-bit. Scripting and programming are all about formal correctness.
So here’s what happens – an incoming note triggers the callback, and the change_pan() function pans the note 70% right. Then, the callback moves to the next line and executes the instructions there. The $PanPos value is being assigned a new value by the := symbol. The new value is the same as the old value, but multiplied by minus one.
That means the next note will be panned to a position of –700, or 70% left. After that, the multiplication by minus one happens again and the value of $PanPos becomes 700 again, ready to pan the next note to the right. And so on, for each incoming note.
Now that you know how the script works, how about adding some enhancements? For starters, that hardcoded “700” is an annoyance. In order to change the amount of panning, you have to open the script and edit it. I think a knob is called for here. It’d also be nice to have the knob show up in Kontakt’s performance view, like this:
And here’s the script that will make it so:
on init
declare ui_knob $PanKnob (0,100,1)
make_persistent ($PanKnob)
declare $PanPos
$PanPos := $PanKnob
make_perfview
end on
on ui_control ($PanKnob)
$PanPos := $PanKnob * 10
end on
on note
change_pan($EVENT_ID,$PanPos,0)
$PanPos := ($PanPos * -1)
end on
You can probably already figure out that declare ui_knob $PanKnob creates a knob. The three parameters (0,100,1) tell Kontakt that the knob will have a range of 0 to 100 and that the ratio of the value displayed will be one to one – it’s possible to have a different resolution than the one displayed.
make_persistent ($PanKnob) tells Kontakt that it should save the knob position when the patch is saved. We’re still using the $PanPos variable but now it gets its value from the persistent knob position.
Another addition to the init section is make_perfview. This tells Kontakt to create a performance view tab for the script, so the instrument doesn’t have to be in edit mode to access the script’s GUI controls.
After the init section we have a new type of callback – on ui_control. This has the $PanKnob variable as a parameter, so any time you adjust the value of the knob, this callback is triggered. It does something very simple – it multiplies the value of $PanKnob by ten and assigns it to $PanPos. The reason the value is multiplied by ten is to scale it up to the –1000 to 1000 range Kontakt uses for panning.
The on note callback remains the same as before. Why use two variables – why not just use $PanKnob in the on note callback? The script has to remember whether the value is going to be positive or negative for the next note – left or right. In programming, there’s usually a bazillion ways to do something, so if you think of a better way, go ahead!
Here’s a before and after example of what the PanPos script does. In the second run-through I’ve set the value at 70% which makes the panning obvious. Try it on headphones. A value of around 40 to 50% lends an instrument some spaciousness in a subtler way.
Kontakt PanPos script from Create Digital Media on Vimeo.
Now how about something completely different – a script that randomly lets note events through, with the velocity determining the probability that an event will trigger a sound. I did something like this in Reaktor in the Frankenloop instrument – now it’s time to implement the function in Kontakt scripting.
Not too elaborate – only two controls! The Random button activates and deactivates the script, and the Target knob chooses the affected note. I like to set the Target knob to affect the hi-hat in a groove, so it creates variation in that but leaves the bass, snare and other drums alone. If you play with the sequenced velocities of your targeted note and use them as probabilities, you can create some very interesting variations. Here’s a before and after video of what it does:
Randomize script in Kontakt from Create Digital Media on Vimeo.
Here’s the script itself:
on init
declare ui_button $Random
make_persistent($Random)
declare ui_knob $Target (0,127,1)
make_persistent($Target)
make_perfview
end on
on note
message("Note: " & $EVENT_NOTE)
if($Random = 1)
if($Target = $EVENT_NOTE)
if ($EVENT_VELOCITY < random(0,127))
ignore_event($EVENT_ID)
end if
end if
end if
end on
A quick rundown of the new elements you’re seeing in this script – there’s a button in this one, and buttons only have two values, zero and one, so we don’t have to assign a range, unlike the knob, which takes a range of zero to 127 to cover possible MIDI note pitches.
When a note hits the script, we employ a message function to print the incoming note’s MIDI pitch in the Kontakt status area (look to the bottom of your Kontakt window, on the left hand side). This will let you play a note that you want to randomize and see its MIDI pitch so you can set the Target knob accordingly.
Now we have some nested if statements in the on note section. I’ll read through it in plain language. If the random button is on, and if the event is the same pitch as the target knob, and if the velocity (volume) of the note is less than a randomly generated value, ignore the note – that is, don’t play it. Otherwise, don’t do anything, which plays the note. Incidentally, what I’m creating by writing here in plain language is something called pseudocode; it can help you to express your program in pseudocode before you write the actual program.
Here’s a zip archive containing the two scripts demonstrated in this article. Your homework, if you choose to accept it, is to work out a way for the Randomize script to accept a range of notes – for example, between the values of two knobs. You’ll probably need to refer to the Kontakt script language manual, and of course you can always ask questions here. Happy scripting!
/* Buy links if custom fields not null and not in cat or search results */ ?> /* End Buy links if custom fields not null and not in cat or search results */ ?>




subscribe
links

2 Comments
Leave a Commentfergy
scripting tutorials for beginners … love it !
January 2, 2009 @ 12:43 pm
dudeguy
It’s ok to have a comment.
February 2, 2009 @ 12:28 am
Leave a comment
RSS feed for comments on this post. TrackBack URI