Noatikl contains a powerful scripting engine, which while entirely optional to use, offers tremendous power.
Introduction to Noatikl Scripting
Noatikl contains several very powerful scripting features, which can be used in two separate contexts.
The most common way to use scripting in Noatikl, it to embed small Trigger Scripts, which are small bits of code in the widely used Lua language, attached to the Piece or to Voice objects. These scripts are triggered when various events happen when Noatikl is playing. Using trigger scripts allows you to tell Noatikl to behave in very powerful ways while it is playing.
The other way to use scripting in Noatikl, is to use the Noatikl Script Window to create and run scripts written in the Lua language, to manipulate Noatikl editor windows. This is done through the Noatikl Script Window. This allows you to, for example, dynamically create random Noatikl compositions.
Noatikl scripts are written using the widely used Lua scripting langauge. Lua is very powerful, fast and easy to learn. Lua is a very popular embedded scripting langage, and is widely used in the gaming and multimedia worlds. Noatikl adds various noatikl-specific functions to the Lua language. These extensions are outlined later in this document. We give you lots of examples to get you started. If you ever get stuck, or if you want to share your cunning scripts with fellow Noatikl users, then please make use of the Noatikl forums!
Note that Noatikl supports the table, string and math standard Lua libraries. It does not support the io or os libraries.
Why would you want to use Noatikl Scripting?
With careful use of trigger scripts, you can use Noatikl to build a custom hyperinstrument!
You can, if you wish, create trigger scripts to run at the following times:
- start of playback
- every bar
- when a note is composed by noatikl
- end of playback
- in response to MIDI CC via e.g. keyboard controller
- in response to MIDI Note on/off via e.g. keyboard controller
Every script can do pretty much anything to the Noatikl engine in real-time, such as manipulating music rules, playing with mutation, and what have you.
We also have a new hyperinstrument mode, and allow the Note on/off commands to control parameters and/or trigger "listening" voices within Noatikl, that can in turn trigger off other musical events such as auto-chording events or following voices.
The scripts are in the very widely used Lua scripting language.
A note on print
Note that the standard Lua function print may be used to display text in the Noatikl console window (if you happen to have that displayed; this is very useful for debugging your scripts!
A note on Comments in Lua script
Single-line comments in Lua script start with the two minus characters:
-- This is a comment
To comment-out a block of text in Lua, enclose the text in --[[ and ]] as in this example
print ("Hello")
--[[
This is a big block
of text that I want to comment out!
]]
print ("World")
Trigger Scripts ("Triggers")
Noatikl Triggers can be assigned to most Noatikl objects, including the Piece and Voice objects.
Not all Noatikl script functions are available to you within Noatikl trigger scripts; specifically, the functions that open and manipulate windows are not available from Triggers (these are reserved for use from the Noatikl Script Window). You can enter these scripts using the following Noatikl views:
There are a variety of Trigger Scripts types that you may invoke.
Start
The Start Trigger Script is called once at the start of the Piece, when the piece starts playing.
function nt_trigger_start()
print ("Piece start!")
end
Bar
The Bar Trigger Script is called at the start of every bar while the piece is playing.
function nt_trigger_bar(bar)
print ("Bar number", bar)
end
Composed
The Composed Script is called when Noatikl composes a note. Only available to voice objects! Use this to emit MIDI CC events and what have you!
Advanced users might also be interested in reading about using this script with embedded calls to noatikl_Trigger_EmitListeningNote, to help build hyperinstruments.
function nt_trigger_composed(noteon, channel, pitch, velocity)
print ("Composed", noteon, channel, pitch, velocity)
end
MIDI In CC
The MIDI In CC Trigger Script is called whenever a MIDI CC event is received by the MIDI Input device.
function nt_trigger_midiin_cc(channel, cc, value)
if (cc == 1)
then
print ("MIDI In CC", channel, cc, value)
end
end
NOTE on Omni: Noatikl delivers all MIDI CC events to this trigger from all MIDI channels, even if this trigger is a voice trigger script with a voice targeting a different MIDI channel. This is known as Omni behaviour. If you want your voice trigger to respond only if the supplied MIDI CC is from the same channel as your voice, use script like this:
function nt_trigger_midiin_cc(channel, cc, value)
if (channel == noatikl_Trigger_GetMidiChannel())
then
-- Matches our voice channel!
print ("MIDI In CC", channel, cc, value)
if (cc == 1)
then
noatikl_Trigger_Parameter_Set("Patch", value)
end
end
end
MIDI In Note
The MIDI In Note Trigger Script is called whenever a MIDI Note On or Off event is received by the MIDI Input device. See the Noatikl hyperinstrument guide for a detailed discussion.
function nt_trigger_midiin_note(noteon, channel, pitch, velocity)
print ("note ", noteon, channel, pitch, velocity)
end
NOTE on Omni: Noatikl delivers all MIDI Note events to this trigger from all MIDI channels, even if this trigger is a voice trigger script with a voice targeting a different MIDI channel. This is known as Omni behaviour. If you want your voice trigger to respond only if the supplied MIDI Note is from the same channel as your voice, use script like this:
function nt_trigger_midiin_note(noteon, channel, pitch, velocity)
if (channel == noatikl_Trigger_GetChannel())
then
print ("note ", noteon, channel, pitch, velocity)
end
end
Stop
The Stop Trigger Script is called once at the end of the Piece, just as the Piece stops playing.
function nt_trigger_stop()
print ("Piece stop!")
end
Tbe Script Editor Window
When you decide to edit a Trigger Script property, you are presented with a Script Editor window.
The text panels support the usual context-sensitive text editor menus and keyboard accelerators (allowing for fast copy and paste operations).
The Script Editor window allows you to edit trigger scripts associated with your object.
Test
Pressing this button will compile any Lua script that you type in the large text area at the top of the window, and display any results in the bottom panel. Use the Test to quickly check your script for obvious syntax errors!
Help
Pressing the Help button displays help on the Noatikl Scripting system!
Clear
Pressing the Clear button quickly erases the text in the top panel.
Default
Pressing the Default button will replace any text in the top panel, with a new, empty default trigger script appropriate to the Noatikl script property you are currently viewing.
OK
Pressing the OK button will save your changes. These are used by Noatikl it next starts playing.
Cancel
Pressing the Cancel button will discard your changes.
Test Results
Any test results are displayed in the Test Results area at the bottom.
Clear
Pressing the Clear button in the bottom area, quickly erases the text in the bottom panel.
Scripting Reference
To find out about all the available objects, parameters, and functions, you should refer to the complete Noatikl scripting reference.
Trigger Script Cookbook
A great way to start thinking about Noatikl trigger scripts, is to look at various real examples of how to do various interesting things with Noatikl trigger scripts!
Example: Change the scale to use depending on time of day
This is a script that you could use as a piece-level Bar trigger script.
function nt_trigger_start()
-- Noatikl script to get hour of day as 24-hour clock value
-- ... and select scale accordingly!
local lTime = tonumber(noatikl_GetDate("%H"))
if ((lTime > 20) or (lTime <8))
then
noatikl_Trigger_Parameter_Set("Scale Rules", "early morning scale")
else
noatikl_Trigger_Parameter_Set("Scale Rules", "middle of day scale")
end
end
Example: randomly select a pattern to use for a voice
This is a voice-level Bar trigger script.
function nt_trigger_start()
-- Get a random integer between 1 and 3 inclusive.
local lValue = noatikl_GetRandomFromTo (1, 3)
print ("lValue", lValue)
local lPattern = ""
if (lValue == 1)
then
lPattern = "<100 B 240 1>"
elseif (lValue == 2)
then
lPattern = "<100 B 120 1 120 2>"
else
lPattern = "<100 B 60 1 60 2 60 3 60 4>"
end
noatikl_Trigger_Parameter_Set("Patterns", lPattern)
end
Example: script trigger that allows Noatikl trigger scripts to emit MIDI CC events, with an optional delay
This is a script that you could use as a piece-level Bar trigger script.
function nt_trigger_bar(bar)
-- Voice trigger...
-- Apply a pan sweep through the bar from left to right,
-- to show-off the use of noatikl_Trigger_EmitMidiCC.
local lDuration = noatikl_Trigger_GetBarDuration()
local lMidiChannel = noatikl_Trigger_GetChannel()
local lDelay = 0
local lCC = 10 -- Pan controller!
local lValue = 0
while lDelay <= lDuration do
local lValue = (127 * lDelay) / lDuration
-- Note that the "lDelay" is optional; we're using the in this specific
-- demo, to get a sweep effect from start to end of the bar.
noatikl_Trigger_EmitMidiCC(lMidiChannel, lCC, lValue, lDelay)
lDelay = lDelay + 20
end
end
Example: piece bar trigger, that automatically adjusts the piece root every 10 bars
function nt_trigger_bar (bar)
if ((bar % 10) == 0)
then
-- Every 10 bars, change the root at random,
-- from all those available!
local lRoots = {"A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"}
local lIndex = noatikl_GetRandomFromTo(1,12)
local lRoot = lRoots[lIndex]
print ("Root", lRoot)
noatikl_Trigger_Parameter_Set("Piece Roots", lRoot)
-- Un-comment the following line to set tempo at random, too,
-- to a value related to the selected root!
-- noatikl_Trigger_Parameter_Set("Tempo", 100 + lIndex * 5)
end
end
Example: piece start trigger, that automatically adjusts the tempo to suit the time of day
function nt_trigger_start()
print("Piece!")
-- Noatikl script to get hour of day as 24-hour clock value
-- ... and adjust tempo accordingly!
local lTime = tonumber(noatikl_GetDate("%H"))
if ((lTime > 20) or (lTime <8))
then
print ("late night / early morning!")
local lRandom = noatikl_GetRandomFromTo(0,50)
noatikl_Trigger_Parameter_Set("Tempo", 50 + lRandom)
else
print ("middle of day!")
local lRandom = noatikl_GetRandomFromTo(0,50)
noatikl_Trigger_Parameter_Set("Tempo", 100 + lRandom)
end
end
Example: voice start trigger, that automatically cycles the patch every time it starts playback
function nt_trigger_start()
print("Voice!")
local lPatch = noatikl_Trigger_Parameter_Get_AsNumber("Patch")
lPatch = lPatch + 1
if (lPatch > 100)
then
lPatch = 0
end
noatikl_Trigger_Parameter_Set("Patch", lPatch)
end
Example: voice trigger, that automatically changes patch every bar
function nt_trigger_bar(bar)
print("Voice1 ", bar)
local lPatch = noatikl_Trigger_Parameter_Get_AsNumber("Patch")
lPatch = lPatch + 1
if (lPatch > 100)
then
lPatch = 0
end
noatikl_Trigger_Parameter_Set("Patch", lPatch)
end
Example: bringing voices into the mix
In this example, imagine that you have a mutating drum Voice that you want to have muted at the start of the piece and come in with a bang at the start of bar 20. And you don't want the mutations to start until bar 21...
How would that work in the world of script?
Here is the Voice Start trigger:
function nt_trigger_start()
-- When we start, disable mutation for this voice!
-- And set mute, too!
noatikl_Trigger_Parameter_Set("Mute", "Yes")
noatikl_Trigger_Parameter_Set("Mutation Factor", 0)
end
Here is the Voice Bar trigger:
function nt_trigger_bar(bar)
if (bar == 20)
then
-- At bar 20, unmute the voice!
noatikl_Trigger_Parameter_Set("Mute", "No")
end
if (bar == 21)
then
-- At bar 21, adjust the mutation factor!
noatikl_Trigger_Parameter_Set("Mutation Factor", 20)
end
end
The power of using scripts like this, is that:
- The drums alway start on the bar specified.
- They don't morph until they are audible.
- The drum elements can now make staggered entry despite all bing on the same midi channel.
Example: Emit MIDI CC in response to composed note events
function nt_trigger_composed(noteon, channel, pitch, velocity)
-- Keep track of last composed note using the global (for this voice)
-- called GLastNote ...
-- Note that the "pitch" parameter should be ignored when noteon is false.
lMidiChannel = noatikl_Trigger_GetChannel()
if (noteon)
then
if (GLastNote ~= nil)
then
noatikl_Trigger_EmitMidiCC(lMidiChannel, 11, GLastNote, 10)
end
GLastNote=pitch
noatikl_Trigger_EmitMidiCC(lMidiChannel, 11, pitch, 0)
else
if (GLastNote ~= nil)
then
noatikl_Trigger_EmitMidiCC(lMidiChannel, 11, GLastNote, 10)
GLastNote = nil
end
end
end
Noatikl Script Window (the Noatikl Script Console)
The Noatikl Script Window is used to create and run scripts to manipulate Noatikl editor windows; for example, to dynamically create random Noatikl compositions.
It is also used for displaying messages from print calls within your trigger scripts!
The text panels support the usual context-sensitive text editor menus and keyboard accelerators (allowing for fast copy and paste operations).
Run Command!
Pressing this button will run any Lua script that you type in the large text area at the top of the window, and display any results in the bottom panel
An example you might like to try would be this:
print ("Hello world!")
History and Results
Any results are displayed in the History and Results area at the bottom.
This is where the output from any print statements in your scripts are displayed (including those within trigger scripts).
Help
Pressing the Help button displays help on the Noatikl Scripting system!
Clear
Pressing the Clear button quickly erases the bottom panel.
Console Script Cookbook
A great way to start thinking about Noatikl console scripting, is to look at various real examples of how to do various interesting things with Noatikl console scripting!
Example: the simplest possible start
print ("Hello world")
Example: open all Noatikl files in a sub-folder with a .txt extension, adjust some properties and re-save with .Noatikl file extension.
local lFileList = noatikl_FindFilePaths("myfolder1", "myfolder2")
local index = 0
while true do
index = index + 1
local lFilePath = lFileList[index];
if (lFilePath == nil)
then
break
end
if (string.find(lFilePath, '.txt'))
then
local lWindow = noatikl_Window_OpenPath(lFilePath)
-- Change some file properties
noatikl_Window_Object_Parameter_Set(lWindow, "File", 1, "Author", "my company")
noatikl_Window_Object_Parameter_Set(lWindow, "File", 1, "Midi Output Device", "?")
noatikl_Window_Object_Parameter_Set(lWindow, "File", 1, "Midi Input Device", "?")
noatikl_Window_Object_Parameter_Set(lWindow, "File", 1, "Midi Sync?", "No")
-- Change some properties for every voice in the file...
local lCount = noatikl_Window_Object_GetCount(lWindow, 'Voice')
local lIndex = 1
while lIndex <= lCount do
noatikl_Window_Object_Parameter_Set(lWindow, "Voice", lIndex, "Copyright", "Copyright my company")
lIndex = lIndex + 1
end
local lSaveToPath = string.gsub(lFilePath, '.txt', '.noatikl')
noatikl_Window_SaveToPath(lWindow, lSaveToPath)
print ("Saved", lFilePath)
noatikl_Window_Close(lWindow)
end
end
print ('Done!')
