diff --git a/otis.lua b/otis.lua index edee622..6f1dcde 100755 --- a/otis.lua +++ b/otis.lua @@ -97,6 +97,9 @@ local skip_pos = {nil, nil} local spds = include("lib/spds") local speed_index = {4, 4} -- maybe move this to spds.lua? +local buf_snapshots = {{}, {}} +local buf_positions = {0, 0} +local buf_snapshots_max = {0, 0} -- flip, skip, and speed controls local function skip(n) @@ -606,9 +609,40 @@ function init() grid_metro.event = function() grid_redraw() end grid_metro:start() + + -- timer to query buffer snapshot and play position + local buf_snapshot_size = 128 + local buf_snapshot_metro = metro.init() + buf_snapshot_metro.time = 1/15 + softcut.event_render(function (ch, start, secpersample, samples) + buf_snapshots[ch] = samples + buf_snapshots_max[ch] = table_getmax(samples) + end) + softcut.event_position(function (ch, position) + buf_positions[ch] = position + end) + buf_snapshot_metro.event = function() + softcut.render_buffer(1, 0, params:get("1loop_end"), buf_snapshot_size) + softcut.render_buffer(2, 0, params:get("2loop_end"), buf_snapshot_size) + softcut.query_position(1) + softcut.query_position(2) + end + buf_snapshot_metro:start() + audio.level_eng_cut(0) end + +function table_getmax(t) + local max = 0 + for _,v in pairs(t) do + if math.abs(v) > max then + max = math.abs(v) + end + end + return util.clamp(max, 0.01, 1) +end + -- screen drawing local function draw_left() -- tape direction indicator @@ -794,8 +828,185 @@ local function draw_lfo_info() screen.text("3. offset: " .. params:get(lfo_index .. "offset")) end +function draw_single_page() + screen.clear() + screen.aa(0) + screen.font_face(25) + screen.font_size(6) + + draw_buffer(1, 28, 12) + draw_buffer(2, 28, 45) + + draw_vbar(0, 20, params:get("1vol"), muted_L, (page == 1 and alt == 0)) + draw_vbar(0, 56, params:get("2vol"), muted_R, (page == 1 and alt == 0)) + + draw_vbar(20, 20, params:get("1feedback"), false, (page == 2 and alt == 1)) + draw_vbar(20, 56, params:get("2feedback"), false, (page == 2 and alt == 1)) + + draw_pan(12, 8, params:get("1pan")) + draw_pan(12, 45, params:get("2pan")) + + draw_button(11, 17, rec1 and "REC" or "") + draw_button(11, 54, rec2 and "REC" or "") + + draw_page_status() + + screen.update() +end + +function draw_page_status() + screen.level(10) + local bt = "mute" + local knobs = "level" + if page == 1 then + if alt == 1 then + knobs = "pan" + end + elseif page == 2 then + if alt == 0 then + bt = "flip" + knobs = "speed" + else + bt = "skip" + knobs = "fdbk" + end + elseif page == 3 then + if alt == 0 then + bt = "rec" + knobs = "start" + else + bt = "clear" + knobs = "end" + end + end + local txt = pages[page] .. ": " .. bt .. "/" .. knobs .. (fine_adjust and "(f)" or "(c)") + if page == 1 then + screen.move(0, 63) + screen.text(txt) + elseif page == 2 then + screen.move(63, 63) + screen.text_center(txt) + elseif page == 3 then + screen.move(127, 63) + screen.text_right(txt) + end +end + + +function draw_button(x, y, char) + screen.level(10) + screen.move(x, y) + screen.text_center(char) +end + +function draw_pan(x, y, val) + -- draw "LR" for panning, crossfading the level to indicate position + -- center if full level + if math.abs(val) < 0.05 then + screen.level(10) + screen.move(x-1, y) + screen.text_center("C") + return + end + screen.level(util.linlin(-1, 1, 15, 0, val)//1) + screen.move(x-1, y) + screen.text_right("L") + screen.level(util.linlin(-1, 1, 0, 15, val)//1) + screen.move(x, y) + screen.text("R") +end + +function draw_vbar(x, y, val, off, active) + local width = 2 + local max_height = 18 + local height = util.linlin(0, 1, 0, max_height, val) + + screen.level(3) + screen.move(x, y-max_height+1) + screen.line_rel(width, 0) + screen.stroke() + if off then + screen.level(1) + else + screen.level(active and 15 or 4) + end + screen.rect(x, y-height, width, height) + screen.fill() +end + +function draw_buffer(n, x_off, y_off) + screen.level(6) + + local max_height = 6 + local y_top = y_off - max_height + local buf_width = 128 - x_off + + local buf = buf_snapshots[n] + if #buf == 0 then return end -- not initialized + local max = buf_snapshots_max[n] + max = 1 + + local x_pos = 0 + for i, s in ipairs(buf) do + local height = util.round(math.abs(s) / max * max_height) + screen.move(util.linlin(0, #buf-1, x_off, x_off+buf_width, x_pos), y_off - height) + screen.line_rel(0, 2 * height) + screen.stroke() + x_pos = x_pos + 1 + end + + screen.level(3) + screen.move(util.linlin(0, params:get(n .. "loop_end"), x_off, x_off+buf_width, buf_positions[n]), y_off - max_height) + screen.line_rel(0, 2 * max_height) + screen.stroke() + + -- edit: start + local l_start = x_off + params:get(n .. "loop_start") / params:get(n .. "loop_end") * buf_width + screen.level((page == 3 and alt == 0) and 15 or 3) + screen.move(l_start+1, y_off - max_height) + screen.line_rel(0, 2 * max_height) + screen.stroke() + + l_start = util.clamp(l_start, x_off+8, x_off+buf_width - 32) + screen.move(l_start, y_off + 2*max_height) + screen.text_center(string.format("%.2f", params:get(n .. "loop_start"))) + + -- edit: end + screen.level((page == 3 and alt == 1) and 15 or 3) + screen.move(x_off+buf_width, y_off - max_height) + screen.line_rel(0, 2 * max_height) + screen.stroke() + screen.move(x_off+buf_width, y_off + 2*max_height) + screen.text_right(string.format("%.2f", params:get(n .. "loop_end"))) + + -- play: speed + screen.level((page == 2 and alt == 0) and 15 or 5) + local center = x_off + buf_width//2 + screen.move(center, y_top) + local speed = params:get(n .. "speed") + screen.text_center(string.format("%.2f", speed)) + + screen.move(center, y_top+1) + screen.line_rel(util.linlin(-4.0, 4.0, -45, 45, speed), 0) + screen.stroke() + + local l,r,lfo = check_for_speed_modulation() + if (n == 1 and l) or (n == 2 and r) then + -- draw offset as small tick + local offset = params:get(n .. "offset") + screen.level(10) + screen.move(center + util.linlin(-4.0, 4.0, -45, 45, offset), y_top-1) + screen.line_rel(0, 3) + screen.stroke() + end + +end function redraw() + -- TODO + draw_single_page() + do return end + screen.clear() screen.aa(0) screen.font_face(25)