UMS Mega Traktorino

Category:

Code


/* Traktorino

The Traktorino is a low-cost DIY MIDI controller for DJs, based in the Arduino platform.
It can control any software that accepts MIDI, like Traktor, Serato, or even Ableton Live.
The Traktorino is completely open-source, which means you can download the code and all the schematics, so you can make one yourself!
And if you want to build this controller, you can buy the kit from us, this way, you will be helping more projects like this to happen!

http://www.musiconerd.com/shop >> buy a Traktorino kit
http://www.musiconerd.com/traktorino >> learn more about the Traktorino
http://github.com/silveirago/traktorino >> Download the traktorino files
[email protected] >> Send me a message if you have any doubt

*/

/////////////////////////////////////////////
// PWM bit shifter
// You can choose the latch pin yourself.
const int ShiftPWM_latchPin = 8;

// ** uncomment this part to NOT use the SPI port and change the pin numbers. This is 2.5x slower **
#define SHIFTPWM_NOSPI
const int ShiftPWM_dataPin = 11;
const int ShiftPWM_clockPin = 12;

// If your LED's turn on if the pin is low, set this to true, otherwise set it to false.
const bool ShiftPWM_invertOutputs = false;

// You can enable the option below to shift the PWM phase of each shift register by 8 compared to the previous.
// This will slightly increase the interrupt load, but will prevent all PWM signals from becoming high at the same time.
// This will be a bit easier on your power supply, because the current peaks are distributed.
const bool ShiftPWM_balanceLoad = false;

/////////////////////////////////////////////
// LIBRARIES
#include // Bit shifter library >> https://github.com/elcojacobs/ShiftPWM - include ShiftPWM.h after setting the pins!
// If using with ATmega328 - Uno, Mega, Nano...
#include // MIDI library (by Forty Seven Effects) >> https://github.com/FortySevenEffects/arduino_midi_library/releases/tag/4.3.1
MIDI_CREATE_DEFAULT_INSTANCE();
#include // Multiplexer CD4067 library >> https://github.com/sumotoy/Multiplexer4067
#include // Threads library (by Ivan seidel) >> https://github.com/ivanseidel/ArduinoThread
#include
#include // Encoder library >> https://github.com/PaulStoffregen/Encoder

/////////////////////////////////////////////
// buttons
const byte muxNButtons = 13; // *coloque aqui o numero de entradas digitais utilizadas no multiplexer
const byte muxNAddonButtons = 12;
const byte NButtons = 1; // *coloque aqui o numero de entradas digitais utilizadas
const byte totalButtons = muxNButtons + muxNAddonButtons + NButtons;
const byte muxButtonPin[muxNButtons] = {0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 14, 15}; // *neste array coloque na ordem desejada os pinos das portas digitais utilizadas
const byte muxAddonButtonPin[muxNAddonButtons] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
const byte buttonPin[NButtons] = {9}; // *neste array coloque na ordem desejada os pinos das portas digitais utilizadas
int buttonCState[totalButtons] = {0}; // estado atual da porta digital
int buttonPState[totalButtons] = {0}; // estado previo da porta digital

/////////////////////////////////////////////
// debounce
unsigned long lastDebounceTime = 0; // the last time the output pin was toggled
unsigned long debounceDelay = 5; // the debounce time; increase if the output flickers

/////////////////////////////////////////////
// potentiometers
const byte muxNPots = 14; // *coloque aqui o numero de entradas analogicas utilizadas
const byte muxNAddonPots = 4;
const byte NPots = 0; // put the number of pots on analog pins here
const byte totalPots = muxNPots + muxNAddonPots + NPots;
const byte muxPotPin[muxNPots] = {0, 1, 2, 3, 4, 5, 6, 15, 14, 13, 12, 11, 10, 8}; // *neste array coloque na ordem desejada os pinos das portas analogicas, ou mux channel, utilizadas
const byte muxAddonPotPin[muxNAddonPots] = {12,13,14,15};
const byte potPin[NPots] = {};
int potCState[totalPots] = {0}; // estado atual da porta analogica
int potPState[totalPots] = {0}; // estado previo da porta analogica
int potVar = 0; // variacao entre o valor do estado previo e o atual da porta analogica
int lastCcValue[totalPots] = {0};

/////////////////////////////////////////////
// pot reading
int TIMEOUT = 50; //quantidade de tempo em que o potenciometro sera lido apos ultrapassar o varThreshold
byte varThreshold = 8; //threshold para a variacao no sinal do potenciometro
boolean potMoving = true; // se o potenciometro esta se movendo
unsigned long pTime[totalPots] = {0}; // tempo armazenado anteriormente
unsigned long timer[totalPots] = {0}; // armazena o tempo que passou desde que o timer foi zerado

