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.
 
 
 
 
MiniDexed/performance_dx5.py

357 lines
11 KiB

import os
performance_names = ["DOUBLE HORN SECTION (DETUNED)",
"FANFARE TRUMPETS 1-2",
"FULL SYNTH BRASS (DETUNED)",
"TIGHT BRASS SECTION",
"SYNTH BRASS",
"SYNTH BRASS [F/C CHORUS]",
"С580 BRASS [F/C VIBRATO]",
"STRINGS & BRASS ENSEMBLE",
"CELLO QUARTET",
"VIOLIN ENSEMBLE",
"ENSEMBLE [L]/SOLO VIOLIN [R]",
"STRING ORCHESTRA",
"HIGH STRINGS (ANALOG TYPE)",
"CELLOS & VIOLINS",
"STRING ENSEMBLE [F/C VIBRATO]",
"STRINGS & VELOCITY TRUMPETS",
"ACOUSTIC GRAND PIANO 1",
"ACOUSTIC GRAND PIANO 2",
"ELECTRIC GRAND PIANO",
"ELECTRIC PIANO [M/W TREMOLO]",
"ELECTRIC PIANO (BRIGHT TINE}",
"DIRTY ELECTRIC PIANO",
"CLAV.ENSEMBLE",
"GRAND HARPSICHORD",
"PIPE ORGAN",
"JAZZ ORGAN",
"ROCK ORGAN WITH OLD TONE CAB",
"E.PIANO [L]/JAZZ GUITAR [R]",
"ELEC. BASS",
"DOUBLE HARPS",
"AFRICAN MALLETS",
"VIBRAPHONE",
"ELECTRIC PIANO & BRASS [BC1]",
"ELECTRIC GRAND & BRASS [BC1]",
"ELECTRIC PIANO & SAX [ВС1]",
"ELEC. PIANO & CLAV ENSEMBLE",
"ELECTRIC PIANO & STRINGS",
"HARPSICHORD & STRING ENSEMBLE",
"FULL ORCHESTRA",
"RIDE CYMBAL",
"KICK DRUM [L]/SNARE [R]",
"НІ-НАТ CLOSING: [L/CYMBAL [R]",
"НАND CLAPS [L]/TOM TOMS [R]",
"LOG DRUMS [LI/ROTO TOMS [9]",
"TAMBOURINE [L]/TIMBALI [R]",
"COWBELL [L]/WOOD BLOCK [R]",
"FRETLESS BASS [L]/SAX [ВС1] [R]",
"ACOUSTIC PIANO [L]/FLUTE [R]",
"SYNTHESIZER UPRISING",
"SAMPLE 8 HOLD [L]/LEAD LINE [R]",
"POLY SYNTH [L]/LEAD SYNTH [R]",
"PERCUSSIVE SYNTH",
"TOY MUSIC BOX",
"FM ENSEMBLE",
"PLANET OF ICE",
"MALE & FEMALE CHOIR",
"\"BIG BEN\" [L]/TUNED BELLS [R]",
"GLASS WIND CHIMES",
"JUNGLE NOISE (GROWL/BIRDS)",
"SIDE TO SIDE",
"TRAFFIC",
"FLOATING CLOUDS",
"COMBAT (EXPLOSION [L]; GUNS [R])",
"BOMBS AWAY!!"]
# The following was determined by looking at the sysex data
# from https://github.com/bladeSk/DX7II-Librarian/issues/3
# in https://bladesk.github.io/DX7II-Librarian/
modes = ["dual",
"dual",
"dual",
"dual",
"dual",
"dual",
"dual",
"split",
"split",
"split",
"split",
"split",
"split",
"split",
"split",
"split",
"dual",
"split",
"split",
"dual",
"dual",
"dual",
"dual",
"dual",
"split",
"dual",
"split",
"dual",
"split",
"dual",
"split",
"dual",
"dual",
"dual",
"dual",
"dual",
"dual",
"dual",
"dual",
"split",
"split",
"split",
"split",
"split",
"split",
"split",
"split",
"split",
"dual",
"split",
"split",
"dual",
"dual",
"dual",
"dual",
"dual",
"split",
"dual",
"split",
"dual",
"split",
"dual",
"split",
"dual"]
split_points = [60, 60, 60, 60, 60, 60, 60, 60,
60, 60, 66, 60, 60, 60, 60, 60,
60, 60, 60, 60, 60, 60, 60, 60,
60, 60, 60, 60, 60, 60, 60, 60,
60, 60, 60, 60, 60, 60, 60, 60,
60, 60, 66, 60, 60, 60, 60, 60,
60, 60, 60, 60, 60, 60, 60, 60,
55, 60, 60, 60, 60, 60, 60, 60]
filename_a = "/tmp/user/_home_user_Downloads_DX5 Carts.zip/DX5A1.SYX"
with open(filename_a, "rb") as file:
data_a = file.read()
basename_a = filename_a.split("/")[-1]
filename_b = "/tmp/user/_home_user_Downloads_DX5 Carts.zip/DX5B1.SYX"
with open(filename_b, "rb") as file:
data_b = file.read()
basename_b = filename_b.split("/")[-1]
# Remove the first 6 bytes (the header) from the data, this is the sysex header
data_a = data_a[6:]
data_b = data_b[6:]
# Put the data into a list of 128-byte ones, but only the first 32 ones
voices_a1 = [data_a[i:i+128] for i in range(0, 128*32, 128)]
voices_b1 = [data_b[i:i+128] for i in range(0, 128*32, 128)]
voicenames_a = []
voicenames_b = []
i = 0
for voice_a in voices_a1:
i += 1
voicenames_a.append(voice_a[-10:].decode("ascii"))
for voice_b in voices_b1:
i += 1
voicenames_b.append(voice_b[-10:].decode("ascii"))
for i in range(0, 32):
print("* %i `%s`: `%s` `%s` + `%s` `%s`" % (i+1, performance_names[i], basename_a, voicenames_a[i], basename_b, voicenames_b[i]))
filename_a = "/tmp/user/_home_user_Downloads_DX5 Carts.zip/DX5A2.SYX"
with open(filename_a, "rb") as file:
data_a = file.read()
basename_a = filename_a.split("/")[-1]
filename_b = "/tmp/user/_home_user_Downloads_DX5 Carts.zip/DX5B2.SYX"
with open(filename_b, "rb") as file:
data_b = file.read()
basename_b = filename_b.split("/")[-1]
# Remove the first 6 bytes (the header) from the data, this is the sysex header
data_a = data_a[6:]
data_b = data_b[6:]
# Put the data into a list of 128-byte voices, but only the first 32 ones
voices_a2 = [data_a[i:i+128] for i in range(0, 128*32, 128)]
voices_b2 = [data_b[i:i+128] for i in range(0, 128*32, 128)]
voicenames_a = []
voicenames_b = []
i = 0
for voice_a in voices_a2:
voicenames_a.append(voice_a[-10:].decode("ascii"))
for voice_b in voices_b2:
voicenames_b.append(voice_b[-10:].decode("ascii"))
for i in range(0, 32):
print("* %i `%s`: `%s` `%s` + `%s` `%s`" % (i+33, performance_names[i+32], basename_a, voicenames_a[i], basename_b, voicenames_b[i]))
def vmem2vced(vmem):
# Borrowed from
# https://github.com/rarepixel/dxconvert/blob/master/DXconvert/dx7.py
if vmem == [vmem[0]] * 128:
return initvced()
vced=[0]*155
for op in range(6):
for p in range(11):
vced[p+21*op] = vmem[p+17*op]&127
vced[11+21*op] = vmem[11+17*op]&0b11
vced[12+21*op] = (vmem[11+17*op]&0b1100)>>2
vced[13+21*op] = vmem[12+17*op]&0b111
vced[20+21*op] = (vmem[12+17*op]&0b1111000)>>3
vced[14+21*op] = vmem[13+17*op]&0b11
vced[15+21*op] = (vmem[13+17*op]&0b11100)>>2
vced[16+21*op] = vmem[14+17*op]&127
vced[17+21*op] = vmem[15+17*op]&1
vced[18+21*op] = (vmem[15+17*op]&0b111110)>>1
vced[19+21*op] = vmem[16+17*op]&127
for p in range(102, 110):
vced[p+24] = vmem[p]&127
vced[134] = vmem[110]&0b11111
vced[135] = vmem[111]&0b0111
vced[136] = (vmem[111]&0b1000)>>3
for p in range(112, 116):
vced[p+25] = vmem[p]&127
vced[141] = vmem[116]&1
vced[142] = (vmem[116]&0b1110)>>1
vced[143] = (vmem[116]&0b1110000)>>4
for p in range(117, 128):
vced[p+27] = vmem[p]
for i in range(len(vced)):
vced[i] = vced[i]&127
# return vced
return bytes(vced)
# Create the performances based on the data from the syx
for i in range(0, 64):
output_lines = []
if i < 32:
voice_data_a = vmem2vced(voices_a1[i]).hex().upper()
else:
voice_data_a = vmem2vced(voices_a1[i-32]).hex().upper()
# Add a blank space after every 2 characters
voice_data_a = " ".join(voice_data_a[i:i+2] for i in range(0, len(voice_data_a), 2))
if i < 32:
voice_data_b = vmem2vced(voices_b1[i]).hex().upper()
else:
voice_data_b = vmem2vced(voices_b2[i-32]).hex().upper()
# Add a blank space after every 2 characters
voice_data_b = " ".join(voice_data_b[i:i+2] for i in range(0, len(voice_data_b), 2))
# output_lines.append("[Performance]")
# output_lines.append("Name=" + performance_names[i])
# output_lines.append("; NOTE: These values are partially guessed and likely wrong")
# output_lines.append("; If you have DX5 performance data, please let us know")
output_lines.append("BankNumber1=1")
output_lines.append("VoiceNumber1=1")
output_lines.append("MIDIChannel1=1")
output_lines.append("Volume1=49")
output_lines.append("Pan1=62")
output_lines.append("Detune1=-3")
output_lines.append("Cutoff1=99")
output_lines.append("Resonance1=0")
output_lines.append("NoteLimitLow1=0")
if modes[i] == "dual":
output_lines.append("NoteLimitHigh1=127")
elif modes[i] == "split":
split_point = split_points[i]-1
output_lines.append("NoteLimitHigh1=%i" % split_point)
output_lines.append("NoteShift1=0")
output_lines.append("ReverbSend1=99")
output_lines.append("PitchBendRange1=2")
output_lines.append("PitchBendStep1=0")
output_lines.append("PortamentoMode1=0")
output_lines.append("PortamentoGlissando1=0")
output_lines.append("PortamentoTime1=0")
output_lines.append("VoiceData1=" + voice_data_a)
output_lines.append("MonoMode1=0")
output_lines.append("ModulationWheelRange1=99")
output_lines.append("ModulationWheelTarget1=1")
output_lines.append("FootControlRange1=99")
output_lines.append("FootControlTarget1=0")
output_lines.append("BreathControlRange1=99")
output_lines.append("BreathControlTarget1=0")
output_lines.append("AftertouchRange1=99")
output_lines.append("AftertouchTarget1=1")
# output_lines.append("")
output_lines.append("BankNumber2=2")
output_lines.append("VoiceNumber2=2")
output_lines.append("MIDIChannel2=1")
output_lines.append("Volume2=49")
output_lines.append("Pan2=65")
output_lines.append("Detune2=3")
output_lines.append("Cutoff2=99")
output_lines.append("Resonance2=0")
if modes[i] == "dual":
output_lines.append("NoteLimitLow2=0")
elif modes[i] == "split":
split_point = split_points[i]
output_lines.append("NoteLimitLow2=%i" % split_point)
output_lines.append("NoteLimitHigh2=127")
output_lines.append("NoteShift2=0")
output_lines.append("ReverbSend2=99")
output_lines.append("PitchBendRange2=2")
output_lines.append("PitchBendStep2=0")
output_lines.append("PortamentoMode2=0")
output_lines.append("PortamentoGlissando2=0")
output_lines.append("PortamentoTime2=0")
output_lines.append("VoiceData2=" + voice_data_b)
output_lines.append("MonoMode2=0")
output_lines.append("ModulationWheelRange2=99")
output_lines.append("ModulationWheelTarget2=1")
output_lines.append("FootControlRange2=99")
output_lines.append("FootControlTarget2=0")
output_lines.append("BreathControlRange2=99")
output_lines.append("BreathControlTarget2=0")
output_lines.append("AftertouchRange2=99")
output_lines.append("AftertouchTarget2=1")
# output_lines.append("")
# FIXME: Tone generators that are not explicitly configured should be set to 0 in the firmware
output_lines.append("MIDIChannel3=0")
output_lines.append("MIDIChannel4=0")
output_lines.append("MIDIChannel5=0")
output_lines.append("MIDIChannel6=0")
output_lines.append("MIDIChannel7=0")
output_lines.append("MIDIChannel8=0")
six_digits_number = "%06d" % (i+1+130)
performance_name = performance_names[i]
performance_name = performance_name.replace("\"", "")
performance_name = performance_name.replace(" ", "_")
performance_name = performance_name.replace("(", "")
performance_name = performance_name.replace(")", "")
performance_name = performance_name.replace("/", "_")
performance_name = performance_name.replace("[", "")
performance_name = performance_name.replace("]", "")
performance_name = six_digits_number + "_" + performance_name.replace(" ", "_")[:10] + ".ini"
print("")
print("performance_name: %s" % performance_name)
for lines in output_lines:
print(lines)
if not os.path.exists("/tmp/performance"):
os.makedirs("/tmp/performance")
# Write the file
with open("/tmp/performance/" + performance_name, "w") as file:
file.write("\n".join(output_lines))