Always consult the Owners Manuals first

MIDI SysEx

From Axe-Fx II Wiki
Jump to: navigation, search

MIDI.png

MIDI SysEx: System Exclusive messages

If you're a MIDI expert, you can use SysEx messages (MIDI System Exclusive) to control Fractal Audio devices.

Learn more about SysEx.

Discussion about Fractal Audio's SysEx implementation.

Axe-Fx III: firmware 1.13 and later have MIDI support for 3rd-party devices to set and/or get scene, channel, bypass, scene names, preset names, tuner data, tempo data, via System Exclusive messages. Documented in Axe-Fx III MIDI for Third-Party Devices.

MIDI SysEx: Standard/Ultra

Ultra-specific SysEx information has been accurately acquired and organized by forum member GM Arts: here.

SysEx commands for retrieving Preset/Effect bypass states.

MIDI SysEx: SysEx Model number per device

The numbers below refer to the processors.

  • 0x00 Axe-Fx Standard
  • 0x01 Axe-Fx Ultra
  • 0x02 MFC-101
  • 0x03 Axe-Fx II
  • 0x04 MFC-101 mk3
  • 0x05 FX8
  • 0x06 Axe-Fx II XL
  • 0x07 Axe-Fx II XL+
  • 0x08 AX8
  • 0x0A FX8 mk2
  • 0x10 Axe-Fx III

MIDI SysEx: Functions

Many Axe-Fx II SysEx messages are similar to Standard/Ultra messages documented here.

The messages documented here are compatible between Axe-Fx II, Axe-Fx II XL, Axe-Fx II XL+ and AX8, FX8 messages are not documented at the moment

Note, many examples on this page are using 3 for the Model #.

All messages you send must be sent with Checksums, but not all response messages will have a Checksum, those documented here will specify if a Checksum is not included.

All Axe-Fx II/AX8 SysEx messages have the same HEADER as follows:

0xF0 sysex start
0x00 Manf. ID byte0
0x01 Manf. ID byte1
0x74 Manf. ID byte2
0xdd Model #

The byte after the Model # will always be the Function ID.

The last byte of each message will be 0xF7, the Checksum is the byte before 0xF7

Here's an example of a sysex message, in this example the AX8 is responding with the preset number, function 0x14 GET_PRESET_NUMBER

[0xF0, 0x00, 0x01, 0x74, 0x08, 0x14, 0x00, 0x00, 0x19, 0xF7];

GET_FIRMWARE_VERSION

This message responds with the firmware version, also this acts as a "Greeting" message, only after the Axe FX II has received a firmware version request it will start sending message 0x21 FRONT_PANEL_CHANGE_DETECTED, if you're writing an app or foot controller that will need to be in sync then the first thing you want to do is request the firmware version so that message 0x21 is sent when changes happen on the front panel. Keep in mind, if you do this you will need to "Disconnect" from the hardware when your app closes by sending function 0x42 DISCONNECT_FROM_CONTROLLER

Message format:

HEADER BYTES
0x08 Function ID (0x08)
0xdd Checksum
0xF7 SysEx End

Response format:

HEADER BYTES
0x08 Function ID (0x08)
0xdd Firmware Version major number
0xdd Firmware Version minor number
0xdd
0xdd
0xdd
0xdd
0xdd Checksum
0xF7 SysEx End

FRONT_PANEL_CHANGE_DETECTED

This message is sent when to notify you that something may have changed on the Hardware, this is the message that causes Axe-Edit/AX8-Edit to "Pause Communication". This message is sent to notify the editor that something has changed and that it should reload the data for that preset, hence why you get the PAUSE overlay on the editor, when you click that overlay the Editor will re-request all the preset data it needs to keep the editor in sync with the hardware.

For example if you select a block on the Axe FX II say the Filter block and you change the gain, then Axe FX will then send this message.

This message is sent about 400ms after the action was complete.

Another example, on the AX8 if you use the Amp Controls on the front panel to change the Gain then you will receive this message. This message is also sent if you press a footswitch that changes a scene/preset/block bypass/XY.

This message is only sent by the hardware if you requested the Firmware version, Read 0x08 GET_FIRMWARE_VERSION

Message format:

HEADER BYTES
0x21 Function ID (0x21)
0xdd Checksum
0xF7 SysEx End

DISCONNECT_FROM_CONTROLLER

This message should be sent when you quit an app connected to the Axe Fx if your app sent the 0x08 GET_FIRMWARE_VERSION message, see the 0x08 GET_FIRMWARE_VERSION section for more info

Message format:

HEADER BYTES
0x42 Function ID (0x42)
0xdd Checksum
0xF7 SysEx End


GET_MIDI_CHANNEL

This message message replies with the midi channel set under SETUP > I/O > MIDI > MIDI CHANNEL

Message format:

