Reverse engineering of the Novation Bass Station II SysEx format.
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
.gitignore added .gitignore Apr 12, 2017
BS2-midi.md Merge all doc in README.md May 15, 2017
LICENSE Initial commit Mar 27, 2017
README.md

README.md

BS2-SysEx

Reverse engineering of the Novation Bass Station II SysEx format.

See also my other project: Bass Station II Web Interface

Summary

Ref: https://www.midi.org/specifications/item/table-1-summary-of-midi-message

A MIDI System Exclusive message has the following format:

N is the number of bytes of bytes of the messages.

Offset Data BS-II Description
0 F0 Mark the start of the SysEx message
1 id 0x00 Manufacturer's ID
2 id 0x20 Manufacturer's ID
3 id 0x29 Manufacturer's ID
4..N-2 xx data (N-5 bytes)
N-1 F7 Mark the end of the SysEx message

Note: "Japanese Group" manufacturers have only one ID byte. See [https://www.midi.org/specifications/item/manufacturer-id-numbers] for more details.

Manufacturer ID for Focusrite/Novation: 0x00 0x20 0x29 (in decimal: 00 32 41)

SysEx messages understood by the Bass Station II

Message Description
F0 00 20 29 00 33 00 40 F7 Request for SysEx. After receiving this message, the Bass Station II will send a SysEx dump of its current configuration.

SysEx data sent by the Bass Station II

By default, the Bass Station II send 154 bytes. However, a patch (.syx file) may be smaller.

  • Offset: index from the start of the SysEx data. First byte (0xF0) has offset=0.
  • Bytes: number of bytes to consider for this parameter
  • Mask: mask to apply to the above bytes to get the bits relative to the parameter
  • Bits: how many bits form the value
Offset Bytes Hex mask Bin mask Bits Description
1 3 7F 7F 7F 01111111 01111111 01111111 3x 8 Manufacturer ID
9 1 7F 01111111 8 Patch number
13 2 03 7C 00000011 01111100 7 Portamento Time
15 1 7E 01111110 7 ?
16 1 7F 01111111 7 Osc Pitch Bend Range
18 1 40 01000000 1 Osc 1-2 Sync
19 1 60 01100000 2 Osc 1 Waveform
19 2 0F 70 00001111 01110000 7 Osc 1 Manual PW
20 2 07 78 00000111 01111000 7 Osc 1 Range
21 2 07 7C 00000111 01111100 8 Osc 1 Coarse
22 2 03 7E 00000011 01111110 8 Osc 1 Fine
24 1 03 00000011 2 Osc 2 Waveform
25 2 3F 40 00111111 01000000 7 Osc 2 Manual PW
26 2 1F 60 00011111 01100000 7 Osc 2 Range
27 2 1F 70 00011111 01110000 8 Osc 2 Coarse
28 2 0F 78 00001111 01111000 8 Osc 2 Fine
36 1 30 00110000 2 Sub Osc Wave
37 1 08 00001000 1 Sub Osc Oct
37 2 07 7C 00000111 01111100 8 Mixer Osc 1 Level
38 2 03 7E 00000011 01111110 8 Mixer Osc 2 Level
39 2 01 7F 00000001 01111111 8 Mixer Sub Osc Level
41 2 7F 40 01111111 01000000 8 Mixer Noise Level
42 2 3F 60 00111111 01100000 8 Mixer Ring Mod Level
43 2 1F 70 00011111 01110000 8 Mixer External Signal Level
44 2 0F 78 00001111 01111000 8 Filter Frequency
45 2 03 7C 00000011 01111100 7 Filter Resonance
46 2 01 7E 00000001 01111110 7 Filter Overdrive
48 1 08 00001000 1 Filter Slope
48 1 04 00000100 1 Filter Type
48 1 03 00000011 2 Filter Shape
49 2 3F 40 00111111 01000000 7 Velocity Amp Env
50 2 1F 60 00011111 01100000 7 Amp Env Attack
51 2 0F 70 00001111 01110000 7 Amp Env Decay
52 2 07 78 00000111 01111000 7 Amp Env Sustain
53 2 03 7C 00000011 01111100 7 Amp Env Release
55 1 06 00000110 2 Amp Env Triggering
56 1 7F 01111111 7 Velocity Mod Env
57 2 3F 40 00111111 01000000 7 Mod Env Attack
58 2 1F 60 00011111 01100000 7 Mod Env Decay
59 2 0F 70 00001111 01110000 7 Mod Env Sustain
60 2 07 78 00000111 01111000 7 Mod Env Release
62 1 0C 00001100 2 Mod Env Triggering
63 1 06 00000110 2 LFO1 Wave
64 1 7F 01111111 7 LFO1 Delay
65 2 3F 40 00111111 01000000 7 LFO1 Slew
66 2 3F 60 00111111 01100000 8 LFO1 Speed
67 2 07 70 00000111 01110000 6 LFO1 Sync Value
69 1 08 00001000 1 LFO1 Speed/Sync
69 1 10 00010000 1 LFO1 Key Sync
70 2 01 7E 00000001 01111110 7 LFO2 Delay
70 1 0C 00001100 2 LFO2 Wave
72 1 7F 01111111 7 LFO2 Slew
73 2 7F 40 01111111 01000000 8 LFO2 Speed
74 2 0F 60 00001111 01100000 6 LFO2 Sync Value
76 1 10 00010000 1 LFO2 Speed/Sync
76 1 20 00100000 1 LFO2 Key Sync
77 1 08 00001000 1 Arp On
77 1 20 00100000 1 Arp Seq Retrig
78 1 1C 00011100 3 Arp Octaves
79 1 0E 00001110 3 Arp Note Mode
80 1 1F 00011111 5 Arp Rhythm
81 2 3F 40 00111111 01000000 7 Arp Swing
82 2 1F 60 00011111 01100000 7 Mod Wheel Filter Freq
83 2 0F 70 00001111 01110000 7 Mod Wheel LFO1 to Osc Pitch
84 2 07 78 00000111 01111000 7 Mod Wheel LFO2 to Filter Freq
85 2 03 7C 00000011 01111100 7 Mod Wheel Osc2 Pitch
86 2 01 7E 00000001 01111110 7 Aftertouch Filter Freq
88 1 7F 01111111 7 Aftertouch LFO1 to Osc 1+2 Pitch
89 2 3F 40 00111111 01000000 7 Aftertouch LFO2 Speed
90 2 3F 60 00111111 01100000 8 Osc1 LFO1 Depth
91 2 1F 70 00011111 01110000 8 Osc2 LFO1 Depth
93 2 03 7C 00000011 01111100 7 Osc1 LFO2 PW Mod
94 2 01 7E 00000001 01111110 7 Osc2 LFO2 PW Mod
97 2 7F 40 01111111 01000000 8 Filter LFO2 Depth
98 2 1F 60 00011111 01100000 7 Osc1 Mod Env Depth
99 2 0F 70 00001111 01110000 7 Osc2 Mod Env Depth
101 2 01 7C 00000001 01111100 6 Osc1 Mod Env PW Mod
102 2 01 7E 00000001 01111110 7 Osc2 Mod Env PW Mod
105 2 3F 40 00111111 01000000 7 Filter Mod Env Depth
106 2 1F 60 00011111 01100000 7 Fx Osc Filter Mod
107 2 0F 70 00001111 01110000 7 Fx Distortion
108 2 07 78 00000111 01111000 7 VCA Limit
137 16 16x 0x7F 16x 01111111 16x 8 Patch name (16 ASCII chars)

Two-bytes values

Some parameters use two bytes to increase the value range from 0..127 to 0..255.

Two-bytes values in SysEx dump:

  • The first byte in the dump is the MSB, Most Significant Byte.
  • The second byte in the dump is the LSB, Least Significant Byte.
  • The msb (most significant bit) of any byte is always 0.

Two-bytes values in MIDI messages:

Sending:

Value = 201. In binary : 11001001

  1. The seven most significants bits are 1100100. Left-pad them to form a byte: 01100100 = 100. This will be the first byte to send.
  2. The least significant bit is 1. We left-shift it by 6 positions : 01000000 = 64. This will be the second byte so send.

In summary:

byte1 = integer part of value/2
byte2 = 0 if value is even, 64 if value is odd
Receiving:

We receive two bytes: 01100100 and 01000000

  1. Left-shift byte 1 by one position: 01100100 << 1 = 11001000
  2. Right-shift byte 2 by 6 position: 01000000 >>> 6 = 00000001
  3. Add them: 11001000 + 00000001 = 11001001 = 201

In summary:

value = byte1*2 + byte2/64

Notes:

Some bytes seem to always have the same value. This is confirmed accross all patch I could get.

  • byte 05 is always 0x33
  • bytes 30..35 are always 0x01 0x00 0x43 0x40 0x20 0x00
  • byte 96 is always 0x40
  • byte 104 is always 0x40

SysEx example

BS II SysEx Message in decimal:

240 000 032 041 000 051 000 000 000 000 000 000 000 000 001 000 
076 000 000 072 004 000 002 000 002 032 016 000 007 048 001 000
067 064 032 000 035 127 127 127 117 000 000 000 013 081 124 000
008 032 001 068 032 000 000 000 113 002 071 071 000 000 000 000
000 000 014 032 000 000 012 000 000 043 000 000 032 040 004 008
029 025 019 104 004 002 001 020 064 032 032 016 008 002 001 000
064 064 016 015 116 002 001 000 064 054 064 000 000 003 016 000
000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
000 000 000 000 000 000 000 000 000 247 

BS II SysEx Message in hexadecimal:

f0 00 20 29 00 33 00 00 00 00 00 00 00 00 01 00 
4c 00 00 48 04 00 02 00 02 20 10 00 07 30 01 00
43 40 20 00 23 7f 7f 7f 75 00 00 00 0d 51 7c 00
08 20 01 44 20 00 00 00 71 02 47 47 00 00 00 00
00 00 0e 20 00 00 0c 00 00 2b 00 00 20 28 04 08
1d 19 13 68 04 02 01 14 40 20 20 10 08 02 01 00
40 40 10 0f 74 02 01 00 40 36 40 00 00 03 10 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 f7 

Decoding example

Let's decode the Osc 1 Range value. The definition is:

Offset Bytes Hex mask Bin mask Bits Description
20 2 07 78 00000111 01111000 7 Osc 1 Range

Take bytes 20 and 21 from the above example:

hex: 48 04
bin: 01001000 00000100

Apply masks:

bin:  01001000 00000100
mask: 00000111 01111000
      -----------------
           000 00000

Value:

value: 00000000 (bin) == 0 (dec)

Encoding example

Let's encode the Osc 1 Coarse value. The definition is:

Offset Bytes Hex mask Bin mask Bits Description
21 2 07 7C 00000111 01111100 8 Osc 1 Coarse

The value we want to encode is 91:

91 (dec) == 01011011 (bin) 

If the mask comprises two bytes, convert the value to encode to a sixteen-bits number, else take the value has an eight-bits value.

01011011 --> 00000000 01011011 (MSB LSB) 

From the mask LSB, count how many bits we need to shift to the left:

01111100 --> 2 bits

Shit the value:

0000000001011011 << 2 --> 0000000101101100   

Get the sysex LSB:

0000000101101100 & 01111100 = 1101100

How many bits has gone into the sysex_lsb?:

LSB_bits = 7 - 2 = 5

Discard, from the original value, this number of bits used for the sysex LSB:

0000000001011011 >>> 5 --> 0000000000000010  

Get the sysex MSB:

0000000000000010 & 00000111 = 00000010 

We can now inject these sysex values into the sysex data:

first, reset the target bits to zero with the inverted masks:     
 
sysex MSB: sysex_data[offset]   = sysex_data[offset]   & 11111000   
sysex LSB: sysex_data[offset+1] = sysex_data[offset+1] & 10000011
 
then inject the value bits: 
 
sysex MSB: sysex_data[offset]   = sysex_data[offset]   | 00000010   
sysex LSB: sysex_data[offset+1] = sysex_data[offset+1] | 01101100

Init patch

$ xxd -g 1 factory-patches/70-127_INIT\ PATCH.syx
0000000: f0 00 20 29 00 33 00 00 00 00 00 00 00 00 01 00  .. ).3..........
0000010: 4c 00 00 48 04 04 02 00 02 20 10 10 08 00 01 00  L..H..... ......
0000020: 43 40 20 00 03 7f 7c 00 00 00 00 00 0f 78 00 00  C@ ...|......x..
0000030: 08 20 00 00 07 78 00 00 40 00 00 0f 70 00 00 00  . ...x..@...p...
0000040: 00 00 12 63 10 00 00 00 00 1a 06 20 20 20 04 00  ...c.......   ..
0000050: 1f 19 10 09 24 02 01 14 40 20 20 10 08 02 01 00  ....$...@  .....
0000060: 40 40 10 08 04 02 01 00 40 20 00 00 00 03 10 00  @@......@ ......
0000070: 00 00 00 00 00 00 00 00 00 f7                    ..........

MIDI resources

Trademarks

Novation is a registered trade mark of Focusrite Audio Engineering Limited.

Bass Station II is a trade mark of Focusrite Audio Engineering Limited.