I find it very handy to have a command at hand to quickly create crossfades for overlapping regions. (As you know, Ardour always adds tiny fades to prevent clicks, but I mean “proper” crossfades. )
Since Ardour 6 it is possible to script that functionality! On execution of the script, crossfades are created for the length of the overlaps at the selected region’s/regions’ start(s) and/or end(s).
I’ve been using it on a couple of projects now and for my needs it works great - so here I’m sharing it… I left some helpful links in there intentionally, so this can also be used to learn from it…
If you add the script in the script manager, you can choose to use it on fade ins, fade outs or both…
I hope it is self-explanatory. If you have any additions or improvements, please comment!
ardour {
["type"] = "EditorAction",
name = "000 _ Crossfade",
license = "MIT",
author = "Alexander Lang",
description = [[Crossfade selected region(s) with overlapping region(s) (2020-08-08)]]
}
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" },
}
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.FadeLinear
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
if config_fadeIns == "no" then
--print ("NO fade ins - param")
DO_FADE_IN = false
end
if config_fadeOuts == "no" then
--print ("NO fade outs - param")
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
--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 (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
--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 (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
I admire your enterprise in learning to create something with Lua, but I hope you are aware that it’s easy to lengthen those short crossfades at either end of a region by a simple mouse drag, to any length, and also to choose from a variety of fade profiles. Is there a particular reason why you need to use the region overlap to define the length of the crossfade?
Thanks for your comment! Yes, I am very well aware of the great fading capabilities, which I do also use…!
Maybe it is just the way I am (and always have been (since 20 years ago in Cubase)) used to do it, but I am a lot faster when cutting stuff, to have multiple regions, see where I want the transition, have them overlap there and just hit a key (I use “x”), instead of using the mouse to drag the fade around (which can be tiny and hard to hit sometimes)…
So maybe it is just trading one mouse-drag for one key-stroke, or my habits might be complicated altogether - but I kinda need that functionality for my ease of mind…
IIRC, Mixbus even has an option to always create crossfades automatically wherever regions overlap. So maybe it is not only me thinking in this direction…?
Earlier versions of Ardour worked that way. You always got a crossfade where regions overlapped, and you set the length of the crossfade by adjusting the region bounds. It looks like Mixbus has retained that feature, or maybe you were using a version of Mixbus based on that earlier Ardour version.
The current Ardour has the advantage that the same tool for adjusting the crossfade also works as a fade-in or fade-out tool if there isn’t an overlapping region. One you’re used to it, I think it’s easier to understand.
I’m talking about the change from 2.x to 3.0, which, as I understand it, is when crossfades were first introduced to the beginning and end of every region.
Prior to that, if I remember correctly, a crossfade happened over the overlap between regions and if you wanted to change its timing, you had to move the region bounds.
Perhaps what I’m forgetting is that with v2.x you didn’t get a crossfade at all unless you asked for one.
Never mind, it’s all history now…
The more I think about it, maybe my old habit of doing it “with overlaps” should be reconsidered… When I learned this stuff, I probably had to do it this way because the tools were different. I will try hard to challenge my habit and maybe improve it - but in any case I am happy to have the option of “x”…
FWIW, when I was doing editing in REAPER, I created a custom action that did exactly you achieved in Ardour. I turned off auto-crossfade, lined up transients, positioned the left-hand edge of the right-hand region and then pressed my “X” shortcut key for an instant invisible short xfade. But, yeah, Ardour does this by default at this point