HEADER BYTES
0x17 Function ID (0x17)
0xdd Checksum
0xF7 SysEx End

Response format:

HEADER BYTES
0x17 Function ID (0x17)
0xdd Midi Channel (single byte)
0xdd Checksum
0xF7 SysEx End


TUNER_INFO

This message is broadcast when the Tuner is engaged. Note that the Axe-FX II does not include the Checksum byte in this message:

HEADER BYTES
0x0D Function ID (0x0D)
0xdd Note (0=A; 1=Bb; 2=B; etc.)
0xdd String number (0=high E string; 5=low E string)
0xdd Tuner data (value of 63 indicates 'perfectly in tune')
0xF7 SysEx End

TUNER_TOGGLE

To turn the tuner on/off you send a MIDI Control Change (CC) the CC value is the same you assign on the Axe-Fx II in the same Channel your Axe-Fx II is set to.

The default CC for the tuner is 15, send value 0 to turn the tuner off, any value of 64 or higher to turn it on.

You can get the MIDI Channel of your Axe-Fx with GET_MIDI_CHANNEL

METRONOME_TOGGLE

To turn the metronome on/off you send a MIDI Control Change (CC) the CC value is the same you assign on the Axe-Fx II in the same Channel your Axe-Fx II is set to.

Send value 0 to turn the Metronome off, any value of 64 or higher to turn it on.

You can get the MIDI Channel of your Axe-Fx with GET_MIDI_CHANNEL

NOTE that the metronome's level can not be edited via midi.

PRESET_BLOCKS_DATA

This message returns a 32-bit unsigned integer split into 5 MIDI words for each block loaded onto the preset, that is, if the amp block is loaded you will get 5 bytes with data for the amp block, etc. The message contains 5 important pieces of data:

The block's current Bypass state (0 if bypassed, 1 if engaged)
The block's current X/Y state (0 if Y, 1 if X)
The block's ID (number ranging from 100 to 170)
The block's bypass CC# (if the value is 0 or more than 127, it means the block doesn't have a CC# assigned)
The block's XY CC# (if the value is 0 or more than 127, it means the block doesn't have a CC# assigned or doesn't have X/Y)


Request format:

HEADER BYTES
0x0E Function ID (0x0E)
0xdd Checksum
0xF7 SysEx End


