From 398101ad92c944604760492d9237971f756beeab Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Mon, 13 Jul 2020 00:53:45 +0200 Subject: [PATCH] Add cross-fade and A/B switch plugins --- .../scripts/{_ab_switch.lua => ab_switch.lua} | 22 ++-- share/scripts/x-fade.lua | 102 ++++++++++++++++++ 2 files changed, 115 insertions(+), 9 deletions(-) rename share/scripts/{_ab_switch.lua => ab_switch.lua} (80%) create mode 100644 share/scripts/x-fade.lua diff --git a/share/scripts/_ab_switch.lua b/share/scripts/ab_switch.lua similarity index 80% rename from share/scripts/_ab_switch.lua rename to share/scripts/ab_switch.lua index e531178df1..fc238b8669 100644 --- a/share/scripts/_ab_switch.lua +++ b/share/scripts/ab_switch.lua @@ -4,14 +4,17 @@ ardour { category = "Amplifier", license = "MIT", author = "Ardour Team", - description = [[Auotomatable A/B Input Select. Channels are mapped in pairs: In 1/2 -> Out 1, In 3/4 -> Out 2, etc.]] + description = [[Auotomatable A/B Input Select. Channels grouped: +Mono out: In 1/2 -> Out 1 +Stereo out: In 1/3 -> Out 1, In 2/4 -> Out 2 +Quad out: In 1/5 -> Out 1, In 2/6 -> Out 2, In 3/7 -> Out 3, In 4/8 -> Out 4 +]] } function dsp_ioconfig () return { + connect_all_audio_outputs = true, -- override strict-i/o -- in theory any combination with N_in = 2 * N_out is possible - -- (and we should inform the host to override strict-i/o - -- connect_all_audio_outputs = true) { audio_in = 2, audio_out = 1}, { audio_in = 4, audio_out = 2}, { audio_in = 8, audio_out = 4}, @@ -51,28 +54,29 @@ function dsp_runmap (bufs, in_map, out_map, n_samples, offset) goto next end - local in_a = c * 2 - 1 - local in_b = c * 2 + local in_a = c + local in_b = c + n_aout local ia = in_map:get (ARDOUR.DataType ("audio"), in_a - 1) local ib = in_map:get (ARDOUR.DataType ("audio"), in_b - 1) local buf_aout = bufs:get_audio(o) - -- optimize fixed gain case + -- optimize fixed gain case (copy buffers) if cur_a == target_A and cur_b == target_B then if target_A == 1.0 then - -- the first (and only first) channel may be in-place + -- the first set of channels channel may be in-place if buf_aout ~= bufs:get_audio(ia) then buf_aout:read_from (bufs:get_audio(ia):data (0), n_samples, offset, offset) end else assert (buf_aout ~= bufs:get_audio(ib)) + assert (target_B == 1.0) buf_aout:read_from (bufs:get_audio(ib):data (0), n_samples, offset, offset) end goto next end - -- apply gain to each input channel + -- apply gain to each input channel in-place if ia ~= ARDOUR.ChanMapping.Invalid and ia ~= ib then cur_a = ARDOUR.Amp.apply_gain (bufs:get_audio(ia), sr, n_samples, gA, target_A, offset) end @@ -83,7 +87,7 @@ function dsp_runmap (bufs, in_map, out_map, n_samples, offset) -- channels are supposed to be in linear order assert (buf_aout ~= bufs:get_audio(ib)) - -- copy input to output if needed (first channel may be in-place) + -- copy input to output if needed (first set of channels may be in-place) if buf_aout ~= bufs:get_audio(ia) then buf_aout:read_from (bufs:get_audio(ia):data (0), n_samples, offset, offset) end diff --git a/share/scripts/x-fade.lua b/share/scripts/x-fade.lua new file mode 100644 index 0000000000..804ac5396b --- /dev/null +++ b/share/scripts/x-fade.lua @@ -0,0 +1,102 @@ +ardour { + ["type"] = "dsp", + name = "a-Cross Fade", + category = "Amplifier", + license = "MIT", + author = "Ardour Team", + description = [[Auotomatable Crossfade. Channels are grouped: +Mono out: In 1/2 -> Out 1 +Stereo out: In 1/3 -> Out 1, In 2/4 -> Out 2 +Quad out: In 1/5 -> Out 1, In 2/6 -> Out 2, In 3/7 -> Out 3, In 4/8 -> Out 4 +]] +} + +function dsp_ioconfig () + return { + connect_all_audio_outputs = true, -- override strict-i/o + -- in theory any combination with N_in = 2 * N_out is possible + { audio_in = 2, audio_out = 1}, + { audio_in = 4, audio_out = 2}, + { audio_in = 8, audio_out = 4}, + } +end + +function dsp_params () + return { { ["type"] = "input", name = "A/B", min = 0, max = 1, default = 0} } +end + +local sr = 48000 +local cur_a = 0.0 +local cur_b = 0.0 + +local n_aout = 0 + +function dsp_init (rate) + sr = rate +end + +function dsp_configure (ins, outs) + n_ainp = ins:n_audio () + n_aout = outs:n_audio () + assert (n_aout * 2 == n_ainp) +end + +-- the DSP callback function +function dsp_runmap (bufs, in_map, out_map, n_samples, offset) + local ctrl = CtrlPorts:array() -- get control port array + local target_B = ctrl[1] + local target_A = 1 - target_B + + local gA = cur_a + local gB = cur_b + + for c = 1, n_aout do + local o = out_map:get (ARDOUR.DataType ("audio"), c - 1) + if o == ARDOUR.ChanMapping.Invalid then + goto next + end + + local in_a = c + local in_b = c + n_aout + local ia = in_map:get (ARDOUR.DataType ("audio"), in_a - 1) + local ib = in_map:get (ARDOUR.DataType ("audio"), in_b - 1) + + local buf_aout = bufs:get_audio(o) + + -- optimize hard A/B fixed gain case (copy buffers) + if cur_a == target_A and cur_b == target_B then + if target_A == 1.0 then + -- the first (and only first) channel may be in-place + if buf_aout ~= bufs:get_audio(ia) then + buf_aout:read_from (bufs:get_audio(ia):data (0), n_samples, offset, offset) + end + goto next + elseif target_B == 1.0 then + assert (buf_aout ~= bufs:get_audio(ib)) + buf_aout:read_from (bufs:get_audio(ib):data (0), n_samples, offset, offset) + goto next + end + end + + -- apply gain to each input channel in-place + if ia ~= ARDOUR.ChanMapping.Invalid and ia ~= ib then + cur_a = ARDOUR.Amp.apply_gain (bufs:get_audio(ia), sr, n_samples, gA, target_A, offset) + end + if ib ~= ARDOUR.ChanMapping.Invalid and ia ~= ib then + cur_b = ARDOUR.Amp.apply_gain (bufs:get_audio(ib), sr, n_samples, gB, target_B, offset) + end + + -- channels are supposed to be in linear order + assert (buf_aout ~= bufs:get_audio(ib)) + + -- copy input to output if needed (first set of channels may be in-place) + if buf_aout ~= bufs:get_audio(ia) then + buf_aout:read_from (bufs:get_audio(ia):data (0), n_samples, offset, offset) + end + + -- add the second buffer + ARDOUR.DSP.mix_buffers_no_gain (buf_aout:data (offset), bufs:get_audio(ib):data (offset), n_samples) + + ::next:: + end +end