Closed trentgill closed 3 years ago
i rebuilt it in lua so rather than comparing input against the previous output voltage, we compare against calculated window-bounds.
the issue was that we used the quantized output which was not necessarily linear (unless using the chromatic mode).
now, whenever a new note is detected we calculate the limits of that window, extended by 5% hysteresis on either side. thus when checking if the new input has left the current note window, we just do a simple bounds check.
here's the code. just need to convert back to C:
-- nb: remove all tracking of previous outputs
function find_bounds(s, ix, oct)
-- find ideal voltage for this window
local sum = (oct*s.scaling) + ix*s.win -- sum in terms of voltage
-- calculate bounds
sum = sum - s.offset
s.lower = sum - s.hyst
s.upper = sum + s.win + s.hyst
print(s.lower, s.upper)
end
function make_scale(scale, scaleLen, divs, scaling)
local t = { scale = scale
, sLen = scaleLen
, divs = divs or 12
, scaling = scaling or 1.0
}
if t.sLen == 0 then -- auto-chromatic
t.sLen = divs
for i=1,divs do t.scale[i] = (i-1)/divs end
end
-- pre-calc for bounds & hysteresis (optimzation)
t.offset = 0.5 * t.scaling / t.divs -- half of a div
t.win = (1.0 / t.sLen) * t.scaling -- a note window in terms of voltage
t.hyst = t.win/20 -- calculate the hysteresis per window (5%)
t.hyst = (t.hyst < 0.006) and 0.006 or t.hyst -- clamp to 1 LSB at 12bit
find_bounds(t, 0, -10) -- set to invalid note
return t
end
function do_scale(s, v)
if v > s.upper
or v < s.lower then
-- offset input to ensure we capture noisy notes at the divs
v = v + s.offset
-- calculate index of input
local n_level = v / s.scaling
local octaves = math.floor(n_level)
local phase = n_level - octaves
local fix = phase * s.sLen
local ix = math.floor(fix)
-- perform scale lookup & prepare outs
local note = s.scale[ix+1]
local noteOct = note + octaves*s.divs
local volts = (note/s.divs + octaves) * s.scaling
-- TODO call action
-- calculate new bounds
find_bounds(s, ix, octaves)
end
end
S = make_scale({5,-12,7,11}, 4)
for i=1,2,0.01 do
do_scale(S, i)
do_scale(S, i)
end
This relates to the input quantizer function, as discussed inline here https://github.com/monome/crow/blob/5abb605ccec9ce3eea912915f53c01f335d5bd88/lib/detect.c#L256
It's more than a simple 'add some hysteresis' problem. I think there is something wrong with the logic of the quantization, so it may need to be approached from first-principles again.