From ca3afdce5eefa48070f91cf71fe4d9d63489da6b Mon Sep 17 00:00:00 2001 From: Markus Golec <56672386+mgolec225@users.noreply.github.com> Date: Sun, 15 Mar 2026 17:44:06 +0100 Subject: [PATCH] Arduino Sketch XDJ200SX.ino Version 1 --- arduino/XDJ200SX.ino | 470 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 470 insertions(+) create mode 100644 arduino/XDJ200SX.ino diff --git a/arduino/XDJ200SX.ino b/arduino/XDJ200SX.ino new file mode 100644 index 0000000..da4e759 --- /dev/null +++ b/arduino/XDJ200SX.ino @@ -0,0 +1,470 @@ +#include // aktuelle Bounce2-Library nutzen +#include +#include +#include + + +// ---------------- Button Pins ---------------- +const int search_back_pin = 12; +const int search_forward_pin = 13; +const int track_previous_pin = 14; +const int track_next_pin = 15; +const int foldersearch_back_pin = 16; +const int foldersearch_forward_pin = 17; +const int tempomode_pin = 20; +const int mastertempo_pin = 21; +const int load_pin = 24; //Encoder Push Button +const int cue_pin = 25; +const int play_pin = 26; +const int autocue_pin = 27; +const int beatloop_pin = 28; +const int eject_pin = 30; +const int jet_pin = 39; +const int zip_pin = 40; +const int wah_pin = 41; +const int hold_pin = 42; +const int loopin_pin = 43; +const int loopout_pin = 44; +const int reloop_pin = 45; + + +// ---------------- Encoder Jogwheel ---------------- +const int jogA_pin = 18; +const int jogB_pin = 19; +const int midiChannel = 2; +const int jogControlNumber = 20; +Encoder jog(jogA_pin, jogB_pin); +long lastPosition_jog = 0; + + +// ---------------- Encoder Browser ---------------- +const int browseA_pin = 36; +const int browseB_pin = 37; +const int midiChannelb = 3; +const int DEBOUNCE_MS = 3; // Debounce curt +const int NOTE_SCROLL_DOWN = 70; +const int NOTE_SCROLL_UP = 71; +elapsedMillis debounceTime_browse; // Temps per filtrar rebots browse¡ +Encoder browse(browseA_pin, browseB_pin); +long lastPosition_browse = 0; // Última posició llegida + +elapsedMillis msec = 0; + + +// ---------------- Pitch ---------------- +const int pitchPin = A0; +ResponsiveAnalogRead analog(pitchPin, true); +int lastMSB = -1; +int lastLSB = -1; + + +// ---------------- LED Pins ---------------- +const int ledCue = 7; +const int ledPlay = 6; +const int ledLoopIn = 8; +const int ledLoopOut = 9; +const int ledLoop = 10; +const int ledMastertempo = 11; +const int ledJog1 = 1; +const int ledJog2 = 2; +const int ledJog3 = 3; +const int ledJog4 = 4; +const int ledJog5 = 5; +const int ledCd = 29; + + +// ---------------- MIDI Channels ---------------- +const int channel = 1; + + +// ---------------- Notes, received from Mixxx ---------------- +const int PLAY_NOTE_INDICATOR = 61; +const int CUE_NOTE_INDICATOR = 62; +const int LEDINTERN_NOTE_INDICATOR = 63; +const int LEDCD_NOTE_INDICATOR = 64; +const int SIESTAPLAY_NOTE_INDICATOR = 65; +bool siestaplay = false; + + +// ---------------- Blink when the track ends ---------------- +bool parpadeig = false; +unsigned long tempsAnterior = 0; + + +// ---------------- Bounce buttons 5ms ---------------- +Bounce search_back_boto = Bounce (search_back_pin, 50); +Bounce search_forward_boto = Bounce (search_forward_pin, 50); +Bounce trackprevious_boto = Bounce (track_previous_pin, 50); +Bounce track_next_boto = Bounce (track_next_pin, 50); +Bounce foldersearch_back_boto = Bounce (foldersearch_back_pin, 50); +Bounce foldersearch_forward_boto = Bounce (foldersearch_forward_pin, 50); +Bounce tempomode_boto = Bounce (tempomode_pin, 50); +Bounce mastertempo_boto = Bounce (mastertempo_pin, 50); +Bounce load_boto = Bounce (load_pin, 50); +Bounce cue_boto = Bounce (cue_pin, 50); +Bounce play_boto = Bounce (play_pin, 50); +Bounce autocue_boto = Bounce (autocue_pin, 50); +Bounce beatloop_boto = Bounce (beatloop_pin, 50); +Bounce eject_boto = Bounce (eject_pin, 50); +Bounce jet_boto = Bounce (jet_pin, 50); +Bounce zip_boto = Bounce (zip_pin, 50); +Bounce wah_boto = Bounce (wah_pin, 50); +Bounce hold_boto = Bounce (hold_pin, 50); +Bounce loopin_boto = Bounce (loopin_pin, 50); +Bounce loopout_boto = Bounce (loopout_pin, 50); +Bounce reloop_boto = Bounce (reloop_pin, 50); + +//Bounce time_boto = Bounce (time_pin, 50); + + +// --- Execute Function if receiving a MIDI Message --- + +// Execute Automatically if receiving a "Note On" +void handleNoteOn(byte channel, byte note, byte velocity) { + // Check if the "Note On" is "PLAY" + if (note == PLAY_NOTE_INDICATOR) { + // If the speed is greater than 0, it means "Play", so we turn on the LED + if (velocity > 0) { + digitalWrite(ledPlay, HIGH); + } + // If the velocity is 0, it is treated as a Note Off, so we turn the LED off. + else { + digitalWrite(ledPlay, LOW); + } + } + if (note == CUE_NOTE_INDICATOR) { + // If the speed is greater than 0, it means "Cue", so we turn on the LED + if (velocity > 0) { + digitalWrite(ledCue, HIGH); + } + // If the velocity is 0, it is treated as a Note Off, so we turn the LED off. + else { + digitalWrite(ledCue, LOW); + } + } + + +// INTERNAL LED MARK THE BPM, ONLY IF IT IS IN PLAY +if(note == SIESTAPLAY_NOTE_INDICATOR){ + siestaplay = true; +} +if (note == LEDINTERN_NOTE_INDICATOR && siestaplay == true) +{ + digitalWrite(ledJog1, HIGH); + digitalWrite(ledJog2, HIGH); + digitalWrite(ledJog3, HIGH); + digitalWrite(ledJog4, HIGH); + digitalWrite(ledJog5, HIGH); +} + // make the CD LED blink when it receives information that the song is ending + if (note == LEDCD_NOTE_INDICATOR) { + parpadeig = (velocity > 0); + } + + +} + + +// Execute Automatically if receiving a "Note Off" +void handleNoteOff(byte channel, byte note, byte velocity) { + // Comprovem si la nota rebuda és la del nostre indicador de Play + if (note == PLAY_NOTE_INDICATOR) { + // Si rebem un Note Off per a aquesta nota, apaguem el LED + digitalWrite(ledPlay, LOW); + } + if (note == CUE_NOTE_INDICATOR) { + // Si rebem un Note Off per a aquesta nota, apaguem el LED + digitalWrite(ledCue, LOW); + } + + if (note == LEDCD_NOTE_INDICATOR) { + parpadeig = false; + } + + if(note == SIESTAPLAY_NOTE_INDICATOR){ + siestaplay = false; + } + if (note == LEDINTERN_NOTE_INDICATOR || siestaplay == false){ + digitalWrite(ledJog1, LOW); + digitalWrite(ledJog2, LOW); + digitalWrite(ledJog3, LOW); + digitalWrite(ledJog4, LOW); + digitalWrite(ledJog5, LOW); + } + +} + +void JogNudge(){ + long newPosition_jog = jog.read(); + + if (newPosition_jog % 4 == 0 && newPosition_jog != lastPosition_jog) { + if (newPosition_jog > lastPosition_jog) { + // Dreta -> Envia 65 + usbMIDI.sendControlChange(jogControlNumber, 65, midiChannel); + } else { + // Esquerra -> Envia 63 + usbMIDI.sendControlChange(jogControlNumber, 63, midiChannel); + } + lastPosition_jog = newPosition_jog; + } + +} + + +void setup() { + +pinMode(search_back_pin, INPUT_PULLUP); +pinMode(search_forward_pin, INPUT_PULLUP); +pinMode(track_previous_pin, INPUT_PULLUP); +pinMode(track_next_pin, INPUT_PULLUP); +pinMode(foldersearch_back_pin, INPUT_PULLUP); +pinMode(foldersearch_forward_pin, INPUT_PULLUP); +pinMode(tempomode_pin, INPUT_PULLUP); +pinMode(mastertempo_pin, INPUT_PULLUP); +pinMode(load_pin, INPUT_PULLUP); +pinMode(cue_pin, INPUT_PULLUP); +pinMode(play_pin, INPUT_PULLUP); +pinMode(autocue_pin, INPUT_PULLUP); +pinMode(beatloop_pin, INPUT_PULLUP); +pinMode(eject_pin, INPUT_PULLUP); +pinMode(jet_pin, INPUT_PULLUP); +pinMode(zip_pin, INPUT_PULLUP); +pinMode(wah_pin, INPUT_PULLUP); +pinMode(hold_pin, INPUT_PULLUP); +pinMode(loopin_pin, INPUT_PULLUP); +pinMode(loopout_pin, INPUT_PULLUP); +pinMode(reloop_pin, INPUT_PULLUP); + + +pinMode(ledCue, OUTPUT); +pinMode(ledPlay, OUTPUT); +pinMode(ledLoopIn, OUTPUT); +pinMode(ledLoopOut, OUTPUT); +pinMode(ledLoop, OUTPUT); +pinMode(ledMastertempo, OUTPUT); +pinMode(ledJog1, OUTPUT); +pinMode(ledJog2, OUTPUT); +pinMode(ledJog3, OUTPUT); +pinMode(ledJog4, OUTPUT); +pinMode(ledJog5, OUTPUT); +pinMode(ledCd, OUTPUT); + + + // --- CONFIGURació MIDI --- + // Assignem les nostres funcions "callback" als esdeveniments MIDI + usbMIDI.setHandleNoteOn(handleNoteOn); + usbMIDI.setHandleNoteOff(handleNoteOff); + + //Inicialitzo jog + jog.write(0); + + //Inicialitzo browse + browse.write(0); + lastPosition_browse = 0; + +} + +void loop() { + +eject_boto.update(); +trackprevious_boto.update(); +track_next_boto.update(); +search_back_boto.update(); +search_forward_boto.update(); +cue_boto.update(); +play_boto.update(); +jet_boto.update(); +zip_boto.update(); +wah_boto.update(); +hold_boto.update(); +//time_boto.update(); +mastertempo_boto.update(); +load_boto.update(); + + +//Play + if(play_boto.fallingEdge()){ + usbMIDI.sendNoteOn(60, 127, channel); + } + if(play_boto.risingEdge()){ + usbMIDI.sendNoteOff(60, 0, channel); + } + //CUE + if(cue_boto.fallingEdge()){ + usbMIDI.sendNoteOn(61, 127, channel); + } + if(cue_boto.risingEdge()){ + usbMIDI.sendNoteOff(61, 0, channel); + } + + +//Master Tempo + if(mastertempo_boto.fallingEdge()){ + usbMIDI.sendNoteOn(62, 127, channel); + } + if(mastertempo_boto.risingEdge()){ + usbMIDI.sendNoteOff(62, 0, channel); + } + +//Eject +if(eject_boto.fallingEdge()){ + usbMIDI.sendNoteOn(63, 127, channel); + } + if(eject_boto.risingEdge()){ + usbMIDI.sendNoteOff(63, 0, channel); + } + //trackprevious +if(trackprevious_boto.fallingEdge()){ + usbMIDI.sendNoteOn(64, 127, channel); + } + if(trackprevious_boto.risingEdge()){ + usbMIDI.sendNoteOff(64, 0, channel); + } + //tracknext +if(track_next_boto.fallingEdge()){ + usbMIDI.sendNoteOn(65, 127, channel); + } + if(track_next_boto.risingEdge()){ + usbMIDI.sendNoteOff(65, 0, channel); + } + //search_back +if(search_back_boto.fallingEdge()){ + usbMIDI.sendNoteOn(66, 127, channel); + } + if(search_back_boto.risingEdge()){ + usbMIDI.sendNoteOff(66, 0, channel); + } + //search_forward +if(search_forward_boto.fallingEdge()){ + usbMIDI.sendNoteOn(67, 127, channel); + } + if(search_forward_boto.risingEdge()){ + usbMIDI.sendNoteOff(67, 0, channel); + } + //jet +if(jet_boto.fallingEdge()){ + usbMIDI.sendNoteOn(68, 127, channel); + } + if(jet_boto.risingEdge()){ + usbMIDI.sendNoteOff(68, 0, channel); + } + //zip +if(zip_boto.fallingEdge()){ + usbMIDI.sendNoteOn(69, 127, channel); + } + if(zip_boto.risingEdge()){ + usbMIDI.sendNoteOff(69, 0, channel); + } + //wah +if(wah_boto.fallingEdge()){ + usbMIDI.sendNoteOn(70, 127, channel); + } + if(wah_boto.risingEdge()){ + usbMIDI.sendNoteOff(70, 0, channel); + } + //hold +if(hold_boto.fallingEdge()){ + usbMIDI.sendNoteOn(71, 127, channel); + } + if(hold_boto.risingEdge()){ + usbMIDI.sendNoteOff(71, 0, channel); + } + //time +//if(time_boto.fallingEdge()){ +// usbMIDI.sendNoteOn(72, 127, channel); +// } +// if(time_boto.risingEdge()){ +// usbMIDI.sendNoteOff(72, 0, channel); +// } + //load +if(load_boto.fallingEdge()){ + usbMIDI.sendNoteOn(73, 127, channel); + } + if(load_boto.risingEdge()){ + usbMIDI.sendNoteOff(73, 0, channel); + } + + + //Jog: cridem la funció JogNudge +JogNudge(); + + +//Browse +long newPosition_browse = browse.read(); + long delta_browse = newPosition_browse - lastPosition_browse; + + if (debounceTime_browse > DEBOUNCE_MS && delta_browse != 0) { + // Convertim els passos de l'encoder a "clics" (canvis de +1 o -1) + // LA CLAU ÉS AQUÍ: Només actuem si la posició és un múltiple de 4 + // i si és diferent de l'última posició VÀLIDA que vam guardar. + if (newPosition_browse % 4 == 0 && newPosition_browse != lastPosition_browse) { + + if (newPosition_browse > lastPosition_browse) { + // Direcció: DRETA (baixar a la llista) + usbMIDI.sendNoteOn(NOTE_SCROLL_DOWN, 127, midiChannelb); + usbMIDI.sendNoteOff(NOTE_SCROLL_DOWN, 0, midiChannelb); + + } else { + // Direcció: ESQUERRA (pujar a la llista) + usbMIDI.sendNoteOn(NOTE_SCROLL_UP, 127, midiChannelb); + usbMIDI.sendNoteOff(NOTE_SCROLL_UP, 0, midiChannelb); + } + + // Actualitzem la posició "antiga" NOMÉS quan tenim un clic complet. + lastPosition_browse = newPosition_browse; + } +} + +/* Pitch old +if (msec >= 100){ + msec = 0; + int n0 = analogRead(A0) / 8; + //transmetre MIDI si A0 canvia + if(n0 != previousA0){ + usbMIDI.sendControlChange(controllerA0, n0, channel_pitch); + previousA0 = n0; + } +} +*/ + +//Pitch 14 bits + +analog.update(); + int raw = analog.getValue(); // valor ja suavitzat + + int value14 = map(raw, 0, 1023, 0, 16383); + + byte msb = (value14 >> 7) & 0x7F; + byte lsb = value14 & 0x7F; + + if (msb != lastMSB) { + usbMIDI.sendControlChange(0, msb, 1); + lastMSB = msb; + } + + if (lsb != lastLSB) { + usbMIDI.sendControlChange(32, lsb, 1); + lastLSB = lsb; + } + + + + +//Parpadeig LED CD si s'acaba la cançó (MIXX envia 127) +if (parpadeig){ + if (millis () - tempsAnterior >= 1000){ + tempsAnterior = millis(); + digitalWrite(ledCd, !digitalRead(ledCd)); + } +} +else{ + digitalWrite(ledCd, LOW); + } + +// Aquesta línia és l'única cosa que necessitem al loop. + // Constantment comprova si ha arribat algun missatge de Mixxx + // i, si és així, crida automàticament a les funcions 'handleNoteOn' o 'handleNoteOff'. + while (usbMIDI.read()){}; + + +}