Skip to content

Instantly share code, notes, and snippets.

@x42
Created March 31, 2021 21:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save x42/53b4971504abe8a812db4bf81d76be10 to your computer and use it in GitHub Desktop.
Save x42/53b4971504abe8a812db4bf81d76be10 to your computer and use it in GitHub Desktop.
ardour {
["type"] = "dsp",
name = "Lua IR Capture and Convolver",
license = "MIT",
author = "Ardour Team",
description = [[Another DSP example]]
}
function dsp_ioconfig () return
{
{ audio_in = 1, audio_out = 1},
}
end
function dsp_params ()
return { { ["type"] = "input", name = "Capture Mode", min = 0, max = 1, default = 0, toggled = true } }
end
local conv
local state
local sweep_sin
local peak
local rec_len
local n_captured
local n_playback
function gen_sweep (fmin, fmax, t_sec, rate)
local n_samples_pre = rate * 0.1
local n_samples_sin = rate * t_sec
local n_samples_end = rate * 0.03
local n_samples = n_samples_pre + n_samples_sin + n_samples_end
local amp = 0.5
local a = math.log (fmax / fmin) / n_samples_sin
local b = fmin / (a * rate)
local r = 4.0 * a * a / amp
local cmem = ARDOUR.DSP.DspShm (n_samples * 2)
local ss = cmem:to_float (0):array()
local si = cmem:to_float (n_samples):array()
for i = 0, n_samples - 1 do
local j = n_samples - i - 1
local gain = 1.0
if i < n_samples_pre then
gain = math.sin (0.5 * math.pi * i / n_samples_pre)
elseif j < n_samples_end then
gain = math.sin (0.5 * math.pi * j / n_samples_end)
end
local d = b * math.exp (a * (i - n_samples_pre))
local p = d - b
local x = gain * math.sin (2 * math.pi * (p - math.floor (p)))
ss[i + 1] = x * amp
si[j + 1] = x * d * r
end
sweep_sin = ARDOUR.AudioRom.new_rom (cmem:to_float (0), n_samples)
-- de-convolver
local sweep_inv = ARDOUR.AudioRom.new_rom (cmem:to_float (n_samples), n_samples)
conv = ARDOUR.DSP.Convolution (Session, 1, 1)
conv:add_impdata (0, 0, sweep_inv, 1.0, 0, 0, 0, 0)
conv:restart ()
sweep_inv = nil
cmem = nil
collectgarbage ()
end
function update_convolver ()
print ("UPDATE.. ", n_playback, sweep_sin:readable_length (), rec_len, n_captured, ARDOUR.DSP.accurate_coefficient_to_dB(peak))
assert (peak >= 0.001)
local trim_start = 0;
local trim_end = 0;
local ir = mem:to_float(0):array ()
while ir[1 + trim_start] < 0.001 do
assert (trim_start < n_captured)
trim_start = trim_start + 1
end
while ir[n_captured - trim_end] < 0.001 do
trim_end = trim_end + 1
end
print ("Trim: ", trim_start, trim_end, n_captured - trim_start - trim_end)
assert (n_captured - trim_start - trim_end > 0)
local ar = ARDOUR.AudioRom.new_rom (mem:to_float (trim_start), n_captured - trim_start - trim_end)
-- TODO write ar to disk..
--ar:save ("/tmp/ir.wav")
conv = ARDOUR.DSP.Convolution (Session, 1, 1)
conv:add_impdata (0, 0, ar, 1.0, 0, 0, 0, 0)
conv:restart ()
assert (n_playback == sweep_sin:readable_length ())
sweep_sin = nil
mem = nil
collectgarbage ()
end
function dsp_init (rate)
local fmax = 20000
local slen = 5 -- sec
local rlen = slen + 2 -- sec
if fmax > rate * .47 then
fmax = rate * .47
end
gen_sweep (20, fmax, 5, rate)
-- capture buffer
rec_len = rlen * rate
mem = ARDOUR.DSP.DspShm (rec_len)
mem:clear ()
-- TODO share with replicated and GUI analysis
-- only allow first instance to record..
--self:shmem ():allocate (rec_len)
n_captured = 0
n_playback = 0
peak = 0
state = 0
end
function dsp_latency ()
return conv:latency()
end
function reset ()
state = 0
if n_captured > 0 then
conv:restart ()
end
n_captured = 0
n_playback = 0
peak = 0
end
function dsp_runmap (bufs, in_map, out_map, n_samples, offset)
local ctrl = CtrlPorts:array() -- get control port array
local capture = ctrl[1] > 0
if state == 0 and capture then
state = 1
print ("START CAPTURE")
end
-- check I/O mapping
if state < 2 then
local i = in_map:get (ARDOUR.DataType ("audio"), 0)
local o = out_map:get (ARDOUR.DataType ("audio"), 0)
if i == ARDOUR.ChanMapping.Invalid or o == ARDOUR.ChanMapping.Invalid then
reset ();
end
end
if state == 1 then -- capture
local i = in_map:get (ARDOUR.DataType ("audio"), 0)
-- record and deconvolv
conv:run (bufs, in_map, out_map, n_samples, offset)
local to_copy = n_samples
if to_copy + n_captured > rec_len then
to_copy = rec_len - n_captured
state = 2
end
ARDOUR.DSP.copy_vector (mem:to_float (n_captured), bufs:get_audio(i):data (offset), to_copy)
peak = ARDOUR.DSP.compute_peak (mem:to_float (n_captured), to_copy, peak) -- compute digital peak
n_captured = n_captured + to_copy
if state == 2 then
if peak <= 0.001 then
reset ();
else
update_convolver()
end
end
end
if state == 2 and not capture then -- process
conv:run (bufs, in_map, out_map, n_samples, offset)
elseif state ~= 1 then
-- idle , silence output
local o = out_map:get (ARDOUR.DataType ("audio"), 0)
if o ~= ARDOUR.ChanMapping.Invalid then
bufs:get_audio (o):silence (n_samples, offset)
end
else
-- play back sine-sweep
local o = out_map:get (ARDOUR.DataType ("audio"), 0)
local copied = sweep_sin:read (bufs:get_audio (o):data (offset), n_playback, n_samples, 0)
n_playback = n_playback + copied
if copied < n_samples then
bufs:get_audio (o):silence (n_samples - copied, offset + copied)
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment