music.maker wrote: ↑Mon Dec 21, 2015 11:31 am
Assumed that a bank dump should be just a collection of single preset dumps, so it would be possible to quickly extract (by software) the 128 presets of a bank dump. Surprisingly, the format of bank dumps appears to be completely different. Is there a specification of the bank dump format ?
Hi,
A bit late in the game, but after many attempts, I think I decoded the secret format of Voyager bank dumps. A bank dump is 18,732 bytes long (exlcluding the initial F0 and F7). Each patch should be 143 bytes long according to
www.moogmusic.de/SysEx.pdf (excluding header info, 4 or 5 bytes), so you already see theres a problem: 143 (bytes per patch) x 128 (patches)=18,304, much less than the bank dump.
I found that patches are byte- and bit-shifted within the bank data. Patch 1 starts on byte 7 of the bank dump (counting from starting byte=0), bit 3 (counting bits 0 to 7 for right to left). Patch number 2 starts 146 bytes and 2 bits afterwards, i.e. byte 154 (again starting from 0), bit 5 (starting at 0 on the right). To convert these "hidden patches" into proper patch sysex data, you have to compensate the bit offset, cosidering that always bit# 7 should be zero. I have no idea what info is in these extra bytes in the bank dump (e.g. from byte 4 to 7, of the extra bytes within the patches). If somebody finds out, please let me know!
I wrote a python function that does just this. I copy it here for better understanding of the details. The function receives the bank dump as a list of integers (mido can easily do that), and returns patch data as another list of integers 143 integers long. As far as I know right know, I think that to decode these bytes you have to use the "Voyager System Exclusive Single Preset Dump Format" (as opposed to Panel Dump Format) detailed in
www.moogmusic.de/SysEx.pdf. So add the first 5 bytes (header + patch number), and treat these 148 bytes as a Single Preset Dump.
In order to read the Patch name, you can use this SysEx.pdf document, and look at byte #102 of the PDF document Single Preset Format (byte 96 within the 143-long data without header) and decode from there.
Hope this helps!
def unpack_bank_voyager(packed_bytes, patch_nr=1):
import bitstring
from bitstring import BitArray, BitStream
bitstring.lsb0 = True
if len(packed_bytes) != 18732: #this is the size of a vogager bank (excluding F0 and F7)
print ('Wrong Length')
return None
if patch_nr -1 not in range(128): #patch numbers must be 1 to 128
print('Patch Number must be 1 to 128')
return None
# first patch info within the bank data is at byte 7, with 3 bits offset: starts at !: 0000!000
start_bit = (3 + (patch_nr -1)*2) %7 #distance within patches is 146 bytes and 2 bits. This one for shifting the bits
byte_offset = (3 + (patch_nr -1)*2) // 7 # this one calculates bytes to move based of the 2 bits each patch adds
start_byte=7 + (146*(patch_nr-1)) + byte_offset
patch_data_len=144 #1 more than needed, for the extra bits in byte 144
bit_array=BitArray()
for i in range(patch_data_len): #create bitarray, adding all the 7 bit bytes together (higher byte nr to the left)
bit_array.append (BitArray(uint=packed_bytes[start_byte+i], length=7))
del bit_array [:start_bit] #offsets bits to the right so the bitarray starts in bit #0 as it should
bit_array.append([0]*start_bit) #add 0s at the beginning, the # of removed bits on the right
patch_data=[0]*(patch_data_len-1) #143 is the patch packed data length
i=0
for byte in bit_array.cut(7):
if i==143:
break
patch_data
=byte.uint
i +=1
return patch_data