def sysex_file_to_csvs(syx_filepath: str, csv_path: str) -> None: common_fieldnames = list( map(lambda x: x[0], HEADER_PARAM_TO_DECODER.values())) common_fieldnames_ = common_fieldnames + list( map(lambda x: x[0], COMMON_PARAM_TO_DECODER.values())) tone_fieldnames = list( map(lambda x: x[0], HEADER_PARAM_TO_DECODER.values())) tone_fieldnames_ = tone_fieldnames + list( map(lambda x: x[0], TONE_PARAM_TO_DECODER.values())) with open(syx_filepath, 'r') as syx_file: msgs = mido.read_syx_file(syx_filepath) file_basename = os.path.splitext(os.path.basename(syx_filepath))[0] common_csvfile_name = csv_path + file_basename + '_common.csv' tones_csvfile_name = csv_path + file_basename + '_tones.csv' # also open write file for common and tone csvs with open(common_csvfile_name, 'w') as common_csvfile: with open(tones_csvfile_name, 'w') as tones_csvfile: common_writer = csv.DictWriter(common_csvfile, fieldnames=common_fieldnames_, extrasaction='ignore') tones_writer = csv.DictWriter(tones_csvfile, fieldnames=tone_fieldnames_, extrasaction='ignore') common_writer.writeheader() tones_writer.writeheader() for patch_msgs in chunk_sysex_msgs(msgs): patch_data_chunks = parse_patch_messages(patch_msgs) com_data = to_row(next(patch_data_chunks)) common_writer.writerow(com_data) for tone_data in patch_data_chunks: tones_writer.writerow(to_row(tone_data))
def consume_syx(path): path = Path(path).expanduser() try: preset = mido.read_syx_file(path.as_posix())[0] except IndexError as e: return None except ValueError as e: return None if len(preset.data) == 0: return None def get_voice(data): unpacked = voice_struct.unpack(data) if not verify(unpacked, VOICE_PARAMETER_RANGES): return None return unpacked get_header = header_struct.unpack sysex_iter = iter(preset.data) try: header = get_header(bytes(take(sysex_iter, len(header_bytes)))) yield from (get_voice(bytes(take(sysex_iter, len(voice_bytes)))) for _ in range(N_VOICES)) except RuntimeError: return None
def presetToCsv(preset): mid = mido.read_syx_file(preset["midiFile"]) mido.write_syx_file('patch.txt', mid, plaintext=True) mid = mido.MidiFile(preset["midiFile"]) #print(mid) try: skip = preset["skip"] except KeyError: skip = 0 for i, track in enumerate(mid.tracks): counter = 0 for m, msg in enumerate(track): #if skip != 0 and not m % 2: # continue #print("--------------------------------", m) try: print("--------------------------------", m, msg.data[3], msg.data[4], msg.data[5], msg.data[6], msg.data[7], msg.data[8], msg.data[9], msg.data[10], msg.data[11], msg.data[12]) allChars = [] patchNameChars = [] for idx, chrOrd in enumerate(msg.data): allChars.append(chr(chrOrd)) if idx < preset["idx"]["titleBegin"] or idx > preset[ "idx"]["titleEnd"]: continue patchNameChars.append(chr(chrOrd)) try: categoryString = preset["categories"][msg.data[ preset["idx"]["cat"]]] except IndexError: categoryString = "" patchName = ''.join(patchNameChars).strip() msb = str(msg.data[preset["idx"]["msb"]]) pc = str(msg.data[preset["idx"]["pc"]]) if dumpAllChars: print(''.join(allChars).strip()) else: print('"' + '","'.join([msb, pc, patchName, categoryString]) + '"') counter += 1 if limitOutputTo == None: continue if counter > limitOutputTo: sys.exit() except AttributeError: continue
def load_file(self, jx8p_sysex_file_path=None, dbg=False): """ Given a path to a .syx file, this function will parse and return a patch object """ print 'loading', jx8p_sysex_file_path if jx8p_sysex_file_path==None: print('give me a patch, dummy.') return 1 syx = mido.read_syx_file(jx8p_sysex_file_path)[0].bytes() # yields an array of bytes if syx[0] != 0xF0: print 'INVALID SYX: MALFORMED HEADER' if syx[1] != self.SYSEX_ROLAND_ID: print 'INVALID SYX: ROLAND ID NOT PRESENT' # PROCESS AS `PROGRAM` MESSAGE if syx[2] == 0x34: print 'SYSEX JX8P `PROGRAM` OPCODE NOT YET IMPLEMENTED' # PROCESS AS `ALL-PARAMETERS` MESSAGE # APR messages are 67 bytes in total # (there may be more messages in the syx file, i havent dealt with that yet) if syx[2] == 0x35 and len(syx) == 67: print 'PROCESSING APR MESSAGE' # The sysex header is 7 bytes long # the parameters follow the header, in sequential order parameter_values = syx[7:-1] index=0 while (index<len(parameter_values)): if self.parameters[index] != None: # some parameters are undefined self.parameters[index].value = parameter_values[index] index+=1 # PROCESS AS `INDIVIDUAL-PARAMETERS` MESSAGE # `IPR` messages are used when 1 or several parameters, but not all, are changed. # However, this message type could send all parameters, but i think it's purpose # was to reduce traffic on the midi ports. Instead of parameter data coming # sequentially (as the `APR` message does), the parameters are represented as # pairs of bytes, where the first byte says which parameter and the second byte # is the data associated with the parameter # # I plan on making real-time interpolation smarter by only sending parameters which # have been changed since the last step, instead of sending all parameters every single step if syx[2] == 0x36: print 'SYSEX JX8P `INDIVIDUAL PARAMETERS` OPCODE NOT YET IMPLEMENTED' if syx[-1] != 0xF7: print 'INVALID SYX: MALFORMED TAIL' if dbg==True: self.info() return self
def start1(): msg = mido.read_syx_file("test.syx") list1 = [[] for x in range(len(msg))] for i in range(len(msg)): list1[i]= [ None for x in range(len(msg[i].data))] for j in range(len(msg[i].data)): #print(" ") list1[i][j]=hex(msg[i].data[j]) print(list1[i]) # Instaciar katana=Katana() # Iniciar conexión con el katana connection_state = "Unplugged" while connection_state=="Unplugged": x=katana.initConnection() if x==1: connection_state = "plugged" else: print("NO se encuentra KATANA") time.sleep(5) #katana.saveChain(0, 0) # Test de funcionamiento while(1): x=int(input("Select preset ")) if x==0: katana.loadPatch(0, 0, 0) elif x==1: katana.loadPatch(0, 0, 1) elif x==2: katana.loadPatch(0, 0, 2) elif x==3: katana.loadPatch(0, 0, 3) elif x==4: katana.loadPatch(0, 1, 0) elif x==5: katana.loadPatch(0, 1, 1) elif x==6: katana.loadPatch(0, 1, 2) elif x==7: katana.loadPatch(0, 1, 3) elif x==8: katana.changeChannel(0) elif x==9: katana.changeChannel(1)
def processFolder(self, folderName): files = os.listdir(folderName + '/') print('Encoding {} MIDI files'.format(len(files))) for f in tqdm(files): try: midFile = MidiFile(f) except Exception: try: midFile = mido.read_syx_file(f) except Exception: continue for track in midFile.tracks: for msg in track: self.track.append(msg) self.mid.save(self.filename) return self.encodeMidi(self.filename)
def _parse_sysex(self, messages): ports = {} try: for msg in messages: if msg[0] not in ports: ports[msg[0]] = mido.open_output(msg[0]) if isinstance(msg[1], int): messages = [msg[1:]] else: messages = mido.read_syx_file(msg[1]) for msgdata in messages: ports[msg[0]].send(mido.Message('sysex', data=msgdata)) for x in ports.keys(): ports[x].close() except: return "Failed to parse or send SYSEX"
def test_3(): messages = mido.read_syx_file(TEST_DATA) for message in messages: gen = iter(message.data) voices = bank_from_packed_stream(gen) op1 = voices[0].operators[0] s = op1.to_packed_stream() op2 = Operator.from_packed_stream(iter(s)) print op1 == op2 voice1 = voices[0] s = voice1.to_packed_stream() voice2 = Voice.from_packed_stream(iter(s)) print voice1 == voice2 voice = Voice()
def upload_patch(self, program_number, patch): ''' Overwrites the patch settings Input -------- program_number (int) number of the patch you want to overwrite. A1 is 0, D8 is 32 patch (list of sysex messages) ''' if type(patch) is str: patch = read_syx_file(patch) if type(program_number) is str: program_number = program_name_to_number(program_number) for m in patch: mess = SH201SysExMessage('put') mess.payload = m.data mess.program = program_number self.port.send(mess.message)
def read_patches(filepath): """Read a DX patch at the given file path. Reface DX patches have one sysex for the main patch, and separate sysex messages for each voice. We'll assume everything in the same sysex file is for a single patch. """ patches = [] current_patch = None messages = mido.read_syx_file(filepath) for message in messages: bytes = message.bin() if (bytes[0] != 0xf0 or bytes[1] != 0x43 or bytes[2] != 0x0 or bytes[3] != 0x7f or bytes[4] != 0x1c): print 'Not reface DX patch.' print '%x %x %x %x %x' % (bytes[0], bytes[1], bytes[2], bytes[3], bytes[4]) if len(bytes) == 13: # header pass elif len(bytes) == 51: # Patch. if current_patch: patches.append(current_patch) current_patch = RefaceDXPatch(filepath) current_patch.collection = os.path.basename( os.path.dirname(filepath)) current_patch.parse(message.bin()) current_patch.name = current_patch.settings['patch_name'] voice_number = 1 elif len(bytes) == 41: # Voice current_patch.parse(message.bin(), definitions=refacedx_voice_definitions, group_key='voice_%d' % voice_number) voice_number += 1 else: print 'Unknown reface dx message in %s' % filepath if current_patch: patches.append(current_patch) return patches
def decode_patches(filepath): """Returns patches found.""" if filepath.endswith('syx'): messages = mido.read_syx_file(filepath) if (messages) == 0: return [] manufacturer = read_manufacturer_from_bytes(messages[0].bin()) return decode_patch(filepath, manufacturer) elif filepath.endswith('mid'): patch_file = mido.MidiFile(filepath) for i, track in enumerate(patch_file.tracks): for msg in track: bytes = msg.bin() bytes = msg.bin() if len(bytes) == 524: manufacturer = read_manufacturer_from_bytes(bytes) return decode_patch(filepath, manufacturer) return []
def read_patches(filepath): """Read multiple Virus TI patches from file.""" patches = [] if filepath.endswith('syx'): # Single patch. messages = mido.read_syx_file(filepath) for message in messages: bytes = message.bin() if len(bytes) != 524: # Not patch. continue patch_name = str(bytes[0xf9:0x103]) patch_name = patch_name.strip() p = AccessPatch(filepath) p.name = patch_name p.collection = os.path.basename(filepath) p.parse(message.bin()) patches.append(p) elif filepath.endswith('mid'): patch_file = mido.MidiFile(filepath) for i, track in enumerate(patch_file.tracks): for msg in track: bytes = msg.bin() if len(bytes) == 524: track_number = msg.bin()[8] patch_name = str(bytes[0xf9:0x103]) patch_name = patch_name.strip() p = AccessPatch(filepath) p.name = patch_name p.collection = os.path.basename(filepath) p.parse(msg.bin()) patches.append(p) return patches
def set_bank_from_file(self, filename): data = mido.read_syx_file(filename)[0].bytes() data = data[1:len(data) - 1] self.connector.set_bank_from_file(filename) return data
def __init__(self): # Carga de presetOperations with open("presetOperations.json", "r") as f: self.presetOperations = json.load(f) #print(self.presetOperations) #print(type(self.defaultPresetOperations)) #print(len(self.defaultPresetOperations)) #print(self.defaultPresetOperations["PedalFXEnable"]) #print(self.defaultPresetOperations["PedalFXEnable"].keys()) #for distro in distros_dict: # print(distro["type"]) # Carga de preset default: with open("defaultPreset.json", "r") as f: self.defaultPreset = json.load(f) print(self.defaultPreset) self.currentPreset = self.defaultPreset self.currentPresetPage = 0 self.currentPresetNumberOfPages = len(self.defaultPreset) currentPresetPage = 0 # Carga de patch default y su enable self.defaultPatch = mido.read_syx_file(self.currentDirectory + "\defaultPatch.syx") with open(self.currentDirectory + "\defaultEnable.csv", "r") as file: for row in csv.reader(file): self.defaultEnable[row[0]] = int(row[1]) # Carga de Panel Chain (default) self.defaultChain = mido.read_syx_file(self.currentDirectory + "\defaultChain.syx") # Ajuste de tamaños de matrices y listas self.groupNames = os.listdir(self.currentDirectory + "/GroupPresets") self.numberOfGroups = len(self.groupNames) self.patchChainMatrix = [[[]] for x in range(self.numberOfGroups)] self.chainMatrix = [[] for x in range(self.numberOfGroups)] self.bankNames = [[] for x in range(self.numberOfGroups)] self.numberOfBanks = [0 for x in range(self.numberOfGroups)] self.patchesNames = [[[]] for x in range(self.numberOfGroups)] self.numberOfPatches = [[] for x in range(self.numberOfGroups)] self.patchesMatrix = [[[[]]] for x in range(self.numberOfGroups)] self.patchEnableFXMatrix = [[[{}]] for x in range(self.numberOfGroups)] #self.presetsNames = [[[]] for x in range(self.numberOfGroups)] #self.numberOfPresets = [[] for x in range(self.numberOfGroups)] #self.presetsMatrix = [[[[]]] for x in range(self.numberOfGroups)] #print(self.groupNames) for i in range(self.numberOfGroups): self.bankNames[i] = os.listdir(self.currentDirectory + "/GroupPresets/" + self.groupNames[i] + "/Banks") self.bankNames[i].sort() self.numberOfBanks[i] = len(self.bankNames[i]) #print(self.bankNames[i]) self.patchChainMatrix[i] = [ 0 for x in range(self.numberOfBanks[i]) ] self.patchesNames[i] = [[] for x in range(self.numberOfBanks[i])] self.numberOfPatches[i] = [0 for x in range(self.numberOfBanks[i])] self.patchesMatrix[i] = [[[]] for x in range(self.numberOfBanks[i])] self.patchEnableFXMatrix[i] = [ [{}] for x in range(self.numberOfBanks[i]) ] # Carga de chains self.chainMatrix[i] = [None for x in range(4)] localChainList = os.listdir(self.currentDirectory + "/GroupPresets/" + self.groupNames[i] + "/Chains/") localChainList.sort() #print(localChainList) for j in localChainList: self.chainMatrix[i][int( j[0])] = mido.read_syx_file(self.currentDirectory + "/GroupPresets/" + self.groupNames[i] + "/Chains/" + j[0] + ".syx")[0] for j in range(self.numberOfBanks[i]): self.patchesNames[i][j] = os.listdir(self.currentDirectory + "/GroupPresets/" + self.groupNames[i] + "/Banks/" + self.bankNames[i][j] + "/patches") self.patchesNames[i][j].sort() self.numberOfPatches[i][j] = len(self.patchesNames[i][j]) #print(self.patchesNames[i][j]) self.patchesMatrix[i][j] = [ [] for x in range(self.numberOfPatches[i][j]) ] self.patchChainMatrix[i][j] = [ None for x in range(self.numberOfPatches[i][j]) ] self.patchEnableFXMatrix[i][j] = [ {} for x in range(self.numberOfPatches[i][j]) ] # Lectura de chainConfig (Que cadena le corresponde a cada pàtch) with open( self.currentDirectory + "/GroupPresets/" + self.groupNames[i] + "/Banks/" + self.bankNames[i][j] + "/chainConfig.csv", "r") as file: for row in csv.reader(file): self.patchChainMatrix[i][j] = row for k in range(len(self.patchChainMatrix[i][j])): self.patchChainMatrix[i][j][k] = int( self.patchChainMatrix[i][j][k]) # Lectura de patches for k in range(self.numberOfPatches[i][j]): auxList = list(self.patchesNames[i][j][k]) auxList.pop() auxList.pop() auxList.pop() auxList.pop() self.patchesNames[i][j][k] = "".join(auxList) #print(self.patchesNames[i][j][k]) self.patchesMatrix[i][j][k] = mido.read_syx_file( self.currentDirectory + "/GroupPresets/" + self.groupNames[i] + "/Banks/" + self.bankNames[i][j] + "/patches/" + self.patchesNames[i][j][k] + ".syx") # Lectura del chainEnable de los patches with open( self.currentDirectory + "/GroupPresets/" + self.groupNames[i] + "/Banks/" + self.bankNames[i][j] + "/enable/" + self.patchesNames[i][j][k] + ".csv", "r") as file: for row in csv.reader(file): self.patchEnableFXMatrix[i][j][k][row[0]] = int( row[1]) #print(row) #print(self.patchEnableFXMatrix[i][j][k]) #print(len(self.patchesMatrix[i][j][k])) # Estado de preset actual self.currentGroup = 0 self.currentLoadedGroup = 0 self.currentBank = 0 self.currentPach = 0 self.currentChain = self.patchChainMatrix[self.currentGroup][ self.currentBank][self.currentPach] #print(self.currentChain) #self.currentPreset = None # Parametros del preset self.presetMaxVolume = 100 self.presetMinVolume = 60
def test_1(): messages = mido.read_syx_file(TEST_DATA) for message in messages: gen = iter(message.data) voices = bank_from_packed_stream(gen)
def load_syx(self, filename): messages = mido.read_syx_file(filename) message = mido.Message('sysex', data=messages[0].data) self.parse_progdump(message)
def read_data_from_file(self, filename): messages = mido.read_syx_file(filename) data = messages[0].bytes() logger.debug('Read data size is {:d}B: "{:s}"...'.format( len(data), self.get_hex_data(data))) return data[1:len(data) - 1]
def load_patches(path_to_syx_file): # TODO: config with mido.open_output('Scarlett 18i8 USB') as ioport: for m in mido.read_syx_file(path_to_syx_file): ioport.send(m)
def initKTNAController(): global bankNames global numberOfBanks global patchesMatrix global chainMatrix global chainModeMatrix global katanaOUT global katanaIN global BankSizes global currentChain global currentBank global currentPach global currentChannel global currentChainMode # "Custom", "1", "2" "3" katanaOUT = mido.open_output("KATANA MIDI 1") katanaIN = mido.open_input("KATANA MIDI 1") bankNames = os.listdir(currentDirectory + "/presets") # Nombre de cada banco numberOfBanks = len(bankNames) # Numero de bancos patchesMatrix = [[None for x in range(4)] for y in range(numberOfBanks) ] # Matriz que contiene .sys de cada banco chainMatrix = [ [None for x in range(4)] for y in range(numberOfBanks) ] # Matriz que contiene Sysex de la cadena custom de cada patch chainModeMatrix = [ [None for x in range(4)] for y in range(numberOfBanks) ] # Matriz que contiene el tipo de cadena de efectos, default o custom BankSizes = [0, 0] # numero de presets por banco # Carga de presets, patches y chains for i in range(numberOfBanks): #Patches patchesMatrix[i][0] = mido.read_syx_file(currentDirectory + "/presets/" + bankNames[i] + "/patches/patchCHA1.syx") patchesMatrix[i][1] = mido.read_syx_file(currentDirectory + "/presets/" + bankNames[i] + "/patches/patchCHA2.syx") patchesMatrix[i][2] = mido.read_syx_file(currentDirectory + "/presets/" + bankNames[i] + "/patches/patchCHB1.syx") patchesMatrix[i][3] = mido.read_syx_file(currentDirectory + "/presets/" + bankNames[i] + "/patches/patchCHB2.syx") # Remplazo de cabecera de FxFloor por KATANA for j in range(len(patchesMatrix[i])): for k in range(len(patchesMatrix[i][j])): if k == 18: tempSysex = list(patchesMatrix[i][j][k].data) del tempSysex[0:10] chainModeMatrix[i][j] = tempSysex[0] print(chainModeMatrix[i][j]) del tempSysex[0] patchesMatrix[i][j][k] = mido.Message( "sysex", data=initialTupleSysex + setDataSysex + [0x60, 0x00, 0x13, 0x00] + tempSysex) else: tempSysex = list(patchesMatrix[i][j][k].data) del tempSysex[0:6] patchesMatrix[i][j][k] = mido.Message( "sysex", data=initialTupleSysex + setDataSysex + tempSysex) # Chains chainMatrixTemp = [[None for x in range(4)] for y in range(numberOfBanks)] chainMatrixTemp[i][0] = mido.read_syx_file(currentDirectory + "/presets/" + bankNames[i] + "/patches/chainCHA1.syx") chainMatrixTemp[i][1] = mido.read_syx_file(currentDirectory + "/presets/" + bankNames[i] + "/patches/chainCHA2.syx") chainMatrixTemp[i][2] = mido.read_syx_file(currentDirectory + "/presets/" + bankNames[i] + "/patches/chainCHB1.syx") chainMatrixTemp[i][3] = mido.read_syx_file(currentDirectory + "/presets/" + bankNames[i] + "/patches/chainCHB2.syx") for j in range(len(patchesMatrix[i])): if chainMatrixTemp[i][j] != []: chainMatrix[i][j] = chainMatrixTemp[i][j][0] chainModeMatrix[i][j] = "Custom" # Esto se debe leer de los temporales de la app-TODO currentChannel = "CHA1" currentPach = 0 currentBank = 0 currentChainMode = "1" currentChain = "NA" changeChannel(currentChannel) setChain(currentBank, currentPach)
return (patch) else: print("[FAILED] Data Broken") TIMESTAMP = datetime.now().strftime('%Y%m%d-%H%M') A4_DATA_SIZE = 725 print(korga4.logo) print(" --[ KORG A4 MIDI Dump Decoder ] --\n") if file_name: try: sysex_data = mido.read_syx_file(file_name) print(sysex_data) data = sysex_data[0].data print(f"[SUCCESS] Data read OK") # To Do:§ # - Decode the data: # - Looks to be patches starting at hex group 8, 24 groups long except: print(f"[FAILED] Something went wrong reading {file_name}.") # Sysex header bytes 0-6 header_id = hex(data[0]) header_format_id = hex(data[1])