#!/usr/bin/env python3 # # loopertrx: import/export audio data from some looper pedals. # # Copyright (C) 2017 Reiner Herrmann # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. import random import struct import sys import argparse import usb.core import usb.util class USBLooper(): VID = 0x0483 PID = 0x572a ENDPOINT_IN = 0x81 ENDPOINT_OUT = 0x01 COMMAND_SIZE = 0xfe COMMAND_DATA = 0xff def __init__(self): self.dev = usb.core.find(idVendor=self.VID, idProduct=self.PID) if not self.dev: raise FileNotFoundError("Device not found.") if self.dev.is_kernel_driver_active(0): self.dev.detach_kernel_driver(0) self.dev.set_configuration() def random_tag(self): return random.randint(0, 1 << 32 - 1) def mass_storage_header(self, data_len, cdb_len, tag=None): header = "USBC".encode('ascii') if not tag: tag = self.random_tag() flags = 0x80 target = 0x00 header += struct.pack(' 0: bufsize = (size >= 65536) and 65536 or size # data needs to be transferred in multiples of 1k blocks padding = (1024 - (bufsize % 1024)) % 1024 buf = self.get_data(bufsize + padding) print('.', end='', flush=True), outfile.write(buf[:bufsize]) size -= bufsize print(" Done.") def transmit_file(self, filename): with open(filename, 'rb') as infile: content = infile.read() tag = self.random_tag() # skip first 44 bytes for now; we assume valid file. TODO: validate content = content[44:] content_size = len(content) print("Transmitting ", end='', flush=True) while len(content) > 0: buf = content[:65536] padsize = (1024 - (len(buf) % 1024)) % 1024 buf += b'\x00' * padsize self.send_data(buf, tag) print('.', end='', flush=True), content = content[65536:] self.submit_data_len(content_size, tag) print(" Done.") def main(): argp = argparse.ArgumentParser() argp.add_argument('action', choices=['rx', 'tx']) argp.add_argument('filename') args = argp.parse_args() try: dev = USBLooper() except FileNotFoundError as e: print(e) sys.exit(1) if args.action == 'rx': dev.receive_file(args.filename) elif args.action == 'tx': dev.transmit_file(args.filename) if __name__ == "__main__": main()