Bank dump format

Tips and techniques for Minimoog Analog Synthesizers
Posts: 2
Joined: Wed Mar 15, 2023 11:37 am

Re: Bank dump format

Post by retango » Wed Mar 15, 2023 11:59 am

RL wrote: Sun Apr 10, 2016 4:48 am Hi music.maker,
there is an additional byte (the preset number) in the single preset dump. The System Exclusive format sends 7 bits instead 8 bits cause bit 7 always must be zero. And that means bit seven of the preset number is on position bit 0 of the second sysex byte (the first preset data byte).

Have fun,
Hi all, thanks for this, but I can't seem to use it to decode a Voyager sysex bank. A sysex sysex bank is a single sysex message of 18732 bytes (exluding F0 and F7). It you substract the first 4 bites for ID, and command (04 01 deice 01) you get 18728 bytes for patch info. If you divide this number by 128 (the number of available patches in a bank) you get 146.3 bytes.. already strange that's not a round number of bytes.
Each patch, without header or patch number info, it's supposed to be 143 bytes long according to the sysex spec (, so the total patch info in a bank should be 18304 bytes long, short 428 bytes of the actual bank data.
If you add 1 byte per patch for patch number (you don't need 8 bits as patch numbers only go up to 128, so 1 "sysex" byte of 7 bits should suffice), a bank should use 18,432 bytes, still short of the total number by 296 byes. Even adding 1 byte + 1 bit, or 2 bytes for patch numbers, the total is still short (280 and 40 bytes short).
I've tried too many combinations, decoding different subgroups of the the bank data according to, with strange results, but no success.

Does anyone know how to split the 18728 bytes of a Voyager sysex bank into 128 sysex patches which follow the sysex decoding map from here Or if we should use a different mapping to decode a sysex bank?
Thanks again

Posts: 2
Joined: Wed Mar 15, 2023 11:37 am

Re: Bank dump format

Post by retango » Thu Mar 16, 2023 7:27 pm

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 ?
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 (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 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
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
for byte in bit_array.cut(7):
if i==143:
i +=1
return patch_data

User avatar
Posts: 768
Joined: Sun Aug 21, 2016 8:37 pm
Location: Canada

Re: Bank dump format

Post by ummagumma » Sat Mar 18, 2023 1:45 pm

Hey that's useful, thanks for posting

Post Reply