You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
MicroDexed/third-party/Synth_Dexed/tools/sysex2c.py

151 lines
4.5 KiB

#!/usr/bin/python3
import sys
import os.path
# From: https://github.com/bwhitman/learnfm/blob/master/dx7db.py
def unpack_packed_patch(p):
# Input is a 128 byte thing from compact.bin
# Output is a 156 byte thing that the synth knows about
o = [0]*156
for op in range(6):
o[op*21:op*21 + 11] = p[op*17:op*17+11]
leftrightcurves = p[op*17+11]
o[op * 21 + 11] = leftrightcurves & 3
o[op * 21 + 12] = (leftrightcurves >> 2) & 3
detune_rs = p[op * 17 + 12]
o[op * 21 + 13] = detune_rs & 7
o[op * 21 + 20] = detune_rs >> 3
kvs_ams = p[op * 17 + 13]
o[op * 21 + 14] = kvs_ams & 3
o[op * 21 + 15] = kvs_ams >> 2
o[op * 21 + 16] = p[op * 17 + 14]
fcoarse_mode = p[op * 17 + 15]
o[op * 21 + 17] = fcoarse_mode & 1
o[op * 21 + 18] = fcoarse_mode >> 1
o[op * 21 + 19] = p[op * 17 + 16]
o[126:126+9] = p[102:102+9]
oks_fb = p[111]
o[135] = oks_fb & 7
o[136] = oks_fb >> 3
o[137:137+4] = p[112:112+4]
lpms_lfw_lks = p[116]
o[141] = lpms_lfw_lks & 1
o[142] = (lpms_lfw_lks >> 1) & 7
o[143] = lpms_lfw_lks >> 4
o[144:144+11] = p[117:117+11]
o[155] = 0x3f
# Clamp the unpacked patches to a known max.
maxes = [
99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, # osc6
3, 3, 7, 3, 7, 99, 1, 31, 99, 14,
99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, # osc5
3, 3, 7, 3, 7, 99, 1, 31, 99, 14,
99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, # osc4
3, 3, 7, 3, 7, 99, 1, 31, 99, 14,
99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, # osc3
3, 3, 7, 3, 7, 99, 1, 31, 99, 14,
99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, # osc2
3, 3, 7, 3, 7, 99, 1, 31, 99, 14,
99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, # osc1
3, 3, 7, 3, 7, 99, 1, 31, 99, 14,
99, 99, 99, 99, 99, 99, 99, 99, # pitch eg rate & level
31, 7, 1, 99, 99, 99, 99, 1, 5, 7, 48, # algorithm etc
126, 126, 126, 126, 126, 126, 126, 126, 126, 126, # name
127 # operator on/off
]
for i in range(156):
if(o[i] > maxes[i]): o[i] = maxes[i]
if(o[i] < 0): o[i] = 0
return o
def print_header_data(voice_data):
print("\t\t\t",end="")
for y in range(0,len(voice_data)):
if(y!=len(voice_data)-1):
print("%3d, " % voice_data[y],end="")
else:
print("%3d\n" % voice_data[y],end="")
if((y+1)%8==0 and y!=len(voice_data)-1):
print("\n\t\t\t",end="")
def help_message():
print(progname+" [--decode] <sysex1> [<sysex2> ... <sysexn>]")
#---------------------------------------------------------------------------
progname=sys.argv.pop(0)
if(len(sys.argv)==0):
help_message()
exit(1)
if(sys.argv[0]=="-h" or sys.argv[0]=="--help"):
help_message()
exit(1)
if(sys.argv[0]=="--decode"):
decode=True
sys.argv.pop(0)
else:
decode=False
print("""
//
// File generated with sysex2c.py
//
#pragma once
""")
if(decode==True):
print("uint8_t progmem_bank[%d][32][156] PROGMEM =\n{" % int(len(sys.argv)))
else:
print("uint8_t progmem_bank[%d][32][128] PROGMEM =\n{" % int(len(sys.argv)))
for sysex in sys.argv:
if(not os.path.isfile(sysex)):
print("* File "+sysex+" does not exists.")
exit(10)
if(not os.access(sysex,os.R_OK)):
print("* File "+sysex+" does not readable.")
exit(11)
print("\t{\t// %s" % os.path.basename(sysex))
with open(sysex, "rb") as f:
header = f.read(6)
if(header[0]!=240):
print("* %s: Start of sysex not found." % sysex)
exit(200)
if(header[1]!=67):
print("* %s: Manufactorer-ID not Yamaha." % sysex)
exit(201)
if(header[3]!=9):
print("* %s: Not a 32 voice sysex file." % sysex)
exit(202)
byte_count = header[4]*128+header[5]
if(byte_count!=4096):
print("* %s: Byte count mismatch." % sysex)
exit(203)
patch_data=f.read(4096)
check = ~sum(patch_data) + 1 & 0x7F
f.seek(4102) # Bulk checksum
checksum=int.from_bytes(f.read(1),"little")
if(check!=checksum):
print("* %s: Checksum mismatch!" % sysex)
exit(204)
f.seek(6)
for v in range(1,33):
data=f.read(128)
patchname=str(data[118:128].decode('ascii')).upper().replace('\\','')
print("\t\t{\t// %d: %s" % (v, patchname))
if(decode==True):
print_header_data(unpack_packed_patch(data))
else:
print_header_data(data)
if(v!=32):
print("\t\t},")
else:
print("\t\t}")
if(sys.argv[len(sys.argv)-1]==sysex):
print("\t}")
else:
print("\t},")
print("};")