Last active
December 25, 2021 03:37
-
-
Save tancredi/15872e8f2fadf13e8be3b04c1a42bcc5 to your computer and use it in GitHub Desktop.
MIDI-Ino - An Arduino custom MIDI controller with Mixxx mappings
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <USB-MIDI.h> | |
USBMIDI_CREATE_DEFAULT_INSTANCE(); | |
const float K_MAX = 690; | |
const float K_THRESHOLD = 1; | |
const byte K_PINS[5]= { A0, A1, A2, A3, A4 }; | |
const byte L_PINS[5]= { 2, 3, 4, 5, 6 }; | |
const byte B_PINS[5]= { 9, 10, 11, 12, 13 }; | |
const float MIDI_MAX_VAL = 127; | |
const int CHANNEL = 1; | |
const int MIDI_START_K = 0x20; | |
const int MIDI_START_L = 0x30; | |
const int MIDI_START_B = 0x40; | |
int k_values[sizeof(K_PINS)]; | |
bool b_values[sizeof(K_PINS)]; | |
bool l_values[sizeof(L_PINS)]; | |
void setup() { | |
MIDI.begin(1); | |
// Serial.begin(9600); | |
for (int i = 0; i < sizeof(K_PINS); i++) { | |
pinMode(K_PINS[i], INPUT); | |
} | |
for (int i = 0; i < sizeof(B_PINS); i++) { | |
pinMode(B_PINS[i], INPUT); | |
} | |
for (int i = 0; i < sizeof(L_PINS); i++) { | |
pinMode(L_PINS[i], OUTPUT); | |
} | |
MIDI.setHandleControlChange(handleControl); | |
} | |
int knobToVelocity(float value) { | |
float out = (value * MIDI_MAX_VAL) / K_MAX; | |
return floor(max(0, min(MIDI_MAX_VAL, out))); | |
} | |
void updateKnob(int i) { | |
int prev = k_values[i]; | |
int val = knobToVelocity(analogRead(K_PINS[i])); | |
if (abs(val - prev) > K_THRESHOLD) { | |
MIDI.sendControlChange(MIDI_START_K + i, val, CHANNEL); | |
k_values[i] = val; | |
} | |
} | |
void updateLed(int i) { | |
int prev = k_values[i]; | |
int val = knobToVelocity(analogRead(K_PINS[i])); | |
digitalWrite(L_PINS[i], l_values[i] ? HIGH : LOW); | |
} | |
void handleControl(byte channel, byte control, byte value) { | |
if (control >= MIDI_START_L && control < MIDI_START_L + sizeof(L_PINS)) { | |
int i = control - MIDI_START_L; | |
l_values[i] = value > 0; | |
} | |
} | |
void updateButton(int i) { | |
bool val = digitalRead(B_PINS[i]); | |
bool prev = b_values[i]; | |
if (val != prev) { | |
MIDI.sendControlChange(MIDI_START_B + i, val, CHANNEL); | |
b_values[i] = val; | |
} | |
} | |
void loop() { | |
MIDI.read(); | |
for (int i = 0; i < sizeof(K_PINS); i++) { | |
updateKnob(i); | |
} | |
for (int i = 0; i < sizeof(B_PINS); i++) { | |
updateButton(i); | |
} | |
for (int i = 0; i < sizeof(L_PINS); i++) { | |
updateLed(i); | |
} | |
delay(1); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const MI = { | |
previewPlaying: false, | |
previewToMiddleOnLoad: false, | |
}; | |
const GROUPS = { PREVIEW: "[PreviewDeck1]" }; | |
const MAX_POSITION = 1.14; | |
const LED_MIDI_START = 0x30; | |
const MIDI_ON = 0x7f; | |
const MIDI_OFF = 0x00; | |
MI.init = function () { | |
engine.makeConnection(GROUPS.PREVIEW, "track_loaded", handlePreviewLoaded); | |
}; | |
MI.shutdown = function () {}; | |
function handlePreviewLoaded(channel, group) { | |
if (MI.previewToMiddleOnLoad) { | |
MI.previewToMiddleOnLoad = false; | |
engine.setValue(GROUPS.PREVIEW, "playposition", MAX_POSITION / 2); | |
} | |
} | |
function setLed(index, status) { | |
midi.sendShortMsg(0xb0, LED_MIDI_START + index, status ? MIDI_ON : MIDI_OFF); | |
} | |
MI.togglePreviewFromTheMiddle = function (channel, group, value) { | |
const pressed = value; | |
const playing = engine.getValue(GROUPS.PREVIEW, "play"); | |
if (!pressed) { | |
setLed(2, false); | |
return engine.setValue(GROUPS.PREVIEW, "play", false); | |
} | |
MI.previewToMiddleOnLoad = true; | |
setLed(2, true); | |
script.triggerControl(GROUPS.PREVIEW, "LoadSelectedTrackAndPlay", true); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version='1.0' encoding='utf-8'?> | |
<MixxxControllerPreset schemaVersion="1" mixxxVersion="2.0.0+"> | |
<info> | |
<name>MIDI-Ino (Custom)</name> | |
<author>Tanc</author> | |
</info> | |
<controller id="MIDI-ino"> | |
<scriptfiles> | |
<file filename="midi-ino.js" functionprefix="MI"/> | |
</scriptfiles> | |
<controls> | |
<control> | |
<group>[EffectRack1_EffectUnit1_Effect1]</group> | |
<key>meta</key> | |
<status>0xB0</status> | |
<midino>0x20</midino> | |
<options> | |
<Invert /> | |
</options> | |
</control> | |
<control> | |
<group>[EffectRack1_EffectUnit1_Effect1]</group> | |
<key>enabled</key> | |
<status>0xB0</status> | |
<midino>0x40</midino> | |
<options> | |
<Normal /> | |
</options> | |
</control> | |
<control> | |
<group>[EffectRack1_EffectUnit1_Effect2]</group> | |
<key>meta</key> | |
<status>0xB0</status> | |
<midino>0x21</midino> | |
<options> | |
<Invert /> | |
</options> | |
</control> | |
<control> | |
<group>[EffectRack1_EffectUnit1_Effect2]</group> | |
<key>enabled</key> | |
<status>0xB0</status> | |
<midino>0x41</midino> | |
<options> | |
<Normal /> | |
</options> | |
</control> | |
<control> | |
<description>Knob 3 (middle)</description> | |
<group>[Master]</group> | |
<key>headMix</key> | |
<status>0xB0</status> | |
<midino>0x22</midino> | |
<options> | |
<Normal /> | |
</options> | |
</control> | |
<control> | |
<description>Button 3 (middle)</description> | |
<group>[PreviewDeck1]</group> | |
<key>MI.togglePreviewFromTheMiddle</key> | |
<status>0xB0</status> | |
<midino>0x42</midino> | |
<options> | |
<script-binding/> | |
</options> | |
</control> | |
<control> | |
<group>[EffectRack1_EffectUnit2_Effect1]</group> | |
<key>meta</key> | |
<status>0xB0</status> | |
<midino>0x23</midino> | |
<options> | |
<Normal /> | |
</options> | |
</control> | |
<control> | |
<group>[EffectRack1_EffectUnit2_Effect1]</group> | |
<key>enabled</key> | |
<status>0xB0</status> | |
<midino>0x43</midino> | |
<options> | |
<Normal /> | |
</options> | |
</control> | |
<control> | |
<group>[EffectRack1_EffectUnit2_Effect2]</group> | |
<key>meta</key> | |
<status>0xB0</status> | |
<midino>0x24</midino> | |
<options> | |
<Invert /> | |
</options> | |
</control> | |
<control> | |
<group>[EffectRack1_EffectUnit2_Effect2]</group> | |
<key>enabled</key> | |
<status>0xB0</status> | |
<midino>0x44</midino> | |
<options> | |
<Normal /> | |
</options> | |
</control> | |
</controls> | |
<outputs> | |
<output> | |
<group>[EffectRack1_EffectUnit1_Effect1]</group> | |
<key>enabled</key> | |
<status>0xB0</status> | |
<midino>0x30</midino> | |
<on>0x7F</on> | |
<off>0x00</off> | |
<minimum>0.5</minimum> | |
</output> | |
<output> | |
<group>[EffectRack1_EffectUnit1_Effect2]</group> | |
<key>enabled</key> | |
<status>0xB0</status> | |
<midino>0x31</midino> | |
<on>0x7F</on> | |
<off>0x00</off> | |
<minimum>0.5</minimum> | |
</output> | |
<output> | |
<group>[EffectRack1_EffectUnit1_Effect3]</group> | |
<key>enabled</key> | |
<status>0xB0</status> | |
<midino>0x32</midino> | |
<on>0x7F</on> | |
<off>0x00</off> | |
<minimum>0.5</minimum> | |
</output> | |
<output> | |
<group>[EffectRack1_EffectUnit2_Effect1]</group> | |
<key>enabled</key> | |
<status>0xB0</status> | |
<midino>0x33</midino> | |
<on>0x7F</on> | |
<off>0x00</off> | |
<minimum>0.5</minimum> | |
</output> | |
<output> | |
<group>[EffectRack1_EffectUnit2_Effect2]</group> | |
<key>enabled</key> | |
<status>0xB0</status> | |
<midino>0x34</midino> | |
<on>0x7F</on> | |
<off>0x00</off> | |
<minimum>0.5</minimum> | |
</output> | |
</outputs> | |
</controller> | |
</MixxxControllerPreset> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment