Created
March 31, 2021 21:18
-
-
Save x42/53b4971504abe8a812db4bf81d76be10 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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