Table of Contents

MIDI Controller Mapping File Format

Current XML file schema revision is: 1

Introduction

Support for additional MIDI devices can be added to Mixxx by creating a new “MIDI mapping” file. This mapping file tells Mixxx how to translate MIDI commands from a controller into commands that Mixxx will understand.

The MIDI mapping files are located in the following paths:

By far, the easiest way to create a new MIDI mapping is by using the MIDI Learn wizard in the Preferences (available in Mixxx 1.7.0 and higher.) You can then modify the XML file it creates (or any of the ones that ship with Mixxx) using the information on this page if you'd like to fine-tune it or add more mappings. When you've finished creating your MIDI mapping, please send it to us and we'll include it in Mixxx.

MIDI Crash Course

Most MIDI messages are three bytes long. The first byte of any MIDI message is called the Status byte. The first nybble (hex digit) is the op-code and the second is the MIDI channel number. So if you have 0x90 the op-code is 0x9 and the channel number is 0x0 (Ch 1.) The full list of MIDI messages is below, where n represents the channel number (0..F inclusive):

StatusFunctionData bytes
0x8nNote offNote numberNote velocity
0x9nNote onNote numberNote velocity
0xAnPolyphonic after-touchNote numberAmount
0xBnControl/mode changeControl numberValue
0xCnProgram changeProgram number(n/a)
0xDnChannel after-touchAmount(n/a)
0xEnPitch wheelLSBMSB
0xF0System Exclusive messageVendor ID(data)
0xF1MIDI Time Code Qtr. Frame(see spec)
0xF2Song Position PointerLSBMSB
0xF3Song SelectSong number(n/a)
0xF4Undefined
0xF5Undefined
0xF6Tune request(n/a)
0xF7End of SysEx (EOX)(n/a)
0xF8Timing clock(n/a)
0xF9Undefined(n/a)
0xFAStart(n/a)
0xFBContinue(n/a)
0xFCStop(n/a)
0xFDUndefined(n/a)
0xFEActive Sensing(n/a)
0xFFSystem Reset(n/a)

The boldface entries in the table above are the messages we are most concerned with since most DJ controllers use only these for all functions. You'll need to consult the MIDI spec for the DJ controller you're working with to determine which messages and note/control numbers correspond to the DJ controller functions & LEDs. If your controller's MIDI spec gives only note names and not numbers, use this table to convert them. To convert from decimal to hex, use this.

(Note that in order to use System Exclusive messages, you will need MIDI Scripting.)

Sniffing your controller

First, try using the MIDI Learn functionality in the Preferences→MIDI Devices window at the bottom (in Mixxx 1.7.0 and higher.) It will help you get many of the essential functions mapped quickly without having to do any hacking.

If you don't have the MIDI spec for your controller, first check the manufacturer's web site under Support. Look for Manuals or User Guides. MIDI specs are usually given in an appendix at the back of the manual. Failing that, you can usually sniff the MIDI data the controller sends.

Linux

Open a console and issue amidi -l. This will list the attached MIDI device(s) like so:

Dir Device    Name
IO  hw:1,0,0  SCS.3d MIDI 1

Then, to dump the data, you just issue amidi -p hw:1,0,0 -d (Replace hw:1,0,0 with whatever device ID your controller shows in the list.) See “All” below for how to interpret this data.

Windows & All OSs using Mixxx >=1.8.0

Start Mixxx from a command prompt using the –midiDebug option like so:

C:\Program Files\Mixxx>mixxx --midiDebug

Then look at the Mixxx.log file which will contain all of the MIDI messages Mixxx receives.

On Windows, you can download tail.exe to watch it as new messages are added or build Mixxx with scons msvcdebug=1 and run it with the –midiDebug option. This will cause it to pop up a console window when you run it and the MIDI messages received by your controller will be displayed there.

Mac OSX

Download the free MIDI Monitor utility and run it.

All

Then as you press buttons or move sliders, the MIDI commands the controller sends will be printed to the screen. Compare the status (first) byte in each line with the table above and then just write down which button/slider/control sends what command.

