note

Novation Bass Station 2 SysEx format

Reverse engineering of the Novation Bass Station II SysEx format.

See also my other project: Bass Station II Web Interface

Generic MIDI SysEx specification

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 the messages.

OffsetDataBS-IIDescription
0F0Mark the start of the SysEx message
1id0x00Manufacturer’s ID
2id0x20Manufacturer’s ID
3id0x29Manufacturer’s ID
4..N-2xxdata (N-5 bytes)
N-1F7Mark the end of the SysEx message

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

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

SysEx messages understood by the Bass Station II

MessageDescription
F0 00 20 29 00 33 00 40 F7Request 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.

OffsetBytesHex maskBin maskBitsDescription
137F 7F 7F01111111 01111111 011111113x 8Manufacturer ID
917F01111111 8Patch number
13203 7C00000011 011111007Portamento Time
1517E 01111110 7?
1617F 01111111 7Osc Pitch Bend Range
18140 01000000 1Osc 1-2 Sync
19160 01100000 2Osc 1 Waveform
1920F 7000001111 011100007Osc 1 Manual PW
20207 7800000111 011110007Osc 1 Range
21207 7C00000111 011111008Osc 1 Coarse
22203 7E00000011 011111108Osc 1 Fine
24103 00000011 2Osc 2 Waveform
2523F 4000111111 010000007Osc 2 Manual PW
2621F 6000011111 011000007Osc 2 Range
2721F 7000011111 011100008Osc 2 Coarse
2820F 7800001111 011110008Osc 2 Fine
36130 00110000 2Sub Osc Wave
37108 00001000 1Sub Osc Oct
37207 7C00000111 011111008Mixer Osc 1 Level
38203 7E00000011 011111108Mixer Osc 2 Level
39201 7F00000001 011111118Mixer Sub Osc Level
4127F 4001111111 010000008Mixer Noise Level
4223F 6000111111 011000008Mixer Ring Mod Level
4321F 7000011111 011100008Mixer External Signal Level
4420F 7800001111 011110008Filter Frequency
45203 7C00000011 011111007Filter Resonance
46201 7E00000001 011111107Filter Overdrive
48108 00001000 1Filter Slope
48104 00000100 1Filter Type
48103 00000011 2Filter Shape
4923F 4000111111 010000007Velocity Amp Env
5021F 6000011111 011000007Amp Env Attack
5120F 7000001111 011100007Amp Env Decay
52207 7800000111 011110007Amp Env Sustain
53203 7C00000011 011111007Amp Env Release
55106 00000110 2Amp Env Triggering
5617F 01111111 7Velocity Mod Env
5723F 4000111111 010000007Mod Env Attack
5821F 6000011111 011000007Mod Env Decay
5920F 7000001111 011100007Mod Env Sustain
60207 7800000111 011110007Mod Env Release
6210C 00001100 2Mod Env Triggering
63106 00000110 2LFO1 Wave
6417F 01111111 7LFO1 Delay
6523F 4000111111 010000007LFO1 Slew
6623F 6000111111 011000008LFO1 Speed
67207 7000000111 011100006LFO1 Sync Value
69108 00001000 1LFO1 Speed/Sync
69110 00010000 1LFO1 Key Sync
70201 7E00000001 011111107LFO2 Delay
7010C 00001100 2LFO2 Wave
7217F 01111111 7LFO2 Slew
7327F 4001111111 010000008LFO2 Speed
7420F 6000001111 011000006LFO2 Sync Value
76110 00010000 1LFO2 Speed/Sync
76120 00100000 1LFO2 Key Sync
77108 00001000 1Arp On
77120 00100000 1Arp Seq Retrig
7811C 00011100 3Arp Octaves
7910E 00001110 3Arp Note Mode
8011F 00011111 5Arp Rhythm
8123F 4000111111 010000007Arp Swing
8221F 6000011111 011000007Mod Wheel Filter Freq
8320F 7000001111 011100007Mod Wheel LFO1 to Osc Pitch
84207 7800000111 011110007Mod Wheel LFO2 to Filter Freq
85203 7C00000011 011111007Mod Wheel Osc2 Pitch
86201 7E00000001 011111107Aftertouch Filter Freq
8817F 01111111 7Aftertouch LFO1 to Osc 1+2 Pitch
8923F 4000111111 010000007Aftertouch LFO2 Speed
9023F 6000111111 011000008Osc1 LFO1 Depth
9121F 7000011111 011100008Osc2 LFO1 Depth
93203 7C00000011 011111007Osc1 LFO2 PW Mod
94201 7E00000001 011111107Osc2 LFO2 PW Mod
9727F 4001111111 010000008Filter LFO2 Depth
9821F 6000011111 011000007Osc1 Mod Env Depth
9920F 7000001111 011100007Osc2 Mod Env Depth
101201 7C00000001 011111006Osc1 Mod Env PW Mod
102201 7E00000001 011111107Osc2 Mod Env PW Mod
10523F 4000111111 010000007Filter Mod Env Depth
10621F 6000011111 011000007Fx Osc Filter Mod
10720F 7000001111 011100007Fx Distortion
108207 7800000111 011110007VCA Limit
111102000000101Paraphonic Off (0) / On (1)
112107000001113Filter tracking
114140010000001Amp Env Retriggering
115120001000001Mod Env Retriggering
115201 7000000001 011100004Tuning table
117138001110003Osc Error
1371616x 0x7F16x 0111111116x 8Patch 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:

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.

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:

OffsetBytesHex maskBin maskBitsDescription
20207 7800000111 011110007Osc 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:

OffsetBytesHex maskBin maskBitsDescription
21207 7C00000111 011111008Osc 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.