mockband/MockBand.ino

178 lines
4.7 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 "piezos.hh"
// 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(BUTTON_GREEN, INPUT);
pinMode(BUTTON_RED, INPUT);
pinMode(BUTTON_YELLOW, INPUT);
pinMode(BUTTON_BLUE, INPUT);
pinMode(BUTTON_ORANGE, INPUT_PULLUP);
pinMode(SOLO_GREEN, INPUT);
pinMode(SOLO_RED, INPUT);
pinMode(SOLO_YELLOW, INPUT);
pinMode(SOLO_BLUE, INPUT);
pinMode(BUTTON_PLUS, INPUT_PULLUP);
pinMode(BUTTON_MINUS, INPUT_PULLUP);
// 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))
#define NOISE_THRESHOLD 40 // Minimum analog value to treat as a hit
// 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 inputs[16] = {0};
uint16_t buttons = 0;
uint16_t samples = 0;
unsigned long next = 0;
uint16_t silence[npins] = {0};
while (1) {
uint16_t edge = 0;
samples++;
inputs[0] = analogRead(INPUT_BLUE);
inputs[1] = analogRead(INPUT_GREEN);
inputs[2] = analogRead(INPUT_RED);
inputs[3] = analogRead(INPUT_YELLOW);
for (uint8_t i = 0; i < 4; i++) {
if (silence[i]) {
silence[i]--;
} else {
bool trigger = inputs[i] > NOISE_THRESHOLD;
if (trigger != bitRead(buttons, i)) {
edge |= bit(i);
silence[i] = SILENCE_SAMPLES;
}
}
}
buttons ^= edge;
// We've sampled everything. Is it time to do calculations and USB?
#ifdef WAMMY
unsigned long now = millis();
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 >> 0) & 0b01111); // Drum pad modifier
bitWrite(buttonState.buttons, 11, (buttons >> 10) & 0b01011); // Cymbals modifier
buttonState.axis[3] = bitRead(buttons, 12)?255:0; // High hat
// rbdrum2midi wants these set
buttonState.velocity[0] = inputs[3]/4; // Y
buttonState.velocity[1] = inputs[2]/4; // R
buttonState.velocity[2] = inputs[1]/2; // G
buttonState.velocity[3] = inputs[0]/4; // B
// Say the D-pad is centered
buttonState.hatAndConstant = 8;
#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;
}
}