This is an old revision of the document!


Ardour Lua Scripting

Lua is a lightweight programming language which lends itself nicely to embedded into other applications.

In Ardour's case Lua is available:

  • DSP Scripts - audio processor - plugins with access to the session
  • Session Scripts - realtime, called at the start of every audio cycle
  • Editor Action Scripts - user accessible actions (menu, bindings)
  • Editor Hooks - event triggered actions, GUI thread
  • Script Console - GUI thread (for development)

Why Lua?

small, lean, rt-safe, easily bindable.

General Concepts

  • Ardour calls Lua (not the other way 'round).
  • There are no bound constructors. ie. Lua asks Ardour to create objects (e.g. add a new track), then receives a reference to the object to modify it.
  • Scripts, once loaded, are saved with the Session (no reference to external files)
  • no external lua modules/libraries can be used, scripts need to be self contained (libs written in lua can be used, and important c-libs/functions can be included with ardour if needed)
  • Lua Scripts are never executed directly. They provide a “factory” method which can have instantiation parameters.
  • All Lua interpreters except the DSP-scripts are singleton instances.
    • Session Scripts: The process-callback run all registered scripts in sequence. Session Script have limited access to the Session (realtime-safe). Scripts are registered/unregistered from Menu → Session → Scripting → Add/Remove Script
    • Editor Action Scripts: These are called from the GUI (explicit user action). 10 Slots are available from Menu → Edit → Scripted Actions. Editor Action Scripts have complete access to the Session and to the Editor.
    • Editor Hooks: They're automatically triggered Action Scripts, connect to signals (block the GUI thread while running). – currently not implemented
    • DSP scripts: are like regular plugins with a generic GUI. The context menu for each Route allows to add them. Using Plugin Controls, these are the only scripts that a user can interact with once they're instantiated.
    • ..except the Script Console, which is currently a separate interpreter (Menu > Window > Scripting) which allows to interactively run Lua code. This interpreter is volatile. The state is not saved with the session.

Script Layout

  • Descriptor: Name, Author, Description, URL,…
  • Factory function: a function which returns the actual script.
  • [optional]: list of parameters for the “factory”.

DSP-plugins have additional list of automatable parameters.

An minimal example script looks like:

ardour {
  ["type"]    = "EditorAction",
  name        = "Rewind",
}
  
function factory (params)
  return function ()
    Session:goto_start()
  end
end

Bindings

Lua has direct access to Ardour internals: C++ classes, methods, data and functions. So writing elaborate scripts requires some knowledge about Ardour's internal interfaces. However the vast majority of simple actions can be done nearly self-contained in Lua.

Ardour comes with Lua 5.3.1, http://www.lua.org/manual/5.3/manual.html

C++ bindings

To access methods or data of specific instances, use a colon ”:”, e.g. Lua Session:get_tracks() is equivalent to C++ _session→get_tracks().

Static variables, static functions, enums or C++ singletons directly access the Object. e.g. Lua: ARDOUR.AudioEngine.create() calls C++ ARDOUR::AudioEngine::create() or Lua: Editing.ImportDistinctFiles refers to the C++ enum Editing::ImportDistinctFiles.

see also Programming in Lua, Object-Oriented Programming.

Pass by value/pass by reference

Script Specifics

The common part for all scripts is the “Descriptor”. It's a Lua table with the following keys (the keys are case-sensitive)

  • type [required]: one of “DSP”, “Session”, “EditorHook”, “EditorAction” (the type is not case-sensitive)
  • name [required]: Name/Title of the script
  • author: Your Name
  • license: The license of the script (e.g. “GPL” or “MIT”)
  • description: A longer text explaining to the user what the script does.

Session Scripts

Session scripts have access to the current session via the global variable Session.

Editor Action Scripts & Hooks

Editor Actions and Hooks both have access to the Session and Editor via the global variables Session and Editor respectively.

DSP Scripts

DSP scripts are the odd one out. An approach not unlike other audio-plugin standard API is used for the script. DSP scripts directly provide functions:

  • dsp_ioconfig() [required], returns a table of possible I/O port configurations
  • dsp (bufs, in_map, out_map, n_samples, offset) [required], process the given buffers
  • dsp_init(sample_rate) [optional], called when the script is instantiated
  • dsp_params() [optional], returns a table of automatable parameters

The script has access to the current session via the global variable Session, control-port data is currently mapped to the global variable CtrlPorts (only valid during dsp()).

The audio-port to buffer-mapping is currently passed to every call to dsp(), via the local in_map, out_map variables, however Ardour's ChanCount is mapped to the global Lua variables InputConfig and OutputConfig.

Current State

Everything except “Editor Hook” is fully functional.

Still it's all in prototyping stage:

  • The GUI to add/configure scripts is rather minimalistic.
  • the interfaces may change (particularly the DSP, run function arguments)

Further planned work:

  • Built-in Script editor (customize/modify Scripts in-place)
  • convenience methods (wrap more complex Ardour actions)
  • add some useful scripts for examples
  • Documentation (incl. bound Ardour API)

Console Examples

print (Session:route_by_remote_id(1):name())

a = Session:route_by_remote_id(1);
print (a:name());

print(Session:get_tracks():size())

for i, v in ipairs(Session:unknown_processors():table()) do print(v) end
for i, v in ipairs(Session:get_tracks():table()) do print(v:name()) end

for t in Session:get_tracks():iter() do print(t:name()) end
for r in Session:get_routes():iter() do print(r:name()) end


Session:tempo_map():add_tempo(ARDOUR.Tempo(100,4), ARDOUR.BBT_TIME(4,1,0))


Editor:set_zoom_focus(Editing.ZoomFocusRight)
print(Editing.ZoomFocusRight);
Editor:set_zoom_focus(1)


files = ARDOUR.StringVector();
files:push_back("/home/rgareus/data/coding/ltc-tools/smpte.wav")
pos = -1
Editor:do_import(files, Editing.ImportDistinctFiles, Editing.ImportAsTrack, ARDOUR.SrcQuality.SrcBest, pos, ARDOUR.PluginInfo())

#or in one line:
Editor:do_import(ARDOUR.StringVector():add({"/path/to/file.wav"}), Editing.ImportDistinctFiles, Editing.ImportAsTrack, ARDOUR.SrcQuality.SrcBest, -1, ARDOUR.PluginInfo())

# called when a new session is loaded:
function new_session (name) print("NEW SESSION:", name) end

LuaSession

There's a standalone tool luasession' which allows to access an Ardour session directly from the commandline. Interaction is limited by the fact that most actions are provided by the Ardour Editor/GUI. The tool provides only two special functions load_session and close_session''.

for i,_ in AudioEngine:available_backends():iter() do print (i.name) end              
backend = AudioEngine:set_backend("ALSA", "", "")
print (AudioEngine:current_backend_name())
for i,_ in backend:enumerate_devices():iter() do print (i.name) end
backend:set_input_device_name("HDA Intel PCH")
backend:set_output_device_name("HDA Intel PCH")
print (backend:buffer_size())
print (AudioEngine:get_last_backend_error())

s = load_session ("/home/rgareus/Documents/ArdourSessions/lua2/", "lua2")
s:request_transport_speed (1.0)
print (s:transport_rolling())
s:goto_start()
close_session()
 
wiki/ardourlua.1454227594.txt.gz · Last modified: 31.01.2016 09:06 by rgareus