Response format: (response doesn't have a Checksum)

HEADER BYTES
0x0E Function ID (0x0E)
Information about each effect block in preset follows, using 5 bytes for each effect block in the preset
0xdd Byte 1 (flags) uint32_t LSB
Bit 0: 0 = Bypassed, 1 = Engaged
Bit 1: 0 = Y, 1 = X
Bit 2: unused
Bit 3: unused
Bit 4: unused
Bit 5: unused
Bit 6: unused
0xdd Byte 2 (bypass cc# number LSB)
Bit 0: unused (Bit 7 for the byte above)
Bit 1: Bypass CC# Bit 0
Bit 2: Bypass CC# Bit 1
Bit 3: Bypass CC# Bit 2
Bit 4: Bypass CC# Bit 3
Bit 5: Bypass CC# Bit 4
Bit 6: Bypass CC# Bit 5
0xdd Byte 3 (bypass cc# MSB and XY cc# LSB)
Bit 0: Bypass CC# Bit 6
Bit 1: Bypass CC# Bit 7
Bit 2: XY CC# Bit 0
Bit 3: XY CC# Bit 1
Bit 4: XY CC# Bit 2
Bit 5: XY CC# Bit 3
Bit 6: XY CC# Bit 4
0xdd Byte 4 (XY cc# MSB and Block ID LSB)
Bit 0: XY CC# Bit 5
Bit 1: XY CC# Bit 6
Bit 2: XY CC# Bit 7
Bit 3: Block ID Bit 0
Bit 4: Block ID Bit 1
Bit 5: Block ID Bit 2
Bit 6: Block ID Bit 3
0xdd Byte 5 (Block ID MSB) uint32_t MSB
Bit 0: Block ID Bit 4
Bit 1: Block ID Bit 5
Bit 2: Block ID Bit 6
Bit 3: Block ID Bit 7
Bit 4: unused
Bit 5: unused
Bit 6: unused

The following C++ code will iterate thru the sysex message array, take each five-byte chunk and convert them into a uint32_t

// "data" is the entire sysex array, "lengthOfMessage" is the length/size of that array

for(uint16_t i = 6, n = lengthOfMessage - 1 ; i < n ; i += 5){
  // convert the 5 bytes into a uint32_t with some bit-shifting
  uint32_t blockData = (data[i] & 0x7F) | ((data[i+1] & 0x7F)<<7) | ((data[i+2] & 0x7F)<<14) | ((data[i+3] & 0x7F)<<21) | ((data[i+4] & 0x7F)<<28);

  bool isBlockEngaged = (bool) (blockData & 0x01); // true if the block is on, false if bypassed
  bool isX            = (bool) (blockData & 0x02); // true if the block is in X, false if Y
  uint8_t id          = (uint8_t) ((blockData & 0xFF000000) >> 24);
  uint8_t bypassCC    = (uint8_t) ((blockData & 0x0000FF00) >> 8); // if this number is 0 or higher than 127, then there's no cc# assigned
  uint8_t xyCC        = (uint8_t) ((blockData & 0x00FF0000) >> 16); // if this number is 0 or higher than 127, then there's no cc# assigned
}


GET/SET_BLOCK_PARAMETER_VALUE

This message will get or set the value of the specified block parameter, this value ranges from 0 to 65534, the response message will contain a string which is the label displayed by the Axe Fx II and it's editor, for example the Bass parameter of the AMP block may have a value of 32767 but the label will be "5.00", the value may be 65534 but the label will be "10.00".

Also many parameters have a low/high limit and step, for example the "Voices" parameter of the CHORUS block will have a low limit: 2, high limit: 8 and step: 2 that means you can send values of 2,4,6,8, if you send a value lower than 2 it will set the parameter to 2, if it's higher than 8 it will set the value to 8.

The Effect Type selector is also a parameter, for example on the AMP block the effect type is parameter 0, most blocks with an effect type use parameter 0 as the effect type but not all, you should monitor the MIDI messages between the Axe FX II and Axe-Edit to make sure which parameter is which.

Bypassing/Engaging a Block is also done with this function with parameter 255, send value 0 to Engage, 1 to Bypass.

When you are getting a parameter value you still have to include a parameter value with your message but this value can be 0.

To convert these bytes to decimal and vice-versa see MIDI Sysex: converting bytes to decimal and vise versa and more

Message format:

HEADER BYTES
0x02 Function ID (0x02)
0xdd effect ID bits 6-0
0xdd effect ID bits 13-7
0xdd parameter ID bits 6-0
0xdd parameter ID bits 13-7
0xdd parameter value bits 6-0
0xdd parameter value bits 13-7
0xdd parameter value bits 15-14
0x00 0=query value, 1=set value
0xdd Checksum
0xF7 SysEx End

Response format:

HEADER BYTES
0x02 Function ID (0x02)
0xdd effect ID bits 6-0
0xdd effect ID bits 13-7
0xdd parameter ID bits 6-0
0xdd parameter ID bits 13-7
0xdd parameter value bits 6-0
0xdd parameter value bits 13-7
0xdd parameter value bits 15-14
0xdd
0xdd
0xdd
0xdd
0xdd
0xdd null-terminated string byte0
0xdd byte1
...
0x00 null character
0xdd Checksum
0xF7 SysEx End


SET_TYPED_BLOCK_PARAMETER_VALUE

This is the function used by Axe-Edit when you type the value of a parameter, if you've read this page you'd learned that parameter values range from 0 to 65534, with that in mind, the Bass on the AMP block displays a value of 0.00 to 10.00 with 0.00 being 0 and 10.00 being 65534. If you want to set the value of that parameter to exactly 6.35 then you would use this function. The parameter value is sent as a 32-bit Signed Float split into five 7-bit bytes, for example the Balance parameter on the AMP block, you can send -50.6 as the parameter value since the knob displays a range from -100.0 to 100.0

NOTE: this function behaves differently with the AMP's Level parameter which doesn't seem to respond with the proper value.

Message format:

HEADER BYTES
0x2E Function ID (0x2E)
0xdd Block ID bits 6-0
0xdd Block ID bits 13-7
0xdd Parameter ID bits 6-0
0xdd Parameter ID bits 13-7
0xdd Parameter Value bits 6-0
0xdd Parameter Value bits 13-7
0xdd Parameter Value bits 21-14
0xdd Parameter Value bits 29-22
0xdd Parameter Value bits 32-30
0xdd Checksum
0xF7 SysEx End

Responds in the same way as 0x02 GET/SET_BLOCK_PARAMETER_VALUE


GET/SET_MODIFIER_VALUE

Message format:

HEADER BYTES
0x07 Function ID (0x07)
0xdd effect ID bits 6-0
0xdd effect ID bits 13-7
0xdd parameter ID bits 6-0
0xdd parameter ID bits 13-7
0xdd modifier parameter selector ID bits 6-0
0xdd 0
0xdd modifier value bits 6-0
0xdd modifier value bits 13-7
0xdd modifier value bits 15-14
0x00 0=query value, 1=set value
0xdd Checksum
0xF7 SysEx End

Response format:

HEADER BYTES
0x02 Function ID (0x02)
0xdd effect ID bits 6-0
0xdd effect ID bits 13-7
0xdd parameter ID bits 6-0
0xdd parameter ID bits 13-7
0xdd modifier parameter selector ID bits 6-0
0xdd 0
0xdd modifier value bits 6-0
0xdd modifier value bits 13-7
0xdd modifier value bits 15-14
0xdd null-terminated string byte0
0xdd byte1
...
0x00 null character
0xdd Checksum
0xF7 SysEx End

Modifier Parameter Selector IDs:

0x0 modifier source
0x1 min
0x2 max
0x3 start
0x4 mid
0x5 end
0x6 slope
0x7 damping
0x8  ?
0x9  ?
0xA auto engage
0xB pc reset
0xC off val
0xD scale
0xE offset


GET_PRESET_NAME

Message format:

HEADER BYTES
0x0F Function ID (0x0F)
0xdd Checksum
0xF7 SysEx End

Response format:

HEADER BYTES
0x0F Function ID (0x0F)
0xdd null-terminated string byte0
0xdd byte1
...
0x00 null character
0xdd Checksum
0xF7 SysEx End


SET_PRESET_NAME

Message format:

HEADER BYTES
0x0F Function ID (0x09)
0xdd Each letter of the preset name sent as an Ascii byte
...
0xdd Checksum
0xF7 SysEx End

Responds with 0x64 MULTIPURPOSE_RESPONSE


MIDI_TEMPO_BEAT

Tempo beat or 'pulse' message sent by Axe-FX II. Note that the Axe-FX II does not include the Checksum byte in this message:

HEADER BYTES
0x10 Function ID (0x10)
0xF7 SysEx End


SET_TAP_TEMPO

If you want to send a BPM value to the Axe-Fx II/AX8 you can do this via Function 0x02 GET/SET_BLOCK_PARAMETER_VALUE. To do this you will send the parameter to the "CONTROLLERS" Block (ID 141), Parameter ID 32, and the value would be a number between 30 and 250


GET_PRESET_NUMBER

Message format:

HEADER BYTES
0x14 Function ID (0x14)
0xdd Checksum
0xF7 SysEx End

Response format:

HEADER BYTES
0x14 Function ID (0x14)
0xdd Preset Number bits 6-0
0xdd Preset Number bits 13-7
0xdd Checksum
0xF7 SysEx End


SET_PRESET_NUMBER

This message sets a preset number of your choice, it will respond with message 0x64 to confirm.

Message format:

HEADER BYTES
0x3C Function ID (0x3C)
0xdd Preset Number bits 6-0
0xdd Preset Number bits 13-7
0xdd Checksum
0xF7 SysEx End

This function will respond with 0x64 MULTIPURPOSE_RESPONSE


GET_GRID_LAYOUT_AND_ROUTING

Message format:

HEADER BYTES
0x20 Function ID (0x20)
0xdd Checksum
0xF7 SysEx End

Response format:

HEADER BYTES
0x20 Function ID (0x20)
Information about each grid location follows. The first 4-byte chunk corresponds to the top-left grid location (column 1, row 1). The next four-byte chunk corresponds to the grid location at column 1, row 2. Following this pattern, each of the 48 grid locations are described.
0xdd Block/Shunt ID bits 6-0
0xdd Block/Shunt ID bits 13-7
0xdd routing flags
Bit 0: connect row 1 to effect input
Bit 1: connect row 2 to effect input
Bit 2: connect row 3 to effect input
Bit 3: connect row 4 to effect input
Bit 4:
Bit 5:
Bit 6:
0xdd (unused?)
... (47 additional four-byte chunks)
0xdd Checksum
0xF7 SysEx End

About Shunts: Each shunt has a unique ID just like blocks, there are 36 shunts, on the Axe-Fx II the Shunt IDs start at 200 up to 235, on the AX8 they start at 300 to 335.


MIDI_LOOPER_STATUS_ENABLE, MIDI_LOOPER_STATUS

Message format:

HEADER BYTES
0x23 Function ID (0x23)
0xdd 0=Disable looper status messages, 1=Enable looper status messages
0xdd Checksum
0xF7 SysEx End

Response format:

HEADER BYTES
0x23 Function ID (0x23)
0xdd Looper Status Bits
Bit 0: Record
Bit 1: Play
Bit 2: Once
Bit 3: Overdub
Bit 4: Reverse
Bit 5: Half
Bit 6: Undo
0xdd Looper Position (range: 0 to 99)
0xdd Checksum
0xF7 SysEx End


GET_SCENE_NUMBER

This is the same as SET_SCENE_NUMBER except you use 0x7F as the value for getting the scene number.

Message format:

HEADER BYTES
0x29 Function ID (0x29)
0x7F Indicator that you want to read the scene number
0xdd Checksum
0xF7 SysEx End

Response format:

HEADER BYTES
0x29 Function ID (0x29)
0xdd Scene Number (range: 0 to 7)
0xdd Checksum
0xF7 SysEx End


SET_SCENE_NUMBER

Message format:

HEADER BYTES
0x29 Function ID (0x29)
0xdd Scene Number (range: 0 to 7)
0xdd Checksum
0xF7 SysEx End

Response format:

HEADER BYTES
0x29 Function ID (0x29)
0xdd Scene Number (range: 0 to 7)
0xdd Checksum
0xF7 SysEx End


GET_CAB_NAME

Message format:

HEADER BYTES
0x12 Function ID (0x12)
0xdd Cab Number
0xdd Checksum
0xF7 SysEx End

Response format:

HEADER BYTES
0x12 Function ID (0x12)
0xdd null-terminated string byte0
0xdd byte1
...
0x00 null character
0xdd Checksum
0xF7 SysEx End


GET_ALL_CAB_NAMES

Message format:

HEADER BYTES
0x12 Function ID (0x12)
0x7F Get all cabs identifier byte 1
0x7F Get all cabs identifier byte 2
0xdd Checksum
0xF7 SysEx End

Response format:

HEADER BYTES
0x12 Function ID (0x12)
0xdd null-terminated string byte0
0xdd byte1
...
0x00 null character
0xdd Checksum
0xF7 SysEx End


MIDI_SET_PRESET

Function number: 14
Example: F0 0 1 74 3 14 0 1 13 0 FF --> to set the current preset (edit buffer) to preset 0 (1 if DISPLAY OFFSET activated)
F0 0 1 74 3 14 1 0 13 0 FF --> to set the current preset (edit buffer) to preset 128 (129 if DISPLAY OFFSET activated)
Send from AXE-FX to AXE-EDIT and MFC-101


GET_BLOCK_PARAMETERS_LIST

This function will get you a list of all the parameters values of a specified block, each parameter with it's value is returned in a separate message.

Message format:

HEADER BYTES
0x01 Function ID (0x01)
0xdd block ID bits 6-0
0xdd block ID bits 13-7
0xdd Checksum
0xF7 SysEx End

This message will respond with 0x32 BATCH_LIST_REQUEST_START confirming that the batch of messages will be sent and how many will be sent.

After that message you will receive messages with function ID 0x01, these messages are identical to function 0x02 with the exception of the function ID being 0x01

Once complete it will respond with 0x33 BATCH_LIST_REQUEST_COMPLETE confirming that they were all sent.

Message 0x01 response format:

HEADER BYTES
0x01 Function ID (0x01)
0xdd block ID bits 6-0
0xdd block ID bits 13-7
0xdd parameter ID bits 6-0
0xdd parameter ID bits 13-7
0xdd parameter value bits 6-0
0xdd parameter value bits 13-7
0xdd parameter value bits 15-14
0xdd
0xdd
0xdd
0xdd
0xdd
0xdd null-terminated string byte0
0xdd byte1
...
0x00 null character
0xdd Checksum
0xF7 SysEx End


BATCH_LIST_REQUEST_START

This message is sent to you when you request a list of certain items, this includes when you request a list of parameters of a block (0x01 GET_BLOCK_PARAMETERS_LIST) or when you request a list of factory/user cab names, you can treat this message as confirmation that those parameters are about to be sent to you. The "Response Length" below represents how many messages will be sent as part of that batch.

Message format:

HEADER BYTES
0x32 Function ID (0x32)
0xdd ID of function that it's replying to
0xdd Response Length bits 6-0
0xdd Response Length bits 13-7
0xdd Checksum
0xF7 SysEx End


BATCH_LIST_REQUEST_COMPLETE

This message is sent to you after a batch of messages you requested was sent to you and it's complete. For Example if you request 0x01 GET_BLOCK_PARAMETERS_LIST, this message will reply confirming that the request has been complete.

The "ID of function that it's replying to" is the ID of the function that requested the list, in the case of 0x01 GET_BLOCK_PARAMETERS_LIST which is function 0x01 it will show this byte as 0x01 (on the AX8 the function ID will be 0x02 even tho the request was for 0x01).

Message format:

HEADER BYTES
0x33 Function ID (0x33)
0xdd ID of function that it's replying to
0xdd Checksum
0xF7 SysEx End


MULTIPURPOSE_RESPONSE

This message is sent by the hardware as a response to certain requests, the first byte after the function id is the requested function id (for example if you change the preset using function id 0x3C the first byte after 0x64 will be 0x3C). The next byte is a response code for the requested function, this code can mean different things, it could mean that the message you first sent had an error, usually if the response code is 0 it means that the task you requested is valid.

Message format:

HEADER BYTES
0x64 Function ID (0x64)
0xdd Response Function ID
0xdd Response Code
0xdd Checksum
0xF7 SysEx End


GET_BLOCK_XY, SET_BLOCK_XY

Message format:

HEADER BYTES
0x11 Function ID (0x11)
0xdd effect ID bits 6-0
0xdd effect ID bits 13-7
0xdd 0 = set to X, 1 = set to Y
0xdd 0 = get value, 1 = set value
0xdd Checksum
0xF7 SysEx End

Response format:

HEADER BYTES
0x11 Function ID (0x11)
0xdd effect ID bits 6-0
0xdd effect ID bits 13-7
0xdd 0 = effect is X, 1 = effect is Y
0xdd Checksum
0xF7 SysEx End


SET_BLOCK_BYPASS_STATE

You can Bypass/Engage a block using Function 0x02 GET/SET_BLOCK_PARAMETER_VALUE. To do this you will use the Block ID that you want to bypass, Parameter ID 255, and the value would be 0 to Engage and 1 to Bypass.

Example, this example will bypass the amp block, keep in mind the checksum must be calculated for the target device:

HEADER BYTES
0x02 Function ID (2)
0x6A effect ID bits 6-0
0x00 effect ID bits 13-7
0x7F parameter ID bits 6-0
0x01 parameter ID bits 13-7
0x01 parameter value bits 6-0
0x00 parameter value bits 13-7
0x00 parameter value bits 15-14
0x01 Set Value
0xXX Checksum
0xF7 SysEx End


GET_CPU_USAGE

Message format:

HEADER BYTES
0x13 Function ID (0x13)
0xdd Checksum
0xF7 SysEx End

Response format:

HEADER BYTES
0x13 Function ID (0x13)
0xdd CPU % (single byte from 0 to 100)
0xdd Checksum
0xF7 SysEx End


GET_PRESET_EDITED_STATUS

The Axe FX and AX8 both have an LED on the front panel labeled EDITED, this LED goes on whenever you make any changes to your preset that have not been saved. This message will request that status. It will reply with 1 if the LED on the front panel (preset has changes that need to be saved) is on and 0 if it's off

Message format:

HEADER BYTES
0x2A Function ID (0x2A)
0xdd Checksum
0xF7 SysEx End

Response format:

HEADER BYTES
0x2A Function ID (0x2A)
0xdd 0 = NO, 1 = YES
0xdd Checksum
0xF7 SysEx End


SET_TARGET_BLOCK

This function is sent when Axe-Edit opens a block for editing, this message should be sent if you will be requesting Real Time modifiers or the GET_MONITOR_GRAPH.

Message format:

HEADER BYTES
0x37 Function ID (0x37)
0xdd Block ID bits 6-0
0xdd Block ID bits 13-7
0xdd Checksum
0xF7 SysEx End

Responds with 0x64 MULTIPURPOSE_RESPONSE


GET_MONITOR_GRAPH

This function responds with the Monitor Graph, this is the "MONITOR" section you see on Axe-Edit displaying the EQ curve of many blocks.
This function's response contains 256 bytes (aside from the header, checksum and sysex end bytes) representing 128 points on the graph, each point made up of 2 bytes.
Each pair of bytes is a 14-bit signed integer, the integer will range from -8191 to 8191 with 0 being the middle of the graph. The Controllers tab also makes use of this graph for ADSR1/2 but the integer will range from 0 to 8191.

When requesting this Graph you must specify the Index of the graph, all blocks have 1 graph (so use 0 as the Graph Index) with the exception of the Controllers which has 2 graphs, ADSR1 Index is 0, ADSR2 Index is 1.

You MUST send SET_TARGET_BLOCK before requesting the graph since the graph request does not include a block id.

TIP: you should be careful with how often you request this graph, you should only do it when after a set interval after the parameter for that block has been edited.

Message format:

HEADER BYTES
0x36 Function ID (0x36)
0xdd Graph Index (0 for most blocks, see the above info)
0xdd Checksum
0xF7 SysEx End

HEADER BYTES
0x36 Function ID (0x36)
256 bytes to follow, representing 128 14-bit Signed Integers
0xdd Point 1 bits 6-0
0xdd Point 1 bits 13-7
0xdd Point 2 bits 6-0
0xdd Point 2 bits 13-7
0xdd Point 3 bits 6-0
0xdd Point 3 bits 13-7
...
0xdd Checksum
0xF7 SysEx End


GET/SET_AX8_FOOTSWITCHES

This function returns the contents of both the per preset and global foot-switches on the AX8.
It includes Eight 6-byte chunks:
The first 2 bytes of the chunk represent the block of the local (per preset) footswitch, the ID will be the Block ID or other IDs representing the function of the footswitch.
The next 2 bytes of the chunk represent the global footswitch block ID
The next byte represents the flags of the global footswitch, as in if the global footswitch is engaged, engaged+momentary & engaged+latching
The next byte represents the flags of the local footswitch.
When the Global Flag is 0 the per preset footswitch is used, when the flag is 1, global is engaged in latching type, when it's 2 it's engaged in momentary type.

Message format:

HEADER BYTES
0x48 Function ID (0x48)
0xdd QUERY, 0=Get Value, 1=Set Value
0xdd Number of Foot-switches (0 to request all)
0xdd Checksum
0xF7 SysEx End

Response format:

HEADER BYTES
0x48 Function ID (0x48)
0xdd QUERY, 0=Get Value, 1=Set Value
0xdd Number of Foot-switches (0x08 on the AX8)
Eight 6-byte chunks to follow (with the first chunk representing footswitch 1, last one footswitch 8)
0xdd Local ID bits 6-0
0xdd Local ID bits 13-7
0xdd Global ID bits 6-0
0xdd Global ID bits 13-7
0xdd Global Flag, 0=Global Disabled, 1=Global Engaged/Latching, 2=Global Engaged/Momentary
0xdd Local Flag, 1=Local Latching, 2=Local Momentary
...
0xdd Checksum
0xF7 SysEx End

To edit footswitches you send the entire layout of footswitches with the QUERY being 1, you would include each 6-byte chunk after the Number of Foot-switches, each chunk would have to have the values you want to set for each footswitch.


MIDI SysEx: Importing/Exporting Presets

MIDI SysEx: calculating the SysEx Checksum

As mentioned above, the Axe-FX II units require a Checksum at the end of the SysEx string that is sent to it (before the terminating F7 byte) as a verification step.

In order to calculate the Checksum, you basically have to XOR every byte from the start of the SysEx message, up to the character BEFORE the terminating F7 byte. For example, to send the following SysEx message (to fetch a preset name):

F0 00 01 74 03 0F F7

We would have to XOR all the byte values from the starting 'F0' to the '0F' which is the second last byte:

0xF0 ^ 0x00 ^ 0x01 ^ 0x74 ^ 0x03 ^ 0x0F = 0x89

Then, we would need to strip the leftmost bit from the result (by ANDing it to 0x7F):

0x89 & 0x7F = 0x09

And, we add this byte (actually, a septet now) to the end of the SysEx string, BEFORE the terminating F7:

F0 00 01 74 03 0F 09 F7

Obviously, in a 'static' SysEx message like above, you do not have to recalculate the Checksum each time as it will always be '09' as the rest of the message does not change, but if you are sending a SysEx string to change a parameter value etc. then you will have to calculate the Checksum on the fly as byte values towards the end of the SysEx string will be different each time.

MIDI SysEx: obtaining parameter values

The old Standard/Ultra devices used to store the parameter values on *most* knobs as 0-254. This was split into two bytes, XX YY where XX was the lowest 4 bits of the value, and YY was the highest 4 bits. Pretty simple.

The new Axe-II now has more granular control over *most* knobs, with the values going from 0-65534. This requires a full 16 bits to store. The problem is that the MIDI specifications means you can only transmit values using 7 bits as the highest bit of each byte must be a zero.

To get around this, the Axe-II uses THREE bytes to transmit the values XX YY ZZ where XX is the lowest 7 bits of the data, YY is the 8th to the 14th bit of the data, and ZZ is the remaining top two bits of the data.

So, if you had the value 52421 on a knob, then this would be represented by the 16 bits: 1100110011000101

If you split this into segments of length 2/7/7 to store in ZZ/YY/XX: 11 0011001 1000101

So XX gets the last segment: 01000101 And YY gets the middle segment: 00011001 And ZZ gets the first segment: 00000011

You will also have to back-calculate the respective knob values to the 16 bit values. For example, a knob that goes from 0 - 10, 0 would of course be 0, but 10 would be 65534. From there, you would work out that 5 is 32767 and 7 would be about 45871 etc.

To convert these bytes to the decimal value and visa-versa read MIDI Sysex: converting bytes to decimal and vise versa and more


MIDI SysEx: loading IRs

The information below was provided by former forum member LMO.

The Axe Fx II supports 2040-point impulse responses that are packaged for download in a series of 66 MIDI SysEx messages, as follows:

MIDI_START_IR_DOWNLOAD

Prepare the Axe-Fx II to receive impulse response data

Message Format:

HEADER BYTES
0x7A function ID
0x20
0x00
0x10
0xdd Checksum
0xF7 SysEx End

MIDI_G2_IR_DATA

There are 64 SysEx messages, each containing 32 chunks of data. Each chunk consists of five bytes and can hold either four text characters or one 32-bit IR data sample.

The first data message sent includes 8 chunks of text that specify the 32-character IR name, and 24 chunks of IR data. The subsequent 63 data messages each contain 32 data samples for a total of 2040 samples.

Message Format:

HEADER BYTES
0x7B function ID
0x20
0x00
0xdd data chunk byte 0
0xdd data chunk byte 1
0xdd data chunk byte 2
0xdd data chunk byte 3
0xdd data chunk byte 4
--- 31 additional five byte data chunks ---
0xdd Checksum
0xF7 SysEx End

MIDI_CLOSE_IR_DOWNLOAD

Terminate the IR download sequence

Message Format:

HEADER BYTES
0x7C function ID
0xdd encoded Checksum byte 0 for IR data
0xdd encoded Checksum byte 1 for IR data
0xdd encoded Checksum byte 2 for IR data
0xdd encoded Checksum byte 3 for IR data
0xdd encoded Checksum byte 4 for IR data
0xdd Checksum
0xF7 SysEx End

Data Chunk Encoding Scheme

The data encoding scheme translates four octets into five septets. Each septet occupies the lower seven bits of a byte, with the most significant bit set to 0.

  • octet is one byte containing 8 bits of data
  • septet is one byte containing 7 bits of data
byte_chunk = (data[0] & 0xFF )<< 24 | (data[1] & 0xFF )<< 16 | (data[2] & 0xFF )<< 8 (data[3] & 0xFF;
  • convert four octets to five septets
septet[0] = byte_chunk & 0xFF;
septet[1] = byte_chunk >> 7 & 0xFF;
septet[2] = byte_chunk >> 14 & 0xFF;
septet[3] = byte_chunk >> 21 & 0xFF;
septet[4] = byte_chunk >> 28 & 0xFF;

MIDI Sysex: converting bytes to decimal and vise versa and more

All functions below written in C++

The following are for each 5 byte chunk of message 0x0E (PRESET_BLOCKS_DATA)

This function returns true if the block is in X state or false if the block is in Y state x is the first byte of each 5 byte chunk of message 0x0E

bool isBlockX(byte x){
  if(x==0x03||x==0x02){
    return true;
  }
  return false;
}

This function returns true if the block is bypassed, false if it's not x is the first byte of each 5 byte chunk of message 0x0E

bool isBlockBypassed(byte x){
  if(x==0x03||x==0x01){
    return false;
  }
  return true;
}

This function converts the 2 bytes for the block's bypass CC (IA CC Number LSB/MSB) into a decimal number LSB is the second byte and MSB is the third byte of each 5 byte chunk of message 0x0E

int toBlockCC(byte LSB, byte MSB){
  return ((LSB & 0x7E) >> 1) + ((MSB & 3) << 6);
}

This function converts the 2 bytes for the block's ID (Effect ID LSB/MSB) into a decimal number LSB is the fourth byte and MSB is the fifth byte of each 5 byte chunk of message 0x0E

int blockID(byte LSB, byte MSB){
  return ((LSB & 0x78) >> 3) + ((MSB & 0x0F) << 4);
}

This function converts the effect ID bytes OR the parameter ID bytes into a decimal number

int bytesToInt(byte byte1, byte byte2){
  return (byte1 & 0x7F) | ((byte2 & 0x7F)<<7);
}

The reverse of the above to turn a decimal number into 2 bytes where x is the decimal number

byte byte1 = (x & 0x7F);

byte byte2 = ((x >> 7) & 0x7F);

This function converts the 3 parameter value bytes on message (0x02) into a decimal number

int parameterValueBytesToInt(byte byte1, byte byte2, byte byte3){
  return (byte1 & 0x7F) | ((byte2 & 0x7F)<<7) | ((byte3 & 0x7F)<<14);
}

The reverse of the above to turn a decimal number into 3 bytes where x is the decimal number

byte byte1 = x & 0x7F;

byte byte2 = (x >> 7) & 0x7F;

byte byte3 = (x >> 14) & 0x7F);

To convert a decimal number into the 2 bytes for a preset change, where x is the decimal number

byte byte1 = x >> 7;

byte byte2 = x & 0x7F;

To convert the 2 bytes received from a preset change to a decimal number:

Axe FX II

int x = (byte1 & 0x7F) << 7 | byte2;

AX8

int x = (byte1 & 0x7F) | ((byte2 & 0x7F) << 7);

To convert the decimal preset number into a Bank/Preset set. This number ranges from 0 to 383 on the Axe FX II, 0 to 767 on the XL/+ and 0 to 511 on the AX8

Axe FX II or later, where x is the decimal number from 0 to 383/767

byte bankNumber = floor(x / 128); // banks are labeled A,B,C,D,E,F where bank A is 0 and bank F is 5

byte presetNumber = x - (bankNumber*128); // preset number with index of 0, to display offset it to 1 just add 1 to this number when displayed

AX8 where x is the decimal number from 0 to 511

byte bankNumber = floor(x / 8); // banks are labeled from 1 to 64, this functions will return a number from 0 to 63, add 1 when you display it

byte presetNumber = x - (bank * 8);


MIDI SysEx: Blocks & Parameters IDs

Read this: MIDI SysEx blocks and parameters IDs.

MIDI SysEx: more information