Skip to content

Instantly share code, notes, and snippets.

@voxels
Last active November 14, 2025 12:39
Show Gist options
  • Select an option

  • Save voxels/16a793881b00527a056dbaef27a366ac to your computer and use it in GitHub Desktop.

Select an option

Save voxels/16a793881b00527a056dbaef27a366ac to your computer and use it in GitHub Desktop.
import Foundation
/// A `Sendable` struct for defining a single MIDI Note message.
public struct MidiNoteMapping: Sendable, Equatable {
public var channel: UInt8
public var note: UInt8
}
/// A `Sendable` struct for defining a single MIDI Control Change (CC) message.
public struct MidiControlChangeMapping: Sendable, Equatable {
public var channel: UInt8
public var controller: UInt8
}
/// Defines all the mappable controls for a single Traktor deck.
public struct TraktorDeckMapping: Sendable, Equatable {
// Transport
public var play: MidiNoteMapping
public var cue: MidiNoteMapping
public var sync: MidiNoteMapping
public var reverse: MidiNoteMapping
// Jog Wheel
public var jogTouch: MidiNoteMapping
public var jogTurn: MidiControlChangeMapping // Relative
// Mixer (Typically on Channel 1 for both)
public var volume: MidiControlChangeMapping // Absolute
public var eqHigh: MidiControlChangeMapping // Absolute
public var eqMid: MidiControlChangeMapping // Absolute
public var eqLow: MidiControlChangeMapping // Absolute
public var filter: MidiControlChangeMapping // Absolute
// Tempo
public var tempo: MidiControlChangeMapping // Absolute
// Hot Cues (A-H)
public var hotCueA: MidiNoteMapping
public var hotCueB: MidiNoteMapping
public var hotCueC: MidiNoteMapping
public var hotCueD: MidiNoteMapping
public var hotCueE: MidiNoteMapping
public var hotCueF: MidiNoteMapping
public var hotCueG: MidiNoteMapping
public var hotCueH: MidiNoteMapping
// Looping
public var loopIn: MidiNoteMapping
public var loopOut: MidiNoteMapping
public var reloopExit: MidiNoteMapping
public var loop4Beat: MidiNoteMapping
public var loop8Beat: MidiNoteMapping
// Beat Jump
public var beatJumpFwd: MidiNoteMapping
public var beatJumpRev: MidiNoteMapping
}
/// A container for all deck and mixer mappings.
public struct TraktorMapping: Sendable, Equatable {
public var deckA: TraktorDeckMapping
public var deckB: TraktorDeckMapping
// Global controls (typically on Channel 1)
public var crossfader: MidiControlChangeMapping
public var browserRotate: MidiControlChangeMapping
/// Provides a default, example mapping.
/// You can edit this to match your Traktor controller setup.
/// This example uses Channel 0 (MIDI Ch 1) for Deck A and Channel 1 (MIDI Ch 2) for Deck B.
/// Global controls are on Channel 0.
public static var defaultNI: TraktorMapping {
.init(
deckA: .init(
play: .init(channel: 0, note: 37), // C#1
cue: .init(channel: 0, note: 39), // D#1
sync: .init(channel: 0, note: 35), // B0
reverse: .init(channel: 0, note: 36), // C1
jogTouch: .init(channel: 0, note: 40), // E1
jogTurn: .init(channel: 0, controller: 20),
volume: .init(channel: 0, controller: 7),
eqHigh: .init(channel: 0, controller: 10),
eqMid: .init(channel: 0, controller: 11),
eqLow: .init(channel: 0, controller: 12),
filter: .init(channel: 0, controller: 13),
tempo: .init(channel: 0, controller: 14),
hotCueA: .init(channel: 0, note: 50), // D2
hotCueB: .init(channel: 0, note: 51), // D#2
hotCueC: .init(channel: 0, note: 52), // E2
hotCueD: .init(channel: 0, note: 53), // F2
hotCueE: .init(channel: 0, note: 54), // F#2
hotCueF: .init(channel: 0, note: 55), // G2
hotCueG: .init(channel: 0, note: 56), // G#2
hotCueH: .init(channel: 0, note: 57), // A2
loopIn: .init(channel: 0, note: 41), // F1
loopOut: .init(channel: 0, note: 42), // F#1
reloopExit: .init(channel: 0, note: 43), // G1
loop4Beat: .init(channel: 0, note: 44), // G#1
loop8Beat: .init(channel: 0, note: 45), // A1
beatJumpFwd: .init(channel: 0, note: 46), // A#1
beatJumpRev: .init(channel: 0, note: 47) // B1
),
deckB: .init(
play: .init(channel: 1, note: 37), // C#1
cue: .init(channel: 1, note: 39), // D#1
sync: .init(channel: 1, note: 35), // B0
reverse: .init(channel: 1, note: 36), // C1
jogTouch: .init(channel: 1, note: 40), // E1
jogTurn: .init(channel: 1, controller: 20),
volume: .init(channel: 1, controller: 7),
eqHigh: .init(channel: 1, controller: 10),
eqMid: .init(channel: 1, controller: 11),
eqLow: .init(channel: 1, controller: 12),
filter: .init(channel: 1, controller: 13),
tempo: .init(channel: 1, controller: 14),
hotCueA: .init(channel: 1, note: 50), // D2
hotCueB: .init(channel: 1, note: 51), // D#2
hotCueC: .init(channel: 1, note: 52), // E2
hotCueD: .init(channel: 1, note: 53), // F2
hotCueE: .init(channel: 1, note: 54), // F#2
hotCueF: .init(channel: 1, note: 55), // G2
hotCueG: .init(channel: 1, note: 56), // G#2
hotCueH: .init(channel: 1, note: 57), // A2
loopIn: .init(channel: 1, note: 41), // F1
loopOut: .init(channel: 1, note: 42), // F#1
reloopExit: .init(channel: 1, note: 43), // G1
loop4Beat: .init(channel: 1, note: 44), // G#1
loop8Beat: .init(channel: 1, note: 45), // A1
beatJumpFwd: .init(channel: 1, note: 46), // A#1
beatJumpRev: .init(channel: 1, note: 47) // B1
),
crossfader: .init(channel: 0, controller: 8), // Ch 1, CC 8
browserRotate: .init(channel: 0, controller: 21) // Ch 1, CC 21
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment