Ardour Crashes while Bounce w/o Processing in Scripts

I have a script which bounce and replace the selected regions without processing (preserving the original audio, without being affected by filters).

  • Case 1: It works fine in normal regions.

  • Case 2: If I add gain by increasing the envelope:

    • Case 2-A: If the result peak level doesn’t exceed 0 db, works fine.
    • Case 2-B: If the result peak level does exceed 0 db, Ardour crashes.

Is there a way I can limit the maximum peak level, without using processing?
Or tell bounce_range function to ignore the envelope, maybe?

I am using Ardour 7.3 on Ubuntu, btw.

Here is the script:

ardour { ["type"] = "EditorAction", name = "mb:Bounce without Processing + Replace Regions",
	license     = "MIT",
	author      = "mb, Ardour Team",
	description = [[Bounce selected regions w/o processing and replace region]]

function factory (params) return function ()
	-- there is currently no direct way to find the track
	-- corresponding to a [selected] region
	function find_track_for_region (region_id)
		for route in Session:get_tracks():iter() do
			local track = route:to_track();
			local pl = track:playlist ()
			if not pl:region_by_id (region_id):isnil () then
				return track
		assert (0); -- can't happen, region must be in a playlist

	-- get selection
	local sel = Editor:get_selection ()

	-- prepare undo operation
	Session:begin_reversible_command ("Bounce+Replace Regions")
	local add_undo = false -- keep track if something has changed

	local proc = ARDOUR.LuaAPI.nil_proc () -- bounce w/o processing -- mb
    local mb_prefix = "mb_bounce_" .. os.time() -- mb

	-- Iterate over Regions part of the selection
	for r in sel.regions:regionlist ():iter () do
		-- each of the items 'r' is a

		local track = find_track_for_region (r:to_stateful():id())
		local playlist = track:playlist ()

		-- clear existing changes, prepare "diff" of state for undo
		playlist:to_stateful ():clear_changes ()

-- print(r:position(), r:length())

		-- bounce the region with processing
		-- local region = track:bounce_range (r:position (), r:position() + r:length (), ARDOUR.InterThreadInfo (), track:main_outs (), false);
		-- local region = track:bounce_range (r:position (), r:position () + r:length (), ARDOUR.InterThreadInfo (), proc, false, "mb_bounce_");
		local gstart = r:position():samples() --r:position ()
		local gstop = gstart + r:length():samples() -- r:position () + r:length ()
		local region = track:bounce_range (gstart, gstop, ARDOUR.InterThreadInfo (), proc, false, mb_prefix);
		-- local region = track:bounce_range (gstart, gstop, ARDOUR.InterThreadInfo (), track:main_outs(), false, mb_prefix);  --processing, using track filters
		-- local region = track:bounce_range (gstart, gstop, ARDOUR.InterThreadInfo (), proc, true, mb_prefix); --with processing

		-- remove old region..
		playlist:remove_region (r);
		-- ..and add the newly bounced one
		-- playlist:add_region (region, r:position (), 1, false, 0, 0)
		playlist:add_region (region, r:position (), 1, false, 0, 0, false)

		-- create a diff of the performed work, add it to the session's undo stack
		-- and check if it is not empty
		if not Session:add_stateful_diff_command (playlist:to_statefuldestructible ()):empty () then
			add_undo = true

	-- all done, commit the combined Undo Operation
	if add_undo then
		-- the 'nil' Command here mean to use the collected diffs added above
		Session:commit_reversible_command (nil)
		Session:abort_reversible_command ()

end end

function icon (params) return function (ctx, width, height, fg)
	local wh = math.min (width, height) * .5
	local ar = wh * .2

	ctx:set_line_width (1)
	function stroke_outline (c)
		ctx:set_source_rgba (0, 0, 0, 1)
		ctx:stroke_preserve ()
		ctx:set_source_rgba (c, c, c, 1)
		ctx:fill ()

	ctx:rectangle (wh - wh * .6, wh - .7 * wh, wh * 1.2, .5 * wh)
	stroke_outline (.7)

	ctx:rectangle (wh - wh * .6, wh + .1 * wh, wh * 1.2, .5 * wh)
	stroke_outline (.9)

	-- arrow
	ctx:set_source_rgba (0, 1, 0, 1)
	ctx:set_line_width (ar * .7)

	ctx:move_to (wh, wh - .5 * wh)
	ctx:rel_line_to (0, wh)
	ctx:stroke ()

	ctx:move_to (wh, wh + .5 * wh)
	ctx:rel_line_to (-ar, -ar)
	ctx:rel_line_to (2 * ar, 0)
	ctx:close_path ()
	ctx:stroke ()

end end

I just tried and cannot reproduce the crash, i can also not think of a reason why clipping would cause a crash.

Could you provide a simple example session that causes this issue, or alternatively a backtrace (see

The script is identical to ardour/share/scripts/bounce_replace.lua at master · Ardour/ardour · GitHub except you have changed the export-endpoint to “Nil”. This way you get the region with only regain-gain and no other processing.

You could first disable the region-gain

local ar = r:to_audioregion()
local env_was_active = ar:envelope_active ()

--[[ ... bounce ... --]]

1 Like

Thank you so much for the code snippet which enable and disable the envelope for a region.
That works like a charm! Ardour doesn’t crash anymore if I disable the envelope before bouncing a region and enable it again for the bounced new region.

I just wonder if it is possible to apply the old envelope shape to the new region with scripts. I mean preserving the envelope values from the old region, instead of resetting it.

By the way, I have tried to collect debug log during crash… Here it is: Mozilla Community Pastebin/5QLsmG4T (Plain Text)


It shows that the crash happens when adding the newly bounced region.

But since source-code line-numbers are missing from the backtrace, it is not obvious where and why. But since the crash happens after the bounce, it is even more mysterious how region-gain plays into this. – Perhaps the region-gain envelope state is corrupted.

Can you reproduce this with any session or any region, or only with a specific session/region?

In theory, yes. Have a look at the snippet ardour/share/scripts/s_region_gain_curve.lua at master · Ardour/ardour · GitHub. Something like

-- region-gain-curve is-a
local ar = r:to_audioregion()
local old_automation_list = ar:envelope()
-- ...
local region = track:bounce_range (r, ....)
local new_automation_list = region:to_audioregion():envelope()

new_automation_list:clear_list ()
for ev in old_automation_list:events ():iter () do
  new_automation_list:add (ev.when, ev.value, false, true)

So you only use bounce/replace to make a dedicated new short source, in order to later clean up some huge original file? Perhaps that should become a built-in feature?

1 Like

Wow! The code snippet you provided is just what I was looking for! Thank you so much! :+1: :scream:

So you only use bounce/replace to make a dedicated new short source, in order to later clean up some huge original file?

You caught me! :rofl:
I save lots of disk space using this approach. Usually after concluding a project, I am able to reduce the size of the project folder from 1GB+ to less than 100MB. :sunglasses:

Perhaps that should become a built-in feature?

That would be fantastic! :heartbeat:

I have some other scripts which helps me to copy regions between sessions. Actually I made a post about that months earlier: Export / Import Regions Between Different Sessions / Projects
If similar function can be built in Ardour, would be amazing.

Can you reproduce this with any session or any region, or only with a specific session/region?

I have just tried the old version of the script with a new session, with another audio clip, but Ardour crashed.
I made a screenshot for the demonstration:

idk why the video looks greeny in browser but mpv plays it just fine. :nerd_face: