Skip to content
Permalink
20bf011e0d
Go to file
 
 
Cannot retrieve contributors at this time
executable file 5947 lines (5520 sloc) 214 KB
-- cheat codes 2
-- a sample playground
-- patch: 201224
-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-- need help?
-- please visit:
-- l.llllllll.co/cheat-codes-2
-- -------------------------------
local pattern_time = include 'lib/cc_pattern_time'
MU = require "musicutil"
fileselect = require 'fileselect'
textentry = require 'textentry'
main_menu = include 'lib/main_menu'
encoder_actions = include 'lib/encoder_actions'
arc_actions = include 'lib/arc_actions'
rightangleslice = include 'lib/zilchmos'
start_up = include 'lib/start_up'
grid_actions = include 'lib/grid_actions'
easingFunctions = include 'lib/easing'
arps = include 'lib/arp_actions'
rnd = include 'lib/rnd_actions'
del = include 'lib/delay'
rytm = include 'lib/euclid'
mc = include 'lib/midicheat'
math.randomseed(os.time())
variable_fade_time = 0.01
--all the .quantize stuff is irrelevant now. it's been replaced by .mode = "quantized"
function make_a_gif(filename,time)
local steps = time*24
local gif_step = 1
local dirnames = {"/home/we/dust/tmp", "/home/we/dust/tmp/frames"}
for i = 1,2 do
if os.rename(dirnames[i], dirnames[i]) == nil then
os.execute("mkdir " .. dirnames[i])
end
end
while gif_step <= steps do
_norns.screen_export_png("/home/we/dust/tmp/frames/"..string.format("%04d",gif_step)..".gif")
gif_step = gif_step + 1
clock.sleep(1/24)
end
print("creating gif...")
os.execute("convert -delay "..(100/24).." -dispose previous -loop 0 /home/we/dust/tmp/frames/*.gif "..'home/we/dust/gifs/'..filename..'.gif')
-- print("converting gif...")
-- os.execute("convert home/we/dust/image.gif -gamma 1.25 -filter point -resize 400% -gravity center -background black -extent 120% home/we/dust/image.gif")
os.execute("rm -r /home/we/dust/tmp/frames/")
print("done!")
end
function record_screen(state)
if state == 1 then
gif_step = 1
recording_screen = true
else
recording_screen = false
end
end
function screenshot()
if recording_screen then
-- os.execute("mkdir /home/we/dust/tmp")
-- os.execute("mkdir /home/we/dust/tmp/frames")
-- local which_screen = string.match(string.match(string.match(norns.state.script,"/home/we/dust/code/(.*)"),"/(.*)"),"(.+).lua")
-- _norns.screen_export_png("/home/we/dust/"..which_screen.."-"..os.time()..".png")
_norns.screen_export_png("/home/we/dust/"..gif_step..".png")
gif_step = gif_step + 1
end
end
-- waveform stuff
local interval = 0
waveform_samples = {}
scale = 25
function on_render(ch, start, i, s)
-- cursor = util.clamp(cursor, 1, #s)
waveform_samples = s
interval = i
if menu ~= 1 then screen_dirty = true end
if ch == 2 then
if start < 33 then
clip[1].waveform_samples = s
elseif start < 65 then
clip[2].waveform_samples = s
else
clip[3].waveform_samples = s
end
elseif ch == 1 then
if start < 9 then
rec[1].waveform_samples = s
elseif start < 17 then
rec[2].waveform_samples = s
else
rec[3].waveform_samples = s
end
end
end
function update_waveform(buffer,winstart,winend,samples)
softcut.render_buffer(buffer, winstart, winend - winstart, 128)
end
--/ waveform stuff
function r()
norns.script.load(norns.state.script)
end
tau = math.pi * 2
arc_param = {}
arc_switcher = {}
for i = 1,3 do
arc_param[i] = 1
--arc_switcher[i] = 0
arc_switcher[i] = {}
end
arc_control = {}
for i = 1,3 do
arc_control[i] = i
end
arc_meta_focus = 1
arc_offset = 0 --IMPORTANT TO REVISIT
clip = {}
for i = 1,3 do
clip[i] = {}
clip[i].length = 90
clip[i].sample_length = 8
clip[i].start_point = nil
clip[i].end_point = nil
clip[i].mode = 1
clip[i].waveform_samples = {}
clip[i].waveform_rendered = false
end
pre_cc2_sample = { false, false, false }
clip[1].min = 1
clip[1].max = 1 + clip[1].sample_length
clip[2].min = 33
clip[2].max = clip[2].min + clip[2].sample_length
clip[3].min = 65
clip[3].max = clip[3].min + clip[3].sample_length
live = {}
for i = 1,3 do
live[i] = {}
live[i].waveform_samples = {}
end
live[1].min = 1
live[1].max = 9
live[2].min = 9
live[2].max = 17
live[3].min = 17
live[3].max = 25
help_menu = "welcome"
function f1()
softcut.post_filter_lp(2,0)
softcut.post_filter_hp(2,1)
softcut.post_filter_fc(2,10)
params:set("filter 1 cutoff",10)
end
function f2()
softcut.post_filter_hp(2,0)
softcut.post_filter_lp(2,1)
softcut.post_filter_fc(2,12000)
params:set("filter 1 cutoff",12000)
end
pattern_saver = { {},{},{} }
for i = 1,3 do
pattern_saver[i].active = false
pattern_saver[i].source = i
pattern_saver[i].save_slot = nil
pattern_saver[i].load_slot = 0
pattern_saver[i].saved = {}
pattern_saver[i].clock = nil
for j = 1,8 do
pattern_saver[i].saved[j] = 0
end
end
env_counter = {}
for i = 1,3 do
env_counter[i] = metro.init()
env_counter[i].time = 0.01
env_counter[i].butt = 1
env_counter[i].l_del_butt = 0
env_counter[i].r_del_butt = 0
env_counter[i].stage = nil
-- env_counter[i].mode = 1 -- this needs to be per pad!!
env_counter[i].event = function() envelope(i) end
end
slew_counter = {}
for i = 1,3 do
slew_counter[i] = metro.init()
slew_counter[i].time = 0.01
slew_counter[i].count = 100
slew_counter[i].current = 0.00
slew_counter[i].event = function() easing_slew(i) end
slew_counter[i].ease = easingFunctions.inSine
slew_counter[i].beginVal = 0
slew_counter[i].endVal = 1
slew_counter[i].change = slew_counter[i].endVal - slew_counter[i].beginVal
slew_counter[i].beginQ = 0
slew_counter[i].endQ = 0
slew_counter[i].changeQ = slew_counter[i].endQ - slew_counter[i].beginQ
slew_counter[i].duration = (slew_counter[i].count/100)-0.01
slew_counter[i].slewedVal = 0
slew_counter[i].prev_tilt = 0
slew_counter[i].next_tilt = 0
slew_counter[i].prev_q = 0
slew_counter[i].next_q = 0
end
quantize = 1
quantize_events = {}
for i = 1,3 do
quantize_events[i] = {}
end
grid_pat_quantize = 1
grid_pat_quantize_events = {}
for i = 1,3 do
grid_pat_quantize_events[i] = {}
end
--[[
grid_pat_quantizer = {}
for i = 1,3 do
grid_pat_quantizer[i] = {}
grid_pat_quantizer[i] = metro.init()
grid_pat_quantizer[i].time = 0.25
grid_pat_quantizer[i].count = -1
--grid_pat_quantizer[i].event = function() grid_pat_q_clock(i) end
grid_pat_quantizer[i].event = function() end
grid_pat_quantizer[i]:start()
end
--]]
function cheat_clock_synced(i)
if #quantize_events[i] > 0 then
for k,e in pairs(quantize_events[i]) do
cheat(i,e)
grid_p[i] = {}
grid_p[i].action = "pads"
grid_p[i].i = i
grid_p[i].id = selected[i].id
grid_p[i].x = selected[i].x
grid_p[i].y = selected[i].y
grid_p[i].rate = bank[i][bank[i].id].rate
grid_p[i].pause = bank[i][bank[i].id].pause
grid_p[i].start_point = bank[i][bank[i].id].start_point
grid_p[i].end_point = bank[i][bank[i].id].end_point
grid_p[i].rate_adjusted = false
grid_p[i].loop = bank[i][bank[i].id].loop
grid_p[i].mode = bank[i][bank[i].id].mode
grid_p[i].clip = bank[i][bank[i].id].clip
grid_pat[i]:watch(grid_p[i])
end
quantize_events[i] = {}
end
end
function how_many_bars(bank)
local total_pattern_time = 0
for i = 1,#grid_pat[bank].event do
total_pattern_time = total_pattern_time + grid_pat[bank].time[i]
end
local time_per_bar = clock.get_beat_sec()*4
local this_many_bars = math.floor((total_pattern_time/time_per_bar)+0.5)
-- need at least ONE bar, so...
if this_many_bars == 0 then this_many_bars = 1 end
return this_many_bars
end
function better_grid_pat_q_clock(i)
if grid_pat[i].rec == 1 then
grid_pat[i]:rec_stop()
midi_clock_linearize(i)
grid_pat[i].loop = 1
if grid_pat[i].count > 0 then
grid_pat[i].tightened_start = 1
if grid_pat[i].auto_snap == 1 then
print("auto-snap")
snap_to_bars(i,how_many_bars(i))
end
end
elseif grid_pat[i].count == 0 then
grid_pat[i]:rec_start()
elseif grid_pat[i].play == 1 then
grid_pat[i]:stop()
elseif grid_pat[i].tightened_start == 1 then
grid_pat[i].tightened_start = 0
grid_pat[i].step = grid_pat[i].start_point
quantized_grid_pat[i].current_step = grid_pat[i].start_point
quantized_grid_pat[i].sub_step = 1
else
grid_pat[i].tightened_start = 1
end
end
function snap_to_bars(bank,bar_count)
if grid_pat[bank].rec == 0 and grid_pat[bank].count > 0 then
local total_time = 0
for i = 1,#grid_pat[bank].event do
total_time = total_time + grid_pat[bank].time[i]
end
print("before total: "..total_time)
if old_pat_time == nil then
old_pat_time = table.clone(grid_pat[bank].time)
end
local bar_time = ((clock.get_beat_sec()*4)*bar_count)/total_time
for k = 1,grid_pat[bank].count do
grid_pat[bank].time[k] = grid_pat[bank].time[k] * bar_time
end
total_time = 0
for i = 1,#grid_pat[bank].event do
total_time = total_time + grid_pat[bank].time[i]
end
print("after total: "..total_time)
snap_to_bars_midi(bank,bar_count)
end
end
local snakes =
{ [1] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 }
, [2] = { 1,2,3,4,8,7,6,5,9,10,11,12,16,15,14,13 }
, [3] = { 1,5,9,13,2,6,10,14,3,7,11,15,4,8,12,16 }
, [4] = { 1,5,9,13,14,10,6,2,3,7,11,15,16,12,8,4 }
, [5] = { 1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10 }
, [6] = { 13,14,15,16,12,8,4,3,2,1,5,9,10,11,7,6 }
, [7] = { 1,2,5,9,6,3,4,7,10,13,14,11,8,12,15,16 }
, [8] = { 1,6,11,16,15,10,5,2,7,12,8,3,9,14,13,4 }
}
function random_grid_pat(which,mode)
local pattern = grid_pat[which]
-- if pattern.playmode == 1 then
-- pattern.playmode = 2
-- pattern.rec_clock_time = 8
-- end
if mode == 1 then
for i = #pattern.time,2,-1 do
local j = math.random(i)
pattern.time[i], pattern.time[j] = pattern.time[j], pattern.time[i]
end
elseif mode == 2 then
stop_pattern(pattern)
for i = #pattern.event,2,-1 do
local j = math.random(i)
local original, shuffled = pattern.event[i], pattern.event[j]
if original ~= "pause" and shuffled ~= "pause" then
original.id, shuffled.id = shuffled.id, original.id
original.rate, shuffled.rate = shuffled.rate, original.rate
original.loop, shuffled.loop = shuffled.loop, original.loop
original.mode, shuffled.mode = shuffled.mode, original.mode
original.pause, shuffled.pause = shuffled.pause, original.pause
original.start_point, shuffled.start_point = shuffled.start_point, original.start_point
original.clip, shuffled.clip = shuffled.clip, original.clip
original.end_point = original.end_point
original.rate_adjusted, shuffled.rate_adjusted = shuffled.rate_adjusted, original.rate_adjusted
original.y, shuffled.y = shuffled.y, original.y
original.x, shuffled.x = shuffled.x, original.x
original.action, shuffled.action = shuffled.action, original.action
original.i, shuffled.i = shuffled.i, original.i
original.previous_rate, shuffled.previous_rate = shuffled.previous_rate, original.previous_rate
original.row, shuffled.row = shuffled.row, original.row
original.con, shuffled.con = shuffled.con, original.con
original.bank, shuffled.bank = shuffled.bank, original.bank
else
original, shuffled = shuffled, original
end
end
elseif mode == 3 then
local auto_pat = params:get("random_patterning_"..which)
if auto_pat ~= 1 then
params:set("pattern_"..which.."_quantization", 2)
local vals_to_dur = {4,8,16,32,64,math.random(4,32)}
local note_val = params:get("rand_pattern_"..which.."_note_length")
pattern.rec_clock_time = vals_to_dur[note_val]
end
if pattern.playmode == 3 or pattern.playmode == 4 then
pattern.playmode = 2
end
local potential_total = pattern.rec_clock_time*4
-- local count = auto_pat == 1 and math.random(2,24) or 16
local count = auto_pat == 1 and (pattern.rec_clock_time * 4) or 16
if pattern.count > 0 or pattern.rec == 1 then
pattern:rec_stop()
stop_pattern(pattern)
pattern.tightened_start = 0
pattern:clear()
pattern_saver[which].load_slot = 0
end
for i = 1,count do
pattern.event[i] = {}
local constructed = pattern.event[i]
constructed.id = auto_pat == 1 and math.random(1,16) or snakes[auto_pat-1][i]
local assigning_pad = bank[which][constructed.id]
local new_rates =
{ [1] = math.pow(2,math.random(-3,-1))*((math.random(1,2)*2)-3)
, [2] = math.pow(2,math.random(-1,1))*((math.random(1,2)*2)-3)
, [3] = math.pow(2,math.random(1,2))*((math.random(1,2)*2)-3)
, [4] = math.pow(2,math.random(-2,2))*((math.random(1,2)*2)-3)
, [5] = assigning_pad.rate
}
constructed.rate = new_rates[pattern.random_pitch_range]
local pre_rate = assigning_pad.rate
assigning_pad.rate = constructed.rate
local new_levels =
{ [0.125] = 1.75
, [0.25] = 1.5
, [0.5] = 1.25
, [1.0] = 1.0
, [2.0] = 0.75
, [4.0] = 0.5
}
if pre_rate == assigning_pad.rate then
assigning_pad.level = assigning_pad.level
else
assigning_pad.level = assigning_pad.level == 0 and 0 or new_levels[math.abs(constructed.rate)]
end
constructed.loop = assigning_pad.loop
constructed.mode = assigning_pad.mode
constructed.pause = assigning_pad.pause
constructed.start_point = (math.random(10,75)/10)+(8*(assigning_pad.clip-1))
constructed.clip = assigning_pad.clip
constructed.end_point = constructed.start_point + (math.random(1,15)/10)
constructed.rate_adjusted = false
assigning_pad.fifth = false
constructed.x = (5*(which-1)+1)+(math.ceil(constructed.id/4)-1)
if (constructed.id % 4) ~= 0 then
constructed.y = 9-(constructed.id % 4)
else
constructed.y = 5
end
constructed.action = "pads"
constructed.i = which
local tempo = clock.get_beat_sec()
local divisors = { 4,2,1,0.5,0.25,math.pow(2,math.random(-2,2)) }
local note_length = (tempo / divisors[params:get("rand_pattern_"..which.."_note_length")])
pattern.time[i] = note_length
pattern.time_beats[i] = pattern.time[i] / tempo
pattern:calculate_quantum(i)
end
pattern.count = count
pattern.start_point = 1
pattern.end_point = count
end
midi_clock_linearize(which)
if pattern.quantize == 0 then
if pattern.auto_snap == 1 then
print("auto-snap")
snap_to_bars(which,how_many_bars(which))
end
start_pattern(pattern)
pattern.loop = 1
else
pattern.loop = 1
if pattern.count > 0 then
pattern.tightened_start = 1
if pattern.auto_snap == 1 then
print("auto-snap")
snap_to_bars(which,how_many_bars(which))
end
end
end
end
function print_my_g_p_q(bank)
for i = #quantized_grid_pat[bank].event,1,-1 do
print(i)
tab.print(quantized_grid_pat[bank].event[i])
end
end
function snap_to_bars_midi(bank,bar_count)
local entry_count = 0
local target_entry_count = bar_count*16
for i = 1,#quantized_grid_pat[bank].event do
entry_count = entry_count + #quantized_grid_pat[bank].event[i]
end
print("before trimming midi event count: "..entry_count)
if entry_count < target_entry_count then
for i = 1,target_entry_count-entry_count do
table.insert(quantized_grid_pat[bank].event[#quantized_grid_pat[bank].event],"nothing")
end
elseif entry_count > target_entry_count then
--print("subtracting...")
local last_event = #quantized_grid_pat[bank].event
local last_group = #quantized_grid_pat[bank].event
--print("last event: "..last_event)
local distance_count = entry_count - target_entry_count
print("removing "..distance_count.." event")
local current_count = 0
while current_count < distance_count do
if last_group > 0 then
if #quantized_grid_pat[bank].event[last_group] > 1 and quantized_grid_pat[bank].event[last_group][#quantized_grid_pat[bank].event[last_group]] == "nothing" then
local check_table = #quantized_grid_pat[bank].event
--print("removing: "..quantized_grid_pat[bank].event[last_group][#quantized_grid_pat[bank].event[last_group]].." from group "..last_group..", entry "..#quantized_grid_pat[bank].event[last_group])
table.remove(quantized_grid_pat[bank].event[last_group])
current_count = current_count + 1
if current_count == distance_count then print("done now!") break end
--print("current count :" .. current_count)
elseif #quantized_grid_pat[bank].event[last_group] == 1 and quantized_grid_pat[bank].event[last_group][#quantized_grid_pat[bank].event[last_group]] == "something" then
--print("skipping: "..quantized_grid_pat[bank].event[last_group][#quantized_grid_pat[bank].event[last_group]].." from group "..last_group..", entry "..#quantized_grid_pat[bank].event[last_group])
last_group = last_group - 1
elseif #quantized_grid_pat[bank].event[last_group] == 1 and quantized_grid_pat[bank].event[last_group][#quantized_grid_pat[bank].event[last_group]] == "nothing" then
--print("there's only nothing in group "..last_group..", but removing it")
table.remove(quantized_grid_pat[bank].event[last_group])
--print_my_g_p_q(1)
current_count = current_count + 1
if current_count == distance_count then print("done now!") break end
--print("current count :" .. current_count)
last_group = last_group - 1
elseif quantized_grid_pat[bank].event[last_group][#quantized_grid_pat[bank].event[last_group]] == nil then
--print("A NIL IN"..last_group)
table.remove(quantized_grid_pat[bank].event,last_group)
last_group = last_group - 1
--break
end
elseif last_group == 0 then
--print("still got some left!!!: "..current_count.." / "..distance_count)
table.remove(quantized_grid_pat[bank].event)
current_count = current_count + 1
end
end
quantized_grid_pat[bank].current_step = grid_pat[bank].start_point
quantized_grid_pat[bank].sub_step = 1
end
local entry_count = 0
for i = 1,#quantized_grid_pat[bank].event do
entry_count = entry_count + #quantized_grid_pat[bank].event[i]
end
print("after trimming midi event count: "..entry_count)
if entry_count ~= target_entry_count then
--doubletap? is this ok??
snap_to_bars_midi(bank,bar_count)
end
end
function copy_entire_pattern(bank)
original_pattern = {}
original_pattern[bank] = {}
original_pattern[bank].time = table.clone(grid_pat[bank].time)
original_pattern[bank].event = {}
for i = 1,#grid_pat[bank].event do
original_pattern[bank].event[i] = {}
-- new stuff!
if grid_pat[bank].event[i] ~= "pause" then
for k,v in pairs(grid_pat[bank].event[i]) do
original_pattern[bank].event[i][k] = v
end
else
original_pattern[bank].event[i] = "pause"
end
end
original_pattern[bank].quantum = {}
for k,v in pairs(grid_pat[bank].quantum) do
original_pattern[bank].quantum[k] = v
end
original_pattern[bank].time_beats = {}
for k,v in pairs(grid_pat[bank].time_beats) do
original_pattern[bank].time_beats[k] = v
end
-- /new stuff!
original_pattern[bank].metro = {}
original_pattern[bank].metro.props = {}
original_pattern[bank].metro.props.time = grid_pat[bank].metro.props.time
original_pattern[bank].prev_time = grid_pat[bank].prev_time
original_pattern[bank].count = grid_pat[bank].count
original_pattern[bank].start_point = grid_pat[bank].start_point
original_pattern[bank].end_point = grid_pat[bank].end_point
original_pattern[bank].mode = grid_pat[bank].mode
-- new stuff
original_pattern[bank].rec_clock_time = grid_pat[bank].rec_clock_time
--/ new stuff
if grid_pat[bank].playmode ~= nil then
if grid_pat[bank].playmode ~= 1 then
original_pattern[bank].playmode = 2
else
original_pattern[bank].playmode = 1
end
else
original_pattern[bank].playmode = 1
end
end
function copy_metatable(obj)
if type(obj) ~= 'table' then return obj end
local res = setmetatable({}, getmetatable(obj))
for k, v in pairs(obj) do res[copy_metatable(k)] = copy_metatable(v) end
return res
end
function commit_midi_to_disk(target)
end
function update_pattern_bpm(bank)
grid_pat[bank].time_factor = 1*(synced_to_bpm/bpm)
end
function table.clone(org)
return {table.unpack(org)}
end
function calc_rec_clock_time(target)
local total_time = 0
for i = 1,#grid_pat[target].time_beats do
total_time = total_time + grid_pat[target].time_beats[i]
end
grid_pat[target].rec_clock_time = util.round(total_time)
end
function unpack_quantized_table(target)
for i = 1,#quantized_grid_pat[target].event do
grid_pat[target].quantum[i] = #quantized_grid_pat[target].event[i] * 0.25
grid_pat[target].time_beats[i] = grid_pat[target].time[i] / clock.get_beat_sec()
end
calc_rec_clock_time(target)
end
function midi_clock_linearize(bank)
quantized_grid_pat[bank].event = {}
for i = 1,grid_pat[bank].count do
quantized_grid_pat[bank].clicks[i] = math.floor((grid_pat[bank].time[i] / (clock.get_beat_sec()/4))+0.5)
quantized_grid_pat[bank].event[i] = {} -- critical
if grid_pat[bank].time[i] == 0 or quantized_grid_pat[bank].clicks[i] == 0 then
quantized_grid_pat[bank].event[i][1] = "nothing"
else
for j = 1,quantized_grid_pat[bank].clicks[i] do
if j == 1 then
quantized_grid_pat[bank].event[i][1] = "something"
else
quantized_grid_pat[bank].event[i][j] = "nothing"
end
end
end
end
quantized_grid_pat[bank].current_step = grid_pat[bank].start_point
quantized_grid_pat[bank].sub_step = 1
end
function midi_clock_linearize_overdub(bank)
local curr = quantized_grid_pat[bank].current_step + 1
local sub = quantized_grid_pat[bank].sub_step
local removed = #quantized_grid_pat[bank].event[quantized_grid_pat[bank].current_step] - quantized_grid_pat[bank].sub_step
for i = quantized_grid_pat[bank].sub_step,#quantized_grid_pat[bank].event[quantized_grid_pat[bank].current_step] do
table.remove(quantized_grid_pat[bank].event[curr-1],sub)
end
table.insert(quantized_grid_pat[bank].event,curr,{"something"})
if removed ~= 0 then
for i = 1,removed do
table.insert(quantized_grid_pat[bank].event[curr],"nothing")
end
end
if quantized_grid_pat[bank].current_step < grid_pat[bank].end_point then
quantized_grid_pat[bank].current_step = quantized_grid_pat[bank].current_step + 1
else
quantized_grid_pat[bank].current_step = 1
end
quantized_grid_pat[bank].sub_step = 1
end
key1_hold = false
key1_hold_and_modify = false
key2_hold_counter = metro.init()
key2_hold_counter.time = 0.25
key2_hold_counter.count = 1
key2_hold_counter.event = function()
key2_hold = true
end
key2_hold = false
key2_hold_and_modify = false
grid.alt = false
-- grid.alt_pp = 0
-- grid.alt_delay = false
grid.loop_mod = 0
local function crow_flush()
crow.reset()
crow.clear()
end
local function crow_init()
for i = 1,4 do
crow.output[i].action = "{to(5,0),to(0,0.05)}"
print("output["..i.."] initialized")
end
crow.input[2].mode("change",2,0.1,"rising")
crow.input[2].change = buff_freeze
end
local lit = {}
zilch_leds =
{ [1] = {{0},{0},{0}}
, [2] = {{0,0},{0,0},{0,0}}
, [3] = {{0,0,0},{0,0,0},{0,0,0}}
, [4] = {{0,0,0,0},{0,0,0,0},{0,0,0,0}}
}
function init()
clock.run(check_page_for_k1)
collection_loaded = false
all_loaded = false
for i = 1,3 do
norns.enc.sens(i,2)
end
grid_p = {}
arc_p = {}
midi_p = {}
rec = {}
rec.state = 1
rec.pause = false
rec.clip = 1
rec.start_point = 1
rec.end_point = 9
rec.loop = 1
rec.clear = 0
rec.rate_offset = 1.0
rec.stopped = false
rec.play_segment = 1
rec.focus = 1
for i = 1,3 do
rec[i] = {}
rec[i].state = 0
rec[i].pause = false
rec[i].clip = 1
rec[i].start_point = 1+(8*(i-1))
rec[i].end_point = 9+(8*(i-1))
rec[i].loop = 1
rec[i].clear = 1
rec[i].rate_offset = 1.0
rec[i].waveform_samples = {}
end
params:add_group("GRID",2)
params:add_option("LED_style","LED style",{"varibright","4-step","grayscale"},1)
params:set_action("LED_style",
function()
grid_dirty = true
if all_loaded then
persistent_state_save()
end
end)
params:add_option("grid_size","grid size",{"128","64"},1)
params:set_action("grid_size",
function()
grid_dirty = true
params:set("LED_style",2)
if all_loaded then
persistent_state_save()
end
end)
params:add_separator("cheat codes params")
params:add_group("collections",7)
params:add_separator("load/save")
params:add_trigger("load", "load collection")
params:set_action("load",
function(x)
local dirname = _path.data.."cheat_codes_2/"
if os.rename(dirname, dirname) == nil then
os.execute("mkdir " .. dirname)
end
local dirname = _path.data.."cheat_codes_2/names/"
if os.rename(dirname, dirname) == nil then
os.execute("mkdir " .. dirname)
end
fileselect.enter(_path.data.."cheat_codes_2/names/", named_loadstate)
end)
params:add_option("collect_live","collect Live buffers?",{"no","yes"})
params:add_trigger("save", "save new collection")
params:set_action("save", function(x)
textentry.enter(pre_save)
end)
params:add_separator("danger zone!")
params:add_trigger("overwrite_coll", "overwrite loaded collection")
-- params:set_action("overwrite_coll", function(x) fileselect.enter(_path.data.."cheat_codes_2/names/", named_overwrite) end)
params:set_action("overwrite_coll", function(x)
if selected_coll ~= 0 then
named_overwrite(_path.data.."cheat_codes_2/names/"..selected_coll..".cc2")
end
end)
params:add_trigger("delete_coll", "delete collection")
params:set_action("delete_coll", function(x) fileselect.enter(_path.data.."cheat_codes_2/names/", pre_delete) end)
menu = 1
for i = 1,4 do
crow.output[i].action = "{to(5,0),to(0,0.05)}"
end
crow.count = {}
crow.count_execute = {}
for i = 1,3 do
crow.count[i] = 1
crow.count_execute[i] = 1
end
screen.line_width(1)
local etap = 0
local edelta = 1
local prebpm = 110
clock_counting = 0
grid_pat = {}
for i = 1,3 do
grid_pat[i] = pattern_time.new("grid_pat["..i.."]")
grid_pat[i].process = grid_pattern_execute
grid_pat[i].tightened_start = 0
grid_pat[i].auto_snap = 0
grid_pat[i].quantize = 0
grid_pat[i].playmode = 1
grid_pat[i].random_pitch_range = 5
grid_pat[i].rec_clock_time = 8
end
quantized_grid_pat = {}
for i = 1,3 do
quantized_grid_pat[i] = {}
quantized_grid_pat[i].clicks = {}
quantized_grid_pat[i].event = {}
quantized_grid_pat[i].sub_step = 1
quantized_grid_pat[i].current_step = grid_pat[i].start_point
end
step_seq = {}
for i = 1,3 do
step_seq[i] = {}
step_seq[i].active = 1
step_seq[i].current_step = 1
step_seq[i].current_pat = nil
step_seq[i].rate = 1
step_seq[i].start_point = 1
step_seq[i].end_point = 16
step_seq[i].length = (step_seq[i].end_point - step_seq[i].start_point) + 1
step_seq[i].meta_step = 1
step_seq[i].meta_duration = 1
step_seq[i].meta_meta_step = 1
step_seq[i].held = 0
for j = 1,16 do
step_seq[i][j] = {}
step_seq[i][j].meta_meta_duration = 4
step_seq[i][j].assigned = 0 --necessary?
step_seq[i][j].assigned_to = 0
step_seq[i][j].loop_pattern = 1
end
step_seq[i].meta_meta_duration = 4
step_seq[i].loop_held = 0
end
function internal_clocking_tightened(bank)
local current = quantized_grid_pat[bank].current_step
local sub_step = quantized_grid_pat[bank].sub_step
if current == 0 then
current = grid_pat[bank].start_point
end
if grid_pat[bank].tightened_start == 1 and grid_pat[bank].count > 0 and current <= grid_pat[bank].end_point and quantized_grid_pat[bank].event[current] ~= nil then
if quantized_grid_pat[bank].event[current][sub_step] == "something" then
--print(current, sub_step, "+++")
if grid_pat[bank].step == 0 then
grid_pat[bank].step = grid_pat[bank].start_point
end
if quantized_grid_pat[bank].current_step == 0 then
quantized_grid_pat[bank].current_step = grid_pat[bank].start_point
end
grid_pattern_execute(grid_pat[bank].event[quantized_grid_pat[bank].current_step])
elseif quantized_grid_pat[bank].event[current][sub_step] == "nothing" then
-- nothing!
if grid_pat[bank].step == 0 then
grid_pat[bank].step = grid_pat[bank].start_point
end
if quantized_grid_pat[bank].current_step == 0 then
print("if you see this message, tell dan!")
quantized_grid_pat[bank].current_step = grid_pat[bank].start_point
end
elseif quantized_grid_pat[bank].event[current][sub_step] == nil and #quantized_grid_pat[bank].event == grid_pat[bank].end_point then
print(current.." is nil!")
table.remove(quantized_grid_pat[bank].event,current)
grid_pat[bank].end_point = grid_pat[bank].end_point - 1
quantized_grid_pat[bank].current_step = quantized_grid_pat[bank].current_step + 1
quantized_grid_pat[bank].sub_step = 1
elseif quantized_grid_pat[bank].event[current][sub_step] == nil then
print("skipping bank "..bank..", step "..current..", sub "..sub_step.."...unsure what to do")
quantized_grid_pat[bank].current_step = quantized_grid_pat[bank].current_step + 1
quantized_grid_pat[bank].sub_step = 1
end
--increase sub_step now
--if quantized_grid_pat[bank].current_step > #quantized_grid_pat[bank].event or quantized_grid_pat[bank].current_step > #grid_pat[bank].event then
if quantized_grid_pat[bank].current_step > grid_pat[bank].end_point then
quantized_grid_pat[bank].current_step = grid_pat[bank].start_point
end
if quantized_grid_pat[bank].sub_step == #quantized_grid_pat[bank].event[quantized_grid_pat[bank].current_step] then
quantized_grid_pat[bank].sub_step = 0
--if we're at the end of the events in this step, move to the next step
if grid_pat[bank].step == grid_pat[bank].end_point then
grid_pat[bank].step = 0
--quantized_grid_pat[bank].current_step = 0
end
--if quantized_grid_pat[bank].current_step == #quantized_grid_pat[bank].event then
if quantized_grid_pat[bank].current_step == grid_pat[bank].end_point then
quantized_grid_pat[bank].current_step = grid_pat[bank].start_point - 1
end
grid_pat[bank].step = grid_pat[bank].step + 1
quantized_grid_pat[bank].current_step = quantized_grid_pat[bank].current_step +1
--quantized_grid_pat[bank].current_step = quantized_grid_pat[bank].current_step + 1
end
quantized_grid_pat[bank].sub_step = quantized_grid_pat[bank].sub_step + 1
else
quantized_grid_pat[bank].current_step = 1
end
end
params:add_number("bpm", "bpm", 1, 480,80)
bpm = params:get("bpm")
params:hide("bpm")
params:add_group("hidden [timing]",6)
params:hide("hidden [timing]")
params:add_option("quantize_pads", "(see [timing] menu)", { "no", "yes" })
params:set_action("quantize_pads", function(x) quantize = x-1 end)
params:add_option("quantize_pats", "(see [timing] menu)", { "no", "yes" })
params:set_action("quantize_pats", function(x)
grid_pat_quantize = x-1
for i = 1,3 do
grid_pat[i].quantize = x-1
end
end)
params:add_number("quant_div", "(see [timing] menu)", 1, 5, 4)
params:add_number("quant_div_pats", "(see [timing] menu)", 1, 5, 4)
params:add_option("lock_pat", "(see [timing] menu)", {"no", "yes"} )
params:add{type = "trigger", id = "sync_pat", name = "(see [timing] menu)"}
params:default()
grid_page = 0
grid_page_64 = 0
bank_64 = 1
page = {}
page.loops = {}
page.loops.frame = 1
page.loops.sel = 1
page.loops.meta_sel = 1
page.loops.meta_option_set = {1,1,1,1}
page.loops.top_option_set = {1,1,1,1}
page.loops.focus_hold = {false, false, false, false}
page.main_sel = 1
page.loops_sel = 1
page.loops_page = 0
page.loops_view = {4,1,1,1}
page.levels_sel = 0
page.panning_sel = 1
page.filtering_sel = 0
page.arc_sel = 0
page.delay_sel = 0
page.delay_section = 1
page.delay_focus = 1
page.delay = {{},{}}
for i = 1,2 do
page.delay[i].menu = 1
page.delay[i].menu_sel = {1,1,1}
end
page.time_sel = 1
page.time_page = {}
page.time_page_sel = {}
page.time_scroll = {}
for i = 1,6 do
page.time_page[i] = 1
page.time_page_sel[i] = 1
page.time_scroll[i] = 1
end
page.time_arc_loop = {1,1,1}
page.track_sel = {}
page.track_page = 1
page.track_page_section = {}
for i = 1,4 do
page.track_sel[i] = 1
page.track_page_section[i] = 1
end
page.track_param_sel = {}
for i = 1,3 do
page.track_param_sel[i] = 1
end
page.arp_page_sel = 1
page.arp_param = {1,1,1}
page.arp_alt = {false,false,false}
page.arp_param_group = {}
for i = 1,3 do
page.arp_param_group[i] = 1
end
page.rnd_page = 1
page.rnd_page_section = 1
page.rnd_page_sel = {}
page.rnd_page_edit = {}
for i = 1,3 do
page.rnd_page_sel[i] = 1
page.rnd_page_edit[i] = 1
end
del.init()
index = 0
edit = "all"
start_up.init()
params:add_group("crow utils",2)
params:hide("crow utils")
params:add{type = "trigger", id = "init_crow", name = "initialize crow", action = crow_init}
params:add{type = "trigger", id = "clear_crow", name = "(reset/clear crow)", action = crow_flush}
bank = {}
reset_all_banks(bank)
params:bang()
selected_coll = 0
--GRID
selected = {}
fingers = {}
counter_two = {}
for i = 1,3 do
selected[i] = {}
selected[i].x = 1 + (5*(i-1))
selected[i].y = 8
selected[i].id = 1
for k = 1,4 do
fingers[k] = {}
fingers[k].dt = 1
fingers[k].t1 = 0
fingers[k].t = 0
fingers[k][i] = {}
fingers[k][i].con = {}
end
end
function record_zilchmo_4(prev,sel,row,con)
grid_p[sel] = {}
grid_p[sel].i = sel
grid_p[sel].action = "zilchmo"
grid_p[sel].con = con
grid_p[sel].row = row
grid_p[sel].bank = sel
grid_p[sel].id = selected[sel].id
grid_p[sel].x = selected[sel].x
grid_p[sel].y = selected[sel].y
grid_p[sel].previous_rate = prev
grid_p[sel].rate = prev
grid_p[sel].start_point = bank[sel][bank[sel].id].start_point
grid_p[sel].end_point = bank[sel][bank[sel].id].end_point
grid_pat[sel]:watch(grid_p[sel])
end
function record_arp()
end
counter_two = {}
counter_two.key_up = metro.init()
counter_two.key_up.time = 0.05
counter_two.key_up.count = 1
counter_two.key_up.event = function()
zilchmo(2,selected_zilchmo_bank)
end
counter_two.key_up:stop()
quantized_grid_pat = {}
for i = 1,3 do
quantized_grid_pat[i] = {}
quantized_grid_pat[i].clicks = {}
quantized_grid_pat[i].event = {}
quantized_grid_pat[i].sub_step = 1
quantized_grid_pat[i].current_step = 1
end
arc_pat = {{},{},{}}
for i = 1,3 do
for j = 1,4 do
arc_pat[i][j] = pattern_time.new("arc_pat["..i.."]["..j.."]")
arc_pat[i][j].process = new_arc_pattern_execute
end
end
for i=1,3 do
cheat(i,bank[i].id)
end
grid_dirty = true
function draw_grid()
if grid_dirty then
grid_redraw()
grid_dirty = false
end
end
function draw_screen()
if screen_dirty then
redraw()
screen_dirty = false
end
end
softcut.poll_start_phase()
filter_types = {"lp", "hp", "bp", "lp/hp"}
rec_state_watcher = metro.init()
rec_state_watcher.time = 0.05
rec_state_watcher.event = function()
if rec[rec.focus].loop == 0 then
if rec[rec.focus].state == 1 then
if rec[rec.focus].end_point < poll_position_new[1] +0.015 then
rec[rec.focus].state = 0
rec_state_watcher:stop()
rec.stopped = true
grid_dirty = true
if menu == 2 then
if page.loops.sel ~= 5 then screen_dirty = true end
-- print("stopped")
end
end
end
end
end
rec_state_watcher.count = -1
already_saved()
params:add_separator("cheat codes external zone")
params:add_group("OSC setup",3)
params:add_text("osc_IP", "source OSC IP", "192.168.")
params:set_action("osc_IP", function() dest = {tostring(params:get("osc_IP")), tonumber(params:get("osc_port"))} end)
params:add_text("osc_port", "OSC port", "9000")
params:set_action("osc_port", function() dest = {tostring(params:get("osc_IP")), tonumber(params:get("osc_port"))} end)
params:add{type = "trigger", id = "refresh_osc", name = "refresh OSC [K3]", action = function()
params:set("osc_IP","none")
params:set("osc_port","none")
osc_communication = false
osc_echo = false
end}
params:add_group("MIDI note/OP-Z setup",16)
params:add_option("midi_control_enabled", "enable MIDI control?", {"no","yes"},1)
params:set_action("midi_control_enabled", function() if all_loaded then persistent_state_save() end end)
-- params:add_option("midi_control_device", "MIDI control device",{"port 1", "port 2", "port 3", "port 4"},1)
local vports = {}
local function refresh_params_vports()
for i = 1,#midi.vports do
vports[i] = midi.vports[i].name ~= "none" and util.trim_string_to_width(midi.vports[i].name,70) or tostring(i)..": [device]"
end
end
refresh_params_vports()
params:add_option("midi_control_device", "MIDI ctrl dev",vports,1)
params:set_action("midi_control_device", function() if all_loaded then persistent_state_save() end end)
params:add_option("midi_echo_enabled", "enable MIDI echo?", {"no","yes"},1)
params:set_action("midi_echo_enabled", function() if all_loaded then persistent_state_save() end end)
local bank_names = {"(a)","(b)","(c)"}
params:add_separator("channel")
params:add_option("midi_control_channel_distribution", "channel distribution: ",{"multi","single"})
params:set_action("midi_control_channel_distribution", function(x)
if all_loaded then
persistent_state_save()
if x == 2 then
for i = 1,3 do params:set("bank_"..i.."_midi_channel",params:get("bank_1_midi_channel")) end
end
end
end)
for i = 1,3 do
params:add_number("bank_"..i.."_midi_channel", "bank "..bank_names[i].." pad channel:",1,16,i)
params:set_action("bank_"..i.."_midi_channel", function(x)
if all_loaded then
persistent_state_save()
if params:get("midi_control_channel_distribution") == 2 then
for j = 1,3 do
params:set("bank_"..(j~=i and j or i).."_midi_channel",x)
end
end
end
end)
end
params:add_separator("note = pad 1")
for i = 1,3 do
params:add_number("bank_"..i.."_pad_midi_base", "bank "..bank_names[i].." midi base:",0,111,53)
params:set_action("bank_"..i.."_pad_midi_base", function() if all_loaded then persistent_state_save() end end)
end
params:add_separator("zilchmo")
for i = 1,3 do
params:add_option("bank_"..i.."_midi_zilchmo_enabled", "bank "..bank_names[i].." midi zilchmo?", {"no","yes"},2)
params:set_action("bank_"..i.."_midi_zilchmo_enabled", function() if all_loaded then persistent_state_save() end end)
end
params:add_group("MIDI encoder setup",7)
params:add_option("midi_enc_control_enabled", "enable MIDI enc control?", {"no","yes"},1)
params:set_action("midi_enc_control_enabled", function() if all_loaded then persistent_state_save() end end)
params:add_option("midi_enc_control_device", "MIDI enc dev",vports,2)
params:set_action("midi_enc_control_device", function() if all_loaded then persistent_state_save() end end)
params:add_option("midi_enc_echo_enabled", "enable MIDI enc echo?", {"no","yes"},1)
params:set_action("midi_enc_echo_enabled", function() if all_loaded then persistent_state_save() end end)
params:add_trigger("ping_for_MFT","refresh for MFT (K3)")
params:set_action("ping_for_MFT",function(x) ping_midi_devices() end)
local bank_names = {"(a)","(b)","(c)"}
for i = 1,3 do
params:add_number("bank_"..i.."_midi_enc_channel", "bank "..bank_names[i].." enc channel:",1,16,i)
params:set_action("bank_"..i.."_midi_enc_channel", function() if all_loaded then persistent_state_save() end end)
end
mc.pad_to_note_params()
crow_init()
task_id = clock.run(globally_clocked)
pad_press_quant = clock.run(pad_clock)
random_rec = clock.run(random_rec_clock)
if params:string("clock_source") == "internal" then
clock.internal.start(bpm)
end
-- local midi_dev_max;
-- for k,v in pairs(midi.devices) do
-- midi_dev_max = midi.devices[k].id
-- end
-- for i = 1,midi_dev_max do
-- if midi.devices[i] ~= nil and midi.devices[i].name == "Midi Fighter Twister" then
-- params:set("midi_enc_control_enabled",2)
-- params:set("midi_enc_control_device",midi.devices[i].port)
-- params:set("midi_enc_echo_enabled",2)
-- mft_connected = true
-- end
-- -- if midi.devices[i] ~= nil and midi.devices[i].name == "OP-Z" then
-- -- params:set("midi_control_enabled",2)
-- -- params:set("midi_control_device",midi.devices[i].port)
-- -- params:set("midi_echo_enabled",2)
-- -- opz_connected = true
-- -- end
-- end
ping_midi_devices()
midi_dev = {}
for j = 1,#midi.vports do
midi_dev[j] = midi.connect(j)
local trigger_bank = {nil,nil,nil}
local b_ch = {}
midi_dev[j].event = function(data)
screen_dirty = true
local d = midi.to_msg(data)
if params:get("midi_control_enabled") == 2 and j == params:get("midi_control_device") then
local received_ch;
-- local b_ch = {}
for i = 1,3 do
if d.ch == params:get("bank_"..i.."_midi_channel") then
-- received_ch = i
b_ch[i] = d.ch
else
b_ch[i] = nil
end
end
for i = 1,3 do
if b_ch[i] ~= nil then
-- local i = received_ch
if d.note ~= nil and i ~= nil then
if d.note >= params:get("bank_"..i.."_pad_midi_base") and d.note <= params:get("bank_"..i.."_pad_midi_base") + (not midi_alt and 15 or 22) then
if not midi_alt then
if d.type == "note_on" then
mc.cheat(i,d.note-(params:get("bank_"..i.."_pad_midi_base")-1))
if midi_pat[i].rec == 1 and midi_pat[i].count == 0 then
end
midi_pattern_watch(i, d.note-(params:get("bank_"..i.."_pad_midi_base")-1))
if menu == 9 then
page.arp_page_sel = i
arps.momentary(i, bank[i].id, "on")
end
elseif d.type == "note_off" then
if menu == 9 then
if not arp[i].hold and page.arp_page_sel == i then
local targeted_pad = d.note-(params:get("bank_"..i.."_pad_midi_base")-1)
arps.momentary(i, targeted_pad, "off")
end
end
end
elseif midi_alt then
if params:get("bank_"..i.."_midi_zilchmo_enabled") == 2 and d.type == "note_on" then
mc.zilch(i,d.note-(params:get("bank_"..i.."_pad_midi_base")-1))
end
end
elseif d.note == params:get("bank_"..i.."_pad_midi_base") + 23 then
if d.type == "note_on" then
midi_alt = true
else
midi_alt = false
end
end
end
if d.type == "cc" and params:get("midi_echo_enabled") == 2 then
if d.cc == 1 then
mc.move_start(bank[i][bank[i].id],d.val)
elseif d.cc == 2 then
mc.move_end(bank[i][bank[i].id],d.val)
elseif d.cc == 3 then
mc.adjust_filter(i,d.val)
elseif d.cc == 4 then
mc.adjust_pad_level(bank[i][bank[i].id],d.val)
end
end
end
end
elseif params:get("midi_enc_control_enabled") == 2 and j == params:get("midi_enc_control_device") then
-- TODO: refine this, shouldn't have to call all 3...
if midi_dev[j].name ~= "Midi Fighter Twister" then
for i = 1,3 do
if d.ch == params:get("bank_"..i.."_midi_enc_channel") then
if d.type == "cc" then
if d.cc == 1 then
mc.move_start(bank[i][bank[i].id],d.val)
elseif d.cc == 2 then
mc.move_end(bank[i][bank[i].id],d.val)
elseif d.cc == 3 then
mc.adjust_filter(i,d.val)
elseif d.cc == 4 then
mc.adjust_pad_level(bank[i][bank[i].id],d.val)
end
end
end
end
elseif midi_dev[j].name == "Midi Fighter Twister" then
-- tab.print(d)
local function check_focus_hold(id)
if bank[id].focus_hold == true then
return bank[id].focus_pad
else
return bank[id].id
end
end
if d.ch == 1 or d.ch == 5 then
if d.cc == 0 or d.cc == 16 or d.cc == 32 then
local id = math.floor(d.cc/16)+1
encoder_actions.change_pad(bank[id][check_focus_hold(id)].bank_id, d.val == 63 and -1 or 1)
if bank[id].focus_hold then
mc.mft_redraw(bank[id][bank[id].focus_pad],"all")
end
elseif d.cc == 1 or d.cc == 17 or d.cc == 33 then
-- pad start point
local id = math.floor(d.cc/16)+1
local resolution = loop_enc_resolution[id] / 10
encoder_actions.move_start(bank[id][check_focus_hold(id)], (d.val == 63 and (d.ch == 1 and -0.1 or -0.01) or (d.ch == 1 and 0.1 or 0.01))/resolution)
mc.mft_redraw(bank[id][check_focus_hold(id)],"start_point")
if bank[id].focus_hold == false then
encoder_actions.sc.move_start(id)
end
elseif d.cc == 2 or d.cc == 18 or d.cc == 34 then
-- pad end point
local id = math.floor(d.cc/16)+1
local resolution = loop_enc_resolution[id] / 10
encoder_actions.move_end(bank[id][check_focus_hold(id)], (d.val == 63 and (d.ch == 1 and -0.1 or -0.01) or (d.ch == 1 and 0.1 or 0.01))/resolution)
mc.mft_redraw(bank[id][check_focus_hold(id)],"end_point")
if bank[id].focus_hold == false then
encoder_actions.sc.move_end(id)
end
elseif d.cc == 3 or d.cc == 19 or d.cc == 35 then
-- pad window
local id = math.floor(d.cc/16)+1
local resolution = loop_enc_resolution[id] / 10
encoder_actions.move_play_window(bank[id][check_focus_hold(id)], (d.val == 63 and (d.ch == 1 and -0.1 or -0.01) or (d.ch == 1 and 0.1 or 0.01))/resolution)
mc.mft_redraw(bank[id][check_focus_hold(id)],"start_point")
mc.mft_redraw(bank[id][check_focus_hold(id)],"end_point")
if bank[id].focus_hold == false then
encoder_actions.sc.move_play_window(id)
end
elseif d.cc == 4 or d.cc == 20 or d.cc == 36 then
--pad level
local id = math.floor(d.cc/16)+1
bank[id][check_focus_hold(id)].level = util.clamp(bank[id][check_focus_hold(id)].level+(d.val == 63 and (d.ch == 1 and -0.01 or -0.001) or (d.ch == 1 and 0.01 or 0.001)),0,2)
if bank[id][check_focus_hold(id)].envelope_mode == 2 or bank[id][check_focus_hold(id)].enveloped == false then
if bank[id].focus_hold == false then
softcut.level_slew_time(id+1,1.0)
softcut.level(id+1,bank[id][check_focus_hold(id)].level*bank[id].global_level)
softcut.level_cut_cut(id+1,5,(bank[id][check_focus_hold(id)].left_delay_level*bank[id][check_focus_hold(id)].level)*bank[id].global_level)
softcut.level_cut_cut(id+1,6,(bank[id][check_focus_hold(id)].right_delay_level*bank[id][check_focus_hold(id)].level)*bank[id].global_level)
end
end
mc.mft_redraw(bank[id][check_focus_hold(id)],"pad_level")
elseif d.cc == 5 or d.cc == 21 or d.cc == 37 then
--bank level
local id = math.floor(d.cc/16)+1
bank[id].global_level = util.clamp(bank[id].global_level+(d.val == 63 and (d.ch == 1 and -0.01 or -0.001) or (d.ch == 1 and 0.01 or 0.001)),0,2)
if bank[id][check_focus_hold(id)].envelope_mode == 2 or bank[id][check_focus_hold(id)].enveloped == false then
if bank[id].focus_hold == false then
softcut.level_slew_time(id+1,1.0)
softcut.level(id+1,bank[id][check_focus_hold(id)].level*bank[id].global_level)
softcut.level_cut_cut(id+1,5,(bank[id][check_focus_hold(id)].left_delay_level*bank[id][check_focus_hold(id)].level)*bank[id].global_level)
softcut.level_cut_cut(id+1,6,(bank[id][check_focus_hold(id)].right_delay_level*bank[id][check_focus_hold(id)].level)*bank[id].global_level)
end
end
mc.mft_redraw(bank[id][check_focus_hold(id)],"bank_level")
elseif d.cc == 6 or d.cc == 22 or d.cc == 38 then
--pad semitones
local id = math.floor(d.cc/16)+1
local current_offset = (math.log(bank[id][check_focus_hold(id)].offset)/math.log(0.5))*-12
current_offset = util.clamp(current_offset+(d.val == 63 and -1 or 1)/32,-1,1)
if current_offset > -0.0001 and current_offset < 0.0001 then
current_offset = 0
end
bank[id][check_focus_hold(id)].offset = math.pow(0.5, -current_offset / 12)
if d.ch == 5 then
local this_pad = check_focus_hold(id)
for i = 1,16 do
bank[id][i].offset = bank[id][check_focus_hold(id)].offset
end
end
if bank[id][check_focus_hold(id)].pause == false and bank[id].id == check_focus_hold(id) then
if bank[id].focus_hold == false then
softcut.rate(id+1, bank[id][check_focus_hold(id)].rate*bank[id][check_focus_hold(id)].offset)
end
end
mc.mft_redraw(bank[id][check_focus_hold(id)],"pad_offset")
elseif d.cc == 7 or d.cc == 23 or d.cc == 39 then
--pad rate
local id = math.floor(d.cc/16)+1
local rates ={-4,-2,-1,-0.5,-0.25,-0.125,0,0.125,0.25,0.5,1,2,4}
if bank[id][check_focus_hold(id)].fifth then
bank[id][check_focus_hold(id)].fifth = false
end
if tab.key(rates,bank[id][check_focus_hold(id)].rate) == nil then
bank[id][check_focus_hold(id)].rate = 1
end
bank[id][check_focus_hold(id)].rate = rates[util.clamp(tab.key(rates,bank[id][check_focus_hold(id)].rate)+(d.val == 63 and -1 or 1),1,#rates)]
if d.ch == 5 then
local this_pad = check_focus_hold(id)
for i = 1,16 do
bank[id][i].rate = bank[id][check_focus_hold(id)].rate
end
end
if bank[id][check_focus_hold(id)].pause == false and bank[id].id == check_focus_hold(id) then
if bank[id].focus_hold == false then
softcut.rate(id+1, bank[id][check_focus_hold(id)].rate*bank[id][check_focus_hold(id)].offset)
end
end
mc.mft_redraw(bank[id][check_focus_hold(id)],"pad_rate")
elseif d.cc == 8 or d.cc == 24 or d.cc == 40 then
--pad / bank pan
local id = math.floor(d.cc/16)+1
if d.ch == 5 then
local pre_pan = bank[id][check_focus_hold(id)].pan
for i = 1,16 do
bank[id][i].pan = util.clamp(pre_pan+(d.val == 63 and -0.01 or 0.01),-1,1)
end
elseif d.ch == 1 then
bank[id][check_focus_hold(id)].pan = util.clamp(bank[id][check_focus_hold(id)].pan+(d.val == 63 and -0.01 or 0.01),-1,1)
end
softcut.pan(id+1, bank[id][check_focus_hold(id)].pan)
mc.mft_redraw(bank[id][check_focus_hold(id)],"pan")
elseif d.cc == 10 or d.cc == 26 or d.cc == 42 then
--bank / pad filter cutoff
local id = math.floor(d.cc/16)+1
if d.ch == 5 then
if slew_counter[id] ~= nil then
slew_counter[id].prev_tilt = bank[id][check_focus_hold(id)].tilt
end
bank[id][check_focus_hold(id)].tilt = util.clamp(bank[id][check_focus_hold(id)].tilt+(d.val == 63 and -0.01 or 0.01),-1,1)
if d.val == 63 then
if util.round(bank[id][check_focus_hold(id)].tilt*100) < 0 and util.round(bank[id][check_focus_hold(id)].tilt*100) > -9 then
bank[id][check_focus_hold(id)].tilt = -0.10
elseif util.round(bank[id][check_focus_hold(id)].tilt*100) > 0 and util.round(bank[id][check_focus_hold(id)].tilt*100) < 32 then
bank[id][check_focus_hold(id)].tilt = 0.0
end
elseif d.val == 65 and util.round(bank[id][check_focus_hold(id)].tilt*100) > 0 and util.round(bank[id][check_focus_hold(id)].tilt*100) < 32 then
bank[id][check_focus_hold(id)].tilt = 0.32
end
if bank[id].focus_hold == false then
slew_filter(id,slew_counter[id].prev_tilt,bank[id][check_focus_hold(id)].tilt,bank[id][check_focus_hold(id)].q,bank[id][check_focus_hold(id)].q,15)
end
elseif d.ch == 1 then
if slew_counter[id] ~= nil then
slew_counter[id].prev_tilt = bank[id][bank[id].id].tilt
end
for j = 1,16 do
bank[id][j].tilt = util.clamp(bank[id][j].tilt+(d.val == 63 and -0.01 or 0.01),-1,1)
if d.val == 63 then
if util.round(bank[id][j].tilt*100) < 0 and util.round(bank[id][j].tilt*100) > -9 then
bank[id][j].tilt = -0.10
elseif util.round(bank[id][j].tilt*100) > 0 and util.round(bank[id][j].tilt*100) < 32 then
bank[id][j].tilt = 0.0
end
elseif d.val == 65 and util.round(bank[id][j].tilt*100) > 0 and util.round(bank[id][j].tilt*100) < 32 then
bank[id][j].tilt = 0.32
end
end
if bank[id].focus_hold == false then
slew_filter(id,slew_counter[id].prev_tilt,bank[id][bank[id].id].tilt,bank[id][bank[id].id].q,bank[id][bank[id].id].q,15)
end
end
mc.mft_redraw(bank[id][check_focus_hold(id)],"filter_tilt")
elseif d.cc == 11 or d.cc == 27 or d.cc == 43 then
--bank / pad filter q
local id = math.floor(d.cc/16)+1
params:delta("filter "..id.." q",(d.val == 63 and -0.5 or 0.5)*-1)
mc.mft_redraw(bank[id][check_focus_hold(id)],"filter_q")
elseif d.cc == 12 or d.cc == 28 or d.cc == 44 then
-- pad / bank L delay send
local id = math.floor(d.cc/16)+1
local k = 3
local v = d.cc == 12 and 1 or (d.cc == 28 and 3 or 5)
local target = bank[id]
local prm = {"left_delay_level","right_delay_level"}
if d.ch == 5 then
for i = 1,16 do
target[i][prm[1]] = util.clamp(target[i][prm[1]] + (d.val == 63 and -0.1 or 0.1),0,1)
if delay_links[del.lookup_prm(k,v)] then
target[i][prm[1 == 1 and 2 or 1]] = target[i][prm[1]]
end
end
elseif d.ch == 1 then
target[check_focus_hold(id)][prm[1]] = util.clamp(target[check_focus_hold(id)][prm[1]] + d/10,0,1)
if delay_links[del.lookup_prm(k,v)] then
target[check_focus_hold(id)][prm[1 == 1 and 2 or 1]] = target[check_focus_hold(id)][prm[1]]
end
end
grid_dirty = true
if target[check_focus_hold(id)].enveloped == false then
softcut.level_cut_cut(util.round(item/2)+1,1+4,(target[check_focus_hold(id)][prm[1]]*target[check_focus_hold(id)].level)*target.global_level)
if delay_links[del.lookup_prm(k,v)] then
local this_one = 1 == 1 and 2 or 1
softcut.level_cut_cut(util.round(item/2)+1,(this_one)+4,(target[check_focus_hold(id)][prm[this_one]]*target[check_focus_hold(id)].level)*target.global_level)
end
end
end
elseif d.ch == 2 then
if d.cc == 0 or d.cc == 16 or d.cc == 32 then
local id = math.floor(d.cc/16)+1
bank[id].focus_hold = d.val == 127 and true or false
mc.mft_redraw(bank[id][check_focus_hold(id)],"all")
grid_dirty = true
end
elseif d.ch == 4 then
if d.val == 127 then
if d.cc == 0 or d.cc == 1 or d.cc == 2 then
mc.mft_redraw(bank[d.cc+1][check_focus_hold(d.cc+1)],"all")
end
end
end
end
end
end
end
midi_alt = false
midi_pat = {}
for i = 1,3 do
midi_pat[i] = pattern_time.new("midi_pat["..i.."]")
midi_pat[i].process = midi_pattern_execute
midi_pat[i].tightened_start = 0
midi_pat[i].auto_snap = 0
midi_pat[i].quantize = 0
midi_pat[i].playmode = 1
midi_pat[i].random_pitch_range = 5
midi_pat[i].clock_time = 4
midi_pat[i].rec_clock_time = 8
midi_pat[i].first_touch = false
end
for i = 1,3 do
arps.init(i)
end
for i = 1,3 do
rnd.init(i)
end
rytm.init()
if g then grid_dirty = true end
-- all_loaded = true
metro_persistent_state_restore = metro.init(persistent_state_restore, 0.1, 1)
metro_persistent_state_restore:start()
hardware_redraw = metro.init(
function()
if all_loaded then draw_grid() end
if all_loaded then arc_redraw() end
if all_loaded then draw_screen() end
end
, 1/30, -1)
hardware_redraw:start()
-- local file = io.open("/home/we/dust/data/cheat_codes_2/names/DEFAULT.cc2", "r")
-- if file == nil then
-- named_savestate("DEFAULT")
-- else
-- named_loadstate("/home/we/dust/data/cheat_codes_2/names/DEFAULT.cc2")
-- end
for i = 1,3 do
update_waveform(1,live[i].min,live[i].max,128)
end
end
---
function ping_midi_devices()
mft_connected = false
local midi_dev_max;
for k,v in pairs(midi.devices) do
midi_dev_max = midi.devices[k].id
end
for i = 1,midi_dev_max do
if midi.devices[i] ~= nil and midi.devices[i].name == "Midi Fighter Twister" then
params:set("midi_enc_control_enabled",2)
params:set("midi_enc_control_device",midi.devices[i].port ~= nil and midi.devices[i].port or 1)
params:set("midi_enc_echo_enabled",2)
mft_connected = true
end
-- if midi.devices[i] ~= nil and midi.devices[i].name == "OP-Z" then
-- params:set("midi_control_enabled",2)
-- params:set("midi_control_device",midi.devices[i].port)
-- params:set("midi_echo_enabled",2)
-- opz_connected = true
-- end
end
screen_dirty = true
if all_loaded and mft_connected then
for i = 1,3 do
mc.mft_redraw(bank[i][bank[i].id],"all")
end
end
end
function sync_clock_to_loop(source,style)
local dur = 0
local pattern_id;
if style == "audio" then
dur = source.end_point-source.start_point
elseif style == "pattern" then
pattern_id = string.match(source.name,"%d+")
if params:string("sync_clock_to_pattern_"..pattern_id) == "yes" then
for i = source.start_point,source.end_point do
dur = dur + source.time[i]
end
end
end
if dur > 0 then
local quarter = dur/4
local derived_bpm = 60/quarter
while derived_bpm < 70 do
derived_bpm = derived_bpm * 2
if derived_bpm > 160 then break end
end
while derived_bpm > 160 do
derived_bpm = derived_bpm/2
if derived_bpm <= 70 then break end
end
if params:get("clock_midi_out") ~= 1 then
params:set("clock_tempo",util.round(derived_bpm))
else
params:set("clock_tempo",util.round(derived_bpm,0.01))
end
end
end
function midi_pattern_watch(target,note)
if note ~= "pause" then
midi_p[target] = {}
midi_p[target].note = note
midi_p[target].target = target
midi_pat[target]:watch(midi_p[target])
else
midi_pat[target]:watch("pause")
end
end
function grid_pattern_watch(target,pad)
if pad ~= "pause" then
grid_p[target] = {}
grid_p[target].action = "pads"
grid_p[target].i = target
grid_p[target].id = selected[target].id
grid_p[target].x = selected[target].x
grid_p[target].y = selected[target].y
grid_p[target].rate = bank[target][bank[target].id].rate
grid_p[target].start_point = bank[target][bank[target].id].start_point
grid_p[target].end_point = bank[target][bank[target].id].end_point
grid_p[target].rate_adjusted = false
grid_p[target].loop = bank[target][bank[target].id].loop
grid_p[target].pause = bank[target][bank[target].id].pause
grid_p[target].mode = bank[target][bank[target].id].mode
grid_p[target].clip = bank[target][bank[target].id].clip
grid_pat[target]:watch(grid_p[target])
else
grid_pat[target]:watch("pause")
end
end
function midi_pattern_execute(entry)
if entry ~= nil then
if entry ~= "pause" then
mc.cheat(entry.target, entry.note)
-- midi_cheat(entry.note, entry.target)
end
end
end
function start_synced_loop(target)
if target.count > 0 then
--pattern_length_to_bars(target)
target.clock = clock.run(synced_loop, target)
end
end
function synced_loop(target, state)
--clock.sleep(clock.get_beat_sec()*target.rec_clock_time)
clock.sync(1)
if state == "restart" then
target:start()
end
--^ would this be problematic?
--clock.sync(4)
while true do
--print("syncing to..."..target.clock_time, clock.get_beats())
clock.sync(target.clock_time)
local overdub_flag = target.overdub
target:stop()
if overdub_flag == 1 then
target.overdub = 1
end
target:start()
end
end
function alt_synced_loop(target,state)
if state == "restart" then
clock.sync(params:get("launch_quantization") == 1 and 1 or 4)
print("restarting")
end
target:start()
target.synced_loop_runner = 1
print("alt_synced")
while true do
clock.sync(1/4)
if target.synced_loop_runner == target.rec_clock_time * 4 then
-- print(clock.get_beats(), target.synced_loop_runner)
local overdub_flag = target.overdub
target:stop()
if overdub_flag == 1 then
target.overdub = 1
end
target:start()
target.synced_loop_runner = 1
else
target.synced_loop_runner = target.synced_loop_runner + 1
end
end
end
function stop_pattern(target)
if target.clock ~= nil then
clock.cancel(target.clock)
end
target.clock = nil
target:stop()
end
function start_pattern(target)
print("new start")
if target.playmode == 2 then
target.clock = clock.run(alt_synced_loop, target, "restart")
else
target:start()
end
end
function synced_record_start(target,i)
--midi_pat[i].sync_hold = true
target.sync_hold = true
clock.sync(4)
--midi_pat[i]:rec_start()
target:rec_start()
--midi_pat[i].sync_hold = false
target.sync_hold = false
if target == midi_pat[i] then
midi_pattern_watch(i, "pause")
elseif target == grid_pat[i] then
grid_pattern_watch(i, "pause")
end
clock.run(synced_pattern_record,target)
end
function synced_pattern_record(target)
clock.sleep(clock.get_beat_sec()*target.rec_clock_time)
if target.rec_clock ~= nil then
target:rec_stop()
-- if target is a grid pat, should do all the grid pat thing:
--[[
midi_clock_linearize(i)
if grid_pat[i].auto_snap == 1 then
print("auto-snap")
snap_to_bars(i,how_many_bars(i))
end
grid_pat[i]:start()
grid_pat[i].loop = 1
--]]
pattern_length_to_bars(target, "destructive")
if target.time[1] ~= nil and target.time[1] < clock.get_beat_sec()/4 and target.event[1] == "pause" then
print("we could lose the first event..."..target.count, target.end_point)
local butts = 0
for i = 1,target.count do
butts = butts + target.time[i]
end
print(butts)
target.time[2] = target.time[2] + target.time[1]
target.time_beats[2] = target.time_beats[2] + target.time_beats[1]
table.remove(target.event,1)
table.remove(target.time,1)
table.remove(target.time_beats,1)
target.count = #target.event
target.end_point = target.count
print(target.count, target.end_point)
for i = 1,target.count do
target:calculate_quantum(i)
end
end
if target.count > 0 then -- just in case the recording was canceled...
--target:start()
print("started first run..."..clock.get_beats())
--target.clock = clock.run(synced_loop, target)
target.clock = clock.run(alt_synced_loop, target)
end
else
print("clock got canceled already, not going to restart it")
end
end
function quantize_pattern_times(target, resolution)
local goal = clock.get_beat_sec()/4
local adjusted = nil
for i = 1,target.count do
target.quantum[i]= util.round(target.time[i] / goal)
print("quantizes to "..target.quantum[i].." sixteenth notes")
--[[
if target.quantum[i] == 0 then
table.remove(target.event,i)
table.remove(target.time,i)
table.remove(target.quantum,i)
end
--]]
end
end
function pattern_length_to_bars(target, style)
if target.rec == 0 and target.count > 0 then
local total_time = 0
for i = target.start_point,target.end_point do
total_time = total_time + target.time[i]
end
local clean_bars_from_time = util.round(total_time/(clock.get_beat_sec()*4),0.25)
local add_time = ((clock.get_beat_sec()*4) * clean_bars_from_time) - total_time
print(add_time, clean_bars_from_time)
if style == "destructive" then
target.time[#target.event] = target.time[#target.event] + add_time
end
target.clock_time = 4 * clean_bars_from_time
end
end
function shuffle_midi_pat(target)
pattern = midi_pat[target]
for i = #pattern.event,2,-1 do
local j = math.random(i)
if pattern.event[j] ~= "pause" then
local original, shuffled = pattern.event[i], pattern.event[j]
original.note, shuffled.note = shuffled.note, original.note
original.target, shuffled.target = shuffled.target, original.target
end
end
end
function random_midi_pat(target)
local pattern = midi_pat[target]
local auto_pat = params:get("random_patterning_"..target)
if pattern.playmode == 2 then
--clock.sync(1/4)
--huh????
end
local count = auto_pat == 1 and math.random(4,24) or 16
if pattern.count > 0 or pattern.rec == 1 then
pattern:rec_stop()
stop_pattern(pattern)
pattern:clear()
end
for i = 1,count do
pattern.event[i] = {}
local constructed = pattern.event[i]
constructed.note = auto_pat == 1 and math.random(1,16) or snakes[auto_pat-1][i]
constructed.target = target
local assigning_pad = bank[target][constructed.note]
local new_rates =
{ [1] = math.pow(2,math.random(-3,-1))*((math.random(1,2)*2)-3)
, [2] = math.pow(2,math.random(-1,1))*((math.random(1,2)*2)-3)
, [3] = math.pow(2,math.random(1,2))*((math.random(1,2)*2)-3)
, [4] = math.pow(2,math.random(-2,2))*((math.random(1,2)*2)-3)
, [5] = assigning_pad.rate
}
assigning_pad.rate = new_rates[pattern.random_pitch_range]
local new_levels =
{ [0.125] = 1.75
, [0.25] = 1.5
, [0.5] = 1.25
, [1.0] = 1.0
, [2.0] = 0.75
, [4.0] = 0.5
}
assigning_pad.level = new_levels[math.abs(assigning_pad.rate)]
local tempo = clock.get_beat_sec()
local divisors = { 4,2,1,0.5,0.25,math.pow(2,math.random(-2,2)) }
local note_length = (tempo / divisors[params:get("rand_pattern_"..target.."_note_length")])
pattern.time[i] = note_length
pattern.time_beats[i] = pattern.time[i] / tempo
pattern:calculate_quantum(i)
end
pattern.count = count
pattern.start_point = 1
pattern.end_point = count
pattern_length_to_bars(pattern, "destructive")
start_pattern(pattern)
end
---
function pad_clock()
while true do
clock.sync(1)
for i = 1,3 do
cheat_clock_synced(i)
end
end
end
function random_rec_clock()
while true do
local lbr = {1,2,4}
local rler = rec_loop_enc_resolution
local rec_distance = rec[rec.focus].end_point - rec[rec.focus].start_point
local bar_count = params:get("rec_loop_enc_resolution") > 2 and (((rec_distance)/(1/rler)) / (rler))*(2*lbr[params:get("live_buff_rate")]) or (rec_distance/clock.get_beat_sec())/4
clock.sync(params:get("rec_loop_"..rec.focus) == 1 and 4 or bar_count)
local random_rec_prob = params:get("random_rec_clock_prob_"..rec.focus)
if random_rec_prob > 0 then
local random_rec_comp = math.random(0,100)
if random_rec_comp < random_rec_prob then
if params:get("rec_loop_"..rec.focus) == 1 then
toggle_buffer(rec.focus,true)
elseif params:get("rec_loop_"..rec.focus) == 2 and rec[rec.focus].end_point < poll_position_new[1] +0.015 then
toggle_buffer(rec.focus,true)
end
end
end
end
end
function run_one_shot_rec_clock()
one_shot_rec_clock = clock.run(one_shot_clock)
end
function cancel_one_shot_rec_clock()
clock.cancel(one_shot_rec_clock)
rec[rec.focus].state = 0
rec_state_watcher:stop()
rec.stopped = true
grid_dirty = true
if menu == 2 then
if page.loops.sel ~= 5 then
screen_dirty = true
end
end
one_shot_rec_clock = nil
end
function one_shot_clock()
if rec[rec.focus].state == 1 and rec_state_watcher.is_running then
rec_state_watcher:stop()
end
if params:get("one_shot_clock_div") < 3 then
local divs = {1,4}
local rate = divs[params:get("one_shot_clock_div")]
clock.sync(rate)
end
-- softcut.loop_start(1,rec[rec.focus].start_point-0.05)
softcut.pre_level(1,params:get("live_rec_feedback_"..rec.focus))
softcut.loop_start(1,rec[rec.focus].start_point-(params:get("one_shot_latency_offset")))
softcut.loop_end(1,rec[rec.focus].end_point-0.01)
softcut.position(1,rec[rec.focus].start_point-((params:get("one_shot_latency_offset")-0.01))) -- TODO CLARIFY IF THIS IS REAL ANYMORE
-- softcut.position(1,rec[rec.focus].start_point+0.01)
rec.play_segment = rec.focus
softcut.rec_level(1,1)
rec[rec.focus].state = 1
rec.stopped = false
rec_state_watcher:start()
if rec[rec.focus].clear == 1 then rec[rec.focus].clear = 0 end
grid_dirty = true
end
function compare_rec_resolution(x)
local current_mult = (rec[rec.focus].end_point - rec[rec.focus].start_point) / (1/rec_loop_enc_resolution)
local resolutions =
{ [1] = 10
, [2] = 100
, [3] = 1/(clock.get_beat_sec()/4)
, [4] = 1/(clock.get_beat_sec()/2)
, [5] = 1/(clock.get_beat_sec())
, [6] = (1/(clock.get_beat_sec()))/2
, [7] = (1/(clock.get_beat_sec()))/4
}
rec_loop_enc_resolution = resolutions[x]
if x > 2 then
local lbr = {1,2,4}
rec[rec.focus].end_point = rec[rec.focus].start_point + (((1/rec_loop_enc_resolution)*current_mult)/lbr[params:get("live_buff_rate")])
softcut.loop_start(1,rec[rec.focus].start_point)
softcut.loop_end(1,rec[rec.focus].end_point)
if menu ~= 1 then screen_dirty = true end
end
end
function compare_loop_resolution(target,x)
for i = 1,16 do
local pad = bank[target][i]
local resolutions =
{ [1] = 10
, [2] = 100
, [3] = 1/(clock.get_beat_sec()/4)
, [4] = 1/(clock.get_beat_sec()/2)
, [5] = 1/(clock.get_beat_sec())
, [6] = (1/(clock.get_beat_sec()))/2
, [7] = (1/(clock.get_beat_sec()))/4
}
loop_enc_resolution[pad.bank_id] = resolutions[x]
if x > 2 then
pad.end_point = pad.start_point + (((1/loop_enc_resolution[pad.bank_id])))
end
end
softcut.loop_start(target+1,bank[target][bank[target].id].start_point)
softcut.loop_end(target+1,bank[target][bank[target].id].end_point)
if menu ~= 1 then screen_dirty = true end
end
function globally_clocked()
while true do
clock.sync(1/4)
if menu == 7 then
if menu ~= 1 then screen_dirty = true end
end
update_tempo()
-- step_sequence()
for i = 1,3 do
step_sequence(i)
if grid_pat[i].led == nil then
grid_pat[i].led = 0
grid_dirty = true
end
if grid_pat[i].rec == 1 then
local blink = math.fmod(clock.get_beats(),1)
if blink <= 0.25 then
blink = 1
elseif blink <= 0.5 then
blink = 2
elseif blink <= 0.75 then
blink = 3
else
blink = 4
end
if blink == 1 then
grid_pat[i].led = 1
grid_dirty = true
else
grid_pat[i].led = 0
grid_dirty = true
end
end
end
for i = 1,3 do
if grid_pat[i].tightened_start == 1 then
internal_clocking_tightened(i)
end
end
-- print("butts")
-- grid_dirty = true
end
end
osc_in = function(path, args, from)
if osc_communication ~= true then
params:set("osc_IP",from[1])
params:set("osc_port",from[2])
osc_communication = true
end
for i = 1,3 do
local target = bank[i][bank[i].id]
if path == "/pad_sel_"..i then
if args[1] ~= 0 then
bank[i].id = util.round(args[1])
cheat(i,bank[i].id)
if menu ~= 1 then screen_dirty = true end
end
elseif path == "/randomize_this_bank_"..i then
random_grid_pat(i,3)
for j = 2,16 do
bank[i][j].start_point = (math.random(10,30)/10)+(8*(bank[i][j].clip-1))
bank[i][j].end_point = bank[i][j].start_point + (math.random(10,60)/10)
bank[i][j].pan = math.random(-100,100)/100
end
grid_pat[i]:rec_stop()
grid_pat[i]:stop()
grid_pat[i].tightened_start = 0
elseif path == "/pad_rate_"..i then
target.rate = args[1]
softcut.rate(i+1,target.rate)
elseif path == "/bank_rate_"..i then
for j = 1,16 do
bank[i][j].rate = args[1]
end
softcut.rate(i+1,target.rate)
elseif path == "/pad_rev_"..i then
target.rate = target.rate * - 1
softcut.rate(i+1,target.rate)
elseif path == "/bank_rev_"..i then
local direction;
if target.rate > 0 then
direction = 1
else
direction = -1
end
for j = 1,16 do
bank[i][j].rate = math.abs(bank[i][j].rate)*(-1*direction)
end
softcut.rate(i+1,target.rate)
elseif path == "/bank_rand_rate_"..i then
for j = 1,16 do
bank[i][j].rate = math.pow(2,math.random(-3,2))*((math.random(1,2)*2)-3)
end
softcut.rate(i+1,target.rate)
elseif path == "/sixteenths_"..i then
for j = 1,16 do
local pad = bank[i][j]
local duration = pad.mode == 1 and 8 or clip[pad.clip].sample_length
local s_p = pad.mode == 1 and live[pad.clip].min or clip[pad.clip].min
pad.end_point = pad.start_point + (clock.get_beat_sec()/4)
end
softcut.loop_start(i+1,target.start_point)
softcut.loop_end(i+1,target.end_point)
elseif path == "/chop_"..i then
for j = 1,16 do
local duration;
local pad = bank[i][j]
if pad.mode == 1 then
--slice within bounds
duration = rec[rec.focus].end_point-rec[rec.focus].start_point
local s_p = rec[rec.focus].start_point+(8*(pad.clip-1))
pad.start_point = (s_p+(duration/16) * (pad.pad_id-1))
pad.end_point = (s_p+((duration/16) * (pad.pad_id)))
else
duration = pad.mode == 1 and 8 or clip[pad.clip].sample_length
pad.start_point = ((duration/16)*(pad.pad_id-1)) + clip[pad.clip].min
pad.end_point = pad.start_point + (duration/16)
end
end
softcut.loop_start(i+1,target.start_point)
softcut.loop_end(i+1,target.end_point)
elseif path == "/rand_loop_points_"..i then
for j = 1,16 do
local duration, max_end, min_start;
local pad = bank[i][j]
if pad.mode == 1 and pad.clip == rec.focus then
duration = rec[rec.focus].end_point-rec[rec.focus].start_point
max_end = math.floor(pad.end_point * 100)-10
if max_end < math.floor(rec[rec.focus].start_point * 100) then
min_start = math.floor(((duration*(pad.clip-1))+1) * 100)
else
min_start = math.floor(rec[rec.focus].start_point * 100) -- this sucks...
end
elseif pad.mode == 2 then
max_end = math.floor(pad.end_point * 100)
min_start = math.floor(clip[pad.clip].min * 100)
else
duration = pad.mode == 1 and 8 or math.modf(clip[pad.clip].sample_length)
max_end = math.floor(pad.end_point * 100)
min_start = math.floor(((duration*(pad.clip-1))+1) * 100)
end
pad.start_point = math.random(min_start,max_end)/100
if pad.mode == 1 and pad.clip == rec.focus then
duration = rec[rec.focus].end_point-rec[rec.focus].start_point
max_end = math.floor(rec[rec.focus].end_point*100)
if pad.start_point > rec[rec.focus].start_point then
min_start = math.floor(pad.start_point * 100)+10
else
min_start = math.floor(rec[rec.focus].start_point * 100)
end
elseif pad.mode == 2 then
max_end = math.floor(clip[pad.clip].max * 100)
min_start = math.floor(pad.start_point * 100)
else
duration = util.round(clip[pad.clip].sample_length)
max_end = math.floor(((duration*pad.clip)+1) * 100)
min_start = math.floor(pad.start_point * 100)
end
pad.end_point = math.random(min_start,max_end)/100
end
softcut.loop_start(i+1,target.start_point)
softcut.loop_end(i+1,target.end_point)
end
end
end
osc.event = osc_in
function osc_redraw(i)
if osc_echo then
local target = bank[i][bank[i].id]
osc.send(dest, "/pad_start_point_"..i, {target.start_point})
osc.send(dest, "/pad_end_point_"..i, {target.end_point})
osc.send(dest, "/pad_rate_"..i, {target.rate})
-- local loop_to_osc = nil
-- if bank[i][bank[i].id].loop == false then
-- loop_to_osc = 0
-- else
-- loop_to_osc = 1
-- end
-- osc.send(dest, "/pad_loop_single_"..i, {loop_to_osc})
-- osc.send(dest, "/rate_"..i, {params:get("rate "..i)})
-- for j = 7,12 do
-- osc.send(dest, "/rate_"..i.."_"..j, {0})
-- end
-- if params:get("rate "..i) > 6 then
-- osc.send(dest, "/rate_"..i.."_"..params:get("rate "..i), {1})
-- osc.send(dest, "/rate_rev_"..i,{0})
-- else
-- osc.send(dest, "/rate_"..i.."_"..math.abs(params:get("rate "..i)-13), {1})
-- osc.send(dest, "/rate_rev_"..i,{1})
-- end
-- -- osc.send(dest, "/pad_start_"..i, {(bank[i][bank[i].id].start_point*100)-((8*(bank[i][bank[i].id].clip-1))*100)})
-- osc.send(dest, "/pad_start_"..i, {(bank[i][bank[i].id].start_point)})
-- -- osc.send(dest, "/pad_start_display_"..i, {tonumber(string.format("%.2f",(bank[i][bank[i].id].start_point) - (8*(bank[i][bank[i].id].clip-1))))})
-- -- osc.send(dest, "/pad_end_"..i, {(bank[i][bank[i].id].end_point*100)-((8*(bank[i][bank[i].id].clip-1))*100)})
-- osc.send(dest, "/pad_end_"..i, {(bank[i][bank[i].id].end_point)})
-- osc.send(dest, "/pad_end_display_"..i, {tonumber(string.format("%.2f",bank[i][bank[i].id].end_point - (8*(bank[i][bank[i].id].clip-1))))})
-- for j = 1,16 do
-- osc.send(dest, "/pad_sel_"..i.."_"..j, {0})
-- end
-- osc.send(dest, "/pad_sel_"..i.."_"..bank[i].id, {1})
-- local rec_state_to_osc = nil
-- if rec[rec.focus].state == 0 then
-- rec_state_to_osc = "not recording"
-- else
-- rec_state_to_osc = "recording"
-- end
-- osc.send(dest, "/buffer_state", {rec_state_to_osc})
-- for j = 1,3 do
-- if rec.focus ~= j then
-- osc.send(dest, "/buffer_LED_"..j, {0})
-- else
-- osc.send(dest, "/buffer_LED_"..rec.focus, {1})
-- end
-- end
end
end
poll_position_new = {}
phase = function(n, x)
poll_position_new[n] = x
if menu == 2 then
local rec_on = 0;
for i = 1,3 do
if rec[i].state == 1 then
rec_on = i
end
end
if rec_on ~= 0 and rec[rec_on].state == 1 then
if page.loops.sel ~= 4 then
local pad = bank[page.loops.sel][bank[page.loops.sel].id]
update_waveform(1,key1_hold and pad.start_point or live[rec_on].min,key1_hold and pad.end_point or live[rec_on].max,128)
elseif page.loops.sel == 4 then
update_waveform(1,key1_hold and rec[rec.focus].start_point or live[rec_on].min,key1_hold and rec[rec.focus].end_point or live[rec_on].max,128)
end
end
screen_dirty = true
-- if page.loops.sel ~= 5 then screen_dirty = true end
end
end
local tap = 0
local deltatap = 1
function update_tempo()
local pre_bpm = bpm
params:set("bpm", util.round(clock.get_tempo()))
bpm = params:get("bpm") -- FIXME this is where the global bpm is defined
local t = params:get("bpm")
local d = params:get("quant_div")
local d_pat = params:get("quant_div_pats")
local interval = (60/t) / d
local interval_pats = (60/t) / d_pat
if pre_bpm ~= bpm then
compare_rec_resolution(params:get("rec_loop_enc_resolution"))
for i = 1,3 do
compare_loop_resolution(i,params:get("loop_enc_resolution_"..i))
end
if math.abs(pre_bpm - bpm) >= 1 then
--print("a change in time!")
end
end
for i = 1,3 do
--quantizer[i].time = interval
--grid_pat_quantizer[i].time = interval_pats
end
end
function rec_count()
rec_time = rec_time + 0.01
end
function step_sequence(i)
-- for i = 1,3 do
if step_seq[i].active == 1 then
step_seq[i].meta_step = step_seq[i].meta_step + 1
if step_seq[i].meta_step > step_seq[i].meta_duration then step_seq[i].meta_step = 1 end
if step_seq[i].meta_step == 1 then
step_seq[i].meta_meta_step = step_seq[i].meta_meta_step + 1
if step_seq[i].meta_meta_step > step_seq[i][step_seq[i].current_step].meta_meta_duration then step_seq[i].meta_meta_step = 1 end
if step_seq[i].meta_meta_step == 1 then
step_seq[i].current_step = step_seq[i].current_step + 1
if step_seq[i].current_step > step_seq[i].end_point then step_seq[i].current_step = step_seq[i].start_point end
local current = step_seq[i].current_step
if grid_pat[i].rec == 0 and step_seq[i][current].assigned_to ~= 0 then
pattern_saver[i].load_slot = step_seq[i][current].assigned_to
test_load(step_seq[i][current].assigned_to+((i-1)*8),i)
grid_pat[i].loop = step_seq[i][current].loop_pattern
end
end
end
end
-- end
if grid_page == 1 then
grid_dirty = true
end
end
function sixteen_slices(x)
local s_p = rec[rec.focus].start_point
local e_p = rec[rec.focus].end_point
local distance = e_p-s_p
local b = bank[x]
local pad = b.focus_hold and b.focus_pad or b.id
local function map_em(i)
b[i].start_point = s_p+((distance/16) * (i-1))
b[i].end_point = s_p+((distance/16) * (i))
b[i].clip = rec.focus
end
if not b.focus_hold then
for i = 1,16 do
map_em(i)
end
else
map_em(pad)
end
if b[b.id].loop == true then
cheat(x,b.id)
end
end
function rec_to_pad(b)
local s_p = rec[rec.focus].start_point
local e_p = rec[rec.focus].end_point
local distance = e_p-s_p
bank[b][bank[b].id].start_point = s_p+((distance/16) * (bank[b].id-1))
bank[b][bank[b].id].end_point = s_p+((distance/16) * (bank[b].id))
bank[b][bank[b].id].clip = rec.focus
if bank[b][bank[b].id].loop == true then
cheat(b,bank[b].id)
end
end
function pad_to_rec(b)
local pad = bank[b][bank[b].id]
local s_p = pad.start_point-(8*(pad.clip-1))
local e_p = pad.end_point-(8*(pad.clip-1))
rec[rec.focus].start_point = s_p+(8*(rec.focus-1))
rec[rec.focus].end_point = e_p+(8*(rec.focus-1))
softcut.loop_start(1,rec[rec.focus].start_point)
softcut.loop_end(1,rec[rec.focus].end_point-0.01)
softcut.position(1,rec[rec.focus].start_point)
end
function reset_all_banks( banks )
cross_filter = {} -- TODO put into the banks
for i = 1,3 do
banks[i] = {}
local b = banks[i] -- alias
b.id = 1 -- currently playing pad_id
b.ext_clock = 1
b.focus_hold = false
b.focus_pad = 1
b.random_mode = 3
b.crow_execute = 1
b.snap_to_bars = 1
b.quantize_press = 0
b.quantize_press_div = 1
b.alt_lock = false
b.global_level = 1.0
for k = 1,16 do
-- TODO suggest nesting tables for delay,filter,tilt etc
b[k] = {}
local pad = b[k] --alias
pad.bank_id = i -- capture which bank we're in
pad.pad_id = k -- capture which pad of 16
pad.clip = 1 -- TODO make this a table with length for start/end calculation
pad.mode = 1
-- TODO these are both identical to zilchmos.start_end_default()
pad.start_point = 1+((8/16) * (pad.pad_id-1))
pad.end_point = 1+((8/16) * pad.pad_id)
pad.sample_end = 8
pad.rate = 1.0
pad.left_delay_time = 0.5 -- [delay] controls these
pad.right_delay_time = 0.5 -- [delay] controls these
pad.pause = false
pad.play_mode = "latch"
pad.level = 1.0
pad.left_delay_level = 1
pad.right_delay_level = 1
pad.loop = false
pad.fifth = false
pad.pan = 0.0
-- FIXME these are both just 0.5. why compute them? could instead call that fn?
pad.left_delay_pan = util.linlin(-1,1,0,1,pad.pan) * pad.left_delay_level
pad.right_delay_pan = util.linlin(-1,1,1,0,pad.pan) * pad.right_delay_level
pad.fc = 12000
pad.q = 2.0
pad.lp = 1.0
pad.hp = 0.0
pad.bp = 0.0
pad.fd = 0.0
pad.br = 0.0
pad.tilt = 0
pad.tilt_ease_type = 1
pad.tilt_ease_time = 50
pad.cf_fc = 12000
pad.cf_lp = 0
pad.cf_hp = 0
pad.cf_dry = 1
pad.cf_exp_dry = 1
pad.filter_type = 4
pad.enveloped = false
pad.envelope_mode = 0
pad.envelope_time = 3.0
pad.envelope_loop = false
pad.clock_resolution = 4
pad.offset = 1.0
pad.crow_pad_execute = 1
pad.left_delay_thru = false
pad.right_delay_thru = false
pad.rate_slew = 0
pad.arp_time = 1/4
end
cross_filter[i] = {}
cross_filter[i].fc = 12000
cross_filter[i].lp = 0
cross_filter[i].hp = 0
cross_filter[i].dry = 1
cross_filter[i].exp_dry = 1
cheat(i,bank[i].id)
end
end
function find_the_key(t,val)
for k,v in pairs(t) do
if v == val then return k end
end
return nil
end
function cheat(b,i)
local pad = bank[b][i]
if all_loaded then
mc.midi_note_from_pad(util.round(b),util.round(i))
mc.route_midi_mod(b,i)
end
if env_counter[b].is_running then
env_counter[b]:stop()
end
softcut.rate_slew_time(b+1,pad.rate_slew)
if pad.enveloped and not pad.pause then
if pad.envelope_mode == 1 then
env_counter[b].butt = pad.level
env_counter[b].l_del_butt = pad.left_delay_level
env_counter[b].r_del_butt = pad.right_delay_level
softcut.level_slew_time(b+1,0.05)
softcut.level(b+1,pad.level*bank[b].global_level)
softcut.level_cut_cut(b+1,5,(pad.level*bank[b].global_level)*pad.left_delay_level)
softcut.level_cut_cut(b+1,6,(pad.level*bank[b].global_level)*pad.right_delay_level)
elseif pad.envelope_mode == 2 or pad.envelope_mode == 3 then
softcut.level_slew_time(b+1,0.01)
softcut.level(b+1,0*bank[b].global_level)
softcut.level_cut_cut(b+1,5,0)
softcut.level_cut_cut(b+1,6,0)
env_counter[b].butt = 0
env_counter[b].l_del_butt = 0
env_counter[b].r_del_butt = 0
if pad.envelope_mode == 3 then env_counter[b].stage = "rising" end
end
env_counter[b].time = (pad.envelope_time/(pad.level/0.05))
env_counter[b]:start()
elseif not pad.enveloped and not pad.pause then
softcut.level_slew_time(b+1,0.1)
softcut.level(b+1,pad.level*bank[b].global_level)
if not delay[1].send_mute then
if pad.left_delay_thru then
softcut.level_cut_cut(b+1,5,pad.left_delay_level)
else
softcut.level_cut_cut(b+1,5,(pad.left_delay_level*pad.level)*bank[b].global_level)
end
end
if not delay[2].send_mute then
if pad.right_delay_thru then
softcut.level_cut_cut(b+1,6,pad.right_delay_level)
else
softcut.level_cut_cut(b+1,6,(pad.right_delay_level*pad.level)*bank[b].global_level)
end
end
end
-- OH ALL THIS SUCKS TODO FIXME
-- if pad.end_point - pad.start_point < 0.11 then
-- pad.end_point = pad.start_point + 0.1
-- end
if pad.mode == 1 then
if pad.end_point == 9 or pad.end_point == 17 or pad.end_point == 25 then
pad.end_point = pad.end_point-0.01
end
end
--/ OH ALL THIS SUCKS TODO FIXME
softcut.fade_time(b+1,variable_fade_time)
softcut.loop_start(b+1,pad.start_point-variable_fade_time)
softcut.loop_end(b+1,pad.end_point-variable_fade_time)
softcut.buffer(b+1,pad.mode)
if pad.pause == false then
softcut.rate(b+1,pad.rate*pad.offset)
else
softcut.rate(b+1,0)
end
if pad.loop == false then
softcut.loop(b+1,0)
else
softcut.loop(b+1,1)
end
if pad.rate > 0 then
-- softcut.position(b+1,pad.start_point+0.05)
softcut.position(b+1,pad.start_point-variable_fade_time)
elseif pad.rate < 0 then
-- softcut.position(b+1,pad.end_point-variable_fade_time-0.05)
softcut.position(b+1,pad.end_point-variable_fade_time)
end
if slew_counter[b] ~= nil then
slew_counter[b].next_tilt = pad.tilt
slew_counter[b].next_q = pad.q
if pad.tilt_ease_type == 1 then
if slew_counter[b].slewedVal ~= nil and math.floor(slew_counter[b].slewedVal*10000) ~= math.floor(slew_counter[b].next_tilt*10000) then
if math.floor(slew_counter[b].prev_tilt*10000) ~= math.floor(slew_counter[b].slewedVal*10000) then
slew_counter[b].interrupted = 1
slew_filter(util.round(b),slew_counter[b].slewedVal,slew_counter[b].next_tilt,slew_counter[b].prev_q,slew_counter[b].next_q,pad.tilt_ease_time)
else
slew_counter[b].interrupted = 0
slew_filter(util.round(b),slew_counter[b].prev_tilt,slew_counter[b].next_tilt,slew_counter[b].prev_q,slew_counter[b].next_q,pad.tilt_ease_time)
end
end
elseif pad.tilt_ease_type == 2 then
slew_filter(util.round(b),slew_counter[b].prev_tilt,slew_counter[b].next_tilt,slew_counter[b].prev_q,slew_counter[b].next_q,pad.tilt_ease_time)
end
end
softcut.pan(b+1,pad.pan)
update_delays()
if slew_counter[b] ~= nil then
slew_counter[b].prev_tilt = pad.tilt
slew_counter[b].prev_q = pad.q
end
previous_pad = bank[b].id
if bank[b].crow_execute == 1 then
if pad.crow_pad_execute == 1 then
crow.output[b]()
end
end
--dangerous??
local rate_array = {-4.0,-2.0,-1.0,-0.5,-0.25,-0.125,0.125,0.25,0.5,1.0,2.0,4.0}
local s = {}
for k,v in pairs(rate_array) do
s[v]=k
end
if pad.fifth == false then
if s[pad.rate] ~= nil then
params:set("rate "..tonumber(string.format("%.0f",b)),s[pad.rate],true) -- TODO: confirm silent update is good...
else
pad.fifth = true
end
end
mc.params_redraw(pad)
if osc_communication == true then
osc_redraw(b)
end
if all_loaded and params:get("midi_control_enabled") == 1 and params:get("midi_echo_enabled") == 2 then
mc.redraw(pad)
end
if all_loaded and params:get("midi_enc_echo_enabled") == 2 then
if midi_dev[params:get("midi_enc_control_device")].name == "Midi Fighter Twister" then
if bank[pad.bank_id].focus_hold == false then
mc.mft_redraw(pad,"all")
end
else
mc.enc_redraw(pad)
end
end
-- redraw waveform if it's zoomed in and the pad changes
if menu == 2 and page.loops.sel == b and page.loops.frame == 2 and not key2_hold and key1_hold then
local focused_pad;
if bank[page.loops.sel].focus_hold then
focused_pad = bank[page.loops.sel].focus_pad
elseif grid_pat[page.loops.sel].play == 0 and midi_pat[page.loops.sel].play == 0 and not arp[page.loops.sel].playing and rytm.track[page.loops.sel].k == 0 then
focused_pad = bank[page.loops.sel].id
else
focused_pad = bank[page.loops.sel].focus_pad
end
local mode = bank[page.loops.sel][focused_pad].mode
local min = bank[page.loops.sel][focused_pad].start_point
local max = bank[page.loops.sel][focused_pad].end_point
update_waveform(mode,min,max,128)
end
end
function envelope(i)
-- softcut.level_slew_time(i+1,0.1)
if bank[i][bank[i].id].envelope_mode == 1 then
falling_envelope(i)
elseif bank[i][bank[i].id].envelope_mode == 2 then
rising_envelope(i)
elseif bank[i][bank[i].id].envelope_mode == 3 then
if env_counter[i].stage == nil then env_counter[i].stage = "rising" end
if env_counter[i].stage == "rising" then
rising_envelope(i)
elseif env_counter[i].stage == "falling" then
falling_envelope(i)
end
end
end
function falling_envelope(i)
if env_counter[i].butt > 0.05 then
env_counter[i].butt = env_counter[i].butt - 0.05
else
env_counter[i].butt = 0
end
if env_counter[i].butt > 0 then
softcut.level_slew_time(i+1,0.05)
softcut.level(i+1,env_counter[i].butt*bank[i].global_level)
-- softcut.level_cut_cut(i+1,5,(env_counter[i].butt*bank[i].global_level)*bank[i][bank[i].id].left_delay_level)
-- softcut.level_cut_cut(i+1,6,(env_counter[i].butt*bank[i].global_level)*bank[i][bank[i].id].right_delay_level)
if delay[1].send_mute then
if bank[i][bank[i].id].left_delay_level == 0 then
softcut.level_cut_cut(i+1,5,(env_counter[i].butt*bank[i].global_level)*1)
else
softcut.level_cut_cut(i+1,5,(env_counter[i].butt*bank[i].global_level)*0)
end
else
softcut.level_cut_cut(i+1,5,(env_counter[i].butt*bank[i].global_level)*bank[i][bank[i].id].left_delay_level)
end
if delay[2].send_mute then
if bank[i][bank[i].id].right_delay_level == 0 then
softcut.level_cut_cut(i+1,6,(env_counter[i].butt*bank[i].global_level)*1)
else
softcut.level_cut_cut(i+1,6,(env_counter[i].butt*bank[i].global_level)*0)
end
else
softcut.level_cut_cut(i+1,6,(env_counter[i].butt*bank[i].global_level)*bank[i][bank[i].id].right_delay_level)
end
else
env_counter[i]:stop()
softcut.level_slew_time(i+1,1.0)
softcut.level(i+1,0*bank[i].global_level)
env_counter[i].butt = bank[i][bank[i].id].level
softcut.level_cut_cut(i+1,5,0)
softcut.level_cut_cut(i+1,6,0)
if bank[i][bank[i].id].envelope_mode == 3 then
env_counter[i].stage = nil
env_counter[i].butt = 0
end
if bank[i][bank[i].id].envelope_loop == true then
env_counter[i]:start()
end
end
end
function rising_envelope(i)
env_counter[i].butt = env_counter[i].butt + 0.05
if env_counter[i].butt < bank[i][bank[i].id].level then
softcut.level_slew_time(i+1,0.1)
softcut.level(i+1,env_counter[i].butt*bank[i].global_level)
-- softcut.level_cut_cut(i+1,5,env_counter[i].butt*(bank[i][bank[i].id].left_delay_level*bank[i].global_level))
-- softcut.level_cut_cut(i+1,6,env_counter[i].butt*(bank[i][bank[i].id].right_delay_level*bank[i].global_level))
if delay[1].send_mute then
if bank[i][bank[i].id].left_delay_level == 0 then
softcut.level_cut_cut(i+1,5,(env_counter[i].butt*bank[i].global_level)*1)
else
softcut.level_cut_cut(i+1,5,(env_counter[i].butt*bank[i].global_level)*0)
end
else
softcut.level_cut_cut(i+1,5,(env_counter[i].butt*bank[i].global_level)*bank[i][bank[i].id].left_delay_level)
end
if delay[2].send_mute then
if bank[i][bank[i].id].right_delay_level == 0 then
softcut.level_cut_cut(i+1,6,(env_counter[i].butt*bank[i].global_level)*1)
else
softcut.level_cut_cut(i+1,6,(env_counter[i].butt*bank[i].global_level)*0)
end
else
softcut.level_cut_cut(i+1,6,(env_counter[i].butt*bank[i].global_level)*bank[i][bank[i].id].right_delay_level)
end
else
env_counter[i]:stop()
softcut.level(i+1,bank[i][bank[i].id].level*bank[i].global_level)
env_counter[i].butt = 0
if bank[i][bank[i].id].left_delay_thru then
softcut.level_cut_cut(i+1,5,bank[i][bank[i].id].left_delay_level)
else
softcut.level_cut_cut(i+1,5,(bank[i][bank[i].id].left_delay_level*bank[i][bank[i].id].level)*bank[i].global_level)
end
if bank[i][bank[i].id].right_delay_thru then
softcut.level_cut_cut(i+1,6,bank[i][bank[i].id].left_delay_level)
else
softcut.level_cut_cut(i+1,6,(bank[i][bank[i].id].left_delay_level*bank[i][bank[i].id].level)*bank[i].global_level)
end
softcut.level_slew_time(i+1,1.0)
if bank[i][bank[i].id].envelope_mode == 3 then
env_counter[i].stage = "falling"
softcut.level_slew_time(i+1,0.05)
env_counter[i].butt = bank[i][bank[i].id].level
env_counter[i].time = (bank[i][bank[i].id].envelope_time/(bank[i][bank[i].id].level/0.05))
env_counter[i]:start()
end
if bank[i][bank[i].id].envelope_loop == true then
env_counter[i]:start()
end
end
end
function slew_filter(i,prevVal,nextVal,prevQ,nextQ,count)
slew_counter[i]:stop()
slew_counter[i].current = 0
slew_counter[i].count = count
slew_counter[i].duration = (slew_counter[i].count/100)-0.01
slew_counter[i].beginVal = prevVal
slew_counter[i].endVal = nextVal
slew_counter[i].change = slew_counter[i].endVal - slew_counter[i].beginVal
slew_counter[i].beginQ = prevQ
slew_counter[i].endQ = nextQ
slew_counter[i].changeQ = slew_counter[i].endQ - slew_counter[i].beginQ
slew_counter[i]:start()
end
function easing_slew(i)
slew_counter[i].slewedVal = slew_counter[i].ease(slew_counter[i].current,slew_counter[i].beginVal,slew_counter[i].change,slew_counter[i].duration)
slew_counter[i].slewedQ = slew_counter[i].ease(slew_counter[i].current,slew_counter[i].beginQ,slew_counter[i].changeQ,slew_counter[i].duration)
slew_counter[i].current = slew_counter[i].current + 0.01
if grid.alt then
try_tilt_process(i,bank[i].id,slew_counter[i].slewedVal,slew_counter[i].slewedQ)
else
for j = 1,16 do
try_tilt_process(i,j,slew_counter[i].slewedVal,slew_counter[i].slewedQ)
end
end
if menu == 5 then
if menu ~= 1 then screen_dirty = true end
end
end
function try_tilt_process(b,i,t,rq)
if util.round(t*100) < 0 then
local trill = math.abs(t)
bank[b][i].cf_lp = math.abs(t)
bank[b][i].cf_dry = 1+t
if util.round(t*100) >= -24 then
bank[b][i].cf_exp_dry = (util.linexp(0,1,1,101,bank[b][i].cf_dry)-1)/100
elseif util.round(t*100) <= -24 and util.round(t*100) >= -50 then
bank[b][i].cf_exp_dry = (util.linexp(0.4,1,1,101,bank[b][i].cf_dry)-1)/100
elseif util.round(t*100) < -50 then
bank[b][i].cf_exp_dry = 0
end
bank[b][i].cf_fc = util.linexp(0,1,16000,10,bank[b][i].cf_lp)
params:set("filter "..b.." cutoff",bank[b][i].cf_fc)
params:set("filter "..b.." lp", math.abs(bank[b][i].cf_exp_dry-1))
params:set("filter "..b.." dry", bank[b][i].cf_exp_dry)
if params:get("filter "..b.." hp") ~= 0 then
params:set("filter "..b.." hp", 0)
end
if bank[b][i].cf_hp ~= 0 then
bank[b][i].cf_hp = 0
end
elseif util.round(t*100) > 0 then
bank[b][i].cf_hp = math.abs(t)
bank[b][i].cf_fc = util.linexp(0,1,10,12000,bank[b][i].cf_hp)
bank[b][i].cf_dry = 1-t
bank[b][i].cf_exp_dry = (util.linexp(0,1,1,101,bank[b][i].cf_dry)-1)/100
params:set("filter "..b.." cutoff",bank[b][i].cf_fc)
params:set("filter "..b.." hp", math.abs(bank[b][i].cf_exp_dry-1))
params:set("filter "..b.." dry", bank[b][i].cf_exp_dry)
if params:get("filter "..b.." lp") ~= 0 then
params:set("filter "..b.." lp", 0)
end
if bank[b][i].cf_lp ~= 0 then
bank[b][i].cf_lp = 0
end
elseif util.round(t*100) == 0 then
bank[b][i].cf_fc = 12000
bank[b][i].cf_lp = 0
bank[b][i].cf_hp = 0
bank[b][i].cf_dry = 1
bank[b][i].cf_exp_dry = 1
params:set("filter "..b.." cutoff",12000)
params:set("filter "..b.." lp", 0)
params:set("filter "..b.." hp", 0)
params:set("filter "..b.." dry", 1)
end
softcut.post_filter_rq(b+1,rq)
end
function buff_freeze()
softcut.recpre_slew_time(1,0.5)
softcut.level_slew_time(1,0.5)
softcut.fade_time(1,0.01)
rec[rec.focus].state = (rec[rec.focus].state + 1)%2
softcut.rec_level(1,rec[rec.focus].state)
if rec[rec.focus].state == 1 then
softcut.pre_level(1,params:get("live_rec_feedback_"..rec.focus))
else
softcut.pre_level(1,1)
end
end
function buff_flush()
softcut.buffer_clear_region_channel(1,rec[rec.focus].start_point, rec[rec.focus].end_point-rec[rec.focus].start_point)
rec[rec.focus].state = 0
rec[rec.focus].clear = 1
softcut.rec_level(1,0)
update_waveform(1,rec[rec.focus].start_point, rec[rec.focus].end_point,128)
grid_dirty = true
end
function buff_pause()
rec[rec.focus].pause = not rec[rec.focus].pause
softcut.rate(1,rec[rec.focus].pause and 0 or 1) -- TODO make this dynamic to include rec rate offsets
end
function toggle_buffer(i,untrue_alt)
grid_dirty = true
softcut.level_slew_time(1,0.5)
softcut.fade_time(1,0.01)
local old_clip = rec.focus
for j = 1,3 do
if j ~= i then
rec[j].state = 0
end
end
rec.focus = i
if rec[rec.focus].loop == 0 and not grid.alt then
if rec[rec.focus].state == 0 then
run_one_shot_rec_clock() -- this runs only if not recording
elseif rec[rec.focus].state == 1 and rec_state_watcher.is_running then -- can have both conditions, right?
cancel_one_shot_rec_clock()
end
elseif rec[rec.focus].loop == 0 and (grid.alt and untrue_alt ~= nil) then
-- buff_flush()
elseif rec[rec.focus].loop == 1 and not grid.alt then
if one_shot_rec_clock ~= nil then
cancel_one_shot_rec_clock()
end
end
softcut.loop_start(1,rec[rec.focus].start_point)
softcut.loop_end(1,rec[rec.focus].end_point-0.01)
rec.play_segment = rec.focus
softcut.loop(1,rec[rec.focus].loop)
if rec.stopped == true then
rec.stopped = false
if rec[rec.focus].loop == 1 then
softcut.position(1,rec[rec.focus].start_point)
end
end
if rec[rec.focus].loop == 1 then
if old_clip ~= rec.focus then rec[rec.focus].state = 0 end
buff_freeze()
if rec[rec.focus].clear == 1 then
rec[rec.focus].clear = 0
end
end
grid_dirty = true
update_waveform(1,key1_hold and rec[rec.focus].start_point or live[rec.focus].min,key1_hold and rec[rec.focus].end_point or live[rec.focus].max,128)
end
function update_delays()
for i = 1,2 do
if delay[i].mode == "clocked" then
local delay_rate_to_time = clock.get_beat_sec() * delay[i].clocked_length * delay[i].modifier
local delay_time = delay_rate_to_time + (41 + (30*(i-1)))
delay[i].end_point = delay_time
softcut.loop_end(i+4,delay[i].end_point)
else
softcut.loop_end(i+4,delay[i].free_end_point)
end
end
end
function sample_callback(path,i)
if path ~= "cancel" and path ~= "" then
load_sample(path,i)
end
_norns.key(1,1)
_norns.key(1,0)
key1_hold = false
end
function load_sample(file,sample)
local old_min = clip[sample].min
local old_max = clip[sample].max
if file ~= "-" then
local ch, len = audio.file_info(file)
if len/48000 < 32 then
clip[sample].sample_length = len/48000
else
clip[sample].sample_length = 32
end
softcut.buffer_clear_region_channel(2,1+(32*(sample-1)),32)
softcut.buffer_read_mono(file, 0, 1+(32*(sample-1)),clip[sample].sample_length + 0.05, 1, 2)
clip_table()
for p = 1,16 do
for b = 1,3 do
if bank[b][p].mode == 2 and bank[b][p].clip == sample and pre_cc2_sample[b] == false then
scale_loop_points(bank[b][p], old_min, old_max, clip[sample].min, clip[sample].max)
end
end
end
end
for i = 1,3 do
pre_cc2_sample[i] = false
end
update_waveform(2,clip[sample].min,clip[sample].max,128)
clip[sample].waveform_samples = waveform_samples
if params:get("clip "..sample.." sample") ~= file then
params:set("clip "..sample.." sample", file, 1)
end
end
function save_sample(i)
local dirname = _path.dust.."audio/cc2_saved_samples/"
if os.rename(dirname, dirname) == nil then
os.execute("mkdir " .. dirname)
end
local name = "cc2_"..os.date("%y%m%d_%X-buff")..i..".wav"
local save_pos = i - 1
softcut.buffer_write_mono(_path.dust.."/audio/cc2_saved_samples/"..name,1+(8*save_pos),8,1)
end
function collect_samples(i,collection) -- this works!!!
local dirname = _path.dust.."audio/cc2_live-audio/"
if os.rename(dirname, dirname) == nil then
os.execute("mkdir " .. dirname)
end
local dirname = _path.dust.."audio/cc2_live-audio/"..collection.."/"
if os.rename(dirname, dirname) == nil then
os.execute("mkdir " .. dirname)
end
local name = "cc2_"..collection.."-"..i..".wav"
local save_pos = i - 1
softcut.buffer_write_mono(_path.dust.."audio/cc2_live-audio/"..collection.."/"..name,1+(8*save_pos),8,1)
end
function reload_collected_samples(file,sample)
if rec[rec.focus].state == 1 then
buff_freeze()
end
if file ~= "-" then
softcut.buffer_read_mono(file, 0, 1+(8 * (sample-1)), 8, 1, 1)
print("reloaded previous session's audio")
end
end
function adjust_key1_timing()
if menu == 1 then
metro[31].time = 0.25
elseif menu ~= 6 then
if metro[31].time ~= 0.1 then metro[31].time = 0.1 end
elseif menu == 6 then
if page.delay[page.delay_focus].menu == 1 and page.delay[page.delay_focus].menu_sel[page.delay[page.delay_focus].menu] == 5 then
metro[31].time = 0.01
else
if metro[31].time ~= 0.1 then metro[31].time = 0.1 end
end
-- else
-- metro[31].time = 0.01
end
end
function midi_pattern_recording(id,state)
if state == "start" then
if midi_pat[id].playmode == 1 then
midi_pat[id]:rec_start()
else
midi_pat[id].rec_clock = clock.run(synced_record_start,midi_pat[id],id)
end
elseif state == "stop" then
midi_pat[id]:rec_stop()
if midi_pat[id].playmode == 1 then
start_pattern(midi_pat[id])
elseif midi_pat[id].playmode == 2 then
midi_pat[id]:rec_stop()
clock.cancel(midi_pat[id].rec_clock)
if midi_pat[id].clock ~= nil then
print("clearing clock: "..midi_pat[id].clock)
clock.cancel(midi_pat[id].clock)
end
midi_pat[id]:clear()
end
end
end
function toggle_midi_pattern_overdub(id)
if midi_pat[id].play == 1 then
midi_pat[id].overdub = midi_pat[id].overdub == 0 and 1 or 0
end
end
function key(n,z)
if menu == "load screen" then
elseif menu == "overwrite screen" then
if z == 1 then
clock.cancel(collection_overwrite_clock)
print("cancel overwrite")
clock.run(canceled_save)
end
elseif menu == "delete screen" then
if z == 1 then
clock.cancel(collection_delete_clock)
print("cancel delete")
clock.run(canceled_delete)
end
else
if n == 3 and z == 1 then
if menu == 1 then
menu = page.main_sel + 1
elseif menu == 2 then
local id = page.loops_sel
if key2_hold then
if page.loops.sel < 4 then
local id = page.loops.sel
bank[id][bank[id].id].loop = not bank[id][bank[id].id].loop
if bank[id][bank[id].id].loop then
softcut.loop(id+1,1)
cheat(id,bank[id].id)
else
softcut.loop(id+1,0)
end
if page.loops.frame == 1 then
for i = 1,16 do
bank[id][i].loop = bank[id][bank[id].id].loop
end
end
elseif page.loops.sel == 4 then
toggle_buffer(rec.focus)
elseif page.loops.sel == 5 then
if page.loops.meta_sel < 4 then
for i = 1,16 do
rightangleslice.end_sixteenths(bank[page.loops.meta_sel][i])
end
end
end
grid_dirty = true
key2_hold_and_modify = true
end
if not key1_hold and not key2_hold then
page.loops.frame = (page.loops.frame%2)+1
elseif key1_hold and not key2_hold then
if page.loops.sel < 4 then
local id = page.loops.sel
if page.loops.frame == 2 then
local which_pad;
if bank[id].focus_hold then
which_pad = bank[id].focus_pad
elseif grid_pat[id].play == 0 and midi_pat[id].play == 0 and not arp[id].playing and rytm.track[id].k == 0 then
which_pad = bank[id].id
else
which_pad = bank[id].focus_pad
end
-- rightangleslice.init(4,id,'23')
rightangleslice.start_end_random(bank[id][which_pad])
update_waveform(bank[id][which_pad].mode,bank[id][which_pad].start_point,bank[id][which_pad].end_point,128)
-- if grid_pat[id].play == 1 and midi_pat[id].play == 0 and not arp[id].playing and rytm.track[id].k == 0 then
if bank[id].id == which_pad then
rightangleslice.sc.start_end(bank[id][which_pad],id)
end
-- end
else
if bank[id][bank[id].id].mode == 2 then
_norns.key(1,1)
_norns.key(1,0)
fileselect.enter(_path.audio,function(n) sample_callback(n,bank[id][bank[id].id].clip) end)
end
end
elseif page.loops.sel == 4 and page.loops.frame == 2 then
-- something else
elseif page.loops.sel == 5 and page.loops.frame == 2 then
if page.loops.meta_sel < 4 then
-- sync to next
local id = page.loops.meta_sel
local src_bank_num = (id == 1 or id == 2) and 3 or 2
local src_bank = bank[src_bank_num]
local src_pad = src_bank[src_bank.id]
-- -- shift start/end by the difference between clips
local reasonable_max = bank[id][bank[id].id].mode == 1 and 8 or clip[bank[id][bank[id].id].clip].sample_length
if src_pad.end_point <= reasonable_max then
bank[id][bank[id].id].start_point = src_pad.start_point
bank[id][bank[id].id].end_point = src_pad.end_point
rightangleslice.sc.start_end( bank[id][bank[id].id], id )
-- if bank[id][bank[id].id].loop then
-- softcut.position(id+1, bank[id][bank[id].id].start_point )
-- end
end
end
end
end
elseif menu == 3 then
local level_nav = (page.levels_sel + 1)%4
page.levels_sel = level_nav
elseif menu == 5 then
local filter_nav = (page.filtering_sel + 1)%4
page.filtering_sel = filter_nav
elseif menu == 6 then
if page.delay_section == 2 then
if key1_hold then
local k = page.delay[page.delay_focus].menu
local v = page.delay[page.delay_focus].menu_sel[page.delay[page.delay_focus].menu]
del.links(del.lookup_prm(k,v))
if k == 1 and v == 5 then
delay[page.delay_focus == 1 and 2 or 1].feedback_mute = not delay[page.delay_focus == 1 and 2 or 1].feedback_mute
elseif k == 1 and v == 4 then
delay[page.delay_focus == 1 and 2 or 1].reverse = delay[page.delay_focus].reverse
end
if delay_links[del.lookup_prm(k,v)] then
local sides = {"L","R"}
params:set("delay "..sides[page.delay_focus == 1 and 2 or 1]..": "..del.lookup_prm(k,v),params:get("delay "..sides[page.delay_focus]..": "..del.lookup_prm(k,v)))
grid_dirty = true
end
else
page.delay_section = page.delay_section == 1 and 2 or 1
end
elseif page.delay_section == 1 then
if key1_hold then
del.link_all(page.delay[page.delay_focus].menu)
else
page.delay_section = page.delay_section == 1 and 2 or 1
end
end
elseif menu == 7 then
local time_nav = page.time_sel
local id = time_nav
if time_nav >= 1 and time_nav < 4 then
if g.device == nil and grid_pat[time_nav].count == 0 then
if page.time_page_sel[time_nav] == 1 then
if midi_pat[time_nav].playmode < 3 then
if midi_pat[time_nav].rec == 0 then
if midi_pat[time_nav].count == 0 and not key1_hold then
midi_pattern_recording(time_nav,"start")
elseif midi_pat[time_nav].count ~= 0 and not key1_hold then
toggle_midi_pattern_overdub(time_nav)
end
elseif midi_pat[time_nav].rec == 1 then
midi_pattern_recording(time_nav,"stop")
end
end
end
end
if page.time_page_sel[time_nav] == 2 then
if g.device ~= nil then
random_grid_pat(id,2)
else
shuffle_midi_pat(id)
end
elseif page.time_page_sel[time_nav] == 4 then
if not key1_hold then
if g.device ~= nil then
random_grid_pat(id,3)
else
random_midi_pat(id)
end
end
end
if key1_hold then
if grid_pat[id].count > 0 then
grid_pat[id]:rec_stop()
grid_pat[id]:stop()
grid_pat[id].tightened_start = 0
grid_pat[id]:clear()
pattern_saver[id].load_slot = 0
end
if midi_pat[id].count > 0 then
midi_pat[id]:rec_stop()
if midi_pat[id].clock ~= nil then
print("clearing clock: "..midi_pat[id].clock)
clock.cancel(midi_pat[id].clock)
end
midi_pat[id]:clear()
end
end
elseif time_nav >= 4 then
if a.device ~= nil then
local pattern = arc_pat[time_nav-3][page.time_page_sel[time_nav]]
if page.time_page_sel[page.time_sel] <= 4 then
if not key1_hold then
if pattern.rec == 0 and pattern.play == 0 and pattern.count == 0 then
pattern:rec_start()
elseif pattern.rec == 1 then
pattern:rec_stop()
pattern:start()
elseif pattern.play == 1 then
pattern:stop()
elseif (pattern.rec == 0 and pattern.play == 0 and pattern.count > 0) then
pattern:start()
end
else
pattern:clear()
end
else
for i = 1,4 do
if page.time_page_sel[page.time_sel] == 5 then
if arc_pat[time_nav-3][i].count > 0 then
arc_pat[time_nav-3][i]:start()
end
elseif page.time_page_sel[page.time_sel] == 6 then
arc_pat[time_nav-3][i]:stop()
elseif page.time_page_sel[page.time_sel] == 7 then
arc_pat[time_nav-3][i]:clear()
end
end
end
end
end
elseif menu == 8 then
if key1_hold then
rytm.reset_pattern(rytm.track_edit)
else
rytm.screen_focus = rytm.screen_focus == "left" and "right" or "left"
end
elseif menu == 9 then
-- arp[page.arp_page_sel].hold = not arp[page.arp_page_sel].hold
local id = page.arp_page_sel
if not arp[id].hold then
if not arp[id].enabled then
arp[id].enabled = true
end
if #arp[id].notes > 0 then
arp[id].hold = true
else
arp[id].enabled = false
end
else
if #arp[id].notes > 0 then
if arp[id].playing == true then
arp[id].hold = not arp[id].hold
if not arp[id].hold then
arps.clear(id)
end
arp[id].enabled = false
-- else
-- arp[id].step = arp[id].start_point-1
-- arp[id].pause = false
-- arp[id].playing = true
end
end
end
grid_dirty = true
-- if not arp[page.arp_page_sel].hold then
-- arps.clear(page.arp_page_sel)
-- end
elseif menu == 10 then
if key1_hold then
local rnd_bank = page.rnd_page
local rnd_slot = page.rnd_page_sel[rnd_bank]
local state = tostring(rnd[rnd_bank][rnd_slot].playing)
rnd.transport(rnd_bank,rnd_slot,state == "false" and "on" or "off")
if state == "true" then
rnd.restore_default(rnd_bank,rnd_slot)
end
else
page.rnd_page_section = page.rnd_page_section == 1 and 2 or 1
end
end
elseif n == 2 and z == 1 then
if menu == 2 and not key1_hold then
-- key2_hold = true
key2_hold_counter:start()
key2_hold_and_modify = false
elseif menu == 2 then
if page.loops.frame == 2 and key1_hold then
if page.loops.sel == 4 then
buff_flush()
elseif page.loops.sel < 4 then
sync_clock_to_loop(bank[page.loops.sel][bank[page.loops.sel].id],"audio")
elseif page.loops.sel == 5 then
if page.loops.meta_sel < 4 then
-- THIS SHOULD CHECK TO SEE IF PAD LOCKED...
-- sync to next
local id = page.loops.meta_sel
local src_bank_num = id == 1 and 2 or 1
local src_bank = bank[src_bank_num]
local src_pad = src_bank[src_bank.id]
-- -- shift start/end by the difference between clips
local reasonable_max = bank[id][bank[id].id].mode == 1 and 8 or clip[bank[id][bank[id].id].clip].sample_length
if src_pad.end_point <= reasonable_max then
bank[id][bank[id].id].start_point = src_pad.start_point
bank[id][bank[id].id].end_point = src_pad.end_point
rightangleslice.sc.start_end( bank[id][bank[id].id], id )
-- softcut.position(id+1, bank[id][bank[id].id].start_point )
end
end
end
end
end
elseif n == 2 and z == 0 and key2_hold == false and menu == 2 and not key1_hold then
key2_hold_counter:stop()
menu = 1
elseif n == 2 and z == 0 and key2_hold_and_modify then
key2_hold = false
key2_hold_and_modify = false
elseif n == 2 and z == 0 and not key2_hold_and_modify then
key2_hold = false
key2_hold_and_modify = false
if menu == 11 then
if help_menu ~= "welcome" then
help_menu = "welcome"
else
menu = 1
end
elseif menu == 8 then
if key1_hold then
for i = 1,3 do
rytm.reset_pattern(i)
end
else
menu = 1
end
elseif menu == 10 then
if key1_hold then
for i = 1,#rnd.targets do
rnd.transport(page.rnd_page,i,"off")
rnd.restore_default(page.rnd_page,i)
end
else
menu = 1
end
elseif menu == 6 then
if key1_hold then
if page.delay[page.delay_focus].menu_sel[page.delay[page.delay_focus].menu] == 4 then
local k = page.delay[page.delay_focus].menu
local v = page.delay[page.delay_focus].menu_sel[page.delay[page.delay_focus].menu]
del.quick_action(page.delay_focus, "reverse")
end
else
menu = 1
end
elseif menu == 2 then
if page.loops.frame == 2 and key1_hold then
if page.loops.sel == 4 then
buff_flush()
elseif page.loops.sel < 4 then
sync_clock_to_loop(bank[page.loops.sel][bank[page.loops.sel].id],"audio")
end
-- if key1_hold and page.loops_sel ~= 4 then
-- if page.loops_view[page.loops_sel] == 1 then
-- sync_clock_to_loop(bank[page.loops_sel][bank[page.loops_sel].id],"audio")
-- elseif page.loops_view[page.loops_sel] == 2 then
-- rightangleslice.init(4,id,'14')
-- end
-- elseif key1_hold and page.loops_sel == 4 then
-- buff_pause()
else
-- if page.loops.frame == 1 then
-- menu = 1
-- end
end
else
menu = 1
end
if menu == 6 and page.delay[page.delay_focus].menu == 1 and page.delay[page.delay_focus].menu_sel[page.delay[page.delay_focus].menu] == 4 then
-- just need a logic break
elseif menu ~= 2 and menu ~= 8 then
if key1_hold == true then key1_hold = false end
end
end
if n == 1 and z == 1 then
if menu == 5 or menu == 11 then
if key1_hold == false then
key1_hold = true
else
key1_hold = false
end
elseif menu == 6 then
key1_hold = true
if page.delay[page.delay_focus].menu == 1 and page.delay[page.delay_focus].menu_sel[page.delay[page.delay_focus].menu] == 5 then
if delay_links["feedback"] then
del.quick_action(1,"feedback_mute",z)
del.quick_action(2,"feedback_mute",z)
else
del.quick_action(page.delay_focus,"feedback_mute",z)
end
grid_dirty = true
end
elseif menu == 7 then
key1_hold = true
elseif menu == 8 then
key1_hold = true
elseif menu == 9 then
key1_hold = true
page.arp_alt[page.arp_page_sel] = not page.arp_alt[page.arp_page_sel]
else
key1_hold = true
if menu == 2 and page.loops.sel < 4 and page.loops.frame == 2 and not key2_hold then
local focused_pad;
if bank[page.loops.sel].focus_hold then
focused_pad = bank[page.loops.sel].focus_pad
elseif grid_pat[page.loops.sel].play == 0 and midi_pat[page.loops.sel].play == 0 and not arp[page.loops.sel].playing and rytm.track[page.loops.sel].k == 0 then
focused_pad = bank[page.loops.sel].id
else
focused_pad = bank[page.loops.sel].focus_pad
end
local mode = bank[page.loops.sel][focused_pad].mode
local min = bank[page.loops.sel][focused_pad].start_point
local max = bank[page.loops.sel][focused_pad].end_point
update_waveform(mode,min,max,128)
elseif menu == 2 and page.loops.sel < 4 and page.loops.frame == 2 and key2_hold then
if bank[page.loops.sel][bank[page.loops.sel].id].mode == 2 then
_norns.key(1,0)
fileselect.enter(_path.audio,function(n) sample_callback(n,bank[page.loops.sel][bank[page.loops.sel].id].clip) end)
if key2_hold then key2_hold = false end
end
elseif menu == 2 and page.loops.sel == 4 and page.loops.frame == 2 then
update_waveform(1,rec[rec.focus].start_point,rec[rec.focus].end_point,128)
elseif menu == 2 and page.loops.sel == 5 and page.loops.frame == 2 then
if not key2_hold then
local id = page.loops.meta_sel
if id < 4 and (grid_pat[id].play == 1 or midi_pat[id].play == 1 or arp[id].playing or rytm.track[id].k ~= 0) then
bank[id].focus_pad = bank[id].id
-- page.loops.focus_hold[page.loops.meta_sel] = not page.loops.focus_hold[page.loops.meta_sel]
end
elseif key2_hold then
if page.loops.meta_sel < 4 then
print("should slice")
for i = 1,16 do
rightangleslice.start_end_default(bank[page.loops.meta_sel][i])
end
key1_hold = false -- right??
end
end
end
end
elseif n == 1 and z == 0 then
if menu == 2 and page.loops.sel < 4 and not key2_hold then
local mode = bank[page.loops.sel][bank[page.loops.sel].id].mode
local min =
{ live[bank[page.loops.sel][bank[page.loops.sel].id].clip].min
, clip[bank[page.loops.sel][bank[page.loops.sel].id].clip].min
}
local max =
{ live[bank[page.loops.sel][bank[page.loops.sel].id].clip].max
, clip[bank[page.loops.sel][bank[page.loops.sel].id].clip].max
}
update_waveform(mode,min[mode],max[mode],128)
elseif menu == 2 and page.loops.sel == 4 then
update_waveform(1,live[rec.focus].min,live[rec.focus].max,128)
end
if menu ~= 5 and menu ~= 11 then
key1_hold = false
end
if menu == 6 then
if page.delay[page.delay_focus].menu == 1 and page.delay[page.delay_focus].menu_sel[page.delay[page.delay_focus].menu] == 5 then
if delay_links["feedback"] then
del.quick_action(1,"feedback_mute",z)
del.quick_action(2,"feedback_mute",z)
else
del.quick_action(page.delay_focus,"feedback_mute",z)
end
grid_dirty = true
end
end
if menu == 7 then
if page.time_sel < 4 then
if key1_hold_and_modify == false then
local time_nav = page.time_sel
local id = time_nav
if midi_pat[id].play == 1 then
if midi_pat[id].clock ~= nil then
clock.cancel(midi_pat[id].clock)
print("pausing clock")
midi_pat[id].step = 1
end
midi_pat[id]:stop()
else
if midi_pat[id].count > 0 then
if midi_pat[id].playmode == 1 then
--midi_pat[id]:start()
start_pattern(midi_pat[id])
elseif midi_pat[id].playmode == 2 then
print("line 2387")
--midi_pat[id].clock = clock.run(synced_loop, midi_pat[id], "restart")
midi_pat[id].clock = clock.run(alt_synced_loop, midi_pat[id], "restart")
end
end
end
if grid_pat[id].count > 0 then
if grid_pat[id].quantize == 0 then
if grid_pat[id].play == 1 then
--grid_pat[id]:stop()
stop_pattern(grid_pat[id])
else
--grid_pat[id]:start()
start_pattern(grid_pat[id])
end
else
grid_pat[id].tightened_start = (grid_pat[id].tightened_start + 1)%2
grid_pat[id].step = grid_pat[id].start_point
quantized_grid_pat[id].current_step = grid_pat[id].start_point
quantized_grid_pat[id].sub_step = 1
end
end
else
key1_hold_and_modify = false
end
end
end
end
end
adjust_key1_timing()
screen_dirty = true
grid_dirty = true
end
function check_page_for_k1()
while true do
clock.sleep(0.25)
if _menu.mode and metro[31].time ~= 0.25 then
metro[31].time = 0.25
elseif not _menu.mode and metro[31].time == 0.25 and menu ~= 1 then
metro[31].time = 0.1
end
end
end
function enc(n,d)
encoder_actions.init(n,d)
adjust_key1_timing()
end
function redraw()
screen.clear()
screen.level(15)
screen.font_size(8)
main_menu.init()
screen.update()
end
--GRID
g = grid.connect()
function grid.add(dev)
grid_dirty = true
end
g.key = function(x,y,z)
grid_actions.init(x,y,z)
end
function jump_live(i,s,y,z)
local pad = bank[i][s]
local old_duration = pad.mode == 1 and 8 or clip[pad.clip].sample_length
local old_clip = pad.clip
local old_min = (1+(old_duration*(old_clip-1)))
local old_max = ((old_duration+1)+(old_duration*(old_clip-1)))
local old_range = old_min - old_max
pad.clip = math.abs(y-5)
local new_duration = pad.mode == 1 and 8 or clip[pad.clip].sample_length
local new_clip = pad.clip
--local new_min = (1+(new_duration*(pad.clip-1)))
if pad.mode == 1 then
local new_min = (1+(new_duration*(pad.clip-1)))
local new_max = ((new_duration+1)+(new_duration*(pad.clip-1)))
local new_range = new_max - new_min
local current_difference = (pad.end_point - pad.start_point) -- is this where it gets weird?
pad.start_point = (((pad.start_point - old_min) * new_range) / old_range) + new_min
pad.end_point = pad.start_point + current_difference
end
--[[
for go = 1,2 do
local old_min = (1+(duration*(bank[i][s].clip-1)))
local old_max = ((duration+1)+(duration*(bank[i][s].clip-1)))
local old_range = old_min - old_max
bank[i][s].clip = math.abs(y-5)
local new_min = (1+(duration*(bank[i][s].clip-1)))
local new_max = ((duration+1)+(duration*(bank[i][s].clip-1)))
local new_range = new_max - new_min
local current_difference = (bank[i][s].end_point - bank[i][s].start_point)
bank[i][s].start_point = (((bank[i][s].start_point - old_min) * new_range) / old_range) + new_min
bank[i][s].end_point = bank[i][s].start_point + current_difference
if menu == 11 then
which_bank = i
help_menu = "buffer jump"
end
end
--]]
if menu == 11 then
which_bank = i
help_menu = "buffer jump"
end
end
function clip_table()
clip[1].min = 1
clip[1].max = clip[1].min + clip[1].sample_length
--clip[2].min = clip[1].max
clip[2].min = 33
clip[2].max = clip[2].min + clip[2].sample_length
--clip[3].min = clip[2].max
clip[3].min = 65
clip[3].max = clip[3].min + clip[3].sample_length
end
-- length mods
function scale_loop_points(pad,old_min,old_max,new_min,new_max)
--local pad = bank[b][p]
local duration = pad.end_point - pad.start_point
pad.start_point = util.linlin(old_min,old_max,new_min,new_max,pad.start_point)
--pad.end_point = util.linlin(old_min,old_max,new_min,new_max,pad.end_point)
if pad.start_point + duration > new_max then
pad.end_point = new_max
else
pad.end_point = pad.start_point + duration
end
print(pad,old_min,old_max,new_min,pad.end_point)
end
function change_mode(target,old_mode)
local live_min = live[target.clip].min
local live_max = live[target.clip].max
local clip_min = clip[target.clip].min
local clip_max = clip[target.clip].max
local duration = target.end_point - target.start_point
if old_mode == 1 then
target.start_point = util.linlin(live_min,live_max,clip_min,clip_max,target.start_point)
elseif old_mode == 2 then
target.start_point = util.linlin(clip_min,clip_max,live_min,live_max,target.start_point)
end
if target.start_point + duration > (old_mode == 1 and clip[target.clip].max or live[target.clip].max) then
target.end_point = (old_mode == 1 and clip[target.clip].max or live[target.clip].max)
else
target.end_point = target.start_point + duration
end
end
function jump_clip(bank_id,pad_id,new_clip)
local pad = bank[bank_id][pad_id]
local current_difference = (pad.end_point - pad.start_point)
if pad.mode == 2 then
local old_clip = pad.clip
pad.clip = new_clip
pad.start_point = util.linlin(clip[old_clip].min,clip[old_clip].max,clip[pad.clip].min,clip[pad.clip].max,pad.start_point)
if pad.start_point + current_difference > clip[pad.clip].max then
pad.end_point = clip[pad.clip].max
else
pad.end_point = pad.start_point + current_difference
end
else
local old_clip = pad.clip
pad.clip = new_clip
pad.start_point = util.linlin(live[old_clip].min,live[old_clip].max,live[pad.clip].min,live[pad.clip].max,pad.start_point)
if pad.start_point + current_difference > live[pad.clip].max then
pad.end_point = live[pad.clip].max
else
pad.end_point = pad.start_point + current_difference
end
end
end
--/ length mods
function grid_entry(e)
if e.state > 0 then
lit[e.id] = {}
lit[e.id].x = e.x
lit[e.id].y = e.y
else
if lit[e.id] ~= nil then
lit[e.id] = nil
end
end
-- grid_redraw()
grid_dirty = true
end
led_maps =
-- { VB,4S,GS }
{
-- main page
["square_off"] = {3,4,15}
, ["square_selected"] = {15,15,0}
, ["square_dim"] = {5,8,0}
, ["zilchmo_off"] = {3,4,15} -- is this right?
, ["zilchmo_on"] = {15,12,0}
, ["pad_pause"] = {15,12,15}
, ["pad_play"] = {3,4,0}
, ["rec_record"] = {9,8,15}
, ["rec_overdub"] = {9,8,15}
, ["rec_play"] = {15,12,15}
, ["rec_pause"] = {5,4,0}
, ["rec_off"] = {3,0,0}
, ["arc_rec_rec"] = {15,12,15}
, ["arc_rec_play"] = {9,8,15}
, ["arc_rec_pause"] = {5,4,0}
, ["arc_rec_off"] = {0,0,0}
, ["arc_param_show"] = {5,4,0}
, ["grid_alt_on"] = {15,12,15}
, ["grid_alt_off"] = {3,4,0}
, ["clip"] = {8,8,15}
, ["mode"] = {6,8,15}
, ["loop_on"] = {4,8,15}
, ["loop_off"] = {2,4,0}
, ["arp_on"] = {4,4,0}
, ["arp_pause"] = {4,8,15}
, ["arp_play"] = {10,12,15}
, ["live_empty"] = {3,4,0}
, ["live_rec"] = {10,12,15}
, ["live_pause"] = {5,8,0}
, ["alt_on"] = {15,12,15}
, ["alt_off"] = {3,4,0}
, ["focus_on"] = {10,8,15}
-- , ["focus_soft"] = {10,8,15}
-- seq page
, ["step_no_data"] = {2,4,0}
, ["step_yes_data"] = {4,8,15}
, ["step_loops"] = {4,8,15}
, ["slot_saved"] = {7,8,0}
, ["slot_empty"] = {2,4,0}
, ["slot_loaded"] = {15,15,15}
, ["step_current"] = {15,15,15}
, ["step_held"] = {9,8,15}
, ["loop_duration"] = {4,4,0}
, ["meta_duration"] = {4,4,15}
, ["meta_step_hi"] = {6,8,15}
, ["meta_step_lo"] = {2,4,0}
, ["loop_mod_hi"] = {12,12,15}
, ["loop_mod_lo"] = {3,4,0}
-- delay page
, ["bundle_empty"] = {2,4,0}
, ["bundle_saved"] = {7,8,0}
, ["bundle_loaded"] = {15,12,15}
, ["time_to_led.5"] = {5,4,15}
, ["time_to_led.25"] = {10,8,15}
, ["time_to_led.125"] = {15,12,15}
, ["time_to_led2"] = {3,4,15}
, ["time_to_led4"] = {6,8,15}
, ["time_to_led8"] = {12,12,15}
, ["time_to_led16"] = {15,12,15}
, ["reverse_on"] = {7,8,15}
, ["reverse_off"] = {3,4,0}
, ["wobble_on"] = {15,12,15}
, ["wobble_off"] = {0,0,0}
, ["level_lo"] = {2,4,0}
, ["level_hi"] = {7,8,15}
, ["selected_bank"] = {7,8,15}
, ["unselected_bank"] = {2,4,0}
, ["64_bank_send"] = {4,8,15}
-- misc
, ["page_led"] = {{0,0,15},{7,8,15},{15,12,15}}
, ["off"] = {0,0,0}
}
function draw_zilch(x,y,z)
g:led(x,y,z == 1 and led_maps["zilchmo_on"][edition] or led_maps["zilchmo_off"][edition])
end
function grid_redraw()
if g.device ~= nil then
if params:string("grid_size") == "128" then
g:all(0)
local edition = params:get("LED_style")
if grid_page == 0 then
for j = 0,2 do
for k = 1,4 do
k = k+(5*j)
for i = 8,5,-1 do
g:led(k,i,led_maps["square_off"][edition])
end
end
end
for i = 0,1 do
for x = 4+i,14+i,5 do
for j = 1,3+i do
g:led(x,j,zilch_leds[i == 0 and 3 or 4][util.round(x/5)][j] == 1 and led_maps["zilchmo_on"][edition] or led_maps["zilchmo_off"][edition])
end
end
end
for x = 3,13,5 do
for j = 1,2 do
g:led(x,j,zilch_leds[2][util.round(x/5)][j] == 1 and led_maps["zilchmo_on"][edition] or led_maps["zilchmo_off"][edition])
end
end
for i = 1,3 do
local target = grid_pat[i]
if target.rec == 1 then
g:led(2+(5*(i-1)),1,(9*target.led))
elseif (target.quantize == 0 and target.play == 1) or (target.quantize == 1 and target.tightened_start == 1) then
if target.overdub == 0 then
g:led(2+(5*(i-1)),1,9)
else
g:led(2+(5*(i-1)),1,15)
end
elseif target.count > 0 then
g:led(2+(5*(i-1)),1,5)
else
g:led(2+(5*(i-1)),1,3)
end
end
for i = 1,3 do
local a_p; -- this will index the arc encoder recorders
if arc_param[i] == 1 or arc_param[i] == 2 or arc_param[i] == 3 then
a_p = 1
else
a_p = arc_param[i] - 2
end
if arc_pat[i][a_p].rec == 1 then
g:led(16,5-i,led_maps["arc_rec_rec"][edition])
elseif arc_pat[i][a_p].play == 1 then
g:led(16,5-i,led_maps["arc_rec_play"][edition])
elseif arc_pat[i][a_p].count > 0 then
g:led(16,5-i,led_maps["arc_rec_pause"][edition])
else
g:led(16,5-i,led_maps["arc_rec_off"][edition])
end
end
if a.device ~= nil then
for i = 1,3 do
for j = 5,15,5 do
g:led(j,8,arc_param[j/5] == 1 and 5 or 0)
g:led(j,7,arc_param[j/5] == 2 and 5 or 0)
g:led(j,6,arc_param[j/5] == 3 and 5 or 0)
if arc_param[j/5] == 4 then
for k = 8,6,-1 do
g:led(j,k,led_maps["arc_param_show"][edition])
end
elseif arc_param[j/5] == 5 then
g:led(j,8,led_maps["arc_param_show"][edition])
g:led(j,7,led_maps["arc_param_show"][edition])
elseif arc_param[j/5] == 6 then
g:led(j,7,led_maps["arc_param_show"][edition])
g:led(j,6,led_maps["arc_param_show"][edition])
end
end
end
end
for i = 1,3 do
if bank[i].focus_hold == false then
g:led(selected[i].x, selected[i].y, led_maps["square_selected"][edition])
if i == nil then print("2339") end
if bank[i].id == nil then print("2340", i) end
if bank[i][bank[i].id].pause == nil then print("2341") end
if bank[i][bank[i].id].pause == true then
g:led(3+(5*(i-1)),1,led_maps["pad_pause"][edition])
g:led(3+(5*(i-1)),2,led_maps["pad_pause"][edition])
else
-- g:led(3+(5*(i-1)),1,led_maps["pad_play"][edition])
-- g:led(3+(5*(i-1)),2,led_maps["pad_play"][edition])
g:led(3+(5*(i-1)),1,zilch_leds[2][i][1] == 1 and led_maps["zilchmo_on"][edition] or led_maps["zilchmo_off"][edition])
g:led(3+(5*(i-1)),2,zilch_leds[2][i][2] == 1 and led_maps["zilchmo_on"][edition] or led_maps["zilchmo_off"][edition])
end
else
local focus_x = (math.ceil(bank[i].focus_pad/4)+(5*(i-1)))
local focus_y = 8-((bank[i].focus_pad-1)%4)
g:led(selected[i].x, selected[i].y, led_maps["square_dim"][edition])
g:led(focus_x, focus_y, led_maps["square_selected"][edition])
if bank[i][bank[i].focus_pad].pause == true then
g:led(3+(5*(i-1)),1,led_maps["square_selected"][edition])
g:led(3+(5*(i-1)),2,led_maps["square_selected"][edition])
else
g:led(3+(5*(i-1)),1,led_maps["square_off"][edition])
g:led(3+(5*(i-1)),2,led_maps["square_off"][edition])
end
end
end
for i = 1,3 do
if bank[i].focus_hold then
g:led(4+(5*(i-1)),4,(10*bank[i][bank[i].focus_pad].crow_pad_execute)+5)
end
-- if bank[i].focus_hold == true then
-- g:led(5*i,5,(10*bank[i][bank[i].focus_pad].crow_pad_execute)+5)
-- else
-- local alt = bank[i].alt_lock and 1 or 0
-- g:led(5*i,5,15*alt)
-- end
local alt = bank[i].alt_lock and 1 or 0
g:led(5*i,5,15*alt)
end
for i,e in pairs(lit) do
g:led(e.x, e.y,led_maps["zilchmo_on"][edition])
end
g:led(16,8,(grid.alt and led_maps["alt_on"][edition] or led_maps["alt_off"][edition]))
for i = 1,3 do
local focused = bank[i].focus_hold == false and bank[i][bank[i].id] or bank[i][bank[i].focus_pad]
g:led(1 + (5*(i-1)), math.abs(focused.clip-5),led_maps["clip"][edition])
g:led(2 + (5*(i-1)), math.abs(focused.mode-5),led_maps["mode"][edition])
g:led(1+(5*(i-1)),1,bank[i].focus_hold == false and led_maps["off"][edition] or led_maps["focus_on"][edition])
if focused.loop == false then
g:led(3+(5*(i-1)),4,led_maps["loop_off"][edition])
elseif focused.loop == true then
g:led(3+(5*(i-1)),4,led_maps["loop_on"][edition])
end
if not arp[i].enabled then
g:led(3+(5*(i-1)),3,led_maps["off"][edition])
else
if arp[i].playing and arp[i].hold then
g:led(3+(5*(i-1)),3,led_maps["arp_play"][edition])
elseif arp[i].hold then
g:led(3+(5*(i-1)),3,led_maps["arp_pause"][edition])
else
g:led(3+(5*(i-1)),3,led_maps["arp_on"][edition])
end
end
end
if rec[rec.focus].clear == 0 then
g:led(16,8-rec.focus,rec[rec.focus].state == 1 and led_maps["live_rec"][edition] or led_maps["live_pause"][edition])
elseif rec[rec.focus].clear == 1 then
g:led(16,8-rec.focus,led_maps["live_empty"][edition])
end
elseif grid_page == 1 then
-- if we're on page 2...
for i = 1,3 do
for j = step_seq[i].start_point,step_seq[i].end_point do
local xval = j < 9 and (i*5)-2 or (i*5)-1
local yval = j < 9 and 9 or 17
g:led(xval,yval-j,led_maps["step_no_data"][edition])
if grid.loop_mod == 1 then
g:led(xval,yval-step_seq[i].start_point,led_maps["step_loops"][edition])
g:led(xval,yval-step_seq[i].end_point,led_maps["step_loops"][edition])
end
end
for j = 1,16 do
if step_seq[i][j].assigned_to ~= 0 then
local xval = j < 9 and (i*5)-2 or (i*5)-1
local yval = j < 9 and 9 or 17
g:led(xval,yval-j,led_maps["step_yes_data"][edition])
end
end
if step_seq[i].current_step < 9 then
g:led((i*5)-2,9-step_seq[i].current_step,led_maps["step_current"][edition])
elseif step_seq[i].current_step >=9 then
g:led((i*5)-1,9-(step_seq[i].current_step-8),led_maps["step_current"][edition])
end
if step_seq[i].held < 9 then
g:led((i*5)-2,9-step_seq[i].held,led_maps["step_held"][edition])
elseif step_seq[i].held >= 9 then
g:led((i*5)-1,9-(step_seq[i].held-8),led_maps["step_held"][edition])
end
g:led((i*5)-3, 9-step_seq[i].meta_duration,led_maps["meta_duration"][edition])
g:led((i*5)-3, 9-step_seq[i].meta_step,led_maps["meta_step_hi"][edition])
if step_seq[i].held == 0 then
g:led((i*5), 9-step_seq[i][step_seq[i].current_step].meta_meta_duration,led_maps["meta_duration"][edition])
g:led((i*5), 9-step_seq[i].meta_meta_step,led_maps["meta_step_hi"][edition])
else
g:led((i*5), 9-step_seq[i].meta_meta_step,led_maps["meta_step_lo"][edition])
g:led((i*5), 9-step_seq[i][step_seq[i].held].meta_meta_duration,led_maps["meta_duration"][edition])
end
if step_seq[i].held == 0 then
g:led(16,8-i,edition == 3 and (15*step_seq[i].active) or ((step_seq[i].active*6)+2))
else
g:led(16,8-i,step_seq[i][step_seq[i].held].loop_pattern*4)
end
end
for i = 1,11,5 do
for j = 1,8 do
local current = math.floor(i/5)+1
local show = step_seq[current].held == 0 and pattern_saver[current].load_slot or step_seq[current][step_seq[current].held].assigned_to
g:led(i,j,edition == 3 and (15*pattern_saver[current].saved[9-j]) or ((5*pattern_saver[current].saved[9-j])+2))
g:led(i,j,j == (9 - show) and 15 or (edition == 3 and (15*pattern_saver[current].saved[9-j]) or ((5*pattern_saver[current].saved[9-j])+2)))
end
end
g:led(16,8,grid.alt and led_maps["alt_on"][edition] or led_maps["alt_off"][edition])
g:led(16,2,grid.loop_mod == 1 and led_maps["loop_mod_hi"][edition] or led_maps["loop_mod_lo"][edition])
elseif grid_page == 2 then
-- delay page!
for i = 1,8 do
local check = {i+8, i}
for j = 1,2 do
g:led(i,j,delay[2].selected_bundle == check[j] and 15 or (delay_bundle[2][check[j]].saved == true and led_maps["bundle_saved"][edition] or led_maps["bundle_empty"][edition]))
g:led(i,j+6,delay[1].selected_bundle == check[j] and 15 or (delay_bundle[1][check[j]].saved == true and led_maps["bundle_saved"][edition] or led_maps["bundle_empty"][edition]))
end
end
-- delay time modifiers
local time_to_led = {{},{},{},{}}
local time = {delay[1].modifier, delay[2].modifier}
for i = 1,2 do
time_to_led[i] = 0
time_to_led[i+2] = 0
if time[i] == 0.5 then
time_to_led[i+2] = led_maps["time_to_led.5"][edition]
elseif time[i] == 0.25 then
time_to_led[i+2] = led_maps["time_to_led.25"][edition]
elseif time[i] == 0.125 then
time_to_led[i+2] = led_maps["time_to_led.125"][edition]
elseif time[i] == 2 then
time_to_led[i] = led_maps["time_to_led2"][edition]
elseif time[i] == 4 then
time_to_led[i] = led_maps["time_to_led4"][edition]
elseif time[i] == 8 then
time_to_led[i] = led_maps["time_to_led8"][edition]
elseif time[i] == 16 then
time_to_led[i] = led_maps["time_to_led16"][edition]
end
end
g:led(1,3,time_to_led[2])
g:led(2,3,time_to_led[4])
g:led(1,6,time_to_led[1])
g:led(2,6,time_to_led[3])
g:led(3,3,delay[2].reverse and led_maps["reverse_on"][edition] or led_maps["reverse_off"][edition])
g:led(3,6,delay[1].reverse and led_maps["reverse_on"][edition] or led_maps["reverse_off"][edition])
rate_to_led = {{},{},{},{}}
local rate = {params:get("delay L: rate"), params:get("delay R: rate")}
for i = 1,2 do
rate_to_led[i] = 0
rate_to_led[i+2] = 0
for j = 1,24 do
if math.modf(rate[i]) >= j then
rate_to_led[i] = math.modf(util.linlin(0,24,3,15,j))
end
end
for j = 0.25,1,0.05 do
if rate[i] >= j then
rate_to_led[i+2] = math.modf(util.linlin(0.25,1,15,0,j))
end
end
if rate[i] == 1 then
rate_to_led[i+2] = 3
end
end
g:led(1,4,rate_to_led[2])
g:led(2,4,rate_to_led[4])
g:led(3,4,delay[2].wobble_hold and led_maps["wobble_on"][edition] or led_maps["wobble_off"][edition])
g:led(1,5,rate_to_led[1])
g:led(2,5,rate_to_led[3])
g:led(3,5,delay[1].wobble_hold and led_maps["wobble_on"][edition] or led_maps["wobble_off"][edition])
-- delay levels
local level_to_led = {{},{}}
local delay_level = {params:get("delay L: global level"), params:get("delay R: global level")}
for i = 1,2 do
if delay_level[i] <= 0.125 then
level_to_led[i] = 0
elseif delay_level[i] <= 0.375 then
level_to_led[i] = 1
elseif delay_level[i] <= 0.625 then
level_to_led[i] = 2
elseif delay_level[i] <= 0.875 then
level_to_led[i] = 3
elseif delay_level[i] <= 1 then
level_to_led[i] = 4
end
end
for i = 8,4,-1 do
g:led(i,6,led_maps["level_lo"][edition])
g:led(i,3,led_maps["level_lo"][edition])
end
for i = 1,2 do
if not delay[i].level_mute then
for j = 8,4+(4-level_to_led[i]),-1 do
g:led(j,i==1 and 6 or 3,led_maps["level_hi"][edition])
end
else
if params:get(i == 1 and "delay L: global level" or "delay R: global level") == 0 then
for j = 8,4,-1 do
g:led(j,i==1 and 6 or 3,led_maps["level_hi"][edition])
end
end
end
end
-- feedback levels
local feed_to_led = {{},{}}
local feedback_level = {params:get("delay L: feedback"), params:get("delay R: feedback")}
for i = 1,2 do
if feedback_level[i] <= 12.5 then
feed_to_led[i] = 0
elseif feedback_level[i] <= 37.5 then
feed_to_led[i] = 1
elseif feedback_level[i] <= 62.5 then
feed_to_led[i] = 2
elseif feedback_level[i] <= 87.5 then
feed_to_led[i] = 3
elseif feedback_level[i] <= 100 then
feed_to_led[i] = 4
end
end
for i = 8,4,-1 do
g:led(i,5,led_maps["level_lo"][edition])
g:led(i,4,led_maps["level_lo"][edition])
end
for i = 1,2 do
if not delay[i].feedback_mute then
for j = 8,4+(4-feed_to_led[i]),-1 do
g:led(j,i==1 and 5 or 4,led_maps["level_hi"][edition])
end
else
if params:get(i == 1 and "delay L: feedback" or "delay R: feedback") == 0 then
for j = 8,4,-1 do
g:led(j,i==1 and 5 or 4,led_maps["level_hi"][edition])
end
end
end
end
for k = 10,13 do
for i = 6,3,-1 do
g:led(k,i,led_maps["square_off"][edition])
end
end
local shifted_x = (selected[delay_grid.bank].x - (5*(delay_grid.bank-1)))+9
local shifted_y = selected[delay_grid.bank].y - 2
g:led(shifted_x, shifted_y, led_maps["square_selected"][edition])
for i = 4,6 do
g:led(14,i,delay_grid.bank == 7-i and led_maps["selected_bank"][edition] or led_maps["unselected_bank"][edition])
end
-- send levels
local send_to_led = {{},{}}
local send_level = {bank[delay_grid.bank][bank[delay_grid.bank].id].left_delay_level, bank[delay_grid.bank][bank[delay_grid.bank].id].right_delay_level}
for i = 1,2 do
if send_level[i] <= 0.125 then
send_to_led[i] = 0
elseif send_level[i] <= 0.375 then
send_to_led[i] = 1
elseif send_level[i] <= 0.625 then
send_to_led[i] = 2
elseif send_level[i] <= 0.875 then
send_to_led[i] = 3
elseif send_level[i] <= 1.0 then
send_to_led[i] = 4
end
end
for i = 1,2 do
if not delay[i].send_mute then
for j = 14,10+(4-send_to_led[i]),-1 do
g:led(j,i==1 and 8 or 1,led_maps["level_hi"][edition])
end
else
if (i == 1 and bank[delay_grid.bank][bank[delay_grid.bank].id].left_delay_level or bank[delay_grid.bank][bank[delay_grid.bank].id].right_delay_level) == 0 then
for j = 14,10,-1 do
g:led(j,i==1 and 8 or 1,led_maps["level_hi"][edition])
end
end
end
end
--arp button
if not arp[delay_grid.bank].enabled then
g:led(12,2,led_maps["off"][edition])
else
if arp[delay_grid.bank].playing and arp[delay_grid.bank].hold then
g:led(12,2,led_maps["arp_play"][edition])
elseif arp[delay_grid.bank].hold then
g:led(12,2,led_maps["arp_pause"][edition])
else
g:led(12,2,led_maps["arp_on"][edition])
end
end
if bank[delay_grid.bank][bank[delay_grid.bank].id].loop == false then
g:led(13,2,led_maps["loop_off"][edition])
else
g:led(13,2,led_maps["loop_on"][edition])
end
g:led(16,8,(grid.alt and led_maps["alt_on"][edition] or led_maps["alt_off"][edition]))
for j = 1,4 do
g:led(15,math.abs(j-7),zilch_leds[4][delay_grid.bank][j] == 1 and led_maps["zilchmo_on"][edition] or led_maps["zilchmo_off"][edition])
end
end
local page_led = {[0] = 0, [1] = 7, [2] = 15}
if grid_page ~= nil then
g:led(16,1,led_maps["page_led"][grid_page+1][edition])
end
g:refresh()
--64 grid / grid 64
elseif params:string("grid_size") == "64" then
g:all(0)
local edition = params:get("LED_style")
g:led(8,1,led_maps["square_off"][edition])
if grid_page_64 == 0 then
for x = 1,3 do
g:led(x,1,x == bank_64 and 12 or 4)
end
--arc recorders
local a_p; -- this will index the arc encoder recorders
if arc_param[bank_64] == 1 or arc_param[bank_64] == 2 or arc_param[bank_64] == 3 then
a_p = 1
else
a_p = arc_param[bank_64] - 2
end
if arc_pat[bank_64][a_p].rec == 1 then
g:led(8,3,led_maps["arc_rec_rec"][edition])
elseif arc_pat[bank_64][a_p].play == 1 then
g:led(8,3,led_maps["arc_rec_play"][edition])
elseif arc_pat[bank_64][a_p].count > 0 then
g:led(8,3,led_maps["arc_rec_pause"][edition])
else
g:led(8,3,led_maps["arc_rec_off"][edition])
end
--main playable grid
for x = 1,4 do
for y = 4,7 do
g:led(x,y,led_maps["square_off"][edition])
end
end
--zilchmos
for x = 5,8 do
g:led(x,8,zilch_leds[4][bank_64][x-4] == 1 and led_maps["zilchmo_on"][edition] or led_maps["zilchmo_off"][edition])
end
for x = 6,8 do
g:led(x,7,zilch_leds[3][bank_64][x-5] == 1 and led_maps["zilchmo_on"][edition] or led_maps["zilchmo_off"][edition])
end
--pattern rec
local target = grid_pat[bank_64]
if target.rec == 1 then
g:led(8,5,(9*target.led))
elseif (target.quantize == 0 and target.play == 1) or (target.quantize == 1 and target.tightened_start == 1) then
if target.overdub == 0 then
g:led(8,5,9)
else
g:led(8,5,15)
end
elseif target.count > 0 then
g:led(8,5,5)
else
g:led(8,5,3)
end
--arc rec
-- local a_p; -- this will index the arc encoder recorders
-- if arc_param[bank_64] == 1 or arc_param[bank_64] == 2 or arc_param[bank_64] == 3 then
-- a_p = 1
-- else
-- a_p = arc_param[bank_64] - 2
-- end
-- if arc_pat[bank_64][a_p].rec == 1 then
-- g:led(7,8,led_maps["arc_rec_rec"][edition])
-- elseif arc_pat[bank_64][a_p].play == 1 then
-- g:led(7,8,led_maps["arc_rec_play"][edition])
-- elseif arc_pat[bank_64][a_p].count > 0 then
-- g:led(7,8,led_maps["arc_rec_pause"][edition])
-- else
-- g:led(7,8,led_maps["arc_rec_off"][edition])
-- end
-- arc control
if a.device ~= nil then
g:led(6,2,arc_param[bank_64] == 1 and led_maps["arc_param_show"][edition] or 0)
g:led(7,2,arc_param[bank_64] == 2 and led_maps["arc_param_show"][edition] or 0)
g:led(8,2,arc_param[bank_64] == 3 and led_maps["arc_param_show"][edition] or 0)
if arc_param[bank_64] == 4 then
for x = 6,8 do
g:led(x,2,led_maps["arc_param_show"][edition])
end
elseif arc_param[bank_64] == 5 then
g:led(6,2,led_maps["arc_param_show"][edition])
g:led(7,2,led_maps["arc_param_show"][edition])
elseif arc_param[bank_64] == 6 then
g:led(7,2,led_maps["arc_param_show"][edition])
g:led(8,2,led_maps["arc_param_show"][edition])
end
end
--4x4 pads
if bank[bank_64].focus_hold == false then
local x_64 = (9-selected[bank_64].y)
local y_64 = selected[bank_64].x - (5*(bank_64-1))
g:led(x_64, y_64+3, led_maps["square_selected"][edition])
if bank[bank_64][bank[bank_64].id].pause == true then
g:led(8,6,led_maps["pad_pause"][edition])
g:led(7,6,led_maps["pad_pause"][edition])
else
g:led(7,6,zilch_leds[2][bank_64][1] == 1 and led_maps["zilchmo_on"][edition] or led_maps["zilchmo_off"][edition])
g:led(8,6,zilch_leds[2][bank_64][2] == 1 and led_maps["zilchmo_on"][edition] or led_maps["zilchmo_off"][edition])
end
else
local x_64 = (9-selected[bank_64].y)
local y_64 = selected[bank_64].x - (5*(bank_64-1))
local focus_x_64 = bank[bank_64].focus_pad - (4*(math.ceil(bank[bank_64].focus_pad/4)-1))
local focus_y_64 = math.ceil(bank[bank_64].focus_pad/4)
g:led(x_64, y_64+3, led_maps["square_dim"][edition])
g:led(focus_x_64, focus_y_64+3, led_maps["square_selected"][edition])
if bank[bank_64][bank[bank_64].focus_pad].pause == true then
g:led(8,6,led_maps["square_selected"][edition])
g:led(7,6,led_maps["square_selected"][edition])
else
g:led(7,6,led_maps["square_off"][edition])
g:led(8,6,led_maps["square_off"][edition])
end
end
-- crow pad execute
if bank[bank_64].focus_hold then
g:led(5,7,(10*bank[bank_64][bank[bank_64].focus_pad].crow_pad_execute)+5)
end
local alt = bank[bank_64].alt_lock and 1 or 0
g:led(4,8,15*alt)
-- for i,e in pairs(lit) do
-- g:led(e.x, e.y,led_maps["zilchmo_on"][edition])
-- end
--alt
g:led(1,8,(grid.alt and led_maps["alt_on"][edition] or led_maps["alt_off"][edition]))
local focused = bank[bank_64].focus_hold == false and bank[bank_64][bank[bank_64].id] or bank[bank_64][bank[bank_64].focus_pad]
--clips + stuff
g:led(focused.clip+4,4,led_maps["clip"][edition])
g:led(focused.mode+4,5,led_maps["mode"][edition])
g:led(8,4,bank[bank_64].focus_hold == false and led_maps["off"][edition] or led_maps["focus_on"][edition])
if focused.loop == false then
g:led(5,6,led_maps["loop_off"][edition])
elseif focused.loop == true then
g:led(5,6,led_maps["loop_on"][edition])
end
if not arp[bank_64].enabled then
g:led(6,6,led_maps["off"][edition])
else
if arp[bank_64].playing and arp[bank_64].hold then
g:led(6,6,led_maps["arp_play"][edition])
elseif arp[bank_64].hold then
g:led(6,6,led_maps["arp_pause"][edition])
else
g:led(6,6,led_maps["arp_on"][edition])
end
end
-- Live buffers
if rec[rec.focus].clear == 0 then
g:led(rec.focus,2,rec[rec.focus].state == 1 and led_maps["live_rec"][edition] or led_maps["live_pause"][edition])
elseif rec[rec.focus].clear == 1 then
g:led(rec.focus,2,led_maps["live_empty"][edition])
end
elseif grid_page_64 == 1 then
-- delay page!
for i = 1,5 do
g:led(8,i+2,delay[2].selected_bundle == i and 15 or (delay_bundle[2][i].saved == true and led_maps["bundle_saved"][edition] or 0))
g:led(1,i+2,delay[1].selected_bundle == i and 15 or (delay_bundle[1][i].saved == true and led_maps["bundle_saved"][edition] or 0))
end
for i = 1,3 do
g:led(2,i,bank[i][bank[i].id].left_delay_level > 0 and led_maps["64_bank_send"][edition] or 0)
g:led(7,i,bank[i][bank[i].id].right_delay_level > 0 and led_maps["64_bank_send"][edition] or 0)
end
g:led(2,4,params:get("delay L: external input") > 0 and led_maps["64_bank_send"][edition] or 0)
g:led(7,4,params:get("delay R: external input") > 0 and led_maps["64_bank_send"][edition] or 0)
-- delay time modifiers
local time_to_led = {{},{},{},{}}
local time = {delay[1].modifier, delay[2].modifier}
for i = 1,2 do
time_to_led[i] = 0
time_to_led[i+2] = 0
if time[i] == 0.5 then
time_to_led[i+2] = led_maps["time_to_led.5"][edition]
elseif time[i] == 0.25 then
time_to_led[i+2] = led_maps["time_to_led.25"][edition]
elseif time[i] == 0.125 then
time_to_led[i+2] = led_maps["time_to_led.125"][edition]
elseif time[i] == 2 then
time_to_led[i] = led_maps["time_to_led2"][edition]
elseif time[i] == 4 then
time_to_led[i] = led_maps["time_to_led4"][edition]
elseif time[i] == 8 then
time_to_led[i] = led_maps["time_to_led8"][edition]
elseif time[i] == 16 then
time_to_led[i] = led_maps["time_to_led16"][edition]
end
end
g:led(6,1,time_to_led[2])
g:led(6,2,time_to_led[4])
g:led(3,1,time_to_led[1])
g:led(3,2,time_to_led[3])
g:led(6,3,delay[2].reverse and led_maps["reverse_on"][edition] or led_maps["reverse_off"][edition])
g:led(3,3,delay[1].reverse and led_maps["reverse_on"][edition] or led_maps["reverse_off"][edition])
rate_to_led = {{},{},{},{}}
local rate = {params:get("delay L: rate"), params:get("delay R: rate")}
for i = 1,2 do
rate_to_led[i] = 0
rate_to_led[i+2] = 0
for j = 1,24 do
if math.modf(rate[i]) >= j then
rate_to_led[i] = math.modf(util.linlin(0,24,3,15,j))
end
end
for j = 0.25,1,0.05 do
if rate[i] >= j then
rate_to_led[i+2] = math.modf(util.linlin(0.25,1,15,0,j))
end
end
if rate[i] == 1 then
rate_to_led[i+2] = 3
end
end
g:led(5,1,rate_to_led[2])
g:led(5,2,rate_to_led[4])
g:led(5,3,delay[2].wobble_hold and led_maps["wobble_on"][edition] or led_maps["wobble_off"][edition])
g:led(4,1,rate_to_led[1])
g:led(4,2,rate_to_led[3])
g:led(4,3,delay[1].wobble_hold and led_maps["wobble_on"][edition] or led_maps["wobble_off"][edition])
-- delay levels
local level_to_led = {{},{}}
local delay_level = {params:get("delay L: global level"), params:get("delay R: global level")}
for i = 1,2 do
if delay_level[i] <= 0.125 then
level_to_led[i] = 0
elseif delay_level[i] <= 0.375 then
level_to_led[i] = 1
elseif delay_level[i] <= 0.625 then
level_to_led[i] = 2
elseif delay_level[i] <= 0.875 then
level_to_led[i] = 3
elseif delay_level[i] <= 1 then
level_to_led[i] = 4
end
end
for i = 8,4,-1 do
g:led(3,i,led_maps["level_lo"][edition])
g:led(6,i,led_maps["level_lo"][edition])
end
for i = 1,2 do
if not delay[i].level_mute then
for j = 8,4+(4-level_to_led[i]),-1 do
g:led(i==1 and 3 or 6,j,led_maps["level_hi"][edition])
end
else
if params:get(i == 1 and "delay L: global level" or "delay R: global level") == 0 then
for j = 8,4,-1 do
g:led(i==1 and 3 or 6,j,led_maps["level_hi"][edition])
end
end
end
end
-- feedback levels
local feed_to_led = {{},{}}
local feedback_level = {params:get("delay L: feedback"), params:get("delay R: feedback")}
for i = 1,2 do
if feedback_level[i] <= 12.5 then
feed_to_led[i] = 0
elseif feedback_level[i] <= 37.5 then
feed_to_led[i] = 1
elseif feedback_level[i] <= 62.5 then
feed_to_led[i] = 2
elseif feedback_level[i] <= 87.5 then
feed_to_led[i] = 3
elseif feedback_level[i] <= 100 then
feed_to_led[i] = 4
end
end
for i = 8,4,-1 do
g:led(4,i,led_maps["level_lo"][edition])
g:led(5,i,led_maps["level_lo"][edition])
end
for i = 1,2 do
if not delay[i].feedback_mute then
for j = 8,4+(4-feed_to_led[i]),-1 do
g:led(i==1 and 4 or 5,j,led_maps["level_hi"][edition])
end
else
if params:get(i == 1 and "delay L: feedback" or "delay R: feedback") == 0 then
for j = 8,4,-1 do
g:led(i==1 and 4 or 5,j,led_maps["level_hi"][edition])
end
end
end
end
end
g:refresh()
end
end
end
--/GRID
function grid_pattern_execute(entry)
if entry ~= nil then
if entry ~= "pause" then
local i = entry.i
local a_p; -- this will index the arc encoder recorders
if arc_param[i] == 1 or arc_param[i] == 2 or arc_param[i] == 3 then
a_p = 1
else
a_p = arc_param[i] - 2
end
if entry.action == "pads" then
if params:get("zilchmo_patterning") == 2 then
bank[i][entry.id].rate = entry.rate
end
selected[i].id = entry.id
selected[i].x = entry.x
selected[i].y = entry.y
bank[i].id = selected[i].id
if params:get("zilchmo_patterning") == 2 then
bank[i][bank[i].id].mode = entry.mode
bank[i][bank[i].id].clip = entry.clip
end
if arc_param[i] ~= 4 and #arc_pat[i][a_p].event == 0 then -- TODO what is this?
if params:get("zilchmo_patterning") == 2 then
bank[i][bank[i].id].start_point = entry.start_point
bank[i][bank[i].id].end_point = entry.end_point
end
end
if rytm.track[i].k == 0 then
cheat(i,bank[i].id)
end
elseif string.match(entry.action, "zilchmo") then
if params:get("zilchmo_patterning") == 2 then
bank[i][entry.id].rate = entry.rate
rightangleslice.init(entry.row,entry.bank,entry.con)
local depth = {'(%d)','(%d)(%d)','(%d)(%d)(%d)','(%d)(%d)(%d)(%d)'}
local y1,y2,y3,y4 = entry.con:match(depth[#entry.con])
zilch_leds[4][entry.bank][y1 ~= nil and 5-tonumber(y1)] = 1
zilch_leds[4][entry.bank][y2 ~= nil and 5-tonumber(y2)] = 1
zilch_leds[4][entry.bank][y3 ~= nil and 5-tonumber(y3)] = 1
zilch_leds[4][entry.bank][y4 ~= nil and 5-tonumber(y4)] = 1
clock.run(recorded_zilch_zero,entry.bank)
if arc_param[i] ~= 4 and #arc_pat[i][a_p].event == 0 then -- TODO what is this?
bank[i][bank[i].id].start_point = entry.start_point
bank[i][bank[i].id].end_point = entry.end_point
softcut.loop_start(i+1,bank[i][bank[i].id].start_point)
softcut.loop_end(i+1,bank[i][bank[i].id].end_point)
end
end
end
grid_dirty = true
if menu ~= 1 then screen_dirty = true end
end
end
end
function recorded_zilch_zero(bank)
clock.sleep(0.1)
for i = 1,4 do
zilch_leds[4][bank][i] = 0
end
grid_dirty = true
end
function new_arc_pattern_execute(entry)
local i = entry.i1
local j = entry.i2
local id = arc_control[i]
local param = entry.param
if param ~= 4 then
local which_pad = entry.pad
if arc_pat[i][j].step ~= 0 then
if arc_pat[i][j].step > 1 then
if params:get("arc_patterning") == 2 then
if arc_pat[i][j].event[arc_pat[i][j].step].pad ~= arc_pat[i][j].event[arc_pat[i][j].step-1].pad then
bank[id].id = arc_pat[i][j].event[arc_pat[i][j].step].pad
selected[id].x = (math.ceil(bank[id].id/4)+(5*(id-1)))
selected[id].y = 8-((bank[id].id-1)%4)
cheat(id,arc_pat[i][j].event[arc_pat[i][j].step].pad)
slew_filter(id,entry.prev_tilt,entry.tilt,bank[id][bank[id].id].q,bank[id][bank[id].id].q,15)
grid_dirty = true
end
end
elseif arc_pat[i][j].step == 1 then
if params:get("arc_patterning") == 2 then
bank[id].id = arc_pat[i][j].event[arc_pat[i][j].step].pad
selected[id].x = (math.ceil(bank[id].id/4)+(5*(id-1)))
selected[id].y = 8-((bank[id].id-1)%4)
cheat(id,arc_pat[i][j].event[arc_pat[i][j].step].pad)
slew_filter(id,arc_pat[i][j].event[arc_pat[i][j].count].tilt,entry.tilt,bank[id][bank[id].id].q,bank[id][bank[id].id].q,15)
grid_dirty = true
end
end
elseif arc_pat[i][j].step == 0 then
arc_pat[i][j].step = 1
if params:get("arc_patterning") == 2 then
bank[id].id = arc_pat[i][j].event[arc_pat[i][j].step].pad
selected[id].x = (math.ceil(bank[id].id/4)+(5*(id-1)))
selected[id].y = 8-((bank[id].id-1)%4)
cheat(id,arc_pat[i][j].event[arc_pat[i][j].step].pad)
slew_filter(id,arc_pat[i][j].event[arc_pat[i][j].count].tilt,entry.tilt,bank[id][bank[id].id].q,bank[id][bank[id].id].q,15)
grid_dirty = true
end
end
if entry.param == 1 or entry.param == 2 or entry.param == 3 then
bank[id][which_pad].start_point = (entry.start_point + (8*(bank[id][which_pad].clip-1)) + arc_offset)
bank[id][which_pad].end_point = (entry.end_point + (8*(bank[id][which_pad].clip-1)) + arc_offset)
if bank[id].id == which_pad then
softcut.loop_start(id+1, (entry.start_point + (8*(bank[id][which_pad].clip-1))) + arc_offset)
softcut.loop_end(id+1, (entry.end_point + (8*(bank[id][which_pad].clip-1))) + arc_offset)
end
elseif entry.param == 5 then
bank[id][which_pad].level = (entry.level + arc_offset)
bank[id].global_level = (entry.global_level + arc_offset)
if bank[id].id == which_pad then
softcut.level(id+1, (entry.level + arc_offset)*bank[id].global_level)
end
elseif entry.param == 6 then
bank[id][which_pad].pan = (entry.pan + arc_offset)
if bank[id].id == which_pad then
softcut.pan(id+1, (entry.pan + arc_offset))
end
end
else
slew_filter(id,entry.prev_tilt,entry.tilt,bank[id][bank[id].id].q,bank[id][bank[id].id].q,15)
end
if menu ~= 1 then screen_dirty = true end
end
function arc_delay_pattern_execute(entry)
local i = entry.i
local side = entry.delay_focus
arc_p[4].delay_focus = side
if side == "L" then
arc_p[4].left_delay_value = entry.left_delay_value
params:set("delay L: div/mult",entry.left_delay_value)
else
arc_p[4].right_delay_value = entry.right_delay_value
params:set("delay R: div/mult",entry.right_delay_value)
end
if menu ~= 1 then screen_dirty = true end
end
function zilchmo(k,i)
rightangleslice.init(k,i)
lit = {}
-- grid_redraw()
grid_dirty = true
if menu ~= 1 then screen_dirty = true end
end
function pad_copy(destination, source)
for k,v in pairs(source) do
if k ~= bank_id and k ~= pad_id then
destination[k] = v
end
end
end
a = arc.connect()
arc_d = {}
for i = 1,3 do
arc_d[i] = {}
end
a.delta = function(n,d)
arc_d[n] = d
arc_actions.init(n,arc_d[n])
end
arc_redraw = function()
a:all(0)
local which_pad = nil
for i = 1,3 do
if bank[arc_control[i]].focus_hold == false then
which_pad = bank[arc_control[i]].id
else
which_pad = bank[arc_control[i]].focus_pad
end
local duration = bank[i][which_pad].mode == 1 and 8 or clip[bank[i][which_pad].clip].sample_length
if arc_param[i] == 1 then
-- if start_to_led <= end_to_led then
-- a:segment(i, util.linlin(0, duration, tau*(1/4), tau*1.23, start_to_led), util.linlin(0, duration, (tau*(1/4))+0.1, tau*1.249999, end_to_led), 15)
-- else
-- a:segment(i, util.linlin(0, duration, (tau*(1/4))+0.1, tau*1.23, end_to_led), util.linlin(0, duration, tau*(1/4), tau*1.249999, start_to_led), 15)
-- end
local minimum = bank[i][which_pad].mode == 1 and live[bank[i][which_pad].clip].min or clip[bank[i][which_pad].clip].min
local maximum = bank[i][which_pad].mode == 1 and live[bank[i][which_pad].clip].max or clip[bank[i][which_pad].clip].max
local start_to_led = bank[arc_control[i]][which_pad].start_point
local end_to_led = bank[arc_control[i]][which_pad].end_point
a:segment(i, util.linlin(minimum, maximum, tau*(1/4), tau*1.23, start_to_led), util.linlin(minimum, maximum, (tau*(1/4))+0.1, tau*1.249999, end_to_led), 15)
-- DOES THERE NEED TO BE AN ELSE CASE TO START < = END ???
end
if arc_param[i] == 2 or arc_param[i] == 3 then
local minimum = bank[i][which_pad].mode == 1 and live[bank[i][which_pad].clip].min or clip[bank[i][which_pad].clip].min
local maximum = bank[i][which_pad].mode == 1 and live[bank[i][which_pad].clip].max or clip[bank[i][which_pad].clip].max
local start_to_led = math.floor(util.linlin(minimum,maximum,1,64,bank[arc_control[i]][which_pad].start_point))
local end_to_led = math.floor(util.linlin(minimum,maximum,1,64,bank[arc_control[i]][which_pad].end_point))
local playhead_to_led = util.linlin(minimum,maximum,1,64,poll_position_new[i+1])
a:led(i,(math.floor(playhead_to_led))+16,5)
a:led(i, arc_param[i] == 2 and (start_to_led+16) or (end_to_led+17),15)
a:led(i, arc_param[i] == 2 and (end_to_led+17) or (start_to_led+16),8)
end
if arc_param[i] == 4 then
local tilt_to_led = slew_counter[i].slewedVal
if bank[i].focus_hold == true then
which_pad = bank[i].focus_pad
tilt_to_led = bank[i][bank[i].focus_pad].tilt
else
which_pad = bank[i].id
end
if tilt_to_led == nil then
tilt_to_led = bank[i][which_pad].tilt
a:led(i,47,5)
a:led(i,48,10)
a:led(i,49,15)
a:led(i,50,10)
a:led(i,51,5)
elseif tilt_to_led >= -0.04 and tilt_to_led <=0.20 then
a:led(i,47,5)
a:led(i,48,10)
a:led(i,49,15)
a:led(i,50,10)
a:led(i,51,5)
elseif tilt_to_led < -0.04 then
a:segment(i, tau*(1/4), util.linlin(-1, 1, (tau*(1/4))+0.1, tau*1.249999, tilt_to_led), 15)
elseif tilt_to_led > 0.20 then
a:segment(i, util.linlin(-1, 1, (tau*(1/4)), (tau*1.24)+0.4, tilt_to_led-0.1), tau*(1/4)+0.1, 15)
end
end
if arc_param[i] == 5 then
local level_to_led;
if key1_hold or bank[i].alt_lock or grid.alt then
level_to_led = bank[i].global_level
else
level_to_led = bank[i][bank[i].id].level
end
for j = 1,17 do
a:led(i,(math.floor(util.linlin(0,2,5,70,(level_to_led)-(1/8*j))))+16,15)
end
end
if arc_param[i] == 6 then
local pan_to_led = bank[i][bank[i].id].pan
a:led(i,(math.floor(util.linlin(-1,1,10,55,pan_to_led)))+22,4)
a:led(i,(math.floor(util.linlin(-1,1,10,55,pan_to_led)))+17,15)
a:led(i,(math.floor(util.linlin(-1,1,10,55,pan_to_led)))+12,4)
end
end
arc_meta_level = {}
for i = 1,6 do
arc_meta_level[i] = util.round(arc_meta_focus) == i and 15 or 5
a:led(4,((i-1)*8)+25,arc_meta_level[i])
end
a:refresh()
end
--file loading
function persistent_state_save()
local dirname = _path.data.."cheat_codes_2/"
if os.rename(dirname, dirname) == nil then
os.execute("mkdir " .. dirname)
end
local file = io.open(_path.data.. "cheat_codes_2/persistent_state.data", "w+")
io.output(file)
io.write("midi_control_enabled: "..params:get("midi_control_enabled").."\n")
io.write("midi_control_device: "..params:get("midi_control_device").."\n")
io.write("midi_echo_enabled: "..params:get("midi_echo_enabled").."\n")
for i = 1,3 do
io.write("bank_"..i.."_midi_channel: "..params:get("bank_"..i.."_midi_channel").."\n")
io.write("bank_"..i.."_pad_midi_base: "..params:get("bank_"..i.."_pad_midi_base").."\n")
end
io.write("preview_clip_change: "..params:get("preview_clip_change").."\n")
io.write("zilchmo_patterning: "..params:get("zilchmo_patterning").."\n")
io.write("LED_style: "..params:get("LED_style").."\n")
io.write("arc_patterning: "..params:get("arc_patterning").."\n")
for i = 1,3 do
io.write("bank_"..i.."_midi_zilchmo_enabled: "..params:get("bank_"..i.."_midi_zilchmo_enabled").."\n")
end
io.write("grid_size: "..params:get("grid_size").."\n")
io.write("global_pad_to_midi_note_enabled: "..params:get("global_pad_to_midi_note_enabled").."\n")
io.write("global_pad_to_midi_note_destination: "..params:get("global_pad_to_midi_note_destination").."\n")
io.write("global_pad_to_midi_note_channel: "..params:get("global_pad_to_midi_note_channel").."\n")
io.write("global_pad_to_midi_note_scale: "..params:get("global_pad_to_midi_note_scale").."\n")
io.write("global_pad_to_midi_note_root: "..params:get("global_pad_to_midi_note_root").."\n")
io.write("global_pad_to_midi_note_root_octave: "..params:get("global_pad_to_midi_note_root_octave").."\n")
for i = 1,3 do
io.write(i.."_pad_to_midi_note_enabled: "..params:get(i.."_pad_to_midi_note_enabled").."\n")
io.write(i.."_pad_to_midi_note_destination: "..params:get(i.."_pad_to_midi_note_destination").."\n")
io.write(i.."_pad_to_midi_note_channel: "..params:get(i.."_pad_to_midi_note_channel").."\n")
io.write(i.."_pad_to_midi_note_scale: "..params:get(i.."_pad_to_midi_note_scale").."\n")
io.write(i.."_pad_to_midi_note_root: "..params:get(i.."_pad_to_midi_note_root").."\n")
io.write(i.."_pad_to_midi_note_root_octave: "..params:get(i.."_pad_to_midi_note_root_octave").."\n")
end
io.write("global_pad_to_jf_note_enabled: "..params:get("global_pad_to_jf_note_enabled").."\n")
for i = 1,3 do
io.write(i.."_pad_to_jf_note_enabled: "..params:get(i.."_pad_to_jf_note_enabled").."\n")
io.write(i.."_pad_to_jf_note_velocity: "..params:get(i.."_pad_to_jf_note_velocity").."\n")
end
io.close(file)
end
function count_lines_in(file)
lines = {}
for line in io.lines(file) do
lines[#lines + 1] = line
end
return #lines
end
function persistent_state_restore()
local file = io.open(_path.data .. "cheat_codes_2/persistent_state.data", "r")
if file then
io.input(file)
for i = 1,count_lines_in(_path.data.. "cheat_codes_2/persistent_state.data") do
local s = io.read()
local param,val = s:match("(.+): (.+)")
params:set(param,tonumber(val))
end
io.close(file)
end
all_loaded = true
mc.init()
end
function named_overwrite(path)
if path ~= 'cancel' then
local file = io.open(path, "r")
if file then
io.input(file)
local collection = io.read()
io.close(file)
pre_overwrite(collection)
end
else
print("nothing overwritten")
end
end
function named_delete(path)
if path ~= 'cancel' then
local file = io.open(path, "r")
if file then
io.input(file)
os.remove(path)
io.close(file)
print("collection deleted")
end
end
end
function pre_overwrite(text)
if text ~= 'cancel' then
collection_overwrite_clock = clock.run(overwrite_screen,text)
_norns.key(1,1)
_norns.key(1,0)
else
print("nothing overwritten")
end
end
function pre_delete(text)
if text ~= 'cancel' then
collection_delete_clock = clock.run(delete_screen,text)
_norns.key(1,1)
_norns.key(1,0)
else
print("nothing deleted")
end
end
function pre_save(text)
if text ~= 'cancel' and text ~= nil then
collection_save_clock = clock.run(save_screen,text)
_norns.key(1,1)
_norns.key(1,0)
else
print("nothing saved")
end
end
function named_savestate(text)
local collection = text
local dirname = _path.data.."cheat_codes_2/"
-- local collection = tonumber(string.format("%.0f",params:get("collection")))
if os.rename(dirname, dirname) == nil then
os.execute("mkdir " .. dirname)
end
local dirname = _path.data.."cheat_codes_2/names/"
if os.rename(dirname, dirname) == nil then
os.execute("mkdir " .. dirname)
end
local name_file = io.open(_path.data .. "cheat_codes_2/names/"..collection..".cc2", "w+")
io.output(name_file)
io.write(collection)
io.close(name_file)
local dirname = _path.data.."cheat_codes_2/collection-"..collection.."/"
if os.rename(dirname, dirname) == nil then
os.execute("mkdir " .. dirname)
end
local dirnames = {"banks/","params/","arc-rec/","patterns/","step-seq/","arps/","euclid/","rnd/","delays/","rec/","misc/"}
for i = 1,#dirnames do
local directory = _path.data.."cheat_codes_2/collection-"..collection.."/"..dirnames[i]
if os.rename(directory, directory) == nil then
os.execute("mkdir " .. directory)
end
end
for i = 1,3 do
tab.save(bank[i],_path.data .. "cheat_codes_2/collection-"..collection.."/banks/"..i..".data")
tab.save(step_seq[i],_path.data .. "cheat_codes_2/collection-"..collection.."/step-seq/"..i..".data")
tab.save(arp[i],_path.data .. "cheat_codes_2/collection-"..collection.."/arps/"..i..".data")
tab.save(rytm.track[i],_path.data .. "cheat_codes_2/collection-"..collection.."/euclid/euclid"..i..".data")
tab.save(rnd[i],_path.data .. "cheat_codes_2/collection-"..collection.."/rnd/"..i..".data")
if params:get("collect_live") == 2 then
collect_samples(i,collection)
end
end
for i = 1,2 do
tab.save(delay[i],_path.data .. "cheat_codes_2/collection-"..collection.."/delays/delay"..(i == 1 and "L" or "R")..".data")
end
tab.save(delay_links,_path.data .. "cheat_codes_2/collection-"..collection.."/delays/delay-links.data")
params:write(_path.data.."cheat_codes_2/collection-"..collection.."/params/all.pset")
-- ultimately, i'll want to remember the mappings of specific devices for specific collections...
-- norns.pmap.rev[dev][ch][cc]
-- dev = vport ID...
-- so, see if there are any mappings and if not then ignore that shit...
-- otherwise, grab the device name
-- if the device is present, then the mapping can restore
-- if not, fuck it.
-- might also need to `norns.pmap.assign(name,m.dev,m.ch,m.cc)`
mc.save_mappings(collection)
tab.save(rec,_path.data .. "cheat_codes_2/collection-"..collection.."/rec/rec[rec.focus].data")
-- GRID pattern save
if selected_coll ~= collection then
meta_copy_coll(selected_coll,collection)
end
meta_shadow(collection)
selected_coll = collection
--/ GRID pattern save
-- MIDI pattern save
for i = 1,3 do
save_midi_pattern(i)
end
--/ MIDI pattern save
-- ARC rec save
local arc_rec_dirty = {false,false,false}
for i = 1,3 do
for j = 1,4 do
if arc_pat[i][j].count > 0 then
arc_rec_dirty[i] = true
end
end
if arc_rec_dirty[i] then
save_arc_pattern(i)
else
local file = io.open(_path.data .. "cheat_codes_2/collection-"..selected_coll.."/arc-rec/encoder-"..i..".data", "r")
if file then
io.input(file)
os.remove(_path.data .. "cheat_codes_2/collection-"..selected_coll.."/arc-rec/encoder-"..i..".data")
io.close(file)
end
end
end
--/ ARC rec save
-- misc save
local file = io.open(_path.data .. "cheat_codes_2/collection-"..selected_coll.."/misc/misc.data", "w+")
if file then
io.output(file)
io.write("clock_tempo: "..params:get("clock_tempo").."\n")
io.close(file)
end
--/ misc save
end
function named_loadstate(path)
local file = io.open(path, "r")
if file then
print("loading...")
for j = 1,3 do
for k = 1,7 do
if rnd[j][k].clock ~= nil then
-- print(rnd[j][k].clock)
clock.cancel(rnd[j][k].clock)
end
end
end
reset_all_banks(bank)
print(path)
io.input(file)
local collection = io.read()
io.close(file)
selected_coll = collection
collection_loaded = true
_norns.key(1,1)
_norns.key(1,0)
clock.run(load_screen)
screen_dirty = true
-- all_loaded = false
params:read(_path.data.."cheat_codes_2/collection-"..collection.."/params/all.pset")
-- persistent_state_restore()
if tab.load(_path.data .. "cheat_codes_2/collection-"..collection.."/rec/rec[rec.focus].data") ~= nil then
rec = tab.load(_path.data .. "cheat_codes_2/collection-"..collection.."/rec/rec[rec.focus].data")
if rec.stopped == nil then rec.stopped = false end
if rec.play_segment == nil then rec.play_segment = rec.focus end
softcut.loop_start(1,rec[rec.focus].start_point)
softcut.loop_end(1,rec[rec.focus].end_point-0.01)
end
for i = 1,3 do
if tab.load(_path.data .. "cheat_codes_2/collection-"..collection.."/banks/"..i..".data") ~= nil then
bank[i] = tab.load(_path.data .. "cheat_codes_2/collection-"..collection.."/banks/"..i..".data")
if bank[i][bank[i].id].loop then
softcut.loop(i+1,1)
cheat(i,bank[i].id)
end
end
if tab.load(_path.data .. "cheat_codes_2/collection-"..collection.."/step-seq/"..i..".data") ~= nil then
step_seq[i] = tab.load(_path.data .. "cheat_codes_2/collection-"..collection.."/step-seq/"..i..".data")
end
if tab.load(_path.data .. "cheat_codes_2/collection-"..collection.."/arps/"..i..".data") ~= nil then
arp[i] = tab.load(_path.data .. "cheat_codes_2/collection-"..collection.."/arps/"..i..".data")
end
if tab.load(_path.data .. "cheat_codes_2/collection-"..collection.."/rnd/"..i..".data") ~= nil then
rnd[i] = tab.load(_path.data .. "cheat_codes_2/collection-"..collection.."/rnd/"..i..".data")
for j = 1,#rnd[i] do
rnd[i][j].clock = nil
if rnd[i][j].playing then
rnd[i][j].clock = clock.run(rnd.advance, i, j)
end
end
end
if params:get("collect_live") == 2 then
reload_collected_samples(_path.dust.."audio/cc2_live-audio/"..collection.."/".."cc2_"..collection.."-"..i..".wav",i)
end
if tab.load(_path.data .. "cheat_codes_2/collection-"..collection.."/euclid/euclid"..i..".data") ~= nil then
rytm.track[i] = tab.load(_path.data .. "cheat_codes_2/collection-"..collection.."/euclid/euclid"..i..".data")
end
end
arps.restore_collection()
rytm.restore_collection()
for i = 1,2 do
if tab.load(_path.data .. "cheat_codes_2/collection-"..collection.."/delays/delay"..(i == 1 and "L" or "R")..".data") ~= nil then
delay[i] = tab.load(_path.data .. "cheat_codes_2/collection-"..collection.."/delays/delay"..(i == 1 and "L" or "R")..".data")
end
end
if tab.load(_path.data .. "cheat_codes_2/collection-"..collection.."/delays/delay-links.data") ~= nil then
delay_links = tab.load(_path.data .. "cheat_codes_2/collection-"..collection.."/delays/delay-links.data")
end
-- GRID pattern restore
if selected_coll ~= collection then
meta_shadow(selected_coll)
elseif selected_coll == collection then
cleanup()
end
one_point_two()
-- / GRID pattern restore
for i = 1,3 do
load_arc_pattern(i)
end
for i = 1,3 do
midi_pat[i]:restore_defaults()
local dirname = _path.data .. "cheat_codes_2/collection-"..selected_coll.."/patterns/midi"..i..".data"
if os.rename(dirname, dirname) ~= nil then
load_midi_pattern(i)
end
end
--TODO confirm this is ok, not a namespace collision?
local file = io.open(_path.data .. "cheat_codes_2/collection-"..selected_coll.."/misc/misc.data", "r")
if file then
io.input(file)
params:set("clock_tempo", tonumber(string.match(io.read(), ': (.*)')))
io.close(file)
end
else
_norns.key(1,1)
_norns.key(1,0)
collection_loaded = false
clock.run(load_fail_screen)
end
ping_midi_devices()
if file then
if tab.load(_path.data .. "cheat_codes_2/collection-"..selected_coll.."/params/mappings.txt") ~= nil then
norns.pmap.rev = tab.load(_path.data .. "cheat_codes_2/collection-"..selected_coll.."/params/mappings.txt")
norns.pmap.data = tab.load(_path.data .. "cheat_codes_2/collection-"..selected_coll.."/params/map-data.txt")
-- BUT, i want the device to be present or reassigned...
end
end
grid_dirty = true
end
function test_save(i)
pattern_saver[i].active = true
clock.sleep(1)
-- if pattern_saver[i].active then
if not grid.alt then
if grid_pat[i].count > 0 and grid_pat[i].rec == 0 then
copy_entire_pattern(i)
save_pattern(i,pattern_saver[i].save_slot+8*(i-1),"pattern")
pattern_saver[i].saved[pattern_saver[i].save_slot] = 1
pattern_saver[i].load_slot = pattern_saver[i].save_slot
g:led(math.floor((i-1)*5)+1,9-pattern_saver[i].save_slot,15)
-- g:refresh()
elseif #arp[i].notes > 0 then
save_pattern(i,pattern_saver[i].save_slot+8*(i-1),"arp")
pattern_saver[i].saved[pattern_saver[i].save_slot] = 1
pattern_saver[i].load_slot = pattern_saver[i].save_slot
g:led(math.floor((i-1)*5)+1,9-pattern_saver[i].save_slot,15)
-- g:refresh()
else
print("no pattern data to save")
g:led(math.floor((i-1)*5)+1,9-pattern_saver[i].save_slot,0)
-- g:refresh()
end
pattern_saver[i].clock = nil
grid_dirty = true
else
if pattern_saver[i].saved[pattern_saver[i].save_slot] == 1 then
delete_pattern(pattern_saver[i].save_slot+8*(i-1))
pattern_saver[i].saved[pattern_saver[i].save_slot] = 0
pattern_saver[i].load_slot = 0
else
print("no pattern data to delete")
end
end
-- end
pattern_saver[i].active = false
end
function test_load(slot,destination)
if pattern_saver[destination].saved[slot-((destination-1)*8)] == 1 then
if grid_pat[destination].play == 1 then
grid_pat[destination]:clear()
elseif arp[destination].playing then
arp[destination].pause = true
arp[destination].playing = false
elseif grid_pat[destination].tightened_start == 1 then -- not relevant?
grid_pat[destination].tightened_start = 0
grid_pat[destination].step = grid_pat[destination].start_point-1
quantized_grid_pat[destination].current_step = grid_pat[destination].start_point
quantized_grid_pat[destination].sub_step = 1
end
load_pattern(slot,destination)
if grid_pat[destination].count > 0 then
start_pattern(grid_pat[destination])
elseif #arp[destination].notes > 0 then
local arp_start =
{
["fwd"] = arp[destination].start_point - 1
, ["bkwd"] = arp[destination].end_point + 1
, ["pend"] = arp[destination].start_point
, ["rnd"] = arp[destination].start_point - 1
}
arp[destination].step = arp_start[arp[destination].mode]
arp[destination].pause = false
arp[destination].playing = true
if arp[destination].mode == "pend" then
arp_direction[destination] = "negative"
end
end
end
end
function save_pattern(source,slot,style)
local dirname = _path.data.."cheat_codes_2/collection-"..selected_coll.."/"
if os.rename(dirname, dirname) == nil then
os.execute("mkdir " .. dirname)
end
local dirname = _path.data.."cheat_codes_2/collection-"..selected_coll.."/patterns/"
if os.rename(dirname, dirname) == nil then
os.execute("mkdir " .. dirname)
end
local file = io.open(_path.data .. "cheat_codes_2/collection-"..selected_coll.."/patterns/"..slot..".data", "w+")
-- local file = io.open(_path.data .. "cheat_codes_2/pattern"..selected_coll.."_"..slot..".data", "w+")
io.output(file)
if style == "pattern" then
io.write("stored pad pattern: collection "..selected_coll.." + slot "..slot.."\n")
io.write(original_pattern[source].count .. "\n")
for i = 1,original_pattern[source].count do
io.write(original_pattern[source].time[i] .. "\n")
-- new stuff
if original_pattern[source].event[i] ~= "pause" then
io.write(original_pattern[source].event[i].id .. "\n")
io.write(original_pattern[source].event[i].rate .. "\n")
io.write(tostring(original_pattern[source].event[i].loop) .. "\n")
if original_pattern[source].event[i].mode ~= nil then
io.write(original_pattern[source].event[i].mode .. "\n")
else
io.write("nil" .. "\n")
end
io.write(tostring(original_pattern[source].event[i].pause) .. "\n")
io.write(original_pattern[source].event[i].start_point .. "\n")
if original_pattern[source].event[i].clip ~= nil then
io.write(original_pattern[source].event[i].clip .. "\n")
else
io.write("nil" .. "\n")
end
io.write(original_pattern[source].event[i].end_point .. "\n")
if original_pattern[source].event[i].rate_adjusted ~= nil then
io.write(tostring(original_pattern[source].event[i].rate_adjusted) .. "\n")
else
io.write("nil" .. "\n")
end
io.write(original_pattern[source].event[i].y .. "\n")
io.write(original_pattern[source].event[i].x .. "\n")
io.write(tostring(original_pattern[source].event[i].action) .. "\n")
io.write(original_pattern[source].event[i].i .. "\n")
if original_pattern[source].event[i].previous_rate ~= nil then
io.write(original_pattern[source].event[i].previous_rate .. "\n")
else
io.write("nil" .. "\n")
end
if original_pattern[source].event[i].row ~=nil then
io.write(original_pattern[source].event[i].row .. "\n")
else
io.write("nil" .. "\n")
end
if original_pattern[source].event[i].con ~= nil then
io.write(original_pattern[source].event[i].con .. "\n")
else
io.write("nil" .. "\n")
end
if original_pattern[source].event[i].bank ~= nil and #original_pattern[source].event > 0 then
io.write(original_pattern[source].event[i].bank .. "\n")
else
io.write("nil" .. "\n")
end
else
io.write("pause" .. "\n")
end
end
--/new stuff!
io.write(original_pattern[source].metro.props.time .. "\n")
io.write(original_pattern[source].prev_time .. "\n")
io.write("which playmode?" .. "\n")
io.write(original_pattern[source].playmode .. "\n")
io.write("start point" .. "\n")
io.write(original_pattern[source].start_point .. "\n")
io.write("end point" .. "\n")
io.write(original_pattern[source].end_point .. "\n")
--new stuff, quantum and time_beats!
io.write("cheat codes 2.0" .. "\n")
for i = 1,original_pattern[source].count do
io.write(original_pattern[source].quantum[i] .. "\n")
io.write(original_pattern[source].time_beats[i] .. "\n")
end
--/new stuff, quantum and time_beats!
-- new stuff, quant or unquant + rec_clock_time
io.write(original_pattern[source].mode.."\n")
io.write(original_pattern[source].rec_clock_time.."\n")
io.close(file)
--GIRAFFE
--save_external_timing(source,slot)
--/GIRAFFE
print("saved pattern "..source.." to slot "..slot)
elseif style == "arp" then
tab.save(arp[source],_path.data .. "cheat_codes_2/collection-"..selected_coll.."/patterns/"..slot..".data")
print("saved arp "..source.." to slot "..slot)
end
end
function already_saved()
for i = 1,24 do
local line_count = 0
local file = io.open(_path.data .. "cheat_codes_2/collection-"..selected_coll.."/patterns/"..i..".data", "r")
if file then
io.input(file)
for lines in io.lines(_path.data .. "cheat_codes_2/collection-"..selected_coll.."/patterns/"..i..".data") do
line_count = line_count + 1
end
if line_count > 0 then
local current = math.floor((i-1)/8)+1
pattern_saver[current].saved[i-(8*(current-1))] = 1
else
local current = math.floor((i-1)/8)+1
pattern_saver[current].saved[i-(8*(current-1))] = 0
-- print("killing yr file4387")
os.remove(_path.data .. "cheat_codes_2/collection-"..selected_coll.."/patterns/"..i..".data")
end
io.close(file)
else
local current = math.floor((i-1)/8)+1
pattern_saver[current].saved[i-(8*(current-1))] = 0
end
end
end
function one_point_two()
for i = 1,24 do
local file = io.open(_path.data .. "cheat_codes_2/collection-"..selected_coll.."/patterns/"..i..".data", "r")
if file then
io.input(file)
local current = math.floor((i-1)/8)+1
load_pattern(i,current)
io.close(file)
end
end
for i = 1,3 do
grid_pat[i]:rec_stop()
grid_pat[i]:stop()
grid_pat[i].tightened_start = 0
grid_pat[i]:clear()
pattern_saver[i].load_slot = 0
end
end
function clear_zero()
for i = 1,24 do
local file = io.open(_path.data .. "cheat_codes_2/collection-0/patterns/"..i..".data", "r")
if file then
io.input(file)
local line_count = 0
for lines in io.lines(_path.data .. "cheat_codes_2/collection-0/patterns/"..i..".data") do
line_count = line_count + 1
end
if line_count > 0 then
os.remove(_path.data .. "cheat_codes_2/collection-0/patterns/"..i..".data")
print("cleared default pattern")
end
io.close(file)
end
end
end
function delete_pattern(slot)
local file = io.open(_path.data .. "cheat_codes_2/collection-"..selected_coll.."/patterns/"..slot..".data", "w+")
io.output(file)
io.write()
io.close(file)
print("deleted pattern from slot "..slot)
end
function copy_pattern_across_coll(read_coll,write_coll,slot)
print("4610: "..read_coll,write_coll,slot)
local infile = io.open(_path.data .. "cheat_codes_2/collection-"..read_coll.."/patterns/"..slot..".data", "r")
local outfile = io.open(_path.data .. "cheat_codes_2/collection-"..write_coll.."/patterns/"..slot..".data", "w+")
io.output(outfile)
for line in infile:lines() do
if line == "stored pad pattern: collection "..read_coll.." + slot "..slot then
io.write("stored pad pattern: collection "..write_coll.." + slot "..slot.."\n")
else
io.write(line.."\n")
end
end
io.close(infile)
io.close(outfile)
end
function shadow_pattern(read_coll,write_coll,slot)
local infile = io.open(_path.data .. "cheat_codes_2/collection-"..read_coll.."/patterns/"..slot..".data", "r")
local outfile = io.open(_path.data .. "cheat_codes_2/collection-"..write_coll.."/patterns/shadow-pattern_"..slot..".data", "w+")
io.output(outfile)
for line in infile:lines() do
-- io.write(line.."\n")
if line == "stored pad pattern: collection "..read_coll.." + slot "..slot then
io.write("stored pad pattern: collection "..write_coll.." + slot "..slot.."\n")
else
io.write(line.."\n")
end
end
io.close(infile)
io.close(outfile)
end
function meta_shadow(coll)
for i = 1,3 do
for j = 1,8 do
if pattern_saver[i].saved[j] == 1 then
shadow_pattern(coll,coll,j+(8*(i-1)))
elseif pattern_saver[i].saved[j] == 0 then
local file = io.open(_path.data .. "cheat_codes_2/collection-"..coll.."/patterns/shadow-pattern_"..j+(8*(i-1))..".data", "w+")
if file then
io.output(file)
io.write()
io.close(file)
end
end
end
end
end
function clear_empty_shadows(coll)
for i = 1,24 do
local file = io.open(_path.data .. "cheat_codes_2/collection-"..coll.."/patterns/shadow-pattern_"..i..".data", "r")
if file then
io.input(file)
local line_count = 0
for lines in io.lines(_path.data .. "cheat_codes_2/collection-"..coll.."/patterns/shadow-pattern_"..i..".data") do
line_count = line_count + 1
end
if line_count > 0 then
local current = math.floor((i-1)/8)+1
pattern_saver[current].saved[i-(8*(current-1))] = 1
else
local current = math.floor((i-1)/8)+1
pattern_saver[current].saved[i-(8*(current-1))] = 0
os.remove(_path.data .. "cheat_codes_2/collection-"..coll.."/patterns/shadow-pattern_"..i..".data")
end
io.close(file)
else
local current = math.floor((i-1)/8)+1
pattern_saver[current].saved[i-(8*(current-1))] = 0
end
end
end
function shadow_to_play(coll,slot)
local infile = io.open(_path.data .. "cheat_codes_2/collection-"..coll.."/patterns/shadow-pattern_"..slot..".data", "r")
local outfile = io.open(_path.data .. "cheat_codes_2/collection-"..coll.."/patterns/"..slot..".data", "w+")
io.output(outfile)
if infile then
for line in infile:lines() do
if line == "stored pad pattern: collection "..coll.." + slot "..slot then
io.write("stored pad pattern: collection "..coll.." + slot "..slot.."\n")
else
io.write(line.."\n")
end
end
io.close(infile)
io.close(outfile)
end
end
function meta_copy_coll(read_coll,write_coll)
for i = 1,3 do
for j = 1,8 do
if pattern_saver[i].saved[j] == 1 then
copy_pattern_across_coll(read_coll,write_coll,j+(8*(i-1)))
elseif pattern_saver[i].saved[j] == 0 then
local file = io.open(_path.data .. "cheat_codes_2/collection-"..write_coll.."/patterns/"..j+(8*(i-1))..".data", "w+")
if file then
io.output(file)
io.write()
io.close(file)
end
end
end
end
end
function load_pattern(slot,destination)
local ignore_external_timing = false
local file = io.open(_path.data .. "cheat_codes_2/collection-"..selected_coll.."/patterns/"..slot..".data", "r")
if file then
io.input(file)
if io.read() == "stored pad pattern: collection "..selected_coll.." + slot "..slot then
print("loading grid pat")
grid_pat[destination].event = {}
grid_pat[destination].count = tonumber(io.read())
for i = 1,grid_pat[destination].count do
grid_pat[destination].time[i] = tonumber(io.read())
-- new stuff
local pause_or_id = io.read()
grid_pat[destination].event[i] = {}
if pause_or_id ~= "pause" then
grid_pat[destination].event[i].id = {}
grid_pat[destination].event[i].rate = {}
grid_pat[destination].event[i].loop = {}
grid_pat[destination].event[i].mode = {}
grid_pat[destination].event[i].pause = {}
grid_pat[destination].event[i].start_point = {}
grid_pat[destination].event[i].clip = {}
grid_pat[destination].event[i].end_point = {}
grid_pat[destination].event[i].rate_adjusted = {}
grid_pat[destination].event[i].y = {}
grid_pat[destination].event[i].x = {}
grid_pat[destination].event[i].action = {}
grid_pat[destination].event[i].i = {}
grid_pat[destination].event[i].previous_rate = {}
grid_pat[destination].event[i].row = {}
grid_pat[destination].event[i].con = {}
grid_pat[destination].event[i].bank = nil
--grid_pat[destination].event[i].id = tonumber(io.read())
-- new stuff
grid_pat[destination].event[i].id = tonumber(pause_or_id)
grid_pat[destination].event[i].rate = tonumber(io.read())
local loop_to_boolean = io.read()
if loop_to_boolean == "true" then
grid_pat[destination].event[i].loop = true
else
grid_pat[destination].event[i].loop = false
end
grid_pat[destination].event[i].mode = tonumber(io.read())
local pause_to_boolean = io.read()
if pause_to_boolean == "true" then
grid_pat[destination].event[i].pause = true
else
grid_pat[destination].event[i].pause = false
end
grid_pat[destination].event[i].start_point = tonumber(io.read())
grid_pat[destination].event[i].clip = tonumber(io.read())
grid_pat[destination].event[i].end_point = tonumber(io.read())
local rate_adjusted_to_boolean = io.read()
if rate_adjusted_to_boolean == "true" then
grid_pat[destination].event[i].rate_adjusted = true
else
grid_pat[destination].event[i].rate_adjusted = false
end
grid_pat[destination].event[i].y = tonumber(io.read())
local loaded_x = tonumber(io.read())
grid_pat[destination].event[i].action = io.read()
grid_pat[destination].event[i].i = destination
local source = tonumber(io.read())
if destination < source then
grid_pat[destination].event[i].x = loaded_x - (5*(source-destination))
elseif destination > source then
grid_pat[destination].event[i].x = loaded_x + (5*(destination-source))
elseif destination == source then
grid_pat[destination].event[i].x = loaded_x
end
grid_pat[destination].event[i].previous_rate = tonumber(io.read())
grid_pat[destination].event[i].row = tonumber(io.read())
grid_pat[destination].event[i].con = io.read()
local loaded_bank = tonumber(io.read())
if loaded_bank ~= nil then
if destination < source then
grid_pat[destination].event[i].bank = loaded_bank - (5*(source-destination))
elseif destination > source then
grid_pat[destination].event[i].bank = loaded_bank + (5*(source-destination))
elseif destination == source then
grid_pat[destination].event[i].bank = loaded_bank
end
end
else
grid_pat[destination].event[i] = "pause"
end
end
grid_pat[destination].metro.props.time = tonumber(io.read())
grid_pat[destination].prev_time = tonumber(io.read())
if io.read() == "which playmode?" then
local pm = tonumber(io.read())
if pm ~= 1 then
grid_pat[destination].playmode = 2
else
grid_pat[destination].playmode = 1
end
else
grid_pat[destination].playmode = 1
end
--set_pattern_mode(grid_pat[destination],destination)
if io.read() == "start point" then
grid_pat[destination].start_point = tonumber(io.read())
else
grid_pat[destination].start_point = 1
end
if io.read() == "end point" then
grid_pat[destination].end_point = tonumber(io.read())
else
grid_pat[destination].end_point = grid_pat[destination].count
end
--new stuff, quantum and time_beats!
if io.read() == "cheat codes 2.0" then
for i = 1,grid_pat[destination].count do
grid_pat[destination].quantum[i] = tonumber(io.read())
grid_pat[destination].time_beats[i] = tonumber(io.read())
end
grid_pat[destination].mode = io.read()
grid_pat[destination].rec_clock_time = tonumber(io.read())
ignore_external_timing = true
end
--/new stuff, quantum and time_beats!
else
-- print("it's an arp!")
arp[destination] = tab.load(_path.data .. "cheat_codes_2/collection-"..selected_coll.."/patterns/"..slot..".data")
-- arp[destination] = tab.load(_path.data .. "cheat_codes_2/pattern"..selected_coll.."_"..slot..".data")
ignore_external_timing = true
end
io.close(file)
if not ignore_external_timing then
print("see load_external_timing")
-- load_external_timing(destination,slot)
end
else
print("no grid patterns to load!")
end
end
function cleanup()
metro[31].time = 0.25
for i = 1,3 do
env_counter[i]:stop()
end
clear_zero()
for i = 1,3 do
for j = 1,8 do
shadow_to_play(selected_coll,j+(8*(i-1)))
end
end
--need all this to just happen at cleanup after save
for i = 1,24 do
local file = io.open(_path.data .. "cheat_codes_2/collection-"..selected_coll.."/patterns/"..i..".data", "r")
if file then
io.input(file)
local line_count = 0
for lines in io.lines(_path.data .. "cheat_codes_2/collection-"..selected_coll.."/patterns/"..i..".data") do
line_count = line_count + 1
end
if line_count > 0 then
local current = math.floor((i-1)/8)+1
pattern_saver[current].saved[i-(8*(current-1))] = 1
else
local current = math.floor((i-1)/8)+1
pattern_saver[current].saved[i-(8*(current-1))] = 0
os.remove(_path.data .. "cheat_codes_2/collection-"..selected_coll.."/patterns/"..i..".data")
end
io.close(file)
else
local current = math.floor((i-1)/8)+1
pattern_saver[current].saved[i-(8*(current-1))] = 0
end
end
clear_empty_shadows(selected_coll)
end
-- arc pattern stuff!
function save_arc_pattern(which)
local file = io.open(_path.data .. "cheat_codes_2/collection-"..selected_coll.."/arc-rec/encoder-"..which..".data", "w+")
io.output(file)
io.write("stored arc pattern: collection "..selected_coll.." + encoder "..which.."\n")
for j = 1,4 do
io.write("total events in recording "..j..": "..arc_pat[which][j].count .. "\n")
for i = 1,arc_pat[which][j].count do
io.write("event "..i.." time: "..arc_pat[which][j].time[i] .. "\n")
io.write("event "..i.." i1: "..arc_pat[which][j].event[i].i1 .. "\n")
io.write("event "..i.." i2: "..arc_pat[which][j].event[i].i2 .. "\n")
io.write("event "..i.." param: "..arc_pat[which][j].event[i].param .. "\n")
io.write("event "..i.." pad: "..arc_pat[which][j].event[i].pad .. "\n")
io.write("event "..i.." start point: "..arc_pat[which][j].event[i].start_point .. "\n")
io.write("event "..i.." end point: "..arc_pat[which][j].event[i].end_point .. "\n")
io.write("event "..i.." prev tilt: "..arc_pat[which][j].event[i].prev_tilt .. "\n")
io.write("event "..i.." tilt: "..arc_pat[which][j].event[i].tilt .. "\n")
io.write("event "..i.." pan: "..arc_pat[which][j].event[i].pan .. "\n")
io.write("event "..i.." level: "..arc_pat[which][j].event[i].level .. "\n")
io.write("event "..i.." global level: "..arc_pat[which][j].event[i].global_level .. "\n")
end
io.write("recording "..j.." props time: "..arc_pat[which][j].metro.props.time .. "\n")
io.write("recording "..j.." prev time: "..arc_pat[which][j].prev_time .. "\n")
io.write("recording "..j.." start point: " .. arc_pat[which][j].start_point .. "\n")
io.write("recording "..j.." end point: " .. arc_pat[which][j].end_point .. "\n")
end
io.close(file)
print("saved arc pattern for encoder "..which)
end
function load_arc_pattern(which)
local file = io.open(_path.data .. "cheat_codes_2/collection-"..selected_coll.."/arc-rec/encoder-"..which..".data", "r")
if file then
io.input(file)
if io.read() == "stored arc pattern: collection "..selected_coll.." + encoder "..which then
for j = 1,4 do
arc_pat[which][j].event = {}
arc_pat[which][j].count = tonumber(string.match(io.read(), ': (.*)'))
for i = 1,arc_pat[which][j].count do
arc_pat[which][j].time[i] = tonumber(string.match(io.read(), ': (.*)'))
arc_pat[which][j].event[i] = {}
arc_pat[which][j].event[i].i1 = {}
arc_pat[which][j].event[i].i2 = {}
arc_pat[which][j].event[i].param = {}
arc_pat[which][j].event[i].pad = {}
arc_pat[which][j].event[i].start_point = {}
arc_pat[which][j].event[i].end_point = {}
arc_pat[which][j].event[i].prev_tilt = {}
arc_pat[which][j].event[i].tilt = {}
arc_pat[which][j].event[i].pan = {}
arc_pat[which][j].event[i].level = {}
arc_pat[which][j].event[i].global_level = {}
--
arc_pat[which][j].event[i].i1 = tonumber(string.match(io.read(), ': (.*)'))
arc_pat[which][j].event[i].i2 = tonumber(string.match(io.read(), ': (.*)'))
arc_pat[which][j].event[i].param = tonumber(string.match(io.read(), ': (.*)'))
arc_pat[which][j].event[i].pad =tonumber(string.match(io.read(), ': (.*)'))
arc_pat[which][j].event[i].start_point = tonumber(string.match(io.read(), ': (.*)'))
arc_pat[which][j].event[i].end_point = tonumber(string.match(io.read(), ': (.*)'))
arc_pat[which][j].event[i].prev_tilt = tonumber(string.match(io.read(), ': (.*)'))
arc_pat[which][j].event[i].tilt = tonumber(string.match(io.read(), ': (.*)'))
arc_pat[which][j].event[i].pan = tonumber(string.match(io.read(), ': (.*)'))
arc_pat[which][j].event[i].level = tonumber(string.match(io.read(), ': (.*)'))
arc_pat[which][j].event[i].global_level = tonumber(string.match(io.read(), ': (.*)'))
end
arc_pat[which][j].metro.props.time = tonumber(string.match(io.read(), ': (.*)'))
arc_pat[which][j].prev_time = tonumber(string.match(io.read(), ': (.*)'))
arc_pat[which][j].start_point = tonumber(string.match(io.read(), ': (.*)'))
arc_pat[which][j].end_point = tonumber(string.match(io.read(), ': (.*)'))
end
end
io.close(file)
grid_dirty = true
else
print("no arc patterns to load")
end
end
function save_midi_pattern(which)
local file = io.open(_path.data .. "cheat_codes_2/collection-"..selected_coll.."/patterns/midi"..which..".data", "w+")
io.output(file)
if midi_pat[which].count > 0 then
io.write("stored midi pattern: collection "..selected_coll..", pattern "..which.."\n")
io.write("total: "..midi_pat[which].count .. "\n")
for i = 1,midi_pat[which].count do
io.write("unquant time: "..midi_pat[which].time[i] .. "\n")
--io.write("quant duration: "..midi_pat[which].time_beats[i] .. "\n")
io.write("quant duration: 0.8".."\n")
io.write("target: "..midi_pat[which].event[i].target .. "\n")
io.write("note: "..midi_pat[which].event[i].note .. "\n")
end
io.write("metro props time: "..midi_pat[which].metro.props.time .. "\n")
io.write("metro prev time: "..midi_pat[which].prev_time .. "\n")
io.write("pattern start point: " .. midi_pat[which].start_point .. "\n")
io.write("pattern end point: " .. midi_pat[which].end_point .. "\n")
io.write("playmode: " .. midi_pat[which].playmode .. "\n")
io.write("random_pitch_range: " .. midi_pat[which].random_pitch_range .. "\n")
io.write("rec_clock_time: " .. midi_pat[which].rec_clock_time .. "\n")
else
io.write("no data present")
end
io.close(file)
print("saved midi pattern "..which)
end
function load_midi_pattern(which)
local file = io.open(_path.data .. "cheat_codes_2/collection-"..selected_coll.."/patterns/midi"..which..".data", "r")
if file then
io.input(file)
if io.read() == "stored midi pattern: collection "..selected_coll..", pattern "..which then
midi_pat[which].event = {}
midi_pat[which].count = tonumber(string.match(io.read(), ': (.*)'))
for i = 1,midi_pat[which].count do
midi_pat[which].time[i] = tonumber(string.match(io.read(), ': (.*)'))
midi_pat[which].time_beats[i] = tonumber(string.match(io.read(), ': (.*)'))
midi_pat[which].event[i] = {}
midi_pat[which].event[i].target = tonumber(string.match(io.read(), ': (.*)'))
midi_pat[which].event[i].note = tonumber(string.match(io.read(), ': (.*)'))
--
end
midi_pat[which].metro.props.time = tonumber(string.match(io.read(), ': (.*)'))
midi_pat[which].prev_time = tonumber(string.match(io.read(), ': (.*)'))
midi_pat[which].start_point = tonumber(string.match(io.read(), ': (.*)'))
midi_pat[which].end_point = tonumber(string.match(io.read(), ': (.*)'))
local full_param, first, second;
for i = 1,3 do
full_param = io.read()
first = full_param:match("(.+):")
second = full_param:match(": (.*)")
midi_pat[which][first] = full_param ~= nil and tonumber(second) or midi_pat[which][first]
end
print("loaded midi pat "..which)
end
io.close(file)
else
print("no midi patterns to load")
end
end