mirror of
https://github.com/ScrelliCopter/VGM-Tools
synced 2025-02-21 04:09:25 +11:00
153 lines
3.8 KiB
Python
Executable File
153 lines
3.8 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# Name: feropm.py
|
|
# Copyright: © 2020 a dinosaur
|
|
# Homepage: https://github.com/ScrelliCopter/VGM-Tools
|
|
# License: Zlib (https://opensource.org/licenses/Zlib)
|
|
# Description: Script to convert csMD presets to VOPM files.
|
|
# Based on documentation provided by MovieMovies1.
|
|
|
|
from argparse import ArgumentParser
|
|
from xml.dom import minidom
|
|
from pathlib import Path
|
|
from typing import TextIO
|
|
|
|
|
|
class Preset:
|
|
class Operator:
|
|
tl = 0
|
|
ml = 0
|
|
dt = 0
|
|
ar = 0
|
|
d1 = 0
|
|
sl = 0
|
|
d2 = 0
|
|
r = 0
|
|
am_mask = 0
|
|
ssg_eg = 0
|
|
kr = 0
|
|
velo = 0
|
|
ks_lvl = 0
|
|
|
|
def __init__(self):
|
|
self.name = ""
|
|
self.alg = 0
|
|
self.fb = 0
|
|
self.lfo_vib = 0
|
|
self.lfo_trem = 0
|
|
self.op = [self.Operator() for i in range(4)]
|
|
|
|
|
|
def parse_fermatap(path: Path) -> Preset:
|
|
xdoc = minidom.parse(str(path))
|
|
xpreset = xdoc.getElementsByTagName("Preset")
|
|
xtarget = xpreset[0].getElementsByTagName("Target")
|
|
xparams = xtarget[0].getElementsByTagName("Param")
|
|
|
|
patch = Preset()
|
|
|
|
clamp = lambda x, a, b: x if x < b else b if x > a else a
|
|
invert = lambda x, a, b: b - clamp(x, a, b)
|
|
|
|
def parseop(op, id, x):
|
|
if id == 0:
|
|
patch.op[op].tl = invert(x, 0, 127)
|
|
elif id == 1:
|
|
patch.op[op].ml = clamp(x, 0, 15)
|
|
elif id == 2:
|
|
x = clamp(x, -3, 3)
|
|
patch.op[op].dt = x if x >= 0 else 4 - x
|
|
elif id == 3:
|
|
patch.op[op].ar = invert(x, 0, 31)
|
|
elif id == 4:
|
|
patch.op[op].d1 = invert(x, 0, 31)
|
|
elif id == 5:
|
|
patch.op[op].sl = invert(x, 0, 15)
|
|
elif id == 6:
|
|
patch.op[op].d2 = invert(x, 0, 31)
|
|
elif id == 7:
|
|
patch.op[op].r = invert(x, 0, 15)
|
|
elif id == 8:
|
|
patch.op[op].am_mask = clamp(x, 0, 1)
|
|
elif id == 9:
|
|
patch.op[op].ssg_eg = clamp(x, 0, 8)
|
|
elif id == 10:
|
|
patch.op[op].kr = clamp(x, 0, 3)
|
|
elif id == 11:
|
|
patch.op[op].velo = clamp(x, 0, 3)
|
|
elif id == 12:
|
|
patch.op[op].ks_lvl = clamp(x, 0, 99)
|
|
|
|
for i in xparams:
|
|
id = int(i.attributes["id"].value)
|
|
x = int(i.attributes["value"].value)
|
|
|
|
if 0 <= id <= 15:
|
|
parseop(0, id, x)
|
|
elif id <= 31:
|
|
parseop(1, id - 16, x)
|
|
elif id <= 47:
|
|
parseop(2, id - 32, x)
|
|
elif id <= 63:
|
|
parseop(3, id - 48, x)
|
|
elif id == 64:
|
|
patch.alg = clamp(x, 0, 7)
|
|
elif id == 65:
|
|
patch.fb = clamp(x, 0, 7)
|
|
elif id == 66:
|
|
patch.lfo_vib = clamp(x, 0, 7)
|
|
elif id == 67:
|
|
patch.lfo_trem = clamp(x, 0, 3)
|
|
elif id <= 71:
|
|
pass
|
|
else:
|
|
print("unrecognised parameter id {}".format(id))
|
|
|
|
return patch
|
|
|
|
|
|
def save_vopm(path: Path, patch: Preset):
|
|
fmtnum = lambda n: " " + f"{n}".rjust(3, " ")
|
|
|
|
def writech(file: TextIO):
|
|
file.write("CH:")
|
|
file.write(fmtnum(64))
|
|
file.write(fmtnum(patch.fb))
|
|
file.write(fmtnum(patch.alg))
|
|
file.write(fmtnum(patch.lfo_trem))
|
|
file.write(fmtnum(patch.lfo_vib))
|
|
file.write(fmtnum(120))
|
|
file.write(fmtnum(0))
|
|
file.write("\n")
|
|
|
|
def writeop(file: TextIO, label: str, op: Preset.Operator):
|
|
file.write(label)
|
|
for i in [op.ar, op.d1, op.d2, op.r, op.sl, op.tl, op.kr, op.ml, op.dt, 0, op.am_mask]:
|
|
file.write(fmtnum(i))
|
|
file.write("\n")
|
|
|
|
with path.open("w", encoding="utf-8") as file:
|
|
file.write(f"@:0 {patch.name}\n")
|
|
file.write("LFO: 0 0 0 0 0\n")
|
|
writech(file)
|
|
writeop(file, "M1:", patch.op[0])
|
|
writeop(file, "C1:", patch.op[1])
|
|
writeop(file, "M2:", patch.op[2])
|
|
writeop(file, "C2:", patch.op[3])
|
|
|
|
|
|
def main():
|
|
p = ArgumentParser(description="Convert fermatap-formatted csMD presets to VOPM (.opm) files.")
|
|
p.add_argument("infile", type=Path, help="Path to input csMD (.fermatap) file")
|
|
p.add_argument("--output", "-o", type=Path, required=False, help="Name of output VOPM (.opm) file")
|
|
|
|
args = p.parse_args()
|
|
patch = parse_fermatap(args.infile)
|
|
patch.name = args.output.name.rstrip(".opm") if args.output is not None else args.infile.name.rstrip(".fermatap")
|
|
|
|
outpath = args.output if args.output is not None else args.infile.parent.joinpath(patch.name + ".opm")
|
|
save_vopm(outpath, patch)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|