/////////////////////////////////////////////
// encoder
Encoder myEnc(3, 2);
long oldPosition = -10;

/////////////////////////////////////////////
// midi
byte midiCh = 1; // *Canal midi a ser utilizado
byte note = 36; // *Nota mais grave que sera utilizada
byte cc = 1; // *CC mais baixo que sera utilizado

int ccLastValue = 0;

/////////////////////////////////////////////
// Leds
const byte ledNum = 24; // total number of leds used
unsigned char maxBrightness = 255;
unsigned char pwmFrequency = 75;
unsigned int numRegisters = 3;
unsigned int numOutputs = numRegisters * 8;
unsigned int numRGBLeds = numRegisters * 8 / 3;
unsigned int fadingMode = 0; //start with all LED's off.

unsigned int VuL[7] = {1, 2, 3, 4, 5, 6, 7}; // VU left pins
unsigned int VuR[7] = {15, 14, 13, 12, 11, 10, 9}; // VU righ pins
unsigned int buttonsLedL[5] = {20, 19, 18, 17, 16};
unsigned int buttonsLedR[5] = {8, 0, 23, 22, 21};

unsigned int red = 180;
unsigned int green = 255;
unsigned int blue = 10;
unsigned int yellow = 100;

byte ledOnOffPin = 10; //On Off pin

/////////////////////////////////////////////
// Multiplexer
Multiplexer4067 mplexPots = Multiplexer4067(4, 5, 6, 7, A0);
Multiplexer4067 mplexButtons = Multiplexer4067(4, 5, 6, 7, A1);
Multiplexer4067 mplexAddon = Multiplexer4067(4, 5, 6, 7, A5);

/////////////////////////////////////////////
// threads - programa cada atividade do Arduino para acontecer em um determinado tempo
Thread threadReadPots; // thread para controlar os pots
Thread threadReadButtons; // thread para controlar os botoes
StaticThreadController<2> cpu(&threadReadPots, &threadReadButtons); //thread master, onde as outras vao ser adicionadas

/////////////////////////////////////////////
void setup() {
Serial.begin(31250); // 115200 for hairless - 31250 for MOCO lufa

MIDI.turnThruOff();

/////////////////////////////////////////////
// Midi in
MIDI.setHandleControlChange(handleControlChange);
MIDI.setHandleNoteOn(handleNoteOn);
MIDI.setHandleNoteOff(handleNoteOff);

/////////////////////////////////////////////
// Multiplexers
mplexPots.begin(); // inicializa o multiplexer
mplexButtons.begin(); // inicializa o multiplexer
mplexAddon.begin();
pinMode(A1, INPUT_PULLUP); // Buttons need input pull up

/////////////////////////////////////////////
// buttons on Arduino Digital pins
for (int i = 0; i < NButtons; i++) { // buttons on Digital pin pinMode(buttonPin[i], INPUT_PULLUP); } ///////////////////////////////////////////// // Leds pinMode(ledOnOffPin, OUTPUT); // Sets the number of 8-bit registers that are used. ShiftPWM.SetAmountOfRegisters(numRegisters); ShiftPWM.SetAll(0); // Sets the number of 8-bit registers that are used. ShiftPWM.SetAmountOfRegisters(numRegisters); // SetPinGrouping allows flexibility in LED setup. // If your LED's are connected like this: RRRRGGGGBBBBRRRRGGGGBBBB, use SetPinGrouping(4). ShiftPWM.SetPinGrouping(1); //This is the default, but I added here to demonstrate how to use the funtion ShiftPWM.Start(pwmFrequency, maxBrightness); ///////////////////////////////////////////// // threads // pots threadReadPots.setInterval(10); threadReadPots.onRun(readPots); // buttons threadReadButtons.setInterval(20); threadReadButtons.onRun(readButtons); ///////////////////////////////////////////// //leds analogWrite(ledOnOffPin, 255); // on/off led } void loop() { cpu.run(); MIDI.read(); readEncoder(); } ///////////////////////////////////////////// // read buttons void readButtons() { for (int i = 0; i < muxNButtons; i++) { //reads buttons on mux int buttonReading = mplexButtons.readChannel(muxButtonPin[i]); if (buttonReading > 100) {
buttonCState[i] = HIGH;
}
else {
buttonCState[i] = LOW;
}
}

