OBS-buttons

Fork project on GitHub

Keyboard "emulator" for OBS Scene control

 

Download OBS-buttons.ino - Arduino Sketch

 

OBS-buttons

#include "Keyboard.h"
#include <elapsedMillis.h>

const int TRANSITION_PIN  =  2;
const int CUT_PIN         =  4;
const int FADE_PIN        =  8;
const int SCENE_1_PIN     = A0;
const int SCENE_2_PIN     = 15;
const int SCENE_3_PIN     = 14;
const int SCENE_4_PIN     = 16;

const int CUT_LED         =  3;
const int FADE_LED        =  5;
const int S1_LED          =  6;
const int S2_LED          =  7;
const int S3_LED          =  9;
const int S4_LED          = 10;

bool cut, fade;
byte scene;

#include "elapsedMillis.h"
 
/*
 * OneShot - wait for a pin to go from HIGH to LOW and back to HIGH as one event, with debouncing
 */

class Switch {
  public:
    enum State   { OFF, PRESS, ON, RELEASE };
    enum OneShot { WAITING, TRIGGERED };
    
    Switch(int pin): _pin(pin), _duration(0), _debounce(WAITING) {
        pinMode(_pin, INPUT_PULLUP);
        check();
    }
    
    State check(void) {
        handle();
        return _state;
    }

    bool triggered(void) {
        handle();
        if (_debounce == TRIGGERED) {
            _debounce = WAITING;
            return true;
        }
        return false;
    }
    
  private:
    void handle(void) {
        byte buttonPos1 = digitalRead(_pin);   delay(1);
        byte buttonPos2 = digitalRead(_pin);
        // debounce: WAITING ------------------> TRIGGERED -> WAITING
        // state:    OFF     -> PRESSED -> ON -> RELEASED  -> OFF
        if (buttonPos1 == buttonPos2) {  // debounce implies both readings are the same
            // oneshot (press followed by release is a single trigger)...
            if (LOW  == buttonPos1) { 
                if (_state == OFF)   {
                    _state = PRESS;
                } else {
                    _state = ON;
                }
            }
            if (HIGH == buttonPos1) {
                if (_state == ON) {
                  _state    = RELEASE;
                } else {
                    _state = OFF;
                }
            }
        }
        if (_state == RELEASE) {
            _debounce = TRIGGERED;
        }
    }

    int _pin;
    State _state;
    OneShot _debounce;
    unsigned long _duration;
    elapsedMillis _downTime;
};

Switch *Transition;
Switch *Cut;
Switch *Fade;
Switch *Sc1;
Switch *Sc2;
Switch *Sc3;
Switch *Sc4;

enum  TransitionType   { T_UNKNOWN, CUT, FADE, T_NONE};
enum  TransitionSource { S_UNKNOWN, S1, S2, S3, S4, S_NONE };

// Current Values
TransitionType     ttype   = FADE;
TransitionSource   tsource = S_NONE;

// Previous values
TransitionType   t = T_UNKNOWN;
TransitionSource s = S_UNKNOWN;

#define DARK LOW
#define LIT  HIGH

void display(TransitionType ttype,TransitionSource tsource) {
    // turn all off...
    digitalWrite(CUT_LED,  DARK); 
    digitalWrite(FADE_LED, DARK); 
    digitalWrite(S1_LED,   DARK); 
    digitalWrite(S2_LED,   DARK); 
    digitalWrite(S3_LED,   DARK); 
    digitalWrite(S4_LED,   DARK); 

    // then turn on the right ones
    if (ttype == CUT)  digitalWrite(CUT_LED,  LIT); else 
    if (ttype == FADE) digitalWrite(FADE_LED, LIT);
                       
    if (tsource == S1) digitalWrite(S1_LED,   LIT); else
    if (tsource == S2) digitalWrite(S2_LED,   LIT); else
    if (tsource == S3) digitalWrite(S3_LED,   LIT); else
    if (tsource == S4) digitalWrite(S4_LED,   LIT);
}

void setup() {  
  Keyboard.begin();
#if SERIAL_DEBUG
  Serial.begin(115200);
  while (!Serial) { delay(10); }
  Serial.println("Keyboard Buttons Test");
#endif

  Transition = new Switch(TRANSITION_PIN);
  Cut        = new Switch(CUT_PIN);
  Fade       = new Switch(FADE_PIN);
  Sc1        = new Switch(SCENE_1_PIN);
  Sc2        = new Switch(SCENE_2_PIN);
  Sc3        = new Switch(SCENE_3_PIN);
  Sc4        = new Switch(SCENE_4_PIN);

  pinMode(TRANSITION_PIN,   INPUT_PULLUP);
  
  pinMode(CUT_LED,   OUTPUT);
  pinMode(FADE_LED,  OUTPUT);
  pinMode(S1_LED,    OUTPUT);
  pinMode(S2_LED,    OUTPUT);
  pinMode(S3_LED,    OUTPUT);
  pinMode(S4_LED,    OUTPUT); 


  display(T_UNKNOWN, S_UNKNOWN);
}


void select_S1(void) { Keyboard.press(KEY_LEFT_ALT); Keyboard.press('1'); delay(100); Keyboard.releaseAll();}
void select_S2(void) { Keyboard.press(KEY_LEFT_ALT); Keyboard.press('2'); delay(100); Keyboard.releaseAll();}
void select_S3(void) { Keyboard.press(KEY_LEFT_ALT); Keyboard.press('3'); delay(100); Keyboard.releaseAll();}
void select_S4(void) { Keyboard.press(KEY_LEFT_ALT); Keyboard.press('4'); delay(100); Keyboard.releaseAll();}

void do_transition(void) {
  switch (tsource) {
      case S1:  select_S1(); break;
      case S2:  select_S2(); break;
      case S3:  select_S3(); break;
      case S4:  select_S4(); break;
      default: break;
  }
  if (ttype == CUT) {
      Keyboard.press(KEY_LEFT_ALT); Keyboard.press('C'); delay(100); Keyboard.releaseAll();
  } else if (ttype == FADE) {
      Keyboard.press(KEY_LEFT_ALT); Keyboard.press('F'); delay(100); Keyboard.releaseAll();
  }
  tsource = S_NONE;  // after we transition to a source, revert to a general transition
}


void loop() {
    if (Transition->triggered())   { do_transition(); }
    
    if (Cut       ->triggered())   { ttype = CUT;  }
    if (Fade      ->triggered())   { ttype = FADE; }

    // selecting a source twice deselects it...
    if (Sc1       ->triggered())   { if (tsource == S1) tsource = S_NONE; else tsource = S1; }
    if (Sc2       ->triggered())   { if (tsource == S2) tsource = S_NONE; else tsource = S2; }
    if (Sc3       ->triggered())   { if (tsource == S3) tsource = S_NONE; else tsource = S3; }
    if (Sc4       ->triggered())   { if (tsource == S4) tsource = S_NONE; else tsource = S4; }
    
#if SERIAL_DEBUG
    if (t != ttype) {
        t = ttype;
        Serial.print("type: "); Serial.println( (ttype == CUT) ? "CUT" : (ttype == FADE) ? "FADE" : "NONE"); 
    }
    if (s != tsource) {
        s = tsource;
        Serial.print("source: ");
        if (tsource == S1) Serial.println("S1"); else
        if (tsource == S2) Serial.println("S2"); else
        if (tsource == S3) Serial.println("S3"); else
        if (tsource == S4) Serial.println("S4"); else
        Serial.println("DEFAULT");
    }
#endif

    display(ttype, tsource);
}
 

This sketch is licensed under the MIT License