From 8593dc955fb676a31907ee0a39a16d94c92b4b47 Mon Sep 17 00:00:00 2001 From: diyelectromusic <68612569+diyelectromusic@users.noreply.github.com> Date: Fri, 26 May 2023 15:52:41 +0100 Subject: [PATCH] Initial implementation of Program Up/Down and Tone Generator Up/Down selection and short cuts as buttons and MIDI buttons. --- src/config.cpp | 75 +++++++++++++++++++++++++ src/config.h | 33 ++++++++++- src/midipin.h | 4 +- src/uibuttons.cpp | 38 +++++++++++-- src/uibuttons.h | 32 +++++++++-- src/uimenu.cpp | 126 +++++++++++++++++++++++++++++++++++++++++- src/uimenu.h | 7 +++ src/userinterface.cpp | 30 +++++++++- 8 files changed, 331 insertions(+), 14 deletions(-) diff --git a/src/config.cpp b/src/config.cpp index c40d29a..d268217 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -109,6 +109,16 @@ void CConfig::Load (void) m_nDoubleClickTimeout = m_Properties.GetNumber ("DoubleClickTimeout", 400); m_nLongPressTimeout = m_Properties.GetNumber ("LongPressTimeout", 600); + m_nButtonPinPgmUp = m_Properties.GetNumber ("ButtonPinPgmUp", 0); + m_nButtonPinPgmDown = m_Properties.GetNumber ("ButtonPinPgmDown", 0); + m_nButtonPinTGUp = m_Properties.GetNumber ("ButtonPinTGUp", 0); + m_nButtonPinTGDown = m_Properties.GetNumber ("ButtonPinTGDown", 0); + + m_ButtonActionPgmUp = m_Properties.GetString ("ButtonActionPgmUp", ""); + m_ButtonActionPgmDown = m_Properties.GetString ("ButtonActionPgmDown", ""); + m_ButtonActionTGUp = m_Properties.GetString ("ButtonActionTGUp", ""); + m_ButtonActionTGDown = m_Properties.GetString ("ButtonActionTGDown", ""); + m_nMIDIButtonCh = m_Properties.GetNumber ("MIDIButtonCh", 0); m_nMIDIButtonNotes = m_Properties.GetNumber ("MIDIButtonNotes", 0); m_nMIDIButtonPrev = m_Properties.GetNumber ("MIDIButtonPrev", 0); @@ -117,6 +127,11 @@ void CConfig::Load (void) m_nMIDIButtonSelect = m_Properties.GetNumber ("MIDIButtonSelect", 0); m_nMIDIButtonHome = m_Properties.GetNumber ("MIDIButtonHome", 0); + m_nMIDIButtonPgmUp = m_Properties.GetNumber ("MIDIButtonPgmUp", 0); + m_nMIDIButtonPgmDown = m_Properties.GetNumber ("MIDIButtonPgmDown", 0); + m_nMIDIButtonTGUp = m_Properties.GetNumber ("MIDIButtonTGUp", 0); + m_nMIDIButtonTGDown = m_Properties.GetNumber ("MIDIButtonTGDown", 0); + m_bEncoderEnabled = m_Properties.GetNumber ("EncoderEnabled", 0) != 0; m_nEncoderPinClock = m_Properties.GetNumber ("EncoderPinClock", 10); m_nEncoderPinData = m_Properties.GetNumber ("EncoderPinData", 9); @@ -336,6 +351,46 @@ unsigned CConfig::GetLongPressTimeout (void) const return m_nLongPressTimeout; } +unsigned CConfig::GetButtonPinPgmUp (void) const +{ + return m_nButtonPinPgmUp; +} + +unsigned CConfig::GetButtonPinPgmDown (void) const +{ + return m_nButtonPinPgmDown; +} + +unsigned CConfig::GetButtonPinTGUp (void) const +{ + return m_nButtonPinTGUp; +} + +unsigned CConfig::GetButtonPinTGDown (void) const +{ + return m_nButtonPinTGDown; +} + +const char *CConfig::GetButtonActionPgmUp (void) const +{ + return m_ButtonActionPgmUp.c_str(); +} + +const char *CConfig::GetButtonActionPgmDown (void) const +{ + return m_ButtonActionPgmDown.c_str(); +} + +const char *CConfig::GetButtonActionTGUp (void) const +{ + return m_ButtonActionTGUp.c_str(); +} + +const char *CConfig::GetButtonActionTGDown (void) const +{ + return m_ButtonActionTGDown.c_str(); +} + unsigned CConfig::GetMIDIButtonCh (void) const { return m_nMIDIButtonCh; @@ -371,6 +426,26 @@ unsigned CConfig::GetMIDIButtonHome (void) const return m_nMIDIButtonHome; } +unsigned CConfig::GetMIDIButtonPgmUp (void) const +{ + return m_nMIDIButtonPgmUp; +} + +unsigned CConfig::GetMIDIButtonPgmDown (void) const +{ + return m_nMIDIButtonPgmDown; +} + +unsigned CConfig::GetMIDIButtonTGUp (void) const +{ + return m_nMIDIButtonTGUp; +} + +unsigned CConfig::GetMIDIButtonTGDown (void) const +{ + return m_nMIDIButtonTGDown; +} + bool CConfig::GetEncoderEnabled (void) const { return m_bEncoderEnabled; diff --git a/src/config.h b/src/config.h index a316be8..d10808f 100644 --- a/src/config.h +++ b/src/config.h @@ -110,7 +110,7 @@ public: unsigned GetButtonPinSelect (void) const; unsigned GetButtonPinHome (void) const; unsigned GetButtonPinShortcut (void) const; - + // Action type for buttons: "click", "doubleclick", "longpress", "" const char *GetButtonActionPrev (void) const; const char *GetButtonActionNext (void) const; @@ -122,6 +122,19 @@ public: unsigned GetDoubleClickTimeout (void) const; unsigned GetLongPressTimeout (void) const; + // GPIO Button Program and TG Selection + // GPIO pin numbers are chip numbers, not header positions + unsigned GetButtonPinPgmUp (void) const; + unsigned GetButtonPinPgmDown (void) const; + unsigned GetButtonPinTGUp (void) const; + unsigned GetButtonPinTGDown (void) const; + + // Action type for buttons: "click", "doubleclick", "longpress", "" + const char *GetButtonActionPgmUp (void) const; + const char *GetButtonActionPgmDown (void) const; + const char *GetButtonActionTGUp (void) const; + const char *GetButtonActionTGDown (void) const; + // MIDI Button Navigation unsigned GetMIDIButtonCh (void) const; unsigned GetMIDIButtonNotes (void) const; @@ -130,6 +143,12 @@ public: unsigned GetMIDIButtonBack (void) const; unsigned GetMIDIButtonSelect (void) const; unsigned GetMIDIButtonHome (void) const; + + // MIDI Button Program and TG Selection + unsigned GetMIDIButtonPgmUp (void) const; + unsigned GetMIDIButtonPgmDown (void) const; + unsigned GetMIDIButtonTGUp (void) const; + unsigned GetMIDIButtonTGDown (void) const; // KY-040 Rotary Encoder // GPIO pin numbers are chip numbers, not header positions @@ -187,12 +206,20 @@ private: unsigned m_nButtonPinSelect; unsigned m_nButtonPinHome; unsigned m_nButtonPinShortcut; + unsigned m_nButtonPinPgmUp; + unsigned m_nButtonPinPgmDown; + unsigned m_nButtonPinTGUp; + unsigned m_nButtonPinTGDown; std::string m_ButtonActionPrev; std::string m_ButtonActionNext; std::string m_ButtonActionBack; std::string m_ButtonActionSelect; std::string m_ButtonActionHome; + std::string m_ButtonActionPgmUp; + std::string m_ButtonActionPgmDown; + std::string m_ButtonActionTGUp; + std::string m_ButtonActionTGDown; unsigned m_nDoubleClickTimeout; unsigned m_nLongPressTimeout; @@ -204,6 +231,10 @@ private: unsigned m_nMIDIButtonBack; unsigned m_nMIDIButtonSelect; unsigned m_nMIDIButtonHome; + unsigned m_nMIDIButtonPgmUp; + unsigned m_nMIDIButtonPgmDown; + unsigned m_nMIDIButtonTGUp; + unsigned m_nMIDIButtonTGDown; bool m_bEncoderEnabled; unsigned m_nEncoderPinClock; diff --git a/src/midipin.h b/src/midipin.h index deb2ca8..d703092 100644 --- a/src/midipin.h +++ b/src/midipin.h @@ -27,8 +27,8 @@ // 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 ccToMidiPin(c) (((c)==0)?0:((c)+MIDI_PINS)) +#define MidiPinToCC(p) (((p)>=MIDI_PINS)?((p)-MIDI_PINS):0) #define isMidiPin(p) (((p)>=MIDI_PINS)?1:0) class CMIDIPin diff --git a/src/uibuttons.cpp b/src/uibuttons.cpp index e3e64f8..11a02c2 100644 --- a/src/uibuttons.cpp +++ b/src/uibuttons.cpp @@ -263,8 +263,13 @@ CUIButtons::CUIButtons ( unsigned backPin, const char *backAction, unsigned selectPin, const char *selectAction, unsigned homePin, const char *homeAction, + unsigned pgmUpPin, const char *pgmUpAction, + unsigned pgmDownPin, const char *pgmDownAction, + unsigned TGUpPin, const char *TGUpAction, + unsigned TGDownPin, const char *TGDownAction, unsigned doubleClickTimeout, unsigned longPressTimeout, - unsigned notesMidi, unsigned prevMidi, unsigned nextMidi, unsigned backMidi, unsigned selectMidi, unsigned homeMidi + unsigned notesMidi, unsigned prevMidi, unsigned nextMidi, unsigned backMidi, unsigned selectMidi, unsigned homeMidi, + unsigned pgmUpMidi, unsigned pgmDownMidi, unsigned TGUpMidi, unsigned TGDownMidi ) : m_doubleClickTimeout(doubleClickTimeout), m_longPressTimeout(longPressTimeout), @@ -278,12 +283,24 @@ CUIButtons::CUIButtons ( m_selectAction(CUIButton::triggerTypeFromString(selectAction)), m_homePin(homePin), m_homeAction(CUIButton::triggerTypeFromString(homeAction)), + m_pgmUpPin(pgmUpPin), + m_pgmUpAction(CUIButton::triggerTypeFromString(pgmUpAction)), + m_pgmDownPin(pgmDownPin), + m_pgmDownAction(CUIButton::triggerTypeFromString(pgmDownAction)), + m_TGUpPin(TGUpPin), + m_TGUpAction(CUIButton::triggerTypeFromString(TGUpAction)), + m_TGDownPin(TGDownPin), + m_TGDownAction(CUIButton::triggerTypeFromString(TGDownAction)), m_notesMidi(notesMidi), m_prevMidi(ccToMidiPin(prevMidi)), m_nextMidi(ccToMidiPin(nextMidi)), m_backMidi(ccToMidiPin(backMidi)), m_selectMidi(ccToMidiPin(selectMidi)), m_homeMidi(ccToMidiPin(homeMidi)), + m_pgmUpMidi(ccToMidiPin(pgmUpMidi)), + m_pgmDownMidi(ccToMidiPin(pgmDownMidi)), + m_TGUpMidi(ccToMidiPin(TGUpMidi)), + m_TGDownMidi(ccToMidiPin(TGDownMidi)), m_eventHandler (0), m_lastTick (0) { @@ -315,14 +332,16 @@ boolean CUIButtons::Initialize (void) // 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_prevMidi, m_nextMidi, m_backMidi, m_selectMidi, m_homeMidi + m_prevPin, m_nextPin, m_backPin, m_selectPin, m_homePin, m_pgmUpPin, m_pgmDownPin, m_TGUpPin, m_TGDownPin, + m_prevMidi, m_nextMidi, m_backMidi, m_selectMidi, m_homeMidi, m_pgmUpMidi, m_pgmDownMidi, m_TGUpMidi, m_TGDownMidi }; CUIButton::BtnTrigger triggers[MAX_BUTTONS] = { // Normal buttons m_prevAction, m_nextAction, m_backAction, m_selectAction, m_homeAction, + m_pgmUpAction, m_pgmDownAction, m_TGUpAction, m_TGDownAction, // MIDI Buttons only support a single click (at present) - CUIButton::BtnTriggerClick, CUIButton::BtnTriggerClick, CUIButton::BtnTriggerClick, CUIButton::BtnTriggerClick, CUIButton::BtnTriggerClick + CUIButton::BtnTriggerClick, CUIButton::BtnTriggerClick, CUIButton::BtnTriggerClick, CUIButton::BtnTriggerClick, CUIButton::BtnTriggerClick, + CUIButton::BtnTriggerClick, CUIButton::BtnTriggerClick, CUIButton::BtnTriggerClick, CUIButton::BtnTriggerClick }; CUIButton::BtnEvent events[MAX_BUTTONS] = { // Normal buttons @@ -331,12 +350,20 @@ boolean CUIButtons::Initialize (void) CUIButton::BtnEventBack, CUIButton::BtnEventSelect, CUIButton::BtnEventHome, + CUIButton::BtnEventPgmUp, + CUIButton::BtnEventPgmDown, + CUIButton::BtnEventTGUp, + CUIButton::BtnEventTGDown, // MIDI buttons CUIButton::BtnEventPrev, CUIButton::BtnEventNext, CUIButton::BtnEventBack, CUIButton::BtnEventSelect, - CUIButton::BtnEventHome + CUIButton::BtnEventHome, + CUIButton::BtnEventPgmUp, + CUIButton::BtnEventPgmDown, + CUIButton::BtnEventTGUp, + CUIButton::BtnEventTGDown }; // Setup normal GPIO buttons first @@ -352,6 +379,7 @@ boolean CUIButtons::Initialize (void) for (unsigned j=0; j using namespace std; +LOGMODULE ("uimenu"); const CUIMenu::TMenuItem CUIMenu::s_MenuRoot[] = { @@ -402,6 +403,16 @@ void CUIMenu::EventHandler (TMenuEvent Event) EventHandler (MenuEventUpdate); break; + case MenuEventPgmUp: + case MenuEventPgmDown: + PgmUpDownHandler(Event); + break; + + case MenuEventTGUp: + case MenuEventTGDown: + TGUpDownHandler(Event); + break; + default: (*m_pParentMenu[m_nCurrentMenuItem].Handler) (this, Event); break; @@ -604,7 +615,9 @@ void CUIMenu::EditProgramNumber (CUIMenu *pUIMenu, TMenuEvent Event) return; } - string voiceName = pUIMenu->m_pMiniDexed->GetVoiceName (nTG); // Skip empty voices + // Skip empty voices. + // Use same criteria in PgmUpDownHandler() too. + string voiceName = pUIMenu->m_pMiniDexed->GetVoiceName (nTG); if (voiceName == "EMPTY " || voiceName == " " || voiceName == "----------" @@ -1188,6 +1201,117 @@ void CUIMenu::OPShortcutHandler (TMenuEvent Event) } } +void CUIMenu::PgmUpDownHandler (TMenuEvent Event) +{ + // If we're on anything apart from the root menu, + // then find the current TG number. Otherwise assume TG1 (nTG=0). + unsigned nTG = 0; + if (m_MenuStackMenu[0] == s_MainMenu) { + nTG = m_nMenuStackSelection[0]; + } + assert (nTG < CConfig::ToneGenerators); + + int nPgm = m_pMiniDexed->GetTGParameter (CMiniDexed::TGParameterProgram, nTG); + + assert (Event == MenuEventPgmDown || Event == MenuEventPgmUp); + if (Event == MenuEventPgmDown) + { + //LOGNOTE("PgmDown"); + if (--nPgm < 0) + { + // Switch down a voice bank and set to the last voice + nPgm = CSysExFileLoader::VoicesPerBank-1; + int nVB = m_pMiniDexed->GetTGParameter(CMiniDexed::TGParameterVoiceBank, nTG); + nVB = m_pMiniDexed->GetSysExFileLoader ()->GetNextBankDown(nVB); + m_pMiniDexed->SetTGParameter (CMiniDexed::TGParameterVoiceBank, nVB, nTG); + } + m_pMiniDexed->SetTGParameter (CMiniDexed::TGParameterProgram, nPgm, nTG); + } + else + { + //LOGNOTE("PgmUp"); + if (++nPgm > (int) CSysExFileLoader::VoicesPerBank-1) + { + // Switch up a voice bank and reset to voice 0 + nPgm = 0; + int nVB = m_pMiniDexed->GetTGParameter(CMiniDexed::TGParameterVoiceBank, nTG); + nVB = m_pMiniDexed->GetSysExFileLoader ()->GetNextBankUp(nVB); + m_pMiniDexed->SetTGParameter (CMiniDexed::TGParameterVoiceBank, nVB, nTG); + } + m_pMiniDexed->SetTGParameter (CMiniDexed::TGParameterProgram, nPgm, nTG); + } + + // Skip empty voices. + // Use same criteria in EditProgramNumber () too. + string voiceName = m_pMiniDexed->GetVoiceName (nTG); + if (voiceName == "EMPTY " + || voiceName == " " + || voiceName == "----------" + || voiceName == "~~~~~~~~~~" ) + { + if (Event == MenuEventPgmUp) { + PgmUpDownHandler (MenuEventPgmUp); + } + if (Event == MenuEventPgmDown) { + PgmUpDownHandler (MenuEventPgmDown); + } + } +} + +void CUIMenu::TGUpDownHandler (TMenuEvent Event) +{ + // This will update the menus to position it for the next TG up or down + unsigned nTG = 0; + + if (CConfig::ToneGenerators <= 1) { + // Nothing to do if only a single TG + return; + } + + // If we're on anything apart from the root menu, + // then find the current TG number. Otherwise assume TG1 (nTG=0). + if (m_MenuStackMenu[0] == s_MainMenu) { + nTG = m_nMenuStackSelection[0]; + } + + assert (nTG < CConfig::ToneGenerators); + assert (Event == MenuEventTGDown || Event == MenuEventTGUp); + if (Event == MenuEventTGDown) + { + //LOGNOTE("TGDown"); + if (nTG > 0) { + nTG--; + } + } + else + { + //LOGNOTE("TGUp"); + if (nTG < CConfig::ToneGenerators - 1) { + nTG++; + } + } + + // Set menu to the appropriate TG menu as follows: + // Top = Root + // Menu [0] = Main + // Menu [1] = TG Menu + m_pParentMenu = s_MainMenu; + m_pCurrentMenu = s_TGMenu; + m_nCurrentMenuItem = nTG; + m_nCurrentSelection = 0; + m_nCurrentParameter = nTG; + m_nCurrentMenuDepth = 1; + + // Place the main menu on the stack with Root as the parent + m_MenuStackParent[0] = s_MenuRoot; + m_MenuStackMenu[0] = s_MainMenu; + m_nMenuStackItem[0] = 0; + m_nMenuStackSelection[0] = nTG; + m_nMenuStackParameter[0] = 0; + + EventHandler (MenuEventUpdate); +} + void CUIMenu::TimerHandler (TKernelTimerHandle hTimer, void *pParam, void *pContext) { CUIMenu *pThis = static_cast (pContext); diff --git a/src/uimenu.h b/src/uimenu.h index 78384be..2b70cfe 100644 --- a/src/uimenu.h +++ b/src/uimenu.h @@ -45,6 +45,10 @@ public: MenuEventStepUp, MenuEventPressAndStepDown, MenuEventPressAndStepUp, + MenuEventPgmUp, + MenuEventPgmDown, + MenuEventTGUp, + MenuEventTGDown, MenuEventUnknown }; @@ -112,6 +116,9 @@ private: void TGShortcutHandler (TMenuEvent Event); void OPShortcutHandler (TMenuEvent Event); + void PgmUpDownHandler (TMenuEvent Event); + void TGUpDownHandler (TMenuEvent Event); + static void TimerHandler (TKernelTimerHandle hTimer, void *pParam, void *pContext); static void InputTxt (CUIMenu *pUIMenu, TMenuEvent Event); diff --git a/src/userinterface.cpp b/src/userinterface.cpp index 0bcd931..247326e 100644 --- a/src/userinterface.cpp +++ b/src/userinterface.cpp @@ -115,6 +115,14 @@ bool CUserInterface::Initialize (void) m_pConfig->GetButtonActionSelect (), m_pConfig->GetButtonPinHome (), m_pConfig->GetButtonActionHome (), + m_pConfig->GetButtonPinPgmUp (), + m_pConfig->GetButtonActionPgmUp (), + m_pConfig->GetButtonPinPgmDown (), + m_pConfig->GetButtonActionPgmDown (), + m_pConfig->GetButtonPinTGUp (), + m_pConfig->GetButtonActionTGUp (), + m_pConfig->GetButtonPinTGDown (), + m_pConfig->GetButtonActionTGDown (), m_pConfig->GetDoubleClickTimeout (), m_pConfig->GetLongPressTimeout (), m_pConfig->GetMIDIButtonNotes (), @@ -122,7 +130,11 @@ bool CUserInterface::Initialize (void) m_pConfig->GetMIDIButtonNext (), m_pConfig->GetMIDIButtonBack (), m_pConfig->GetMIDIButtonSelect (), - m_pConfig->GetMIDIButtonHome () + m_pConfig->GetMIDIButtonHome (), + m_pConfig->GetMIDIButtonPgmUp (), + m_pConfig->GetMIDIButtonPgmDown (), + m_pConfig->GetMIDIButtonTGUp (), + m_pConfig->GetMIDIButtonTGDown () ); assert (m_pUIButtons); @@ -320,6 +332,22 @@ void CUserInterface::UIButtonsEventHandler (CUIButton::BtnEvent Event) m_Menu.EventHandler (CUIMenu::MenuEventHome); break; + case CUIButton::BtnEventPgmUp: + m_Menu.EventHandler (CUIMenu::MenuEventPgmUp); + break; + + case CUIButton::BtnEventPgmDown: + m_Menu.EventHandler (CUIMenu::MenuEventPgmDown); + break; + + case CUIButton::BtnEventTGUp: + m_Menu.EventHandler (CUIMenu::MenuEventTGUp); + break; + + case CUIButton::BtnEventTGDown: + m_Menu.EventHandler (CUIMenu::MenuEventTGDown); + break; + default: break; }