For example, when you move a slider, you might see

Linux & MacWindows
B0 02 3D
B0 02 3A
B0 02 3D
B0 02 3B
B0 02 3C
Debug: []: "MIDI status: B0, ctrl: 2, val: 3D" 
Debug: []: "MIDI status: B0, ctrl: 2, val: 3A" 
Debug: []: "MIDI status: B0, ctrl: 2, val: 3D" 
Debug: []: "MIDI status: B0, ctrl: 2, val: 3B" 
Debug: []: "MIDI status: B0, ctrl: 2, val: 3C" 

In this instance, it's sending 0xB0, which when we look at the table above, we see that it's a Control Change message on channel 1. We also see that the second byte, 0x02 in this case, is the control number, and the third is the value, which you can ignore for the purposes of mapping. You would then just plug the first two bytes into a <control> XML block (detailed below) for <status> and <midino> respectively.

File Format

Mixxx uses a well defined XML format to store its MIDI mappings. The format is used for storing and distributing MIDI mappings from multiple scopes.

<?xml version="1.0" encoding="utf-8"?>
    <MixxxMIDIPreset schemaVersion="1" mixxxVersion="1.7.0+"> <!-- Schema version number to help compatibility, should the MIDI format change -->
	<info><!-- Optional - information about the preset file -->
		<name>Example MIDI Preset for Mixxx</name>
		<author>Tom Care</author>
		<description>This is an example XML MIDI preset for Mixxx. The scope of the preset could be from a small functionality addition, to a complete mapping for a controller, to a complex personal setup with multiple controllers. This description is intended for distribution and could include comments about the extent of the functionality.</description>
	</info>

The first part of the file defines the version of the mapping (for future compatibility, as the Mixxx MIDI abilities become more complex) and an optional info tag which contains information about the preset (primarily used for distribution of presets).

	<controller id="controller name" port=""> <!-- Many controllers in one file supported. A controller should only appear once -->

The “controller id” is the brand & model of the controller, e.g. “Stanton SCS.3d”. Leave “port” empty.

The core part of the file contains a definition for a single controller. There may be multiple controllers in one file (for more complex setups). Each controller definition contains two sections: input bindings (controls) and output bindings.

		<controls> <!-- One control group -->
			<control> <!-- Several controls -->
				<group>[Master]</group>
				<key>crossfader</key>

Group and key define the part of Mixxx that is being controlled. For a list of what these values can be, see below.

				<status>0xB0</status> <-- CC on channel 1 -->
				<midino>0x07</midino>

These tags define the MIDI event that Mixxx will listen for.

				<options>
					<!-- all control specific options should go here - sensitivity etc. Specifics to be decided by spec -->
				</options>

The options further refine the behavior of the control. The list of generic options may expand as Mixxx development continues, but any controller-specific refinements (translations, sensitivity, acceleration, etc.) belong in a MIDI script. Necessary options will have default values, eg a jogwheel might have no acceleration by default.

			</control>
		</controls>
		<outputs>

The next section defines outputs that use “short” (3-byte) MIDI messages. (For SYSEX messages, you need to use scripting.)

			<output>
				<group>[Channel1]</group>
				<key>play</key>
				<status>0x7F</status>  <!-- First byte sent to device -->
				<midino>0x08</midino>  <!-- Second byte -->
				<on>0x01</on>  <!-- Third byte. If not specified, 0x7F is used. -->
				<off>0x00</off> <!-- Alternate third byte. 0x00 is the default. If set to 0xFF, nothing is sent.-->
				<maximum>0.99</maximum>  <!-- Optional upper value for the Mixxx control, above which the 'off' value is sent. 1.0 is the default. -->
				<minimum>0.9</minimum>   <!-- Lower value for the Mixxx control, below which the 'off' value is sent -->

This allows you to send any three bytes to the MIDI controller in the order Status, Midino, on/off. Minimum and maximum define the range within which the 'on' value is sent. Outside this range, the 'off' value is sent. If 'off' is set to 0xFF, no message will be sent outside the range. (Useful for LED sequences.)

			</output>
		</outputs>
	</controller>
