//Sketch -> Include Library > Manage Library... > Search for "Encoder" then install it. #include // Arduino Uno Sound Voltex Controller Script // By 5argon // https://github.com/5argon/SDVXArduinoUno // Contact - @5argondesu //Uncomment to send serial button message to Arduino debug console. //Serial message also activates pin 1 (TX), so if your config used pin 1 this may causes problems. //#define SERIAL_DEBUGGING // -- Setup your button connections to the Arduino Uno pins here. -- //Button switch. The other side should be connecting to GND. (Switch is in pull-up mode when not pressed) int const BTA = 0; int const BTB = 12; int const BTC = 6; int const BTD = 11; int const FXL = 5; int const FXR = 7; int const START = 555; //My controller don't have a start button //Button's LED. From Arduino pin to LED + resistor to GND. int const BTLA = A5; int const BTLB = A4; int const BTLC = A2; int const BTLD = A0; int const FXLL = 8; int const FXLR = 10; int const STARTL = 556; //My controller don't have a start button //Encoders. If you are using a Copal, the white cable is A and the green cable is B. (Red goes to 5V and black goes to GND) //VOLL is the left encoder, VOLR is the right encoder. Please DO NOT use pin 13 on Uno. (LED connected pin) //You MUST connect one of each encoder's white or green cable to pin 2 and 3. These 2 pins on an Uno are special external interrupt pins. (It's fast) //For example, VOLLA = 2 and VOLLRA = 3. (both encoder's white). The green cable can choose any pin. //In short, this will make both encoder good. Without this you cannot pass a chart like Firestorm EXH. int const VOLLA = 2; int const VOLLB = 4; int const VOLRA = 3; int const VOLRB = 9; // -- Key mapping -- // Go to http://www.usb.org/developers/hidpage/Hut1_12v2.pdf page 53 // For the list of key specifications from official USB devs. // Or this for Japanese keyboards http://www2d.biglobe.ne.jp/~msyk/keyboard/layout/usbkeycode.html (look at the last column, it's in HEX) uint8_t keyBTA = 22; //s uint8_t keyBTB = 7; //d uint8_t keyBTC = 14; //k uint8_t keyBTD = 15; //l uint8_t keyFXL = 6; //c uint8_t keyFXR = 16; //m //日本人の方はこちらです //uint8_t keyFXL = 0x8A; //無変換 //uint8_t keyFXR = 0x8B; //変換 uint8_t keySTART = 43; //Enter uint8_t keyVOLLCCW = 20; //q uint8_t keyVOLLCW = 26; //w uint8_t keyVOLRCCW = 18; //o uint8_t keyVOLRCW = 19; //p // -- More options -- //If you experience double presses of buttons when you pressed only once, try increasing this value. unsigned const long debounceDelay = 5; //Bigger value makes the knob less sensitive. Note that it should not be 0. When it's 0 when you spin quickly the knob will report both CW and CCW directions. //Value too low can also make the knob go either direction randomly when you just touch the knob. unsigned const long spinTolerance = 4; // ---- Encoder encL(VOLLA,VOLLB); Encoder encR(VOLRA,VOLRB); long encLPosition, encRPosition = 0; uint8_t buf[8] = { 0 }; typedef enum KnobState { CW, CCW, Stop } KnobState; bool BTAState, BTBState, BTCState, BTDState, FXLState, FXRState, StartState = LOW; bool BTAHwState, BTBHwState, BTCHwState, BTDHwState, FXLHwState, FXRHwState, StartHwState = LOW; KnobState VOLLState, VOLRState = Stop; unsigned long BTADebounce, BTBDebounce, BTCDebounce, BTDDebounce, FXLDebounce, FXRDebounce, StartDebounce = 0; void setup() { // put your setup code here, to run once: Serial.begin(9600); setupButton(BTA); setupButton(BTB); setupButton(BTC); setupButton(BTD); setupButton(FXL); setupButton(FXR); setupLED(BTLA); setupLED(BTLB); setupLED(BTLC); setupLED(BTLD); setupLED(FXLL); setupLED(FXLR); pinMode(12,OUTPUT); digitalWrite(12,HIGH); } void setupButton(int button) { pinMode(button, INPUT_PULLUP); } void setupLED(int led) { pinMode(led, OUTPUT); } void checkButton(int button) { int hardwareState = digitalRead(button); if(hardwareState != getButtonHwState(button)) { setDebounce(button,millis()); } if((millis() - getDebounce(button)) > debounceDelay) { if(hardwareState == HIGH) { if(getButtonState(button) == HIGH) { lightOff(button); setButtonState(button,LOW); buttonReleaseAction(button); } } else { if(getButtonState(button) == LOW) { lightOn(button); releaseKey(button); setButtonState(button,HIGH); buttonPressAction(button); } } } setButtonHwState(button,hardwareState); } void lightOff(int inputPin) { digitalWrite(buttonToLight(inputPin), LOW); } void lightOn(int inputPin) { digitalWrite(buttonToLight(inputPin), HIGH); } void checkKnob(int knobA, int knobB) { int readPosition; if(knobA == VOLLA || knobB == VOLLB) { readPosition = encL.read(); if(readPosition > (long)(encLPosition + spinTolerance)) { knobLActionCCW(); encLPosition = readPosition; } else if(readPosition < (long)(encLPosition - spinTolerance) ) { knobLActionCW(); encLPosition = readPosition; } else { knobLActionStop(); } } else { readPosition = encR.read(); if(readPosition > (long)(encRPosition + spinTolerance)) { knobRActionCCW(); encRPosition = readPosition; } else if(readPosition < (long)(encRPosition - spinTolerance) ) { knobRActionCW(); encRPosition = readPosition; } else { knobRActionStop(); } } } void knobLActionCW() { debugInput("Spin",VOLLA); setVolLState(CW); } void knobLActionCCW() { debugInput("Spin",VOLLB); setVolLState(CCW); } void knobRActionCW() { debugInput("Spin",VOLRA); setVolRState(CW); } void knobRActionCCW() { debugInput("Spin",VOLRB); setVolRState(CCW); } void knobLActionStop() { setVolLState(Stop); } void knobRActionStop() { setVolRState(Stop); } void setVolLState(KnobState state) { //only set and send if state changes. if(VOLLState != state) { VOLLState = state; serialFromState(); } } void setVolRState(KnobState state) { //only set and send if state changes. if(VOLRState != state) { VOLRState = state; serialFromState(); } } void buttonPressAction(int button) { debugInput("Pressed",button); serialFromState(); } void buttonReleaseAction(int button) { debugInput("Released",button); serialFromState(); } void serialFromState() { //USB HID limits to 6 keys, which SDVX has 6 + 2 knobs. //We prioritize buttons first as the knobs can be repeatedly pressed and released. //Check buttons int buttons[6] = {BTA,BTB,BTC,BTD,FXL,FXR}; int slotIndex = 2; for( int i = 0; i < 6; i++) { if(getButtonState(buttons[i]) == HIGH) { buf[slotIndex] = getKey(buttons[i]); slotIndex++; } } //Check knobs, if there are more spaces in the message. if(slotIndex < 8) { if(VOLLState == CW) { buf[slotIndex] = getKey(VOLLB); slotIndex++; } else if (VOLLState == CCW) { buf[slotIndex] = getKey(VOLLA); slotIndex++; } } if(slotIndex < 8) { if(VOLRState == CW) { buf[slotIndex] = getKey(VOLRB); slotIndex++; } else if (VOLRState == CCW) { buf[slotIndex] = getKey(VOLRA); slotIndex++; } } //Fill remainings with zeroes. This will be a key-release also. for(int i = slotIndex; i < 8; i++) { buf[slotIndex] = 0; } //Send the message Serial.write(buf, 8); } uint8_t getKey(int inputPin) { switch(inputPin) { case BTA: { return keyBTA; break; } case BTB: { return keyBTB; break; } case BTC: { return keyBTC; break; } case BTD: { return keyBTD; break; } case FXL: { return keyFXL; break; } case FXR: { return keyFXR; break; } case START: { return keySTART; break; } case VOLLA: { return keyVOLLCCW; break; } case VOLLB: { return keyVOLLCW; break; } case VOLRA: { return keyVOLRCCW; break; } case VOLRB: { return keyVOLRCW; break; } } } void debugInput(String message, int inputPort) { #ifdef SERIAL_DEBUGGING Serial.print(message); Serial.print(" - "); Serial.println(getName(inputPort)); #endif } void setButtonState(int button, bool state) { switch(button) { case BTA: { BTAState = state; break; } case BTB: { BTBState = state; break; } case BTC: { BTCState = state; break; } case BTD: { BTDState = state; break; } case FXL: { FXLState = state; break; } case FXR: { FXRState = state; break; } case START: { StartState = state; break; } } } bool getButtonState(int button) { switch(button) { case BTA: { return BTAState; break; } case BTB: { return BTBState; break; } case BTC: { return BTCState; break; } case BTD: { return BTDState; break; } case FXL: { return FXLState; break; } case FXR: { return FXRState; break; } case START: { return StartState; break; } } } String getName(int inputPort) { switch(inputPort) { case BTA: { return "BTA"; break; } case BTB: { return "BTB"; break; } case BTC: { return "BTC"; break; } case BTD: { return "BTD"; break; } case FXL: { return "FXL"; break; } case FXR: { return "FXR"; break; } case START: { return "Start"; break; } case VOLLA: { return "VOL-L CW"; break; } case VOLLB: { return "VOL-L CCW"; break; } case VOLRA: { return "VOL-R CW"; break; } case VOLRB: { return "VOL-R CCW"; break; } } } bool getButtonHwState(int button) { switch(button) { case BTA: { return BTAHwState; break; } case BTB: { return BTBHwState; break; } case BTC: { return BTCHwState; break; } case BTD: { return BTDHwState; break; } case FXL: { return FXLHwState; break; } case FXR: { return FXRHwState; break; } case START: { return StartHwState; break; } } } void setButtonHwState(int button, bool state) { switch(button) { case BTA: { BTAHwState = state; break; } case BTB: { BTBHwState = state; break; } case BTC: { BTCHwState = state; break; } case BTD: { BTDHwState = state; break; } case FXL: { FXLHwState = state; break; } case FXR: { FXRHwState = state; break; } case START: { StartState = state; break; } } } void setDebounce(int button, unsigned long value) { switch(button) { case BTA: { BTADebounce = value; break; } case BTB: { BTBDebounce = value; break; } case BTC: { BTCDebounce = value; break; } case BTD: { BTDDebounce = value; break; } case FXL: { FXLDebounce = value; break; } case FXR: { FXRDebounce = value; break; } case START: { StartDebounce = value; break; } } } unsigned long getDebounce(int button) { switch(button) { case BTA: { return BTADebounce; break; } case BTB: { return BTBDebounce; break; } case BTC: { return BTCDebounce; break; } case BTD: { return BTDDebounce; break; } case FXL: { return FXLDebounce; break; } case FXR: { return FXRDebounce; break; } case START: { return StartDebounce; } } } int buttonToLight(int button) { switch(button) { case BTA: { return BTLA; break; } case BTB: { return BTLB; break; } case BTC: { return BTLC; break; } case BTD: { return BTLD; break; } case FXL: { return FXLL; break; } case FXR: { return FXLR; break; } case START: { return STARTL; break; } } } void loop() { checkButton(BTA); checkButton(BTB); checkButton(BTC); checkButton(BTD); checkButton(FXL); checkButton(FXR); checkKnob(VOLLA, VOLLB); checkKnob(VOLRA, VOLRB); } void pressKey() { //buf[2] = 128; //Serial.write(buf, 8); } void releaseKey(int button) { //buf[0] = 0; // buf[2] = 0; // Serial.write(buf, 8); // Release key }