diff --git a/README.md b/README.md index 358b181..716559f 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,10 @@ # MiniDexed  - + -[Dexed](https://asb2m10.github.io/dexed/) is a FM synthesizer closely modeled on the famous DX7 by a well-known Japanese manufacturer. MiniDexed is a port to run it on a bare metal Raspberry Pi (without a Linux kernel or operating system). __This is a work in progress. Contributions are highly welcome.__ +[Dexed](https://asb2m10.github.io/dexed/) is a FM synthesizer closely modeled on the famous DX7 by a well-known Japanese manufacturer. MiniDexed is a port to run it on a bare metal Raspberry Pi (without a Linux kernel or operating system). On Raspberry Pi 2 and larger, it can run 8 Dexed instances, basically creating an open source equivalent of the TX802 (8 DX7 instances without the keyboard in one box). -## TODO - - Contributions are highly welcome. +## Features - [x] Get [Synth_Dexed](https://codeberg.org/dcoredump/Synth_Dexed) to build with [circle-stdlib](https://github.com/smuehlst/circle-stdlib) - [x] Upload SD card contents to [GitHub Releases](../../releases) @@ -32,7 +30,7 @@ - [x] Add reverb effect - [ ] Make it possible to assign voice parameters to sliders and knobs on MIDI controllers -I am wondering whether we can run multiple Dexed instances, in order to recreate basically an open source equivalent of the TX802 (8 DX7 instances without the keyboard in one box). +Contributions are highly welcome. ## Usage @@ -52,11 +50,11 @@ I am wondering whether we can run multiple Dexed instances, in order to recreate ## Pinout -All devices on Raspberry Pi GPIOs are optional. +All devices on Raspberry Pi GPIOs are **optional**. __CAUTION:__ All GPIO numbers are [chip numbers](https://pinout.xyz/), not header positions. -|GPIO | Device | | Function | Direction | Commant| +|GPIO | Device | | Function | Direction | Comment| |---|---|---|---|---|---| |14 | UART | | TXD | | OUT | | serial MIDI| |15 | UART | | RXD | | IN | | serial MIDI| diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 640f31d..492aac8 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -37,6 +37,7 @@ const CUIMenu::TMenuItem CUIMenu::s_MenuRoot[] = {0} }; +// inserting menu items before "TG1" affect TGShortcutHandler() const CUIMenu::TMenuItem CUIMenu::s_MainMenu[] = { {"TG1", MenuHandler, s_TGMenu, 0}, @@ -335,8 +336,7 @@ void CUIMenu::MenuHandler (CUIMenu *pUIMenu, TMenuEvent Event) break; default: - assert (0); - break; + return; } if (pUIMenu->m_pCurrentMenu) // if this is another menu? @@ -429,6 +429,11 @@ void CUIMenu::EditVoiceBankNumber (CUIMenu *pUIMenu, TMenuEvent Event) CMiniDexed::TGParameterVoiceBank, nValue, nTG); break; + case MenuEventPressAndStepDown: + case MenuEventPressAndStepUp: + pUIMenu->TGShortcutHandler (Event); + return; + default: return; } @@ -472,6 +477,11 @@ void CUIMenu::EditProgramNumber (CUIMenu *pUIMenu, TMenuEvent Event) pUIMenu->m_pMiniDexed->SetTGParameter (CMiniDexed::TGParameterProgram, nValue, nTG); break; + case MenuEventPressAndStepDown: + case MenuEventPressAndStepUp: + pUIMenu->TGShortcutHandler (Event); + return; + default: return; } @@ -519,6 +529,11 @@ void CUIMenu::EditTGParameter (CUIMenu *pUIMenu, TMenuEvent Event) pUIMenu->m_pMiniDexed->SetTGParameter (Param, nValue, nTG); break; + case MenuEventPressAndStepDown: + case MenuEventPressAndStepUp: + pUIMenu->TGShortcutHandler (Event); + return; + default: return; } @@ -566,6 +581,11 @@ void CUIMenu::EditVoiceParameter (CUIMenu *pUIMenu, TMenuEvent Event) pUIMenu->m_pMiniDexed->SetVoiceParameter (nParam, nValue, CMiniDexed::NoOP, nTG); break; + case MenuEventPressAndStepDown: + case MenuEventPressAndStepUp: + pUIMenu->TGShortcutHandler (Event); + return; + default: return; } @@ -614,6 +634,11 @@ void CUIMenu::EditOPParameter (CUIMenu *pUIMenu, TMenuEvent Event) pUIMenu->m_pMiniDexed->SetVoiceParameter (nParam, nValue, nOP, nTG); break; + case MenuEventPressAndStepDown: + case MenuEventPressAndStepUp: + pUIMenu->TGShortcutHandler (Event); + return; + default: return; } @@ -837,6 +862,36 @@ string CUIMenu::ToOscillatorDetune (int nValue) return Result; } +void CUIMenu::TGShortcutHandler (TMenuEvent Event) +{ + assert (m_nCurrentMenuDepth >= 2); + assert (m_MenuStackMenu[0] = s_MainMenu); + unsigned nTG = m_nMenuStackSelection[0]; + assert (nTG < CConfig::ToneGenerators); + assert (m_nMenuStackItem[1] == nTG); + assert (m_nMenuStackParameter[1] == nTG); + + assert ( Event == MenuEventPressAndStepDown + || Event == MenuEventPressAndStepUp); + if (Event == MenuEventPressAndStepDown) + { + nTG--; + } + else + { + nTG++; + } + + if (nTG < CConfig::ToneGenerators) + { + m_nMenuStackSelection[0] = nTG; + m_nMenuStackItem[1] = nTG; + m_nMenuStackParameter[1] = nTG; + + EventHandler (MenuEventUpdate); + } +} + void CUIMenu::TimerHandler (TKernelTimerHandle hTimer, void *pParam, void *pContext) { CUIMenu *pThis = static_cast<CUIMenu *> (pContext); diff --git a/src/uimenu.h b/src/uimenu.h index d43a7b7..0da612b 100644 --- a/src/uimenu.h +++ b/src/uimenu.h @@ -43,6 +43,8 @@ public: MenuEventHome, MenuEventStepDown, MenuEventStepUp, + MenuEventPressAndStepDown, + MenuEventPressAndStepUp, MenuEventUnknown }; @@ -100,6 +102,8 @@ private: static std::string ToOscillatorMode (int nValue); static std::string ToOscillatorDetune (int nValue); + void TGShortcutHandler (TMenuEvent Event); + static void TimerHandler (TKernelTimerHandle hTimer, void *pParam, void *pContext); private: diff --git a/src/userinterface.cpp b/src/userinterface.cpp index f504d9d..058f14e 100644 --- a/src/userinterface.cpp +++ b/src/userinterface.cpp @@ -34,6 +34,7 @@ CUserInterface::CUserInterface (CMiniDexed *pMiniDexed, CGPIOManager *pGPIOManag m_pLCD (0), m_pLCDBuffered (0), m_pRotaryEncoder (0), + m_bSwitchPressed (false), m_Menu (this, pMiniDexed) { } @@ -177,12 +178,22 @@ void CUserInterface::EncoderEventHandler (CKY040::TEvent Event) { switch (Event) { + case CKY040::EventSwitchDown: + m_bSwitchPressed = true; + break; + + case CKY040::EventSwitchUp: + m_bSwitchPressed = false; + break; + case CKY040::EventClockwise: - m_Menu.EventHandler (CUIMenu::MenuEventStepUp); + m_Menu.EventHandler (m_bSwitchPressed ? CUIMenu::MenuEventPressAndStepUp + : CUIMenu::MenuEventStepUp); break; case CKY040::EventCounterclockwise: - m_Menu.EventHandler (CUIMenu::MenuEventStepDown); + m_Menu.EventHandler (m_bSwitchPressed ? CUIMenu::MenuEventPressAndStepDown + : CUIMenu::MenuEventStepDown); break; case CKY040::EventSwitchClick: @@ -193,17 +204,17 @@ void CUserInterface::EncoderEventHandler (CKY040::TEvent Event) m_Menu.EventHandler (CUIMenu::MenuEventSelect); break; + case CKY040::EventSwitchTripleClick: + m_Menu.EventHandler (CUIMenu::MenuEventHome); + break; + case CKY040::EventSwitchHold: - if (m_pRotaryEncoder->GetHoldSeconds () >= 3) + if (m_pRotaryEncoder->GetHoldSeconds () >= 10) { delete m_pLCD; // reset LCD reboot (); } - else - { - m_Menu.EventHandler (CUIMenu::MenuEventHome); - } break; default: diff --git a/src/userinterface.h b/src/userinterface.h index 6f29d5c..437993a 100644 --- a/src/userinterface.h +++ b/src/userinterface.h @@ -64,6 +64,7 @@ private: CWriteBufferDevice *m_pLCDBuffered; CKY040 *m_pRotaryEncoder; + bool m_bSwitchPressed; CUIMenu m_Menu; };