</MixxxMIDIPreset>

Definitions of the elements:

These define the part of Mixxx that is being controlled:

These tags define the MIDI event that Mixxx will listen for or send out:

Input tags:

Output tags:

Old format (before schema versioning, Mixxx 1.6.1 and prior.)

The old midi mapping format is here for reference. The same options apply as above, except use <threshold> for <minimum>, there's no <maximum> (it's always 1.0,) and obviously <Script-Binding> won't work. It looks like this:

 <!DOCTYPE controller>
 <controller>
   <controls>
     <control>
       <group>[[Master]]</group>
       <key>crossfader</key>
       <miditype>Ctrl</miditype>
       <midino>0x31</midino>
       <options>
         <hercjog/>
       </options>
     </control>
     ...
   </controls>
   <lights>
     <light>
       <group>[[Channel1]]</group>
       <key>VuMeter</key>
       <status>0xB0</status>
       <midino>0x16</midino>
       <threshold>0.5</threshold>
     </light>
     ...
   </lights>
 </controller>

UI/MIDI Controls and Names

Each control inside Mixxx is identified by a unique string. These strings are used in the keyboard mappings, the MIDI mappings, and inside Mixxx to gain access to the controls. The following is a list of controls that can be used in any of the above contexts.

List of Controls

The default range is 0.0 to 1.0, unless otherwise noted. Binary means it's either on (non-zero) or off (zero.)

Please keep the controls in alphabetical order by group

