From c7168d434fe7c6ccdf51df6e007664dea2552820 Mon Sep 17 00:00:00 2001 From: probonopd Date: Mon, 3 Oct 2022 21:55:18 +0200 Subject: [PATCH] Enable buttons on MIDI controllers to be used (#365) * Initial commit for MIDI user interface button support. Status: first successful build. * Second try with more functionality plugged in and compiling... * First "it seems to work for me" version for initial testing of MIDI buttons. * Fix Off/Omni logic * Fix order of Prev/Next when initialising the button UI. Co-authored-by: Kevin <68612569+diyelectromusic@users.noreply.github.com> --- src/Makefile | 2 +- src/config.cpp | 37 +++++++++++++ src/config.h | 15 ++++++ src/mididevice.cpp | 19 ++++++- src/mididevice.h | 4 +- src/midikeyboard.cpp | 4 +- src/midikeyboard.h | 2 +- src/midipin.cpp | 55 ++++++++++++++++++++ src/midipin.h | 54 +++++++++++++++++++ src/minidexed.cpp | 6 +-- src/minidexed.ini | 11 ++++ src/pckeyboard.cpp | 4 +- src/pckeyboard.h | 2 +- src/serialmididevice.cpp | 4 +- src/serialmididevice.h | 2 +- src/uibuttons.cpp | 109 +++++++++++++++++++++++++++++++++------ src/uibuttons.h | 27 +++++++--- src/userinterface.cpp | 45 +++++++++++++++- src/userinterface.h | 6 +++ 19 files changed, 369 insertions(+), 39 deletions(-) create mode 100644 src/midipin.cpp create mode 100644 src/midipin.h diff --git a/src/Makefile b/src/Makefile index d379b88..540ae68 100644 --- a/src/Makefile +++ b/src/Makefile @@ -9,7 +9,7 @@ CMSIS_DIR = ../CMSIS_5/CMSIS OBJS = main.o kernel.o minidexed.o config.o userinterface.o uimenu.o \ mididevice.o midikeyboard.o serialmididevice.o pckeyboard.o \ sysexfileloader.o performanceconfig.o perftimer.o \ - effect_compressor.o effect_platervbstereo.o uibuttons.o + effect_compressor.o effect_platervbstereo.o uibuttons.o midipin.o OPTIMIZE = -O3 diff --git a/src/config.cpp b/src/config.cpp index b38991f..ad87b80 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -104,6 +104,13 @@ void CConfig::Load (void) m_nDoubleClickTimeout = m_Properties.GetNumber ("DoubleClickTimeout", 400); m_nLongPressTimeout = m_Properties.GetNumber ("LongPressTimeout", 600); + m_nMIDIButtonCh = m_Properties.GetNumber ("MIDIButtonCh", 0); + m_nMIDIButtonPrev = m_Properties.GetNumber ("MIDIButtonPrev", 0); + m_nMIDIButtonNext = m_Properties.GetNumber ("MIDIButtonNext", 0); + m_nMIDIButtonBack = m_Properties.GetNumber ("MIDIButtonBack", 0); + m_nMIDIButtonSelect = m_Properties.GetNumber ("MIDIButtonSelect", 0); + m_nMIDIButtonHome = m_Properties.GetNumber ("MIDIButtonHome", 0); + m_bEncoderEnabled = m_Properties.GetNumber ("EncoderEnabled", 0) != 0; m_nEncoderPinClock = m_Properties.GetNumber ("EncoderPinClock", 10); m_nEncoderPinData = m_Properties.GetNumber ("EncoderPinData", 9); @@ -293,6 +300,36 @@ unsigned CConfig::GetLongPressTimeout (void) const return m_nLongPressTimeout; } +unsigned CConfig::GetMIDIButtonCh (void) const +{ + return m_nMIDIButtonCh; +} + +unsigned CConfig::GetMIDIButtonPrev (void) const +{ + return m_nMIDIButtonPrev; +} + +unsigned CConfig::GetMIDIButtonNext (void) const +{ + return m_nMIDIButtonNext; +} + +unsigned CConfig::GetMIDIButtonBack (void) const +{ + return m_nMIDIButtonBack; +} + +unsigned CConfig::GetMIDIButtonSelect (void) const +{ + return m_nMIDIButtonSelect; +} + +unsigned CConfig::GetMIDIButtonHome (void) const +{ + return m_nMIDIButtonHome; +} + bool CConfig::GetEncoderEnabled (void) const { return m_bEncoderEnabled; diff --git a/src/config.h b/src/config.h index dc5e7a3..b970ebb 100644 --- a/src/config.h +++ b/src/config.h @@ -117,6 +117,14 @@ public: unsigned GetDoubleClickTimeout (void) const; unsigned GetLongPressTimeout (void) const; + // MIDI Button Navigation + unsigned GetMIDIButtonCh (void) const; + unsigned GetMIDIButtonPrev (void) const; + unsigned GetMIDIButtonNext (void) const; + unsigned GetMIDIButtonBack (void) const; + unsigned GetMIDIButtonSelect (void) const; + unsigned GetMIDIButtonHome (void) const; + // KY-040 Rotary Encoder // GPIO pin numbers are chip numbers, not header positions bool GetEncoderEnabled (void) const; @@ -177,6 +185,13 @@ private: unsigned m_nDoubleClickTimeout; unsigned m_nLongPressTimeout; + unsigned m_nMIDIButtonCh; + unsigned m_nMIDIButtonPrev; + unsigned m_nMIDIButtonNext; + unsigned m_nMIDIButtonBack; + unsigned m_nMIDIButtonSelect; + unsigned m_nMIDIButtonHome; + bool m_bEncoderEnabled; unsigned m_nEncoderPinClock; unsigned m_nEncoderPinData; diff --git a/src/mididevice.cpp b/src/mididevice.cpp index 7b3683f..463dc9c 100644 --- a/src/mididevice.cpp +++ b/src/mididevice.cpp @@ -27,6 +27,7 @@ #include "config.h" #include #include +#include "userinterface.h" LOGMODULE ("mididevice"); @@ -59,9 +60,10 @@ LOGMODULE ("mididevice"); CMIDIDevice::TDeviceMap CMIDIDevice::s_DeviceMap; -CMIDIDevice::CMIDIDevice (CMiniDexed *pSynthesizer, CConfig *pConfig) +CMIDIDevice::CMIDIDevice (CMiniDexed *pSynthesizer, CConfig *pConfig, CUserInterface *pUI) : m_pSynthesizer (pSynthesizer), - m_pConfig (pConfig) + m_pConfig (pConfig), + m_pUI (pUI) { for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++) { @@ -181,6 +183,19 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign } else { + // Perform any MiniDexed level MIDI handling before specific Tone Generators + switch (ucType) + { + case MIDI_CONTROL_CHANGE: + if (nLength < 3) + { + break; + } + m_pUI->UIMIDICCHandler (ucChannel, pMessage[1], pMessage[2]); + break; + } + + // Process MIDI for each Tone Generator for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++) { if (ucStatus == MIDI_SYSTEM_EXCLUSIVE_BEGIN) diff --git a/src/mididevice.h b/src/mididevice.h index 1bd5396..44be25a 100644 --- a/src/mididevice.h +++ b/src/mididevice.h @@ -28,6 +28,7 @@ #include #include #include +#include "userinterface.h" class CMiniDexed; @@ -43,7 +44,7 @@ public: }; public: - CMIDIDevice (CMiniDexed *pSynthesizer, CConfig *pConfig); + CMIDIDevice (CMiniDexed *pSynthesizer, CConfig *pConfig, CUserInterface *pUI); virtual ~CMIDIDevice (void); void SetChannel (u8 ucChannel, unsigned nTG); @@ -59,6 +60,7 @@ protected: private: CMiniDexed *m_pSynthesizer; CConfig *m_pConfig; + CUserInterface *m_pUI; u8 m_ChannelMap[CConfig::ToneGenerators]; diff --git a/src/midikeyboard.cpp b/src/midikeyboard.cpp index 054352c..169f165 100644 --- a/src/midikeyboard.cpp +++ b/src/midikeyboard.cpp @@ -35,8 +35,8 @@ TMIDIPacketHandler * const CMIDIKeyboard::s_pMIDIPacketHandler[MaxInstances] = MIDIPacketHandler3 }; -CMIDIKeyboard::CMIDIKeyboard (CMiniDexed *pSynthesizer, CConfig *pConfig, unsigned nInstance) -: CMIDIDevice (pSynthesizer, pConfig), +CMIDIKeyboard::CMIDIKeyboard (CMiniDexed *pSynthesizer, CConfig *pConfig, CUserInterface *pUI, unsigned nInstance) +: CMIDIDevice (pSynthesizer, pConfig, pUI), m_nInstance (nInstance), m_pMIDIDevice (0) { diff --git a/src/midikeyboard.h b/src/midikeyboard.h index a530c25..0868f9c 100644 --- a/src/midikeyboard.h +++ b/src/midikeyboard.h @@ -39,7 +39,7 @@ public: static const unsigned MaxInstances = 4; public: - CMIDIKeyboard (CMiniDexed *pSynthesizer, CConfig *pConfig, unsigned nInstance = 0); + CMIDIKeyboard (CMiniDexed *pSynthesizer, CConfig *pConfig, CUserInterface *pUI, unsigned nInstance = 0); ~CMIDIKeyboard (void); void Process (boolean bPlugAndPlayUpdated); diff --git a/src/midipin.cpp b/src/midipin.cpp new file mode 100644 index 0000000..d03d73a --- /dev/null +++ b/src/midipin.cpp @@ -0,0 +1,55 @@ +// +// midipin.cpp +// +// MiniDexed - Dexed FM synthesizer for bare metal Raspberry Pi +// Copyright (C) 2022 The MiniDexed Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +#include "midipin.h" +#include +#include + +LOGMODULE ("midipin"); + +CMIDIPin::CMIDIPin (unsigned nPinNumber) +: m_nPinNumber (nPinNumber), + m_nValue (HIGH) +{ +} + +CMIDIPin::~CMIDIPin (void) +{ +} + +unsigned CMIDIPin::Read (void) +{ + return m_nValue; +} + +void CMIDIPin::Write (unsigned nValue) +{ + // Takes values in the MIDI controller range 0 to 127 + // and OFF < 64 < ON. + // Simulates a PULLUP IO pin, so "true" is LOW (0) + if (nValue >= 64) { + // "on" + m_nValue = LOW; + } else { + // "off" + m_nValue = HIGH; + } + return; +} + diff --git a/src/midipin.h b/src/midipin.h new file mode 100644 index 0000000..deb2ca8 --- /dev/null +++ b/src/midipin.h @@ -0,0 +1,54 @@ +// +// midipin.h +// +// MiniDexed - Dexed FM synthesizer for bare metal Raspberry Pi +// Copyright (C) 2022 The MiniDexed Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +#ifndef _midipin_h +#define _midipin_h + +#include +#include + +// MIDI CC numbers go 0 to 127. +// Normal GPIO pins are below 100. +// So use a "pin number" of 128 + MIDI CC message for a "MIDI Pin" +#define MIDI_PINS 128 +#define ccToMidiPin(c) ((c)+MIDI_PINS) +#define MidiPinToCC(p) ((p)-MIDI_PINS) +#define isMidiPin(p) (((p)>=MIDI_PINS)?1:0) + +class CMIDIPin +{ +public: + CMIDIPin (unsigned nPinNumber); // pinNumber = ccToMidiPin (MIDI CC number) + ~CMIDIPin (void); + + // Will return MP_HIGH or MP_LOW. + // Should be treated as a PULLED UP IO pin + // i.e. treated as "active low" (LOW) when pressed. + unsigned Read (void); + + // MIDI CC values >=64 will set the MIDI pin to LOW ("on") + // MIDI CC values <= 63 will set the MIDI pin to HIGH ("off") + void Write (unsigned nValue); + +private: + unsigned m_nPinNumber; + unsigned m_nValue; +}; + +#endif diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 2cbbfb9..0240ea5 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -39,8 +39,8 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, m_pConfig (pConfig), m_UI (this, pGPIOManager, pI2CMaster, pConfig), m_PerformanceConfig (pFileSystem), - m_PCKeyboard (this, pConfig), - m_SerialMIDI (this, pInterrupt, pConfig), + m_PCKeyboard (this, pConfig, &m_UI), + m_SerialMIDI (this, pInterrupt, pConfig, &m_UI), m_bUseSerial (false), m_pSoundDevice (0), m_bChannelsSwapped (pConfig->GetChannelsSwapped ()), @@ -98,7 +98,7 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, for (unsigned i = 0; i < CConfig::MaxUSBMIDIDevices; i++) { - m_pMIDIKeyboard[i] = new CMIDIKeyboard (this, pConfig, i); + m_pMIDIKeyboard[i] = new CMIDIKeyboard (this, pConfig, &m_UI, i); assert (m_pMIDIKeyboard[i]); } diff --git a/src/minidexed.ini b/src/minidexed.ini index d9beec5..de8587d 100644 --- a/src/minidexed.ini +++ b/src/minidexed.ini @@ -57,6 +57,17 @@ ButtonPinShortcut=11 DoubleClickTimeout=400 LongPressTimeout=400 +# MIDI Button Navigation +# Specify MIDI CC to act as a button +# NB: Off < 64 < ON +# CC channel: 0=OFF; 1-16 MIDI Ch; >16 Omni +MIDIButtonCh=0 +MIDIButtonPrev=85 +MIDIButtonNext=86 +MIDIButtonHome=87 +MIDIButtonSelect=89 +MIDIButtonBack=90 + # KY-040 Rotary Encoder EncoderEnabled=1 EncoderPinClock=10 diff --git a/src/pckeyboard.cpp b/src/pckeyboard.cpp index fbd8ea5..79fe92c 100644 --- a/src/pckeyboard.cpp +++ b/src/pckeyboard.cpp @@ -60,8 +60,8 @@ static TKeyInfo KeyTable[] = CPCKeyboard *CPCKeyboard::s_pThis = 0; -CPCKeyboard::CPCKeyboard (CMiniDexed *pSynthesizer, CConfig *pConfig) -: CMIDIDevice (pSynthesizer, pConfig), +CPCKeyboard::CPCKeyboard (CMiniDexed *pSynthesizer, CConfig *pConfig, CUserInterface *pUI) +: CMIDIDevice (pSynthesizer, pConfig, pUI), m_pKeyboard (0) { s_pThis = this; diff --git a/src/pckeyboard.h b/src/pckeyboard.h index 6baf520..ceea6c4 100644 --- a/src/pckeyboard.h +++ b/src/pckeyboard.h @@ -31,7 +31,7 @@ class CMiniDexed; class CPCKeyboard : public CMIDIDevice { public: - CPCKeyboard (CMiniDexed *pSynthesizer, CConfig *pConfig); + CPCKeyboard (CMiniDexed *pSynthesizer, CConfig *pConfig, CUserInterface *pUI); ~CPCKeyboard (void); void Process (boolean bPlugAndPlayUpdated); diff --git a/src/serialmididevice.cpp b/src/serialmididevice.cpp index 5978ecc..186efc3 100644 --- a/src/serialmididevice.cpp +++ b/src/serialmididevice.cpp @@ -29,8 +29,8 @@ LOGMODULE("serialmididevice"); CSerialMIDIDevice::CSerialMIDIDevice (CMiniDexed *pSynthesizer, CInterruptSystem *pInterrupt, - CConfig *pConfig) -: CMIDIDevice (pSynthesizer, pConfig), + CConfig *pConfig, CUserInterface *pUI) +: CMIDIDevice (pSynthesizer, pConfig, pUI), m_pConfig (pConfig), m_Serial (pInterrupt, TRUE), m_nSerialState (0), diff --git a/src/serialmididevice.h b/src/serialmididevice.h index 1f3619e..1a5b465 100644 --- a/src/serialmididevice.h +++ b/src/serialmididevice.h @@ -38,7 +38,7 @@ class CMiniDexed; class CSerialMIDIDevice : public CMIDIDevice { public: - CSerialMIDIDevice (CMiniDexed *pSynthesizer, CInterruptSystem *pInterrupt, CConfig *pConfig); + CSerialMIDIDevice (CMiniDexed *pSynthesizer, CInterruptSystem *pInterrupt, CConfig *pConfig, CUserInterface *pUI); ~CSerialMIDIDevice (void); boolean Initialize (void); diff --git a/src/uibuttons.cpp b/src/uibuttons.cpp index 7635b18..8f2599a 100644 --- a/src/uibuttons.cpp +++ b/src/uibuttons.cpp @@ -4,9 +4,6 @@ // MiniDexed - Dexed FM synthesizer for bare metal Raspberry Pi // Copyright (C) 2022 The MiniDexed Team // -// Original author of this class: -// R. Stange -// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or @@ -31,6 +28,7 @@ LOGMODULE ("uibuttons"); CUIButton::CUIButton (void) : m_pinNumber (0), m_pin (0), + m_midipin (0), m_lastValue (1), m_timer (0), m_debounceTimer (0), @@ -49,6 +47,10 @@ CUIButton::~CUIButton (void) { delete m_pin; } + if (m_midipin) + { + delete m_midipin; + } } void CUIButton::reset (void) @@ -72,7 +74,14 @@ boolean CUIButton::Initialize (unsigned pinNumber, unsigned doubleClickTimeout, if (m_pinNumber != 0) { - m_pin = new CGPIOPin (m_pinNumber, GPIOModeInputPullUp); + if (isMidiPin(m_pinNumber)) + { + LOGDBG("MIDI Button on pin: %d (%x)", m_pinNumber, m_pinNumber); + m_midipin = new CMIDIPin (m_pinNumber); + } else { + LOGDBG("GPIO Button on pin: %d (%x)", m_pinNumber, m_pinNumber); + m_pin = new CGPIOPin (m_pinNumber, GPIOModeInputPullUp); + } } return TRUE; } @@ -99,13 +108,25 @@ unsigned CUIButton::getPinNumber(void) CUIButton::BtnTrigger CUIButton::ReadTrigger (void) { - if (!m_pin) + unsigned value; + if (isMidiPin(m_pinNumber)) { - // Always return "not pressed" if not configured - return BtnTriggerNone; + if (!m_midipin) + { + // Always return "not pressed" if not configured + return BtnTriggerNone; + } + value = m_midipin->Read(); + } + else + { + if (!m_pin) + { + // Always return "not pressed" if not configured + return BtnTriggerNone; + } + value = m_pin->Read(); } - - unsigned value = m_pin->Read(); if (m_timer < m_longPressTimeout) { m_timer++; @@ -188,6 +209,15 @@ CUIButton::BtnTrigger CUIButton::ReadTrigger (void) return BtnTriggerNone; } +void CUIButton::Write (unsigned nValue) { + // This only makes sense for MIDI buttons. + if (m_midipin && isMidiPin(m_pinNumber)) + { + // Update the "MIDI Pin" + m_midipin->Write(nValue); + } +} + CUIButton::BtnEvent CUIButton::Read (void) { BtnTrigger trigger = ReadTrigger(); @@ -233,7 +263,8 @@ CUIButtons::CUIButtons ( unsigned backPin, const char *backAction, unsigned selectPin, const char *selectAction, unsigned homePin, const char *homeAction, - unsigned doubleClickTimeout, unsigned longPressTimeout + unsigned doubleClickTimeout, unsigned longPressTimeout, + unsigned prevMidi, unsigned nextMidi, unsigned backMidi, unsigned selectMidi, unsigned homeMidi ) : m_doubleClickTimeout(doubleClickTimeout), m_longPressTimeout(longPressTimeout), @@ -247,6 +278,11 @@ CUIButtons::CUIButtons ( m_selectAction(CUIButton::triggerTypeFromString(selectAction)), m_homePin(homePin), m_homeAction(CUIButton::triggerTypeFromString(homeAction)), + m_prevMidi(ccToMidiPin(prevMidi)), + m_nextMidi(ccToMidiPin(nextMidi)), + m_backMidi(ccToMidiPin(backMidi)), + m_selectMidi(ccToMidiPin(selectMidi)), + m_homeMidi(ccToMidiPin(homeMidi)), m_eventHandler (0), m_lastTick (0) { @@ -274,15 +310,27 @@ boolean CUIButtons::Initialize (void) longPressTimeout = doubleClickTimeout; } - // Each button can be assigned up to 3 actions: click, doubleclick and - // longpress. We may not initialise all of the buttons + // Each normal button can be assigned up to 3 actions: click, doubleclick and + // longpress. We may not initialise all of the buttons. + // MIDI buttons only support a single click. unsigned pins[MAX_BUTTONS] = { - m_prevPin, m_nextPin, m_backPin, m_selectPin, m_homePin + m_prevPin, m_nextPin, m_backPin, m_selectPin, m_homePin, + m_prevMidi, m_nextMidi, m_backMidi, m_selectMidi, m_homeMidi }; CUIButton::BtnTrigger triggers[MAX_BUTTONS] = { - m_prevAction, m_nextAction, m_backAction, m_selectAction, m_homeAction + // Normal buttons + m_prevAction, m_nextAction, m_backAction, m_selectAction, m_homeAction, + // MIDI Buttons only support a single click (at present) + CUIButton::BtnTriggerClick, CUIButton::BtnTriggerClick, CUIButton::BtnTriggerClick, CUIButton::BtnTriggerClick, CUIButton::BtnTriggerClick }; CUIButton::BtnEvent events[MAX_BUTTONS] = { + // Normal buttons + CUIButton::BtnEventPrev, + CUIButton::BtnEventNext, + CUIButton::BtnEventBack, + CUIButton::BtnEventSelect, + CUIButton::BtnEventHome, + // MIDI buttons CUIButton::BtnEventPrev, CUIButton::BtnEventNext, CUIButton::BtnEventBack, @@ -290,7 +338,8 @@ boolean CUIButtons::Initialize (void) CUIButton::BtnEventHome }; - for (unsigned i=0; i -// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or @@ -25,11 +22,14 @@ #include #include +#include "midipin.h" #include "config.h" #define BUTTONS_UPDATE_NUM_TICKS 100 #define DEBOUNCE_TIME 100 -#define MAX_BUTTONS 5 +#define MAX_GPIO_BUTTONS 5 +#define MAX_MIDI_BUTTONS 5 +#define MAX_BUTTONS (MAX_GPIO_BUTTONS+MAX_MIDI_BUTTONS) class CUIButtons; @@ -69,14 +69,17 @@ public: BtnTrigger ReadTrigger (void); BtnEvent Read (void); + void Write (unsigned nValue); // MIDI buttons only! static BtnTrigger triggerTypeFromString(const char* triggerString); - + private: // Pin number unsigned m_pinNumber; // GPIO pin CGPIOPin *m_pin; + // MIDI pin + CMIDIPin *m_midipin; // The value of the pin at the end of the last loop unsigned m_lastValue; // Set to 0 on press, increment each read, use to trigger events @@ -110,7 +113,8 @@ public: unsigned backPin, const char *backAction, unsigned selectPin, const char *selectAction, unsigned homePin, const char *homeAction, - unsigned doubleClickTimeout, unsigned longPressTimeout + unsigned doubleClickTimeout, unsigned longPressTimeout, + unsigned prevMidi, unsigned nextMidi, unsigned backMidi, unsigned selectMidi, unsigned homeMidi ); ~CUIButtons (void); @@ -121,9 +125,11 @@ public: void Update (void); void ResetButton (unsigned pinNumber); + + void BtnMIDICCHandler (unsigned nMidiCC, unsigned nMidiData); private: - // Array of 5 buttons + // Array of normal GPIO buttons and "MIDI buttons" CUIButton m_buttons[MAX_BUTTONS]; // Timeout for double click in tenths of a millisecond @@ -142,6 +148,13 @@ private: CUIButton::BtnTrigger m_selectAction; unsigned m_homePin; CUIButton::BtnTrigger m_homeAction; + + // MIDI button configuration + unsigned m_prevMidi; + unsigned m_nextMidi; + unsigned m_backMidi; + unsigned m_selectMidi; + unsigned m_homeMidi; BtnEventHandler *m_eventHandler; void *m_eventParam; diff --git a/src/userinterface.cpp b/src/userinterface.cpp index 17083bd..b5e11d2 100644 --- a/src/userinterface.cpp +++ b/src/userinterface.cpp @@ -114,7 +114,13 @@ bool CUserInterface::Initialize (void) m_pConfig->GetButtonPinHome (), m_pConfig->GetButtonActionHome (), m_pConfig->GetDoubleClickTimeout (), - m_pConfig->GetLongPressTimeout () ); + m_pConfig->GetLongPressTimeout (), + m_pConfig->GetMIDIButtonPrev (), + m_pConfig->GetMIDIButtonNext (), + m_pConfig->GetMIDIButtonBack (), + m_pConfig->GetMIDIButtonSelect (), + m_pConfig->GetMIDIButtonHome () + ); assert (m_pUIButtons); if (!m_pUIButtons->Initialize ()) @@ -123,6 +129,7 @@ bool CUserInterface::Initialize (void) } m_pUIButtons->RegisterEventHandler (UIButtonsEventStub, this); + UISetMIDICCChannel (m_pConfig->GetMIDIButtonCh ()); LOGDBG ("Button User Interface initialized"); @@ -322,3 +329,39 @@ void CUserInterface::UIButtonsEventStub (CUIButton::BtnEvent Event, void *pParam pThis->UIButtonsEventHandler (Event); } + +void CUserInterface::UIMIDICCHandler (unsigned nMidiCh, unsigned nMidiCC, unsigned nMidiData) +{ + if (m_nMIDIButtonCh == CMIDIDevice::Disabled) + { + // MIDI buttons are not enabled + return; + } + if ((m_nMIDIButtonCh != nMidiCh) && (m_nMIDIButtonCh != CMIDIDevice::OmniMode)) + { + // Message not on the MIDI Button channel and MIDI buttons not in OMNI mode + return; + } + + if (m_pUIButtons) + { + m_pUIButtons->BtnMIDICCHandler (nMidiCC, nMidiData); + } +} + +void CUserInterface::UISetMIDICCChannel (unsigned uCh) +{ + // Mirrors the logic in Performance Config for handling MIDI channel configuration + if (uCh == 0) + { + m_nMIDIButtonCh = CMIDIDevice::Disabled; + } + else if (uCh < CMIDIDevice::Channels) + { + m_nMIDIButtonCh = uCh - 1; + } + else + { + m_nMIDIButtonCh = CMIDIDevice::OmniMode; + } +} \ No newline at end of file diff --git a/src/userinterface.h b/src/userinterface.h index 8d03503..3a2d27d 100644 --- a/src/userinterface.h +++ b/src/userinterface.h @@ -52,6 +52,9 @@ public: void DisplayWrite (const char *pMenu, const char *pParam, const char *pValue, bool bArrowDown, bool bArrowUp); + // To be called from the MIDI device on reception of a MIDI CC message + void UIMIDICCHandler (unsigned nMidiCh, unsigned nMidiCC, unsigned nMidiData); + private: void LCDWrite (const char *pString); // Print to optional HD44780 display @@ -59,6 +62,7 @@ private: static void EncoderEventStub (CKY040::TEvent Event, void *pParam); void UIButtonsEventHandler (CUIButton::BtnEvent Event); static void UIButtonsEventStub (CUIButton::BtnEvent Event, void *pParam); + void UISetMIDICCChannel (unsigned uCh); private: CMiniDexed *m_pMiniDexed; @@ -73,6 +77,8 @@ private: CUIButtons *m_pUIButtons; + unsigned m_nMIDIButtonCh; + CKY040 *m_pRotaryEncoder; bool m_bSwitchPressed;