1ardour { 2 ["type"] = "dsp", 3 name = "ACE Cross Fade", 4 category = "Amplifier", 5 license = "MIT", 6 author = "Ardour Community", 7 description = [[Auotomatable Crossfade. Channels are grouped: 8Mono out: In 1/2 -> Out 1 9Stereo out: In 1/3 -> Out 1, In 2/4 -> Out 2 10Quad out: In 1/5 -> Out 1, In 2/6 -> Out 2, In 3/7 -> Out 3, In 4/8 -> Out 4 11]] 12} 13 14function dsp_ioconfig () 15 return { 16 connect_all_audio_outputs = true, -- override strict-i/o 17 -- in theory any combination with N_in = 2 * N_out is possible 18 { audio_in = 2, audio_out = 1}, 19 { audio_in = 4, audio_out = 2}, 20 { audio_in = 8, audio_out = 4}, 21 } 22end 23 24function dsp_params () 25 return { { ["type"] = "input", name = "A/B", min = 0, max = 1, default = 0} } 26end 27 28local sr = 48000 29local cur_a = 0.0 30local cur_b = 0.0 31 32local n_aout = 0 33 34function dsp_init (rate) 35 sr = rate 36end 37 38function dsp_configure (ins, outs) 39 n_ainp = ins:n_audio () 40 n_aout = outs:n_audio () 41 assert (n_aout * 2 == n_ainp) 42end 43 44-- the DSP callback function 45function dsp_runmap (bufs, in_map, out_map, n_samples, offset) 46 local ctrl = CtrlPorts:array() -- get control port array 47 local target_B = ctrl[1] 48 local target_A = 1 - target_B 49 50 local gA = cur_a 51 local gB = cur_b 52 53 for c = 1, n_aout do 54 local o = out_map:get (ARDOUR.DataType ("audio"), c - 1) 55 if o == ARDOUR.ChanMapping.Invalid then 56 goto next 57 end 58 59 local in_a = c 60 local in_b = c + n_aout 61 local ia = in_map:get (ARDOUR.DataType ("audio"), in_a - 1) 62 local ib = in_map:get (ARDOUR.DataType ("audio"), in_b - 1) 63 64 local buf_aout = bufs:get_audio(o) 65 66 -- optimize hard A/B fixed gain case (copy buffers) 67 if cur_a == target_A and cur_b == target_B then 68 if target_A == 1.0 then 69 if ia == ARDOUR.ChanMapping.Invalid then 70 buf_aout:silence (n_samples, offset) 71 elseif buf_aout ~= bufs:get_audio(ia) then 72 buf_aout:read_from (bufs:get_audio(ia):data (0), n_samples, offset, offset) 73 end 74 goto next 75 elseif target_B == 1.0 then 76 if ib == ARDOUR.ChanMapping.Invalid then 77 buf_aout:silence (n_samples, offset) 78 else 79 assert (buf_aout ~= bufs:get_audio(ib)) 80 buf_aout:read_from (bufs:get_audio(ib):data (0), n_samples, offset, offset) 81 end 82 goto next 83 end 84 end 85 86 -- apply gain to each input channel in-place 87 if ia ~= ARDOUR.ChanMapping.Invalid and ia ~= ib then 88 cur_a = ARDOUR.Amp.apply_gain (bufs:get_audio(ia), sr, n_samples, gA, target_A, offset) 89 end 90 if ib ~= ARDOUR.ChanMapping.Invalid and ia ~= ib then 91 cur_b = ARDOUR.Amp.apply_gain (bufs:get_audio(ib), sr, n_samples, gB, target_B, offset) 92 end 93 94 -- copy input to output if needed (first set of channels may be in-place) 95 if ia == ARDOUR.ChanMapping.Invalid then 96 buf_aout:silence (n_samples, offset) 97 elseif buf_aout ~= bufs:get_audio(ia) then 98 buf_aout:read_from (bufs:get_audio(ia):data (0), n_samples, offset, offset) 99 end 100 101 -- add the second buffer 102 if ib ~= ARDOUR.ChanMapping.Invalid then 103 ARDOUR.DSP.mix_buffers_no_gain (buf_aout:data (offset), bufs:get_audio(ib):data (offset), n_samples) 104 end 105 106 ::next:: 107 end 108end 109