Last active
November 26, 2021 14:24
-
-
Save dndrks/ff326eb2f7bdf30955987b41e630fe71 to your computer and use it in GitHub Desktop.
norns USB TAPE copy
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- USB tape copy | |
-- | |
-- * attach a USB drive | |
-- * choose a TAPE, press K3: | |
-- * copy | |
-- * copy+delete | |
-- * delete | |
-- | |
-- if you see "NO USB DETECTED", | |
-- reconnect and wait a minute | |
-- then try again | |
local UI = require "ui" | |
function build_filelist() | |
local filepath = _path.audio.."tape/" | |
audio_filepaths = {} | |
for i in io.popen("ls "..filepath):lines() do | |
if string.find(i,"%.wav$") then table.insert(audio_filepaths,filepath..i) end | |
end | |
tape_names = {} | |
tape_sizes = {} | |
for i = 1,#audio_filepaths do | |
tape_names[i] = string.gsub(audio_filepaths[i],"/home/we/dust/audio/tape/","") | |
local temp_sizer = io.open(audio_filepaths[i]) | |
tape_sizes[i] = util.round(fsize(temp_sizer)/1000000,0.01) | |
io.close(temp_sizer) | |
end | |
end | |
function build_ui_lists() | |
tape_list = UI.ScrollingList.new(0,5,1,tape_names) | |
tape_list.num_above_selected = 0 | |
tape_list.num_visible = 5 | |
size_list = UI.ScrollingList.new(60,5,1,tape_sizes) | |
size_list.num_above_selected = 0 | |
size_list.num_visible = 5 | |
end | |
function fsize (file) | |
local current = file:seek() -- get current position | |
local size = file:seek("end") -- get file size | |
file:seek("set", current) -- restore position | |
return size | |
end | |
function check_usb_for_tape_folder() | |
if not util.file_exists("/media/usb0/norns_tapes") then | |
os.execute("sudo mkdir /media/usb0/norns_tapes") | |
end | |
end | |
function check_usb_for_tape(id) | |
if util.file_exists("/media/usb0/norns_tapes/"..id) then | |
return true | |
else | |
return false | |
end | |
end | |
function usb_actions(state) | |
if state == "copy" or state == "copy and delete" then | |
_ui.focus = "copying" | |
redraw() | |
local name_id = string.gsub(tape_names[tape_list.index],".wav","") | |
local name_index = 1 | |
while check_usb_for_tape(name_id..'.wav') do | |
if name_id:match("(.+)-(.+)") ~= nil then | |
name_id = name_id:match("(.+)-(.+)") | |
end | |
name_id = name_id.."-"..name_index | |
name_index = name_index+1 | |
end | |
os.execute('sudo cp -r ~/dust/audio/tape/'..tape_names[tape_list.index]..' /media/usb0/norns_tapes/'..name_id..'.wav') | |
local checked = check_sum(_path.audio.."/tape/"..tape_names[tape_list.index], "/media/usb0/norns_tapes/"..name_id..".wav") | |
if checked and state == "copy and delete" then | |
clock.run(function() clock.sleep(1) _ui.focus = "delete confirmation" redraw() end) | |
elseif checked and state == "copy" then | |
clock.run(function() clock.sleep(1) _ui.focus = "tape_scroll" redraw() end) | |
elseif not checked and (state == "copy and delete" or state == "copy") then | |
clock.run(function() | |
_ui.focus = "unsuccessful copy" | |
redraw() | |
drive_connected = false | |
clock.sleep(2) | |
_ui.focus = "manage" | |
redraw() | |
end) | |
end | |
elseif state == "delete" then | |
_ui.focus = "delete confirmation" | |
redraw() | |
end | |
end | |
function usb_delete(file) | |
os.execute('sudo rm ~/dust/audio/tape/'..file) | |
build_filelist() | |
local old_index = tape_list.index | |
build_ui_lists() | |
tape_list.index = util.clamp(old_index,1,#tape_list.entries) | |
size_list.index = util.clamp(old_index,1,#size_list.entries) | |
_ui.focus = "tape_scroll" | |
redraw() | |
end | |
function CRC(data, length) | |
sum = 65535 | |
local d | |
for i = 1, length do | |
if data ~= nil then | |
d = string.byte(data, i) -- get i-th element, like data[i] in C | |
sum = ByteCRC(sum, d) | |
else | |
break | |
end | |
end | |
return sum | |
end | |
function ByteCRC(sum, data) | |
sum = sum ~ data | |
for i = 0, 7 do -- lua for loop includes upper bound, so 7, not 8 | |
if ((sum & 1) == 0) then | |
sum = sum >> 1 | |
else | |
sum = (sum >> 1) ~ 0xA001 -- it is integer, no need for string func | |
end | |
end | |
return sum | |
end | |
function check_sum(first,second) | |
local source = io.open(first,"rb") | |
local copy = io.open(second,"rb") | |
local flag; | |
while true do | |
if copy ~= nil then | |
local source_chunk = source:read(16*1024) -- 16kB at a time | |
local copy_chunk = copy:read(16*1024) -- 16kB at a time | |
if not source_chunk and not copy_chunk then break end | |
local source_hash = CRC(source_chunk,3) | |
local copy_hash = CRC(copy_chunk,3) | |
if source_hash == copy_hash then flag = true else flag = false end | |
else | |
flag = false | |
break | |
print("no copy") | |
end | |
end | |
if flag == true then | |
_ui.focus = "successful copy" | |
elseif flag == false then | |
_ui.focus = "unsuccessful copy" | |
end | |
io.close(source) | |
io.close(copy) | |
redraw() | |
return flag | |
end | |
function tape_delete() | |
_ui.focus = "deleting" | |
redraw() | |
local name_id = string.gsub(tape_names[tape_list.index],".wav","") | |
local name_index = 1 | |
while check_usb_for_tape(name_id..'.wav') do | |
if name_id:match("(.+)-(.+)") ~= nil then | |
name_id = name_id:match("(.+)-(.+)") | |
end | |
name_id = name_id.."-"..name_index | |
name_index = name_index+1 | |
end | |
os.execute('sudo cp -r ~/dust/audio/tape/'..tape_names[tape_list.index]..' /media/usb0/norns_tapes/'..name_id..'.wav') | |
_ui.focus = "tape_scroll" | |
redraw() | |
end | |
function init() | |
key1_hold = false | |
drive_connected = os.execute("mount | grep sda1") | |
drive_connected = drive_connected and true or false | |
check_usb_for_tape_folder() | |
build_filelist() | |
print("there are "..#audio_filepaths.." tapes in your TAPE folder") | |
build_ui_lists() | |
_ui = {} | |
_ui.focus = "tape_scroll" | |
_ui.manage_index = 1 | |
end | |
function enc(n,d) | |
if n == 2 then | |
if _ui.focus == "tape_scroll" then | |
tape_list:set_index_delta(d) | |
size_list:set_index_delta(d) | |
elseif _ui.focus == "manage" then | |
_ui.manage_index = util.clamp(_ui.manage_index+d,1,3) | |
end | |
redraw() | |
end | |
end | |
function key(n,z) | |
if n == 1 then | |
key1_hold = z == 1 and true or false | |
elseif n == 3 and z == 1 then | |
if _ui.focus == "tape_scroll" and not key1_hold then | |
_ui.focus = "manage" | |
elseif _ui.focus == "tape_scroll" and key1_hold then | |
build_filelist() | |
local old_index = tape_list.index | |
build_ui_lists() | |
tape_list.index = util.clamp(old_index,1,#tape_list.entries) | |
size_list.index = util.clamp(old_index,1,#size_list.entries) | |
elseif _ui.focus == "manage" then | |
if drive_connected then | |
local actions = {"copy","copy and delete","delete"} | |
usb_actions(actions[_ui.manage_index]) | |
end | |
elseif _ui.focus == "delete confirmation" then | |
usb_delete(tape_names[tape_list.index]) | |
end | |
elseif n == 2 and z == 1 then | |
if _ui.focus == "manage" then | |
_ui.focus = "tape_scroll" | |
elseif _ui.focus == "delete confirmation" then | |
_ui.focus = "tape_scroll" | |
end | |
end | |
redraw() | |
end | |
function redraw() | |
if not drive_connected then | |
drive_connected = os.execute("mount | grep sda1") | |
drive_connected = drive_connected and true or false | |
end | |
screen.clear() | |
if _ui.focus == "tape_scroll" then | |
screen.font_size(8) | |
tape_list:redraw() | |
size_list:redraw() | |
elseif _ui.focus == "manage" then | |
screen.font_size(8) | |
screen.level(15) | |
local y_pos; | |
if tape_list.index == #tape_list.entries-1 then | |
y_pos = 21 | |
elseif tape_list.index == #tape_list.entries then | |
y_pos = 32 | |
else | |
y_pos = 10 | |
end | |
screen.move(0,y_pos) | |
screen.text(tape_names[tape_list.index]) | |
screen.move(60,y_pos) | |
screen.text(tape_sizes[tape_list.index]) | |
local edit_options = {"copy to USB","copy to USB + delete","delete"} | |
if drive_connected then | |
for i = 1,3 do | |
screen.move(30,y_pos+(i*10)) | |
screen.level(_ui.focus == "tape_scroll" and 3 or (_ui.manage_index == i and 15 or 3)) | |
screen.text(edit_options[i]) | |
end | |
else | |
screen.move(0,y_pos+10) | |
screen.text("NO USB DRIVE DETECTED") | |
end | |
elseif _ui.focus == "copying" then | |
screen.level(15) | |
screen.font_size(8) | |
screen.move(64,27) | |
screen.text_center("copying") | |
screen.move(64,37) | |
screen.text_center(tape_list.entries[tape_list.index]) | |
screen.font_size(8) | |
screen.move(64,50) | |
if tape_sizes[tape_list.index] > 20 and tape_sizes[tape_list.index] < 40 then | |
screen.text_center("may take a minute") | |
elseif tape_sizes[tape_list.index] >= 40 and tape_sizes[tape_list.index] < 100 then | |
screen.text_center("may take several minutes") | |
elseif tape_sizes[tape_list.index] >= 100 and tape_sizes[tape_list.index] < 250 then | |
screen.text_center("will take several minutes") | |
elseif tape_sizes[tape_list.index] >= 250 then | |
screen.text_center("will take 10+ minutes") | |
elseif tape_sizes[tape_list.index] < 20 then | |
end | |
elseif _ui.focus == "successful copy" then | |
screen.level(15) | |
screen.font_size(8) | |
screen.move(64,32) | |
screen.text_center("success!") | |
elseif _ui.focus == "unsuccessful copy" then | |
screen.level(15) | |
screen.font_size(20) | |
screen.move(64,32) | |
screen.text_center("error!") | |
elseif _ui.focus == "delete confirmation" then | |
screen.level(15) | |
screen.font_size(8) | |
screen.move(64,27) | |
screen.text_center("K3: delete "..tape_list.entries[tape_list.index]) | |
screen.move(64,37) | |
screen.text_center("K2: do not delete") | |
end | |
screen.update() | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment