def OnDump(self, event): item = self.listCtrl.GetFocusedItem() prgname = self.listCtrl.GetItemText(item, col=1) print(f"{prgname}") patchdata = self.zipobj.read(self.proglist[item]) print(common.flavour_to_product[common.patch_type(patchdata)] + " patch") dump.print_patch(patchdata) print_sep()
def print_patch(patchdata): import copy patch = common.parse_patchdata(patchdata) if common.patch_type(patchdata) == "og": patch = og.normalise_og_patch(patch) patchcopy = copy.deepcopy(vars(patch)) for key in patchcopy: val = patchcopy[key] if isinstance(val, (bytes, bytearray)) and len(val) > 12: patchcopy[key] = val.hex() pprint(patchcopy)
def LoadData(self, fileobj): self.zipobj = ZipFile(fileobj.name, "r", compression=ZIP_DEFLATED, compresslevel=9) self.proglist = common.zipread_progbins(self.zipobj) lc = self.listCtrl lc.ClearAll() lc.AppendColumn("id") lc.AppendColumn("name") lc.AppendColumn("md5:4") lc.SetColumnWidth(0, 40) lc.SetColumnWidth(1, 200) lc.SetColumnWidth(2, 50) for i, p in enumerate(self.proglist): patchdata = self.zipobj.read(p) hash = hashlib.md5(patchdata).hexdigest() flavour = common.patch_type(patchdata) if not common.is_init_patch(flavour, hash): prgname = common.program_name(patchdata, flavour) lc.Append([i+1, prgname, hash[:4]])
def dump(filename, match_name, match_ident, verbose, md5): """Dump contents of FILENAME to stdout. Supports minilogue og and xd patch files. \b Examples -------- dump og_program_bank.mnlgpreset dump xd_program_bank.mnlgxdlib dump OGProgName.mnlgprog dump XDProgName.mnlgxdprog dump -n OGProgName og_program_bank.mnlgpreset dump -n "OG Prog Name" og_program_bank.mnlgpreset dump -i 10 og_program_bank.mnlgpreset dump -i 10 -m og_program_bank.mnlgpreset """ zipobj = zipfile.ZipFile(filename, "r") proglist = common.zipread_progbins(zipobj) if match_name is not None: match_ident = common.id_from_name(zipobj, match_name) if match_ident is not None: proglist = [proglist[match_ident - 1]] for p in proglist: patchdata = zipobj.read(p) flavour = common.patch_type(patchdata) prgname = common.program_name(patchdata, flavour) if common.is_init_program_name(prgname): continue checksum = "" if md5: checksum = hashlib.md5(patchdata).hexdigest() print(f"{int(p[5:8])+1:03d}: {prgname:12s} {checksum}") if verbose: print_patch(patchdata) print()
def translate(filename, match_name, match_ident, verbose, unskip_init, force_preset): """Translate a minilogue program or program bank to the minilogue xd. \b Examples -------- translate og_program_bank.mnlgpreset translate -n OGProgName og_program_bank.mnlgpreset translate -n "OG Prog Name" og_program_bank.mnlgpreset translate OGProgName.mnlgprog """ input_file = pathlib.Path(filename) assert input_file.suffix in { ".mnlgprog", ".mnlgpreset", ".mnlglib", ".prlgprog", ".prlgpreset", ".prlglib", ".molgprog", ".molgpreset", ".molglib", ".mnlgxdpreset", ".mnlgxdlib", ".syx" } if input_file.suffix != ".syx": out_flavour = "xd" zipobj = ZipFile(filename, "r", compression=ZIP_DEFLATED, compresslevel=9) proglist = common.zipread_progbins(zipobj) if input_file.suffix in {".mnlgprog", ".syx"}: # single patch/program match_name = input_file match_ident = 1 elif match_name is not None: # patch library/program pack match_ident = common.id_from_name(zipobj, match_name) if input_file.suffix == ".syx": stem = input_file.stem proglist = ["Prog_000.prog_bin"] out_flavour, patchdata = convert_from_syx(input_file) patch_ext = { "monologue":".molgprog", "xd":".mnlgxdprog", "og":".mnlgprog", "prologue":".prlgprog" }[out_flavour] elif match_ident is not None: proglist = [proglist[match_ident - 1]] # https://stackoverflow.com/a/13593932 stem = re.sub(r"[^\w\-_\.]", "_", match_name.stem) patch_ext = ".mnlgxdprog" else: stem = input_file.stem patch_ext = ".mnlgxdlib" if force_preset: patch_ext = ".mnlgxdpreset" output_file = input_file.with_name(stem).with_suffix(patch_ext) # Read any information from preset if available dataid = stem name = stem version = None date = None prefix = None copyright = None author = None comment = None if input_file.suffix in {".mnlgxdpreset", ".mnlgpreset", ".prlgpreset", ".molgpreset"}: dataid, name, author, version, numofprog, date, prefix, copyright = common.all_from_presetinformation_xml(zipobj) if dataid is None: dataid = name non_init_patch_ids = [] numofprog = 0 with ZipFile(output_file, "w") as xdzip: for i, p in enumerate(proglist): if input_file.suffix != ".syx": patchdata = zipobj.read(p) flavour = common.patch_type(patchdata) if common.is_init_patch(flavour, hash): # Init Program identified based on hash; i.e. a "True" Init Program continue prgname = common.program_name(patchdata, flavour) if common.is_init_program_name(prgname) and not unskip_init: # Init Program found and option not to skip is unchecked continue non_init_patch_ids.append(i) print(f"{int(p[5:8])+1:03d}: {prgname}") if input_file.suffix != ".syx": if flavour == 'og': raw_patch = common.parse_patchdata(patchdata) patch = og.normalise_og_patch(raw_patch) patch_xd, patchdata = convert_to_xd(patch, flavour) elif flavour == 'prologue': raw_patch = common.parse_patchdata(patchdata) patch = prologue.normalise_patch(raw_patch) patch_xd, patchdata = convert_to_xd(patch, flavour) elif flavour == 'monologue': raw_patch = common.parse_patchdata(patchdata) patch = monologue.normalise_patch(raw_patch) patch_xd, patchdata = convert_to_xd(patch, flavour) # .prog_bin record/file xdzip.writestr(f"Prog_{i:03d}.prog_bin", patchdata) # .prog_info record/file prog_info_xd = common.prog_info_template_xml(out_flavour) xdzip.writestr(f"Prog_{i:03d}.prog_info", prog_info_xd) numofprog += 1 if verbose: pprint(vars(patch)) print() if len(proglist) > 1 and not force_preset: if out_flavour == "prologue": xdzip.writestr(f"LivesetData.lvs_data", getattr(globals()[out_flavour], "favorite_template")) else: # FavoriteData.fav_data record/file try: xdzip.writestr(f"FavoriteData.fav_data", getattr(globals()[out_flavour], "favorite_template")) except: pass if force_preset: xdzip.writestr(f"PresetInformation.xml", common.presetinfo_xml(out_flavour, dataid, name, author, version, str(numofprog), date, prefix, copyright)) # FileInformation.xml record/file xdzip.writestr(f"FileInformation.xml", common.fileinfo_xml(out_flavour, non_init_patch_ids, force_preset)) print("Wrote", output_file)
def explode(filename, match_name, match_ident, prepend_id, append_md5_4, append_version, unskip_init): """Explode a minilogue og or xd or prologue program bank or extract a program. \b Examples -------- explode xd_program_bank.mnlgxdlib explode -n XDProgName xd_program_bank.mnlgxdlib """ zipobj = ZipFile(filename, "r", compression=ZIP_DEFLATED, compresslevel=9) proglist = common.zipread_progbins(zipobj) proginfo_dict = common.zipread_all_prog_info(zipobj) if match_name is not None: match_ident = common.id_from_name(zipobj, match_name) if match_ident is not None: proglist = [proglist[match_ident - 1]] # Create directory based on the filename stem input_file = pathlib.Path(filename) dir_path = input_file.with_suffix("") dir_path.mkdir(exist_ok=True) if input_file.suffix in {".mnlgxdpreset", ".mnlgxdlib"}: suffix = ".mnlgxdprog" flavour = "xd" elif input_file.suffix in {".mnlgpreset", ".mnlglib"}: suffix = ".mnlgprog" flavour = "og" elif input_file.suffix in {".prlgpreset", ".prlglib"}: suffix = ".prlgprog" flavour = "prologue" elif input_file.suffix in {".molgpreset", ".molglib"}: suffix = ".molgprog" flavour = "monologue" elif input_file.suffix in {".kklib"}: suffix = ".kkprog" flavour = "kk" fileinfo_xml = common.fileinfo_xml(flavour, [0]) # Read any copyright and author information if available copyright = None author = None comment = None if input_file.suffix in { ".mnlgxdpreset", ".mnlgpreset", ".prlgpreset", ".molgpreset" }: author, copyright = common.author_copyright_from_presetinformation_xml( zipobj) sanitise = common.sanitise_patchname() for i, p in enumerate(proglist): patchdata = zipobj.read(p) hash = hashlib.md5(patchdata).hexdigest() flavour = common.patch_type(patchdata) if common.is_init_patch(flavour, hash): # Init Program identified based on hash; i.e. a "True" Init Program continue prgname = common.program_name(patchdata, flavour) if common.is_init_program_name(prgname) and not unskip_init: # Init Program found and option not to skip is unchecked continue if prepend_id: prgname = f"{i+1:03d}_{prgname}" if append_md5_4: hash = hashlib.md5(patchdata).hexdigest() prgname = f"{prgname}-{hash[:4]}" if append_version: ver = version.__version__.replace(".", "") prgname = f"{prgname}-v{ver}" output_path = (dir_path / (sanitise(prgname) + suffix)) with ZipFile(output_path, "w") as zip: binary = zipobj.read(p) # .prog_bin record/file zip.writestr(f"Prog_000.prog_bin", binary) # .prog_info record/file # Use any available presetinformation_xml author and copyright fields if author is not None: comment = f"Author: {author}" proginfo_comment = (proginfo_dict[p])['Comment'] if proginfo_comment is not None: comment = f"{comment}, " + proginfo_comment prog_info_template = common.prog_info_template_xml( flavour, comment=comment, copyright=copyright) zip.writestr(f"Prog_000.prog_info", prog_info_template) # FileInformation.xml record/file zip.writestr(f"FileInformation.xml", fileinfo_xml) print(f"{int(p[5:8])+1:03d}: {prgname:<12s} -> {output_path}")
def collapse(filename, unskip_init, force_preset): proglist = [] for p in common.patch_suffixes: proglist.extend(glob.glob(join(filename, "*" + p))) (flavor, lib_ext, preset_ext) = { ".molgprog": ("monologue", ".molglib", ".molgpreset"), ".mnlgxdprog": ("xd", ".mnlgxdlib", ".mnlgxdpreset"), ".mnlgprog": ("og", ".mnlglib", ".mnlgpreset"), ".prlgprog": ("prologue", ".prlglib", ".prlgpreset") }[splitext(proglist[0])[1]] if force_preset: output_file = filename + preset_ext else: output_file = filename + lib_ext name = split(filename)[1] dataid = name version = None date = None prefix = None copyright = None author = None comment = None non_init_patch_ids = [] numofprog = 0 with ZipFile(output_file, "w") as xdzip: for i, p in enumerate(proglist): zipobj = ZipFile(p, "r", compression=ZIP_DEFLATED, compresslevel=9) patchdata = zipobj.read(common.zipread_progbins(zipobj)[0]) flavour = common.patch_type(patchdata) if flavor != flavour: # actual patch type did not match with the first one continue if common.is_init_patch(flavour, hash): # Init Program identified based on hash; i.e. a "True" Init Program continue prgname = common.program_name(patchdata, flavour) if common.is_init_program_name(prgname) and not unskip_init: # Init Program found and option not to skip is unchecked continue non_init_patch_ids.append(i) print(f"{i+1:03d}: {prgname}") # .prog_bin record/file xdzip.writestr(f"Prog_{i:03d}.prog_bin", patchdata) # .prog_info record/file prog_info = common.prog_info_template_xml(flavor) xdzip.writestr(f"Prog_{i:03d}.prog_info", prog_info) numofprog += 1 if force_preset: xdzip.writestr( f"PresetInformation.xml", common.presetinfo_xml(flavor, dataid, name, author, version, str(numofprog), date, prefix, copyright)) elif flavor == "prologue": xdzip.writestr(f"LivesetData.lvs_data", getattr(globals()[flavor], "favorite_template")) else: # FavoriteData.fav_data record/file try: xdzip.writestr(f"FavoriteData.fav_data", getattr(globals()[flavor], "favorite_template")) except: pass # FileInformation.xml record/file xdzip.writestr( f"FileInformation.xml", common.fileinfo_xml(flavor, non_init_patch_ids, force_preset)) print("Wrote", output_file)
def translate(filename, match_name, match_ident, verbose, unskip_init): """Translate a minilogue program or program bank to the minilogue xd. \b Examples -------- translate og_program_bank.mnlgpreset translate -n OGProgName og_program_bank.mnlgpreset translate -n "OG Prog Name" og_program_bank.mnlgpreset translate OGProgName.mnlgprog """ zipobj = ZipFile(filename, "r", compression=ZIP_DEFLATED, compresslevel=9) proglist = common.zipread_progbins(zipobj) input_file = pathlib.Path(filename) assert input_file.suffix in {".mnlgprog", ".mnlgpreset", ".mnlglib"} if input_file.suffix == ".mnlgprog": # single patch/program match_name = input_file match_ident = 1 elif match_name is not None: # patch library/program pack match_ident = common.id_from_name(zipobj, match_name) if match_ident is not None: proglist = [proglist[match_ident - 1]] # https://stackoverflow.com/a/13593932 stem = re.sub(r"[^\w\-_\.]", "_", match_name.stem) patch_ext = ".mnlgxdprog" else: stem = input_file.stem patch_ext = ".mnlgxdlib" output_file = input_file.with_name(stem).with_suffix(patch_ext) # Read any copyright and author information if available copyright = None author = None comment = None if input_file.suffix == ".mnlgpreset": author, copyright = common.author_copyright_from_presetinformation_xml(zipobj) non_init_patch_ids = [] with ZipFile(output_file, "w") as xdzip: for i, p in enumerate(proglist): patchdata = zipobj.read(p) flavour = common.patch_type(patchdata) if common.is_init_patch(flavour, hash): # Init Program identified based on hash; i.e. a "True" Init Program continue prgname = common.program_name(patchdata, flavour) if common.is_init_program_name(prgname) and not unskip_init: # Init Program found and option not to skip is unchecked continue non_init_patch_ids.append(i) print(f"{int(p[5:8])+1:03d}: {prgname}") raw_og_patch = common.parse_patchdata(patchdata) patch = og.normalise_og_patch(raw_og_patch) patch_xd, binary_xd = convert_og_to_xd(patch) # .prog_bin record/file xdzip.writestr(f"Prog_{i:03d}.prog_bin", binary_xd) # .prog_info record/file prog_info_xd = common.prog_info_template_xml("xd") xdzip.writestr(f"Prog_{i:03d}.prog_info", prog_info_xd) if verbose: pprint(vars(patch)) print() if len(proglist) > 1: # FavoriteData.fav_data record/file xdzip.writestr(f"FavoriteData.fav_data", xd.favorite_template) # FileInformation.xml record/file xdzip.writestr(f"FileInformation.xml", common.fileinfo_xml("xd", non_init_patch_ids)) print("Wrote", output_file)