X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=include%2Flua-scripting.html;h=3d7fd70afd5514b18b18ef33f877274dbdb8e608;hb=79232552462511443d8267bdda6d99281d4716c6;hp=439b61ad606c31f904f71b991535d8572479d23d;hpb=2098e011e638b5c86c56e68df7757975fc4d728f;p=ardour-manual diff --git a/include/lua-scripting.html b/include/lua-scripting.html index 439b61a..3d7fd70 100644 --- a/include/lua-scripting.html +++ b/include/lua-scripting.html @@ -3,9 +3,448 @@ Starting with version 4.7.213, Ardour supports Lua scripts.
+-Lua Integration is Work in Progress and far from complete. +This Documentation is Work in Progress and far from complete. Also the documented API may be subject to change. +
+ ++There are cases that Ardour cannot reasonably cater to with core functionality alone, either because they're session specific +or user specific edge cases. +
+Examples for these include voice-activate (record-arm specific tracks and roll transport depending on signal levels), +rename all regions after a specific timecode, launch an external application when a certain track is soloed, generate +automation curves or simply provide a quick shortcut for a custom batch operation. +
+Cases like this call for means to extend the DAW without actually changing the DAW itself. This is where scripting comes in. +
+"Scripting" refers to tasks that could alternatively be executed step-by-step by a human operator. +
+Lua is a tiny and simple language which is easy to learn, yet allows for comprehensive solutions. +Lua is also a glue language it allows to tie existing component in Ardour together in unprecedented ways, +and most importantly Lua is one of the few scripting-languages which can be safely used in a real-time environment. +
+A good introduction to Lua is the book Programming in Lua. The first edition is +available online, but if you have the means buy a copy of the book, it not only helps to support the Lua project, but provides +for a much nicer reading and learning experience. +
+ ++The core of Ardour is a real-time audio engine that runs and processes audio. One interfaces with an engine by sending it +commands. Scripting can be used to interact with or modify the active Ardour session, just like a user uses the Editor/Mixer +GUI to modify the state or parameters of the session. +
+Doing this programmatically requires some knowledge about the objects used internally. +Most Ardour C++ objects and their methods are directly exposed to Lua and one can call functions or modify variables: +
+ +
+ session->set_transport_speed (1.0);
+
+
+ Session:set_transport_speed (1.0)
+
+ +You may notice that there is only a small syntactic difference in this case. +While C++ requires recompiling the application for every change, Lua script can be loaded, written or modified while the +application is running. Lua also abstracts away many of the C++ complexities such as object lifetime, type conversion and +null-pointer checks. +
+Close ties with the underlying C++ components is where the power of scripting comes from. +A script can orchestrate interaction of lower-level components which take the bulk of the CPU time of the final program. +
++At the time of writing Ardour integrates Lua 5.3.2: Lua 5.3 reference +manual. +
+ ++Like Control surfaces and the GUI, Lua Scripts are confined to certain aspects of the program. Ardour provides the framework +and runs Lua (not the other way around). +
++In Ardour's case Lua is available: +
+ +Editor Action Scripts | User initiated actions (menu, shortcuts) for batch processing |
---|---|
Editor Hooks/Callbacks | Event triggered actions for the Editor/Mixer GUI |
Session Scripts | Scripts called at the start of every audio cycle (session, real-time) |
DSP Scripts | Audio/Midi processor - plugins with access to the Ardour session (per track/bus, real-time) |
Script Console | Action Script commandline |
+There are is also a special mode: +
+Commandline Tool | Replaces the complete Editor GUI, direct access to libardour (no GUI) from the
+ commandline. + Be aware that the vast majority of complex functionality is provided by the Editor UI. |
---|
+Ardour searches for Lua scripts in the scripts
folder in $ARDOUR_DATA_PATH
,
+Apart from scripts included directly with Ardour, this includes
GNU/Linux | $HOME/.config/ardour5/scripts |
---|---|
Mac OS X | $HOME/Library/Preferences/Ardour5/scripts |
Windows | %localappdata%\ardour5\scripts |
Files must end with .lua
file extension.
Scripts are managed via the GUI
+Editor Action Scripts | Menu → Edit → Scripted Actions → Manage |
---|---|
Editor Hooks/Callbacks | Menu → Edit → Scripted Actions → Manage |
Session Scripts | Menu → Session → Scripting → Add/Remove Script |
DSP Scripts | Mixer-strip → context menu (right click) → New Lua Proc |
Script Console | Menu → Window → Scripting |
ardour
descriptor table. Required fields are "Name" and "Type".dsp_run
function, more on that later.A minimal example script looks like:
+
+ ardour {
+ ["type"] = "EditorAction",
+ name = "Rewind",
+ }
+
+ function factory (unused_params)
+ return function ()
+ Session:goto_start() -- rewind the transport
+ end
+ end
+
++The common part for all scripts is the "Descriptor". It's a Lua function which returns a table (key/values) 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 |
+Scripts that come with Ardour (currently mostly examples) can be found in the +Source Tree. +
+ +Action scripts are the simplest form. An anonymous Lua function is called whenever the action is triggered. A simple action +script is shown above.
+There are 10 action script slots available, each of which is a standard GUI action available from the menu and hence can be +bound to a keyboard shortcut.
+ +Session scripts similar to Actions Scripts, except the anonymous function is called periodically every process cycle. +The function receives a single parameter - the number of audio samples which are processed in the given cycle
+
+ardour {
+ ["type"] = "session",
+ name = "Example Session Script",
+ description = [[
+ An Example Ardour Session Script.
+ This example stops the transport after rolling for a specific time.]]
+}
+
+
+-- instantiation options, these are passed to the "factory" method below
+function sess_params ()
+ return
+ {
+ ["print"] = { title = "Debug Print (yes/no)", default = "no", optional = true },
+ ["time"] = { title = "Timeout (sec)", default = "90", optional = false },
+ }
+end
+
+function factory (params)
+ return function (n_samples)
+ local p = params["print"] or "no"
+ local timeout = params["time"] or 90
+ a = a or 0
+ if p ~= "no" then print (a, n_samples, Session:frame_rate (), Session:transport_rolling ()) end -- debug output (not rt safe)
+ if (not Session:transport_rolling()) then
+ a = 0
+ return
+ end
+ a = a + n_samples
+ if (a > timeout * Session:frame_rate()) then
+ Session:request_transport_speed(0.0, true)
+ end
+ end
+end
+
+Action hook scripts must define an additional function which returns a Set of Signal that which trigger the +callback (documenting available slots and their parameters remains to be done).
+
+ardour {
+ ["type"] = "EditorHook",
+ name = "Hook Example",
+ description = "Rewind On Solo Change, Write a file when regions are moved.",
+}
+
+function signals ()
+ s = LuaSignal.Set()
+ s:add (
+ {
+ [LuaSignal.SoloActive] = true,
+ [LuaSignal.RegionPropertyChanged] = true
+ }
+ )
+ return s
+end
+
+function factory (params)
+ return function (signal, ref, ...)
+ -- print (signal, ref, ...)
+
+ if (signal == LuaSignal.SoloActive) then
+ Session:goto_start()
+ end
+
+ if (signal == LuaSignal.RegionPropertyChanged) then
+ obj,pch = ...
+ file = io.open ("/tmp/test" ,"a")
+ io.output (file
+ io.write (string.format ("Region: '%s' pos-changed: %s, length-changed: %s\n",
+ obj:name (),
+ tostring (pch:containsFramePos (ARDOUR.Properties.Start)),
+ tostring (pch:containsFramePos (ARDOUR.Properties.Length))
+ ))
+ io.close (file)
+ end
+ end
+end
+
+See the scripts folder for examples for now.
+Some notes for further doc:
+dsp_ioconfig ()
: return a list of possible audio I/O configurations - follows Audio
+ Unit conventions.dsp_dsp_midi_input ()
: return true if the plugin can receive midi inputdsp_params ()
: return a table of possible parameters (automatable)dsp_init (samplerate)
: called when instantiation the plugin with given samplerate.dsp_configure (in, out)
: called after instantiation with configured plugin i/o.dsp_run (ins, outs, n_samples)
OR dsp_runmap (bufs, in_map, out_map, n_samples,
+ offset)
: DSP process callback. The former is a convenient abstraction that passes mapped buffers (as table). The
+ latter is a direct pass-through matching Ardour's internal ::connect_and_run()
API, which requires the caller
+ to map and offset raw buffers.CtrlPorts
.mididata
which is valid during dsp_run
only.
+ (dsp_runmap requires the script to pass raw data from the buffers according to in_map)
+The top most object in Ardour is the ARDOUR::Session
.
+Fundamentally, a Session is just a collection of other things:
+Routes (tracks, busses), Sources (Audio/Midi), Regions, Playlists, Locations, Tempo map, Undo/Redo history, Ports, Transport
+state and controls, etc.
+
+Every Lua interpreter can access it via the global variable Session
.
+
+GUI context interpreters also have an additional object in the global environment: The Ardour Editor
. The Editor
+provides access to high level functionality which is otherwise triggered via GUI interaction such as undo/redo, open/close
+windows, select objects, drag/move regions. It also holds the current UI state: snap-mode, zoom-range, etc.
+The Editor also provides complex operations such as "import audio" which under the hood, creates a new Track, adds a new
+Source Objects (for every channel) with optional resampling, creates both playlist and regions and loads the region onto the
+Track all the while displaying a progress information to the user.
+
+Documenting the bound C++ methods and class hierarchy is somewhere on the ToDo list. +Meanwhile luabindings.cc is the best we +can offer. +
+ ++Ardour is a highly multithreaded application and interaction between the different threads, particularly real-time threads, +needs to to be done with care. This part has been abstracted away by providing separate Lua interpreters in different contexts +and restricting available interaction: +
++The available interfaces differ between contexts. For example, it is not possible to create new tracks or import audio from +real-time context; while it is not possible to modify audio buffers from the GUI thread. +
+ +run()
.Apart from the scripts included with the source-code +here are a few examples without further comments... + +
+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), Timecode.BBT_TIME(4,1,0))
+
+
+Editor:set_zoom_focus(Editing.ZoomFocusRight)
+print(Editing.ZoomFocusRight);
+Editor:set_zoom_focus(1)
+
+
+files = C.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(C.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
+
+
+# read/set/describe a plugin parameter
+route = Session:route_by_remote_id(1)
+processor = route:nth_plugin(0)
+plugininsert = processor:to_insert()
+
+plugin = plugininsert:plugin(0)
+print (plugin:label())
+print (plugin:parameter_count())
+
+x = ARDOUR.ParameterDescriptor ()
+_, t = plugin:get_parameter_descriptor(2, x) -- port #2
+paramdesc = t[2]
+print (paramdesc.lower)
+
+ctrl = Evoral.Parameter(ARDOUR.AutomationType.PluginAutomation, 0, 2)
+ac = plugininsert:automation_control(ctrl, false)
+print (ac:get_value ())
+ac:set_value(1.0, PBD.GroupControlDisposition.NoGroup)
+
+# the same using a convenience wrapper:
+route = Session:route_by_remote_id(1)
+proc = t:nth_plugin (i)
+ARDOUR.LuaAPI.set_processor_param (proc, 2, 1.0)
+
+
+The standalone tool luasession
allows one to access an Ardour session directly from the commandline.
+Interaction is limited by the fact that most actions in Ardour are provided by the Editor GUI.
+
+luasession
provides only two special functions load_session
and close_session
and
+exposes the AudioEngine
instance as global variable.
+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()
+
+
+