You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
241 lines
7.8 KiB
C++
241 lines
7.8 KiB
C++
#include <MIDI.h>
|
|
#include "TimedPin.h"
|
|
#include "ui.h"
|
|
|
|
|
|
/***************************************************************************//**
|
|
* @brief Timer class for generate cyclic signals
|
|
*******************************************************************************/
|
|
struct Tmr {
|
|
int32_t Period; // cycle length (it must be initialized!)
|
|
uint32_t TrefMillis;
|
|
//---------------------------------------------------------------------------
|
|
bool Check(uint32_t t) { // check with external timebase
|
|
int32_t tdif = t - TrefMillis;
|
|
if (tdif >= Period) { // period expired
|
|
TrefMillis += Period;
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
|
|
bool Check() { // check with millisec timebase
|
|
uint32_t t = millis();
|
|
int32_t tdif = t - TrefMillis;
|
|
if (tdif >= Period) { // period expired
|
|
TrefMillis += Period;
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
};
|
|
|
|
Tmr Tmr10ms = { .Period = 10 };
|
|
Tmr Tmr100ms = { .Period = 100 };
|
|
Tmr Tmr1s = { .Period = 1000 };
|
|
|
|
/***************************************************************************//**
|
|
* @brief Volume buttons and LEDs
|
|
*******************************************************************************/
|
|
const uint8_t pinLedInc1 = 2;
|
|
const uint8_t pinBtnInc1 = 3;
|
|
|
|
const uint8_t pinGndDec1 = 4;
|
|
const uint8_t pinLedDec1 = 5;
|
|
const uint8_t pinBtnDec1 = 6;
|
|
|
|
const uint8_t pinGndInc2 = 7;
|
|
const uint8_t pinLedInc2 = 8;
|
|
const uint8_t pinBtnInc2 = 9;
|
|
|
|
const uint8_t pinGndDec2 = A4;
|
|
const uint8_t pinLedDec2 = A5;
|
|
const uint8_t pinBtnDec2 = A6;
|
|
|
|
/***************************************************************************//**
|
|
* @brief Mute buttons and LEDs
|
|
*******************************************************************************/
|
|
const uint8_t pinGndChOn1 = A3;
|
|
const uint8_t pinLedChOn1 = A2;
|
|
const uint8_t pinBtnChOn1 = A1;
|
|
|
|
const uint8_t pinGndChOn2 = 12;
|
|
const uint8_t pinLedChOn2 = 11;
|
|
const uint8_t pinBtnChOn2 = 10;
|
|
|
|
/***************************************************************************//**
|
|
* @brief Relay
|
|
*******************************************************************************/
|
|
const uint8_t pinRelay = A0;
|
|
|
|
TimedPin RelayMute(pinRelay);
|
|
|
|
/***************************************************************************//**
|
|
* @brief LED
|
|
*******************************************************************************/
|
|
TimedPin LedBoard(LED_BUILTIN);
|
|
TimedPin LedChOn1(pinLedChOn1);
|
|
TimedPin LedChOn2(pinLedChOn2);
|
|
TimedPin LedInc1(pinLedInc1);
|
|
TimedPin LedDec1(pinLedDec1);
|
|
TimedPin LedInc2(pinLedInc2);
|
|
TimedPin LedDec2(pinLedDec2);
|
|
|
|
|
|
|
|
bool MidiCfgTxOnly; /// duplex or only tx configuration (without MIDI rx line)
|
|
|
|
MixerMuteState AirMutes[2] = {
|
|
// No LED Relay init button
|
|
MixerMuteState(22, &LedChOn1, &RelayMute, 0, BTN_CH_ON1, EV_UI_RX_MUTE_CH1_ON, EV_UI_RX_MUTE_CH1_OFF),
|
|
MixerMuteState( 4, &LedChOn2, 1, BTN_CH_ON2, EV_UI_RX_MUTE_CH2_ON, EV_UI_RX_MUTE_CH2_OFF)
|
|
};
|
|
|
|
MixerFaderState AirFaders[2] = {
|
|
MixerFaderState(0, 80, 96, 112, &LedInc1, &LedDec1, BTN_INC1, BTN_DEC1),
|
|
MixerFaderState(1, 80, 96, 112, &LedInc2, &LedDec2, BTN_INC2, BTN_DEC2)
|
|
};
|
|
|
|
|
|
/***************************************************************************//**
|
|
* @brief MIDI instance (serial port)
|
|
*******************************************************************************/
|
|
MIDI_CREATE_DEFAULT_INSTANCE();
|
|
|
|
// -----------------------------------------------------------------------------
|
|
void MidiCCHandler(byte channel, byte ctrl_no, byte val) {
|
|
if (channel == 1) { // Faders: ch=1
|
|
for (uint_fast8_t i=0; i<ELEMCNT(AirFaders); i++) {
|
|
MixerFaderState& fader = AirFaders[i];
|
|
if (ctrl_no == fader.MidiCtrlNr) {
|
|
fader.VolumeReceived(val);
|
|
UI_EventProc(EV_UI_RX_MIDI);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (channel == 2) { // Mutes: ch=2
|
|
for (uint_fast8_t i=0; i<ELEMCNT(AirMutes); i++) {
|
|
MixerMuteState& mute = AirMutes[i];
|
|
if (ctrl_no == mute.MidiCtrlNr) {
|
|
mute.MuteMixer = (val >= 64);
|
|
mute.MuteLocal = mute.MuteMixer;
|
|
mute.Led->Set(!mute.MuteMixer);
|
|
UI_EventProc(mute.MuteMixer ? mute.UiEventOff : mute.UiEventOn);
|
|
LedBoard.OnTimed(200);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
void setup() {
|
|
pinMode(pinBtnInc1, INPUT_PULLUP);
|
|
pinMode(pinBtnDec1, INPUT_PULLUP);
|
|
pinMode(pinBtnInc2, INPUT_PULLUP);
|
|
pinMode(pinBtnDec2, INPUT_PULLUP);
|
|
pinMode(pinBtnChOn1, INPUT_PULLUP);
|
|
pinMode(pinBtnChOn2, INPUT_PULLUP);
|
|
|
|
pinMode(pinRelay, OUTPUT);
|
|
pinMode(pinGndDec1, OUTPUT);
|
|
pinMode(pinGndInc2, OUTPUT);
|
|
pinMode(pinGndDec2, OUTPUT);
|
|
pinMode(pinGndChOn1, OUTPUT);
|
|
pinMode(pinGndChOn2, OUTPUT);
|
|
|
|
digitalWrite(pinRelay, LOW);
|
|
digitalWrite(pinGndDec1, LOW);
|
|
digitalWrite(pinGndInc2, LOW);
|
|
digitalWrite(pinGndDec2, LOW);
|
|
digitalWrite(pinGndChOn1, LOW);
|
|
digitalWrite(pinGndChOn2, LOW);
|
|
|
|
LedBoard.begin();
|
|
LedChOn1.begin();
|
|
LedChOn2.begin();
|
|
LedInc1.begin();
|
|
LedDec1.begin();
|
|
LedInc2.begin();
|
|
LedDec2.begin();
|
|
RelayMute.begin();
|
|
|
|
MIDI.setHandleControlChange(MidiCCHandler);
|
|
MIDI.begin(MIDI_CHANNEL_OMNI); // Initiate MIDI communications, listen to all channels
|
|
MIDI.turnThruOff();
|
|
|
|
UI_Init(); // Start user interface (main state machine)
|
|
}
|
|
|
|
static uint8_t BtnPrev = 0x00;
|
|
uint8_t ButtonGetVal() { return BtnPrev; }
|
|
bool ButtonCheck(uint8_t btn) {
|
|
return (BtnPrev & (1 << btn)) ? true : false;
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief Main loop
|
|
*******************************************************************************/
|
|
void loop() {
|
|
MIDI.read(); // Call MIDI.read the fastest you can for real-time performance.
|
|
|
|
uint32_t t = millis();
|
|
// execute every 10ms *******************************************************
|
|
if (Tmr10ms.Check(t)) {
|
|
static uint8_t BtnNew = 0;
|
|
static uint8_t BtnRel = 0;
|
|
uint8_t btn = (digitalRead(pinBtnInc1) ? 0: (1 << BTN_INC1 ))
|
|
| (digitalRead(pinBtnDec1) ? 0: (1 << BTN_DEC1 ))
|
|
| (digitalRead(pinBtnInc2) ? 0: (1 << BTN_INC2 ))
|
|
| (digitalRead(pinBtnDec2) ? 0: (1 << BTN_DEC2 ))
|
|
| (digitalRead(pinBtnChOn1) ? 0: (1 << BTN_CH_ON1))
|
|
| (digitalRead(pinBtnChOn2) ? 0: (1 << BTN_CH_ON2));
|
|
BtnNew |= btn & (~BtnPrev);
|
|
BtnRel |= (~btn) & BtnPrev;
|
|
BtnPrev = btn;
|
|
uint8_t mask = 1;
|
|
if (BtnNew) {
|
|
for (uint_fast8_t i = 0; i < 8; i++) {
|
|
if (BtnNew & mask) {
|
|
BtnNew &= ~mask; // Bit clr
|
|
UI_EventProc(EV_UI_KEY_PRESS + i);
|
|
LedBoard.OnTimed(50);
|
|
break;
|
|
}
|
|
mask <<= 1;
|
|
}
|
|
}else if (BtnRel) { // released button
|
|
for (uint_fast8_t i = 0; i < 8; i++) {
|
|
if (BtnRel & mask) {
|
|
BtnRel &= ~mask; // Bit clr
|
|
UI_EventProc(EV_UI_KEY_REL + i);
|
|
break;
|
|
}
|
|
mask <<= 1;
|
|
}
|
|
}
|
|
UI_EventProc(EV_TIMER_TICK);
|
|
UI_EventProc(EV_UI_TICK_10MS);
|
|
UI_CheckEvent();
|
|
|
|
LedBoard.update();
|
|
LedChOn1.update();
|
|
LedChOn2.update();
|
|
LedInc1.update();
|
|
LedDec1.update();
|
|
LedInc2.update();
|
|
LedDec2.update();
|
|
RelayMute.update();
|
|
}
|
|
// execute every 100ms ******************************************************
|
|
if (Tmr100ms.Check(t)) {
|
|
UI_EventProc(EV_UI_TICK_100MS);
|
|
}
|
|
// execute every 1s *********************************************************
|
|
if (Tmr1s.Check(t)) {
|
|
UI_EventProc(EV_UI_TICK_1S);
|
|
}
|
|
}
|