if (muxNAddonButtons > 0) { //reads buttons on add-on mux
pinMode(A5, INPUT_PULLUP);
for (int i = 0; i < muxNAddonButtons; i++) { //reads buttons on muxAddon int buttonReading = mplexAddon.readChannel(muxAddonButtonPin[i]); if (buttonReading > 100) {
buttonCState[i + muxNButtons] = HIGH;
}
else {
buttonCState[i + muxNButtons] = LOW;
}
}
}

for (int i = 0; i < NButtons; i++) { //read buttons on Arduino buttonCState[i + muxNButtons + muxNAddonButtons] = digitalRead(buttonPin[i]); // stores in the rest of buttonCState } for (int i = 0; i < totalButtons; i++) { if ((millis() - lastDebounceTime) > debounceDelay) {

if (buttonCState[i] != buttonPState[i]) {
lastDebounceTime = millis();

if (buttonCState[i] == LOW) {
MIDI.sendNoteOn(note + i, 127, midiCh); // envia NoteOn(nota, velocity, canal midi)
buttonPState[i] = buttonCState[i];
}
else {
MIDI.sendNoteOn(note + i, 0, midiCh);
buttonPState[i] = buttonCState[i];
}
}
}

}
}

////////////////////////////////////////////
//read potentiometers

void readPots() {
for (int i = 0; i < muxNPots; i++) { // le todas entradas analogicas utilizadas, menos a dedicada a troca do canal midi potCState[i] = mplexPots.readChannel(muxPotPin[i]); } if (muxNAddonPots > 0) {
pinMode(A5, INPUT);
for (int i = 0; i < muxNAddonPots; i++) { // reads pots on add-on mux potCState[i + muxNPots] = mplexAddon.readChannel(muxAddonPotPin[i]); } } for (int i = 0; i < NPots; i++) { // read pots attached to analog pins potCState[i + muxNPots + muxNAddonPots] = analogRead(potPin[i]); } for (int i = 0; i < totalPots; i++) { potVar = abs(potCState[i] - potPState[i]); // calcula a variacao da porta analogica if (potVar >= varThreshold) { //sets a threshold for the variance in the pot state, if it varies more than x it sends the cc message
pTime[i] = millis(); // armazena o tempo previo
}
timer[i] = millis() - pTime[i]; // reseta o timer
if (timer[i] < TIMEOUT) { // se o timer for menor que o tempo maximo permitido significa que o potenciometro ainda esta se movendo potMoving = true; } else { potMoving = false; } if (potMoving == true) { // se o potenciometro ainda esta se movendo, mande o control change int ccValue = map(potCState[i], 0, 1023, 0, 127); if (lastCcValue[i] != ccValue) { MIDI.sendControlChange(cc + i, map(potCState[i], 0, 1023, 0, 127), 11); // envia Control Change (numero do CC, valor do CC, canal midi) potPState[i] = potCState[i]; // armazena a leitura atual do potenciometro para comparar com a proxima lastCcValue[i] = ccValue; } } } } //////////////////////////////////////////// //// read encoder void readEncoder () { int newPosition = myEnc.read(); int encoderVal = map(newPosition, -1024, 1024, -256, 256); int encoderValue; if (encoderVal != oldPosition) { if ((encoderVal - oldPosition) > 0) {
encoderValue = 127;
}
else {
encoderValue = 1;
}

MIDI.sendControlChange(14, encoderValue, 1);

oldPosition = encoderVal;
}
}

