Last active
July 11, 2019 04:26
-
-
Save unbracketed/cea880dd291b673310411cde2d970a8b to your computer and use it in GitHub Desktop.
Utility for managing BOSS RC-300 memory slots and settings
This file contains 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
import csv | |
import os | |
import shutil | |
import logging | |
log = logging.getLogger(__name__) | |
UPLOAD_QUEUE = "~/.rc300-queue.csv" | |
RC300_BASE = "/Volumes/BOSS_RC-300/ROLAND/" | |
DATA_DIR = "{}/DATA".format(RC300_BASE) | |
WAVE_DIR = "{}/WAVE".format(RC300_BASE) | |
MEMORY_HEADER_SIZE = 32 | |
MEMORY_SLOT_SIZE = 748 | |
MEMORY_SLOT_NAME_SIZE = 64 | |
MEMORY_TRACK_NAME_SIZE = 40 | |
class MemorySlot: | |
def __init__(self, name, track_1, track_2, track_3): | |
self.name = name | |
self.track_1 = track_1 | |
self.track_2 = track_2 | |
self.track_3 = track_3 | |
class BossMemoryFile: | |
def __init__(self, path): | |
self.data = open(path, "rb").read() | |
def get_memory_slot(self, num): | |
"Gets data for a memory slot" | |
start = MEMORY_HEADER_SIZE + (MEMORY_SLOT_SIZE * (num - 1)) | |
end = start + MEMORY_SLOT_SIZE | |
slot = self.data[start:end] | |
name_chrs = [] | |
for i in range(0, 64, 4): | |
name_chrs.append(chr(slot[i])) | |
name = "".join(name_chrs) | |
track_1, track_2, track_3 = self.get_slot_tracks(num) | |
return MemorySlot(name.strip(), track_1, track_2, track_3) | |
def get_slot_tracks(self, num): | |
start = ( | |
MEMORY_HEADER_SIZE | |
+ (99 * MEMORY_SLOT_SIZE) | |
+ ((num - 1) * MEMORY_TRACK_NAME_SIZE) * 3 | |
) | |
end = start + MEMORY_TRACK_NAME_SIZE | |
track_1 = self.data[start:end] | |
start += MEMORY_TRACK_NAME_SIZE | |
end += MEMORY_TRACK_NAME_SIZE | |
track_2 = self.data[start:end] | |
start += MEMORY_TRACK_NAME_SIZE | |
end += MEMORY_TRACK_NAME_SIZE | |
track_3 = self.data[start:end] | |
return track_1, track_2, track_3 | |
def rename_memory_slot(self, num, name): | |
"""Updates name for a memory slot""" | |
# TODO max length | |
buf = bytearray(MEMORY_TRACK_NAME_SIZE) | |
slot = self.get_memory_slot(num) | |
def as_csv(self): | |
with open("BOSS_RC-300_Memory.csv", "w") as outfile: | |
writer = csv.writer(outfile) | |
for i in range(1, 100): | |
slot = self.get_memory_slot(i) | |
writer.writerow((slot["name"],)) | |
def get_memory_file(): | |
""""Copy MEMORY.RC3 to local system""" | |
shutil.copyfile(os.path.join(DATA_DIR, "MEMORY.RC3"), ".") | |
def get_system_file(): | |
"""Copy SYSTEM.RC3 to local system""" | |
shutil.copyfile(os.path.join(DATA_DIR, "SYSTEM.RC3"), ".") | |
def push_memory_file(): | |
"""Copy local MEMORY.RC3 to RC-300""" | |
shutil.copyfile("MEMORY.RC3", DATA_DIR) | |
def push_system_file(): | |
""""Copy local SYSTEM.RC3 to RC-300""" | |
shutil.copyfile("SYSTEM.RC3", DATA_DIR) | |
def push_track(slot, track_num, path): | |
# Todo verify source 16bit stereo 44kHz | |
dst = "{}/{}/{}_{}".format(WAVE_DIR, slot, slot, track_num) | |
shutil.copyfile(path, dst) | |
def do_push_from_csv(slots, dry_run=True): | |
with open(UPLOAD_QUEUE, "r") as queue: | |
reader = csv.reader(queue) | |
for (slot_num, name, track_1, track_2, track_3) in reader: | |
slot = slots.get_memory_slot(slot_num) | |
if slot.name != name: | |
log.warning("Overwriting name") | |
if not dry_run: | |
slots.rename_memory_slot(slot_num, name) | |
# TODO DOS shorten style | |
# TODO clear existing track | |
if track_1 and track_1 != slot.track_1: | |
log.warning("Overwriting track 1") | |
if not dry_run: | |
push_track(slot_num, 1, track_1) | |
if track_2 and track_2 != slot.track_2: | |
log.warning("Overwriting track 2") | |
if not dry_run: | |
push_track(slot_num, 2, track_2) | |
if track_3 and track_3 != slot.track_3: | |
log.warning("Overwriting track 3") | |
if not dry_run: | |
push_track(slot_num, 3, track_3) | |
""" | |
First 32 bytes are the header / ignore | |
--- | |
Memory Slots: | |
748 bytes per slot | |
1 - 64 Name | |
--- | |
File / track list: | |
40 bytes per name, some have additional chars... | |
""" | |
if __name__ == "__main__": | |
slots = BossMemoryFile("MEMORY.RC3") | |
slots.as_csv() | |
# TODO full backup | |
do_push_from_csv(slots) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment