→ 2025-03-07 Update: I also added a fade shape selector in the initial menu.
Hello,
This is an updated version of a Lua script that @laex wrote a few years back (~Thanks, Alex!
) that allows you to easily, automatically apply crossfades to the overlaps of selected, overlapping regions - now in Ardour 8. This functionality is very, very handy for me as I ‘copy and paste’ (i.e. export and embed (or import)) regions from one project session into another (-there are Lua scripts for those as well, located here!).
Mediafire link to Download: Crossfade(A8).lua (7kb)
(You can also copy the raw script from below.)
The original Crossfades script (posted here) worked fine on Ardour 6.9, but not 8. So with no scripting experience whatsoever, I got the help of Chat GPT (of course
) to troubleshoot and make the few, necessary changes needed (-took about 45min). All Hail the AI God. Now, I’m not claiming that the script is ideal, but it seems to work great for me! 
In this example I’ve set it as a shortcut in the top-right (which anyone can do using the menu at Edit > Lua Scripting > Script Manager):

According to the Ardour manual information here, its best to place any .lua files in a folder named “scripts” (which you may have to create) located at:
GNU/Linux |
$HOME/.config/ardour8/scripts |
Mac OS X |
$HOME/Library/Preferences/Ardour8/scripts |
Windows |
%localappdata%\ardour8\scripts |
I should also specify that I tested it in Ardour 8.11.0 on a 2013 Mac Pro running macOS Mojave 10.14.6.
Thanks, 
-J
2 Likes
ardour { ["type"] = "EditorAction", name = "Crossfade(A8)",
license = "MIT",
author = "Alexander Lang (+ChatGPT & J.K.Lookinland)",
description = [[Crossfade selected regions with overlapping regions.
(2020-08-08)
(2025-03-06: made compatible with Ardour 8, added a fade shape selector)]]
}
function action_params ()
return {
fadeIns = { title = "Create fade in(s) of selected region(s) (yes/no):", default = "yes" },
fadeOuts = { title = "Create fade out(s) of selected region(s) (yes/no):", default = "yes" },
fadeShape = {
title = "Choose Crossfade Shape (i.e. FadeLinear, FadeConstantPower, FadeSymmetric, FadeSlow, or FadeFast):",
type = "string",
default = "FadeConstantPower"
}
}
end
function factory (params) return function ()
-- ################# config ##################
local DO_FADE_IN = true
local DO_FADE_OUT = true
local BRING_SELECTION_TO_FRONT = false
local FADE_SHAPE = ARDOUR.FadeShape.FadeConstantPower -- Default fade shape
local ADJUST_LOWER_REGIONS_FADES = true -- set fades of covererd regions to minimum
local MINIMAL_FADE_LENGTH = 64 -- mini fade on region boundaries to prevent clicks (in samples)
-- get configuration parameters
local p = params or {}
local config_fadeIns = p["fadeIns"] or true
local config_fadeOuts = p["fadeOuts"] or true
local selected_fade_shape = p["fadeShape"] or "FadeConstantPower"
-- Set fade shape based on user selection
if selected_fade_shape == "FadeLinear" then
FADE_SHAPE = ARDOUR.FadeShape.FadeLinear
elseif selected_fade_shape == "FadeConstantPower" then
FADE_SHAPE = ARDOUR.FadeShape.FadeConstantPower
elseif selected_fade_shape == "FadeSymmetric" then
FADE_SHAPE = ARDOUR.FadeShape.FadeSymmetric
elseif selected_fade_shape == "FadeSlow" then
FADE_SHAPE = ARDOUR.FadeShape.FadeSlow
elseif selected_fade_shape == "FadeFast" then
FADE_SHAPE = ARDOUR.FadeShape.FadeFast
end
-- Update fadeIn/Out settings based on params
if config_fadeIns == "no" then
DO_FADE_IN = false
end
if config_fadeOuts == "no" then
DO_FADE_OUT = false
end
-- ###########################################
-- prepare undo operation
Session:begin_reversible_command ("Crossfade")
local add_undo = false -- keep track if something has changed
-- ensure globally that fades are used and visible
-- (Session > Properties > Fades)
assert (Session:cfg():get_use_region_fades())
assert (Session:cfg():get_show_region_fades())
-- get Editor selection
-- http://manual.ardour.org/lua-scripting/class_reference/#ArdourUI:Editor
-- http://manual.ardour.org/lua-scripting/class_reference/#ArdourUI:Selection
local sel = Editor:get_selection ()
-- iterate over selected Regions
-- http://manual.ardour.org/lua-scripting/class_reference/#ArdourUI:RegionSelection
for r in sel.regions:regionlist ():iter () do
-- test if it is an audio region
-- http://manual.ardour.org/lua-scripting/class_reference/#ARDOUR:Region
local ar = r:to_audioregion ()
if ar:isnil () then goto nextSelectedRegion end
--local regionName = r:name ()
--print ("Selected Region:", regionName)
local rStart = r:position()
local rLength = r:length()
local rEnd = rStart+rLength
--print ("startPosition: ", rStart)
--print ("length: ", rLength)
--print ("endPosition: ", rEnd)
-- get playlist of selected region
local rPL = r:playlist()
--print("regPL: ", rPL:name())
local regFadeInLen = MINIMAL_FADE_LENGTH
local regFadeOutLen = MINIMAL_FADE_LENGTH
-- get other regions within the selected region's boundaries
local regionsTouched = rPL:regions_touched(rStart, rEnd)
-- prepare selected region(s) for undo
r:to_stateful ():clear_changes ()
if BRING_SELECTION_TO_FRONT then
Editor:access_action("Region","raise-region-to-top")
end
for touchedRegion in regionsTouched:iter () do
local touchedAudioRegion = touchedRegion:to_audioregion ()
if touchedAudioRegion:isnil () then goto nextTouchedRegion end
if touchedRegion == r then
--print("found itself")
else
-- prepare touched region(s) for undo
touchedRegion:to_stateful ():clear_changes ()
local arIsAlreadyOnTop = true
if ar:layer() < touchedAudioRegion:layer() then
arIsAlreadyOnTop = false
end
--print ("Region touched: ", touchedRegion:name ())
local touchedRegionStart = touchedRegion:position()
local touchedRegionEnd = touchedRegionStart+touchedRegion:length()
if DO_FADE_OUT and touchedRegionStart > rStart then
regFadeOutLen = (rEnd - touchedRegionStart):samples()
--print (" >>> Fade OUT - length: ", regFadeOutLen)
if BRING_SELECTION_TO_FRONT or arIsAlreadyOnTop then
ar:set_fade_out_shape (FADE_SHAPE)
ar:set_fade_out_length (tonumber(regFadeOutLen))
ar:set_fade_out_active (true)
if ADJUST_LOWER_REGIONS_FADES then
touchedAudioRegion:set_fade_in_length (MINIMAL_FADE_LENGTH)
end
else
touchedAudioRegion:set_fade_in_shape (FADE_SHAPE)
touchedAudioRegion:set_fade_in_length (regFadeOutLen)
touchedAudioRegion:set_fade_in_active (true)
if ADJUST_LOWER_REGIONS_FADES then
ar:set_fade_out_length (MINIMAL_FADE_LENGTH)
end
end
elseif DO_FADE_IN and touchedRegionEnd < rEnd then
regFadeInLen = (touchedRegionEnd - rStart):samples()
--print (" >>> Fade IN - length: ", regFadeInLen)
if BRING_SELECTION_TO_FRONT or arIsAlreadyOnTop then
ar:set_fade_in_shape (FADE_SHAPE)
ar:set_fade_in_length (tonumber(regFadeInLen))
ar:set_fade_in_active (true)
if ADJUST_LOWER_REGIONS_FADES then
touchedAudioRegion:set_fade_out_length (MINIMAL_FADE_LENGTH)
end
else
touchedAudioRegion:set_fade_out_shape (FADE_SHAPE)
touchedAudioRegion:set_fade_out_length (regFadeInLen)
touchedAudioRegion:set_fade_out_active (true)
if ADJUST_LOWER_REGIONS_FADES then
ar:set_fade_in_length (MINIMAL_FADE_LENGTH)
end
end
end
end
-- save changes for touched region(s) (if any) to undo command
if not Session:add_stateful_diff_command (touchedRegion:to_statefuldestructible ()):empty () then
add_undo = true
end
::nextTouchedRegion::
end
-- save changes for selected region(s) (if any) to undo command
if not Session:add_stateful_diff_command (r:to_statefuldestructible ()):empty () then
add_undo = true
end
--print("############# END OF REGION #############")
::nextSelectedRegion::
end
-- all done, commit the combined Undo Operation
if add_undo then
-- the 'nil' Command here means to use the collected diffs added above
Session:commit_reversible_command (nil)
else
Session:abort_reversible_command ()
end
end end