////////////////////////////////////////////
// led feedback
void handleControlChange(byte channel, byte number, byte value) {
int value_ = value;

if (value_ != ccLastValue) {

// Left VU
if (number == 12) {
switch (value_) {
case 0:
for (int i = 0; i < 7; i++) { ShiftPWM.SetOne(VuL[i], LOW); } break; case 1: for (int i = 1; i < 7; i++) { ShiftPWM.SetOne(VuL[i], LOW); } ShiftPWM.SetOne(VuL[0], green); break; case 2: for (int i = 2; i < 7; i++) { ShiftPWM.SetOne(VuL[i], LOW); } for (int i = 0; i < 2; i++) { ShiftPWM.SetOne(VuL[i], green); } break; case 3: for (int i = 3; i < 7; i++) { ShiftPWM.SetOne(VuL[i], LOW); } for (int i = 0; i < 3; i++) { ShiftPWM.SetOne(VuL[i], green); } break; case 4: for (int i = 4; i < 7; i++) { ShiftPWM.SetOne(VuL[i], LOW); } for (int i = 0; i < 4; i++) { ShiftPWM.SetOne(VuL[i], green); } break; case 5: for (int i = 5; i < 7; i++) { ShiftPWM.SetOne(VuL[i], LOW); } for (int i = 0; i < 5; i++) { ShiftPWM.SetOne(VuL[i], green); } break; case 6: for (int i = 6; i < 7; i++) { ShiftPWM.SetOne(VuL[i], LOW); } for (int i = 0; i < 5; i++) { ShiftPWM.SetOne(VuL[i], green); } ShiftPWM.SetOne(VuL[5], yellow); break; case 7: for (int i = 6; i < 7; i++) { ShiftPWM.SetOne(VuL[i], LOW); } for (int i = 0; i < 5; i++) { ShiftPWM.SetOne(VuL[i], green); } ShiftPWM.SetOne(VuL[5], yellow); ShiftPWM.SetOne(VuL[6], red); break; } } // Right VU if (number == 13) { switch (value_) { case 0: for (int i = 0; i < 7; i++) { ShiftPWM.SetOne(VuR[i], LOW); } break; case 1: for (int i = 1; i < 7; i++) { ShiftPWM.SetOne(VuR[i], LOW); } ShiftPWM.SetOne(VuR[0], green); break; case 2: for (int i = 2; i < 7; i++) { ShiftPWM.SetOne(VuR[i], LOW); } for (int i = 0; i < 2; i++) { ShiftPWM.SetOne(VuR[i], green); } break; case 3: for (int i = 3; i < 7; i++) { ShiftPWM.SetOne(VuR[i], LOW); } for (int i = 0; i < 3; i++) { ShiftPWM.SetOne(VuR[i], green); } break; case 4: for (int i = 4; i < 7; i++) { ShiftPWM.SetOne(VuR[i], LOW); } for (int i = 0; i < 4; i++) { ShiftPWM.SetOne(VuR[i], green); } break; case 5: for (int i = 5; i < 7; i++) { ShiftPWM.SetOne(VuR[i], LOW); } for (int i = 0; i < 5; i++) { ShiftPWM.SetOne(VuR[i], green); } break; case 6: for (int i = 6; i < 7; i++) { ShiftPWM.SetOne(VuR[i], LOW); } for (int i = 0; i < 5; i++) { ShiftPWM.SetOne(VuR[i], green); } ShiftPWM.SetOne(VuR[5], yellow); break; case 7: for (int i = 6; i < 7; i++) { ShiftPWM.SetOne(VuR[i], LOW); } for (int i = 0; i < 5; i++) { ShiftPWM.SetOne(VuR[i], green); } ShiftPWM.SetOne(VuR[5], yellow); ShiftPWM.SetOne(VuR[6], red); break; } } ccLastValue = value; } } void handleNoteOn(byte channel, byte number, byte value) { switch (number) { // Left buttons case 40: //sync ShiftPWM.SetOne(buttonsLedL[0], blue); break; case 39: //cue ShiftPWM.SetOne(buttonsLedL[1], blue); break; case 38: //play ShiftPWM.SetOne(buttonsLedL[2], blue); break; case 37: //phones ShiftPWM.SetOne(buttonsLedL[3], blue); break; case 36: //filter on ShiftPWM.SetOne(buttonsLedL[4], blue); break; // Righ buttons case 44: //sync ShiftPWM.SetOne(buttonsLedR[0], blue); break; case 45: //cue ShiftPWM.SetOne(buttonsLedR[1], blue); break; case 46: //play ShiftPWM.SetOne(buttonsLedR[2], blue); break; case 47: //phones ShiftPWM.SetOne(buttonsLedR[3], blue); break; case 48: //filter on ShiftPWM.SetOne(buttonsLedR[4], blue); break; } } void handleNoteOff(byte channel, byte number, byte value) { switch (number) { // Left buttons case 40: //sync ShiftPWM.SetOne(buttonsLedL[0], LOW); break; case 39: //cue ShiftPWM.SetOne(buttonsLedL[1], LOW); break; case 38: //play ShiftPWM.SetOne(buttonsLedL[2], LOW); break; case 37: //phones ShiftPWM.SetOne(buttonsLedL[3], LOW); break; case 36: //filter on ShiftPWM.SetOne(buttonsLedL[4], LOW); break; // Righ buttons case 44: //sync ShiftPWM.SetOne(buttonsLedR[0], LOW); break; case 45: //cue ShiftPWM.SetOne(buttonsLedR[1], LOW); break; case 46: //play ShiftPWM.SetOne(buttonsLedR[2], LOW); break; case 47: //phones ShiftPWM.SetOne(buttonsLedR[3], LOW); break; case 48: //filter on ShiftPWM.SetOne(buttonsLedR[4], LOW); break; } } /* buttons midi order 40 44 - sync 39 45 - cue 38 46 - play 37 47 - phones 36 48 - filter VU order 7 9 6 10 5 11 4 12 3 13 2 14 1 15 */