[Group]Key/ControlRangeWhat it doesOn-screen feedback
[Flanger]lfoDepthdefaultAdjusts the intensity of the flange effectDepth knob
[Flanger]lfoDelay50..10000Adjusts the phase delay of the flange effect in microsecondsDelay knob
[Flanger]lfoPeriod50000..2000000Adjusts the wavelength of the flange effect in microsecondsLFO knob
—-—-—-—-—-
[Master]balance-1.0..1.0Adjusts the left/right channel balance on the Master outputCenter Balance knob
[Master]crossfader-1.0..1.0Adjusts the crossfader between players/decks (-1.0 is all the way left, Deck 1)Crossfader slider
[Master]headVolume0.0..1.0..5.0Adjusts the headphone output volumeHead Vol knob
[Master]headMix-1.0..1.0Adjusts the cue/main mix in the headphone outputPre/Main knob
[Master]latencyabsolute valueLatency setting (sound buffer size) in milliseconds (default 64)Latency slider in the prefs
[Master]PeakIndicatorbinaryIndicates when the signal is clipping (too loud for the hardware and is being distorted)Clip light
[Master]samplerateabsolute valueThe current output sample rate in Hz (default 44100)(none)
[Master]volume0.0..1.0..5.0Adjusts the Master output volumeCenter Volume knob
[Master]VuMeterdefaultOutputs the current instantaneous master volume (composite)Master meter (mono)
[Master]VuMeterLdefaultOutputs the current instantaneous master volume for the left channelMaster meter L
[Master]VuMeterRdefaultOutputs the current instantaneous master volume for the right channelMaster meter R
—-—-—-—-—-
[Playlist]LoadSelectedIntoFirstStoppedbinaryLoads the currently highlighted song into the first stopped deckWaveform view
[Playlist]SelectNextPlaylistbinarySwitches to the next view (Library, Queue, etc.)Playlist/tracktable display
[Playlist]SelectNextTrackbinaryScrolls to the next track in the Playlist/tracktablePlaylist/tracktable highlight
[Playlist]SelectPrevPlaylistbinarySwitches to the previous view (Library, Queue, etc.)Playlist/tracktable display
[Playlist]SelectPrevTrackbinaryScrolls to the previous track in the Playlist/tracktablePlaylist/tracktable highlight
[Playlist]SelectTrackKnobrelative valueScrolls the given number of tracks in the Playlist/tracktable (can be negative for reverse direction)Playlist/tracktable highlight
(N=1 or 2 below)—-—-—-—-
[ChannelN]backbinaryFast rewind (REW)< button
[ChannelN]beatsyncbinarySyncs the BPM to that of the other track (if BPM is detected on both)SYNC button & Pitch slider snaps to the appropriate value
[ChannelN]bpmabsolute valueReads or sets the track's current BPM (changing the pitch)BPM value display
[ChannelN]cue_defaultbinaryIn CDJ mode, when playing, returns to the cue point & pauses. If stopped, sets a cue point at the current location. If stopped and at a cue point, plays from that point until released (set to 0.)CUE button
[ChannelN]cue_pointabsolute valueThe current position of the cue point in samplesCue point marker
[ChannelN]cue_previewbinaryPlays from the current cue pointCUE button lights & waveform moves
[ChannelN]cue_setbinarySets a cue point?Cue mark appears on the waveform?
[ChannelN]cue_simplebinary??
[ChannelN]durationabsolute valueOutputs the length of the current song in seconds(none)
[ChannelN]file_bpm???
[ChannelN]filterHigh0.0..1.0..4.0Adjusts the gain of the high EQ filterHIGH knob
[ChannelN]filterHighKillbinaryHolds the gain of the high EQ to -inf while activeHIGH knob
[ChannelN]filterLow0.0..1.0..4.0Adjusts the gain of the low EQ filterLOW knob
[ChannelN]filterLowKillbinaryHolds the gain of the low EQ to -inf while activeLOW knob
[ChannelN]filterMid0.0..1.0..4.0Adjusts the gain of the mid EQ filterMID knob
[ChannelN]filterMidKillbinaryHolds the gain of the mid EQ to -inf while activeMID knob
[ChannelN]flangerbinaryToggles the flange effectFLANGER button
[ChannelN]fwdbinaryFast forward (FF)> button
[ChannelN]Hercules1???
[ChannelN]Hercules2???
[ChannelN]Hercules3???
[ChannelN]Hercules4???
[ChannelN]jog-3.0..3.0Affects relative play speed & direction for short instances (additive & is automatically reset to 0)Waveform
[ChannelN]LoadSelectedTrackbinaryLoads the currently highlighted track into the deckTrack name & waveform change
[ChannelN]loop???
[ChannelN]NextTask???
[ChannelN]NextTrack???
[ChannelN]PeakIndicatorbinaryIndicates when the signal is clipping (too loud for the hardware and is being distorted)Clip light
[ChannelN]pflbinaryToggles headphone cueingHeadphone button
[ChannelN]playbinaryToggles playing or pausing the trackPlay/pause button
[ChannelN]playpositiondefaultSets the absolute position in the track (0=beginning, 1=end)Waveform
[ChannelN]pregain0.0..1.0..4.0Adjusts the pre-fader gain of the track (to avoid clipping)GAIN knob
[ChannelN]PrevTask???
[ChannelN]PrevTrack???
[ChannelN]rate-1.0..1.0Pitch controlPitch slider
[ChannelN]rate_dir???
[ChannelN]rate_perm_down_smallbinarySets the pitch 1% lowerPerm down button & Pitch slider
[ChannelN]rate_perm_up_smallbinarySets the pitch 1% higherPerm up button & Pitch slider
[ChannelN]rate_temp_downbinaryHolds the pitch 4% lower while activeTemp down button & Pitch slider
[ChannelN]rate_temp_upbinaryHolds the pitch 4% higher while activeTemp up button & Pitch slider
[ChannelN]rateRange0.0..3.0Sets the range of the pitch slider (0.08 = 8%)none, until you move the pitch slider
[ChannelN]reversebinaryToggles playing the track backwardsREV button
[ChannelN]scratch-3.0..3.0Affects play speed & direction (differently whether currently playing or not) (multiplicative)Waveform
[ChannelN]transform???
[ChannelN]volumedefaultAdjusts the channel volume faderVOL fader
[ChannelN]VuMeterdefaultOutputs the current instantaneous channel volumeChannel meter
[ChannelN]wheel-3.0..3.0Affects relative play speed & direction persistently (additive offset & must manually be undone)Waveform

