| -- lofi OB4 | |
| -- holds the input in softcut in case you need it | |
| -- enc 2 = scrub buffer | |
| -- key 2 = rewind?? | |
| -- key 3 = jump to real time | |
| -- arc 1 = scrub buffer | |
| -- arc 2 = not interactive, graphics only | |
| rate = 1 --longer values increase buffer but cost fidelity | |
| local live_playback = 0 | |
| local tape_position = 0 | |
| local display_tape_position = 0 | |
| local buffer_length = 340 | |
| local scrub_resolution = .1 * rate | |
| local overwriting = false | |
| local rewinding= false | |
| local relative_buffer_start | |
| local start_time = util.time() | |
| local live = true | |
| local state_change=false | |
| local initital_monitor_level | |
| local initital_reverb_onoff | |
| local initital_compressor_onoff | |
| local ar = arc.connect() | |
| local arcDirty = true | |
| local tau = math.pi * 2 | |
| local framerate = 20 | |
| function update_positions(i,pos) | |
| --if the buffer runs long enough to loop we want to be able to rewind into the previous buffer up to tape head | |
| if not overwriting then | |
| buffer_check = (util.time() - start_time) | |
| if buffer_check>=buffer_length/rate then | |
| overwriting= true | |
| end | |
| end | |
| if i==1 then | |
| live_playback=(pos) | |
| end | |
| if i==3 and pos > live_playback and not overwriting then | |
| if rewinding then | |
| tape_position = 0 | |
| rewinding=false | |
| for i=3,4 do softcut.rate(i,rate) end | |
| else | |
| tape_position = live_playback - .001 | |
| end | |
| end | |
| --logic for what voices to hear | |
| if live then | |
| tape_position = live_playback - .001 --untested belief that this address crunchiness | |
| display_tape_position = live_playback | |
| params:set('monitor_level',0) | |
| for x=3,4 do softcut.level(x,0.0) end | |
| elseif not live then | |
| if i==3 then | |
| display_tape_position = pos | |
| tape_position = pos | |
| if rewinding then tape_position = pos end | |
| end | |
| for x=3,4 do softcut.level(x,1.0) end | |
| params:set('monitor_level', -math.huge) | |
| end | |
| redraw() | |
| end | |
| function scrubber(d) | |
| --ban negative numbers | |
| if tape_position < 0 then | |
| if overwriting then | |
| tape_position = buffer_length | |
| else | |
| tape_position = 0.1 | |
| end | |
| --ban portions of the loop not yet used | |
| elseif tape_position > live_playback then | |
| if overwriting then | |
| if tape_position > live_playback then | |
| tape_position = tape_position + d*scrub_resolution | |
| end | |
| elseif not overwriting then | |
| live = true | |
| tape_position = live_playback - .002 | |
| end | |
| --normal use within buffer | |
| elseif tape_position >= 0 and tape_position < live_playback then | |
| tape_position = tape_position + d*scrub_resolution | |
| end | |
| --updates position | |
| for i=3,4 do | |
| softcut.position(i,tape_position) | |
| end | |
| end | |
| function rewinder() | |
| if rewinding then | |
| --ban negative numbers | |
| if tape_position < 0 then | |
| if overwriting then | |
| tape_position = buffer_length | |
| for i=3,4 do softcut.rate(i,-1.5*rate) end | |
| else | |
| tape_position = 0 | |
| for i=3,4 do softcut.rate(i,1*rate) end | |
| rewinding = false | |
| end | |
| --ban portions of the loop not yet used | |
| elseif tape_position > live_playback and not overwriting then | |
| live = true | |
| tape_position = live_playback - .002 | |
| rewinding = false | |
| elseif tape_position > 0 and tape_position < live_playback then | |
| for i=3,4 do softcut.rate(i,-1.5*rate) end | |
| end | |
| end | |
| if not rewinding then | |
| for i=3,4 do softcut.rate(i,rate) end | |
| end | |
| end | |
| function enc(n,d) | |
| if n==1 then | |
| elseif n==2 then | |
| if live then | |
| tape_position = display_tape_position | |
| live = false | |
| scrubber(d) | |
| elseif not live then | |
| scrubber(d) | |
| end | |
| elseif n==3 then | |
| end | |
| end | |
| function ar.delta(n, delta) | |
| if n==1 then | |
| if live then | |
| tape_position = display_tape_position | |
| live = false | |
| scrubber(delta/10) | |
| elseif not live then | |
| scrubber(delta/10) | |
| end | |
| end | |
| end | |
| function key(n,z) | |
| relative_buffer_start= util.time()-start_time | |
| if n==1 then | |
| elseif n==2 then | |
| tape_position = display_tape_position-1 | |
| if z==1 then | |
| if live then | |
| live = false | |
| end | |
| rewinding = true | |
| rewinder() | |
| elseif z==0 then | |
| rewinding = false | |
| rewinder() | |
| end | |
| elseif n==3 then | |
| if z==1 then | |
| if not live then | |
| live = true | |
| tape_position = live_playback | |
| for i=3,4 do softcut.position(i,tape_position) end | |
| end | |
| end | |
| end | |
| end | |
| function init() | |
| local panning = {-1,1,-1,1} | |
| -- send audio input to softcut input | |
| audio.level_adc_cut(1) | |
| -- Turn off the built-in monitoring, reverb, etc. | |
| initital_monitor_level = params:get('monitor_level') | |
| params:set('monitor_level', -math.huge) | |
| initital_reverb_onoff = params:get('reverb') | |
| params:set('reverb', 1) -- 1 is OFF | |
| initital_compressor_onoff = params:get('compressor') | |
| params:set('compressor', 1) -- 1 is OFF | |
| --recordhead | |
| for i=1,2 do | |
| softcut.enable(i,1) | |
| softcut.buffer(i,i) | |
| softcut.level(i,1.0) | |
| softcut.pan(i,panning[i]) | |
| softcut.loop(i,1) | |
| softcut.loop_start(i,0) | |
| softcut.loop_end(i,buffer_length) | |
| softcut.position(i,0) | |
| softcut.rate(i,rate) | |
| softcut.level_input_cut(i,i,1.0) | |
| softcut.level_input_cut(i,i,1.0) | |
| softcut.rec_level(i,1) | |
| softcut.pre_level(i,0) | |
| softcut.rec(i,1) | |
| softcut.phase_quant(i,scrub_resolution) | |
| end | |
| --playhead | |
| for i=3,4 do | |
| softcut.enable(i,1) | |
| softcut.buffer(i,i-2) | |
| softcut.pan(i,panning[i]) | |
| softcut.loop(i,1) | |
| softcut.loop_start(i,0) | |
| softcut.loop_end(i,buffer_length) | |
| softcut.position(i,0) | |
| softcut.rate(i,rate) | |
| softcut.pre_level(i,0) | |
| softcut.rec(i,0) | |
| softcut.phase_quant(i,scrub_resolution) | |
| softcut.level(i,0.0) | |
| end | |
| --polls | |
| softcut.event_phase(update_positions) | |
| softcut.poll_start_phase() | |
| local arc_redraw_metro = metro.init() | |
| arc_redraw_metro.event = function() | |
| arc_redraw() | |
| redraw() | |
| end | |
| arc_redraw_metro:start(1 /framerate) | |
| for i = 3,4 do softcut.play(i,1) end | |
| end | |
| function arc_redraw() | |
| local brightness | |
| local tape_led = tape_position/buffer_length | |
| local live_led = live_playback/buffer_length | |
| ar:all(0) | |
| if not overwriting then | |
| ar:segment(2,0,live_led*tau,8) | |
| ar:led(2,math.ceil(live_led*64),15) | |
| ar:led(2,math.ceil(tape_led*64),15) | |
| else | |
| for i=1,64 do ar:led(2,i,8) end | |
| ar:segment(2,tau*live_led+.2,live_led*tau,13) | |
| end | |
| ar:segment(1,tape_led*tau,tau*tape_led+.2,15) | |
| ar:refresh() | |
| end | |
| function redraw() | |
| screen.clear() | |
| screen.move(0,20) | |
| screen.font_size(25) | |
| screen.font_face(8) | |
| if live then | |
| screen.text('LIVE') | |
| else | |
| screen.text('TAPE') | |
| end | |
| screen.font_face(1) | |
| screen.font_size(8) | |
| screen.move(128,25) | |
| screen.text_right('(' .. string.format("%.2f",(buffer_length/rate)/60) ..' minutes)') | |
| screen.font_size(8) | |
| screen.move(5,35) | |
| screen.text('SIZE:') | |
| screen.move(128,35) | |
| screen.text_right(string.format("%.2f",(buffer_length/rate)).. ' seconds') | |
| screen.move(5,45) | |
| screen.text("LIVE: ") | |
| screen.move(128,45) | |
| screen.text_right(string.format("%.2f",live_playback/rate) .. ' seconds') | |
| screen.move(5,55) | |
| screen.text("TAPE: ") | |
| screen.move(128,55) | |
| screen.text_right(string.format("%.2f",display_tape_position/rate).. ' seconds') | |
| screen.update() | |
| end | |
| function cleanup() | |
| -- Put user's audio settings back where they were | |
| params:set('monitor_level', initital_monitor_level) | |
| params:set('reverb', initital_reverb_onoff) | |
| params:set('compressor', initital_compressor_onoff) | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment