182 lines
5.0 KiB
C++
182 lines
5.0 KiB
C++
#include <stdint.h>
|
|
#include <Arduino.h>
|
|
#include <PluggableUSB.h>
|
|
|
|
//#define DEBUG
|
|
|
|
#include "hid.hh" // Modified HID library: doesn't prefix each packet with ID
|
|
#include "instrument.hh"
|
|
#include "standard.hh" // Standard pins
|
|
|
|
// If defined, we will check the wammy bar input
|
|
//#define WAMMY
|
|
|
|
// Maximum time between wammy bar updates.
|
|
#define UPDATE_INTERVAL_MS 20
|
|
|
|
// After an edge on a pin, stop listening for this long, to debounce it
|
|
#define SILENCE_INTERVAL_MS 40
|
|
|
|
// Your measured samples per frame, more or less
|
|
#define SAMPLES_PER_FRAME 127
|
|
|
|
// Some arithmetic for the compiler, to make the code fast
|
|
#define SAMPLES_PER_MS (SAMPLES_PER_FRAME / UPDATE_INTERVAL_MS)
|
|
#define SILENCE_SAMPLES (SAMPLES_PER_MS * SILENCE_INTERVAL_MS)
|
|
|
|
#if USB_VID != 0x1bad
|
|
#error USB_VID must be set to 0x1bad: see INSTALL.md
|
|
#endif
|
|
|
|
#if USB_PID == 0x0004
|
|
#define GUITAR
|
|
#elif USB_PID == 0x0005
|
|
#define DRUM // Wii RB1
|
|
#elif USB_PID == 0x3110
|
|
#define DRUM // Wii RB2
|
|
#else
|
|
#error USB_PID not recognized: see INSTALL.md
|
|
#endif
|
|
|
|
InstrumentButtonState buttonState = {0};
|
|
|
|
void setup() {
|
|
pinMode(STRUM_DOWN, INPUT_PULLUP);
|
|
pinMode(STRUM_UP, INPUT_PULLUP);
|
|
pinMode(TILT_SWITCH, INPUT_PULLUP);
|
|
pinMode(BUTTON_GREEN, INPUT_PULLUP);
|
|
pinMode(BUTTON_RED, INPUT_PULLUP);
|
|
pinMode(BUTTON_YELLOW, INPUT_PULLUP);
|
|
pinMode(BUTTON_BLUE, INPUT_PULLUP);
|
|
pinMode(BUTTON_ORANGE, INPUT_PULLUP);
|
|
pinMode(SOLO_GREEN, INPUT_PULLUP);
|
|
pinMode(SOLO_RED, INPUT_PULLUP);
|
|
pinMode(SOLO_YELLOW, INPUT_PULLUP);
|
|
pinMode(SOLO_BLUE, INPUT_PULLUP);
|
|
pinMode(SOLO_ORANGE, INPUT_PULLUP);
|
|
pinMode(BUTTON_PLUS, INPUT_PULLUP);
|
|
pinMode(BUTTON_MINUS, INPUT_PULLUP);
|
|
pinMode(ANALOG_WAMMY, INPUT);
|
|
pinMode(ANALOG_DPAD, INPUT);
|
|
|
|
// Initialize HID
|
|
static HIDSubDescriptor node(_hidReportDescriptor, sizeof(_hidReportDescriptor));
|
|
HID().AppendDescriptor(&node);
|
|
|
|
buttonState.finalConstant = 0x0200020002000200;
|
|
}
|
|
|
|
// Order of pins in sample
|
|
uint8_t pins[] = {
|
|
BUTTON_BLUE,
|
|
BUTTON_GREEN,
|
|
BUTTON_RED,
|
|
BUTTON_YELLOW,
|
|
BUTTON_ORANGE,
|
|
TILT_SWITCH,
|
|
STRUM_UP, // Not in USB packet
|
|
STRUM_DOWN, // Not in USB packet
|
|
BUTTON_MINUS,
|
|
BUTTON_PLUS,
|
|
SOLO_BLUE, // Not in USB packet
|
|
SOLO_GREEN, // Not in USB packet
|
|
SOLO_RED, // Not in USB packet
|
|
SOLO_YELLOW, // Not in USB packet
|
|
SOLO_ORANGE, // Not in USB packet
|
|
};
|
|
#define npins (sizeof(pins) / sizeof(*pins))
|
|
|
|
// The 3.3v Pro Micro is on the slow side.
|
|
// Our strategy is to poll button state as quickly as possible,
|
|
// and hope we don't miss anything while we're doing USB stuff.
|
|
void loop() {
|
|
uint16_t buttons = 0;
|
|
uint16_t samples = 0;
|
|
unsigned long next = 0;
|
|
uint16_t silence[npins] = {0};
|
|
|
|
while (1) {
|
|
#ifdef WAMMY
|
|
unsigned long now = millis();
|
|
#endif
|
|
uint16_t edge = 0;
|
|
|
|
samples++;
|
|
|
|
for (uint8_t i = 0; i < npins; i++) {
|
|
if (silence[i]) {
|
|
silence[i]--;
|
|
} else if (bitRead(buttons, i) != !digitalRead(pins[i])) {
|
|
edge |= bit(i);
|
|
silence[i] = SILENCE_SAMPLES;
|
|
}
|
|
}
|
|
buttons ^= edge;
|
|
|
|
// We've sampled everything. Is it time to do calculations and USB?
|
|
#ifdef WAMMY
|
|
if (!edge && (next > now)) {
|
|
continue;
|
|
}
|
|
next = now + UPDATE_INTERVAL_MS;
|
|
buttonState.axis[2] = analogRead(ANALOG_WAMMY) / 4; // Wammy bar
|
|
#else
|
|
if (!edge) {
|
|
continue;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Calculate and send an HID update
|
|
//
|
|
|
|
buttonState.buttons = (buttons & 0b1100111111); // +-..!OYRGB
|
|
#ifdef GUITAR
|
|
buttonState.buttons |= (buttons >> 10) & 0b11111; // Solo keys
|
|
bitWrite(buttonState.buttons, 6, buttons & (0b11111 << 10)); // Solo modifier
|
|
|
|
if (bitRead(buttons, 6)) {
|
|
buttonState.hatAndConstant = 0; // up
|
|
} else if bitRead(buttons, 7) { //
|
|
buttonState.hatAndConstant = 4; // down
|
|
} else {
|
|
buttonState.hatAndConstant = 8; // nothing
|
|
}
|
|
#else // DRUMS
|
|
buttonState.buttons |= (buttons >> 10) & 0b01011; // Cymbals
|
|
bitWrite(buttonState.buttons, 10, buttons & (0b01111 << 0)); // Drum pad modifier
|
|
bitWrite(buttonState.buttons, 11, buttons & (0b01011 << 10)); // Cymbals modifier
|
|
buttonState.axis[3] = bitRead(buttons, 12)?255:0; // High hat
|
|
|
|
// rbdrum2midi wants these set
|
|
buttonState.velocity[0] = bitRead(buttonState.buttons, 3)?127:0; // Y
|
|
buttonState.velocity[1] = bitRead(buttonState.buttons, 2)?127:0; // R
|
|
buttonState.velocity[2] = bitRead(buttonState.buttons, 1)?127:0; // G
|
|
buttonState.velocity[3] = bitRead(buttonState.buttons, 0)?127:0; // B
|
|
|
|
// Use the cymbals for up and down, since I don't have a D-pad
|
|
if bitRead(buttons, 13) {
|
|
buttonState.hatAndConstant = 0; // up
|
|
} else if bitRead(buttons, 10) {
|
|
buttonState.hatAndConstant = 4; // down
|
|
} else {
|
|
buttonState.hatAndConstant = 8; // nothing
|
|
}
|
|
#endif
|
|
|
|
#ifdef DPAD
|
|
#error DPAD isn't implemented yet
|
|
#endif
|
|
|
|
#ifdef DEBUG
|
|
// Log sample rate to the first X axis
|
|
buttonState.axis[0] = samples & 0xff;
|
|
#endif
|
|
|
|
// Send an update
|
|
HID().SendReport(0, (uint8_t *)&buttonState, 27);
|
|
|
|
samples = 0;
|
|
}
|
|
}
|