And coming up in v1.8:

[Group]Key/ControlRangeWhat it doesOn-screen feedback
[ChannelN]loop_inbinarySets the player loop in position to the current play position.Loop-in marker changes on waveform.
[ChannelN]loop_outbinarySets the player loop out position to the current play position.Loop-out marker changes on waveform.
[ChannelN]reloop_exitbinaryToggles the current loop on or off.Loop range in waveform activates or deactivates.
[ChannelN]loop_in_positionpositive integerThe player loop-in position, -1 if not set.Loop-in marker changes on waveform.
[ChannelN]loop_out_positionpositive integerThe player loop-out position, -1 if not set.Loop-out marker shows on waveform.
[ChannelN]hotcue_X_positionpositive integerThe position of hotcue X, -1 if not set.Hotcue X marker changes on waveform.
[ChannelN]hotcue_X_enabledread-only, binary1 if hotcue X is active, (position is not -1), 0 otherwise.
[ChannelN]hotcue_X_setbinarySet hotcue X to the current play position. If hotcue X was previously set, clears its hotcue status.Hotcue X marker changes on waveform.
[ChannelN]hotcue_X_clearbinaryIf hotcue X is set, clears its hotcue status.Hotcue X marker changes on waveform.
[ChannelN]hotcue_X_gotobinaryIf hotcue X is set, seeks the player to hotcue X's position.Player may change position.
[ChannelN]hotcue_X_gotoandstopbinaryIf hotcue X is set, seeks the player to hotcue X's position and stops.Player may change position.
[ChannelN]hotcue_X_activatebinaryIf hotcue X is set, seeks the player to hotcue X's position. If hotcue X is not set, sets hotcue X to the current play position. Player may change position. Hotcue X marker may change on waveform.
[ChannelN]scratch2_enablebinaryTakes over play speed & direction for scratch2.Waveform
[ChannelN]scratch2-3.0..3.0Affects absolute play speed & direction whether currently playing or not when scratch2_enabled is active. (multiplicative)Waveform

This list contains nearly all of the controls that are useful to MIDI mapping developers.

If you were so inclined, the full list (with mixed up [Groups], internal objects and other things you shouldn't touch…be warned!) can be generated by running the following script in your mixxx/src directory:

#!/bin/sh
# set -x
IFS='
'
last_control=

for ck in `grep ConfigKey *.cpp | sed -e 's/ConfigKey(group/ConfigKey("[Master]"/g' | grep 'ConfigKey("' | grep -v "Channel2" | sed -e 's/.*ConfigKey(//g' -e 's/, */,/g' | cut -d\) -f1 | sed -e 's/\[Channel1\]/\[ChannelN\] (where N is a number 1 or 2)/g' | sort -fu`; do
  control=`echo $ck|cut -d\" -f2`
  if [ "$control" != "$last_control" ]; then
    echo
    echo $control
    last_control=$control
  fi
  key=`echo $ck|cut -d\" -f4`
  if [ ! -z "${key}" ]; then echo "* ${key}"; fi
done

Using Controls Inside Mixxx (for developers)

If you want to access one of these controls inside Mixxx, you can do so with something like this:

 ControlObjectThreadMain* controlRightPitch = new ControlObjectThreadMain(ControlObject::getControl(ConfigKey("[[Channel2]]", "rate")));

That line will give you a ControlObject which allows you to read and control the pitch of the right channel in Mixxx. For example, to increase the pitch of the track in the right channel, one could do something like this:

 float fRightPitch = controlRightPitch->get();
 controlRightPitch->slotSet(fRightPitch + 0.10);

This would increase the pitch of the right channel inside Mixxx, and the GUI controls would automatically reflect this change. Access to ControlObjects is also thread-safe when used this way.

Important note: Different types of ControlObject wrappers must be used depending on what thread your code is running in. This example assumes the code will run in the GUI (ie. main) thread. The ControlObjects wrappers should be used as follows: