Lua scripting: how to run/edit cycle using an external editor

Hello Ardour community,

I’m dabbling in some Lua scripting, making myself a tool to help with a repetitive task. I first ran a few tests using the inbuilt Scripting window, but soon discovered that I’m much more comfortable in my usual editor. For now I edit in an external editor, then paste into the Scripting window, and click Run.

Is there a better way to do it?

I’m thinking, something in Ardour that would pick up external updates to the .lua file?

This works…

In the scripting window use this script:

local f, err = loadfile("xxx"); if err then error(err) else f(); end

…where xxx = the full path and filename of your Lua script.

It loads your script and runs it. After making a change to your script, and saving it, just click Run again in the scripting window.

If your script is already in Ardour’s scripts folder, e.g. on Linux: ~/.config/ardour7/scripts, then you can use the following instead of specifying the path to your script:

local f, err = loadfile(ARDOUR.user_config_directory(-1).."/scripts/your_script.lua"); if err then error(err) else f(); end

…or for better readability:

local scriptPath = ARDOUR.user_config_directory(-1).."/scripts/your_script.lua"
local f, err = loadfile(scriptPath); if err then error(err) else f(); end


local scriptFilename = "your_script.lua"
local scriptPath = ARDOUR.user_config_directory(-1).."/scripts/"..scriptFilename
local f, err = loadfile(scriptPath); if err then error(err) else f(); end

…so you only need change that very obvious first line for any scripts you’re wanting to test.

1 Like

Correction: “invokes”, not “runs”, for what it’s worth. Your script is loaded as the body of a function, in this case function “f”, and the above script then invokes/calls that function. A technicality, but we don’t run functions, we invoke them.

That loadfile() mechanism can also be used by scripts to ‘include’ other scripts, which is effectively exactly what we’re doing here. E.g. One could write a library/collection of useful helper functions which other scripts can then include, avoiding the need to duplicate those same functions over and over again across multiple scripts. I do this and it has drastically reduced development time, script sizes and headaches.


The scripting window has a “Revert” button.

I often create a script and save it from the scripting window.

After modifying the file externally, I go back to the Scripting Window, type something, and then “Revert”, which re-loads the file from disk and pulls in external modifications.

It’s not great, but a lot less work than implementing cross-platform file modification watch in Ardour…

1 Like

Ardour does not generally allow loadfile since that will make sessions dependent on external resource.

You cannot move the session to a different machine, and the session may also behave differently if the external script file changes.

The scripting window allows to source external files, but scripts that are saved with the session do not.

1 Like

Thank you!

I did some practical exercises this evening and I found that calling f() doesn’t produce any noticeable reaction from Ardour. I went on to read a bit about loadfile and realized that calling f() would create a function called factory, and wouldn’t do anything else. Calling factory() afterwards only instantiates a function, and doesn’t call it. So we need to:

  1. Call f()
  2. Now that we have factory, call factory() and catch the output (which is a function)
  3. Call that output

In other words:

local scriptFilename = "your_script.lua"
local scriptPath = ARDOUR.user_config_directory(-1).."/scripts/"..scriptFilename
local f, err = loadfile(scriptPath); if err then error(err) else f(); factory()(); end

Ardour scripts have additional features like params, which I haven’t played around with yet, so if I had a script with that, I’d need to write something more sophisticated. But the above works for the time being.

1 Like

The idea is to run the factory to create a script instance. Ardour saves the bytecode of the produced result.

An example for this is the “Shortcut” script. - You can define which shortcut is to be triggered when you assign the script to an Action Button.

Most scripts do not need this parametrized template mechanism and you can simply ignore it.

Ah, apologies for my premature “this works”. I did test it before posting but now realise that the script I was loading was not a full Ardour action script - it didn’t have the function factory (params) return function () and subsequent end end lines, only the body script that lies between them.

Thanks for posting the true solution. Like you, my testing of action scripts until now involved copying from my text editor and pasting into the scripting window. I’m liking this loadfile() idea as an alternative.

Good points about the limitations of loadfile() in Ardour.

I believe that the script types that are saved with the session are Session and DSP. EditorAction and ActionHook type scripts are not and loadfile() is confirmed to be working in those.

However, it does not work in template scripts despite them not (?) being saved with the session. There was talk here on these, that there’s no particular reason why they’re prevented from using certain functions such as loadfile().

On the subject of template scripts, I’m not sure if they’re documented anywhere other than in some script comments. So, at the risk of being off topic here, from what I can gather they are these:

  • Session Templates

    • type = “SessionInit”
    • type = “EditorAction” with an additional session_setup() function that just returns true. An alternative to the above.
    • These appear as extra choices in the New Session dialog.
    • E.g. session_template_record.lua, which also has some explanatory comments.
  • Track Templates

    • type = “EditorAction” with an additional route_setup() function.
    • These appear as extra choices in the Add Track/Bus/VCA dialog.

Ardour automatically picks them up; they do not need to be added into the Script Manager.

An EditorAction script with both session_setup() and route_setup() functions will make it a template of both kinds, showing in both dialogs.