diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c3a85ab..dc5ad01 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -94,6 +94,13 @@ jobs: zip -r ../MiniDexed_$GITHUB_RUN_NUMBER_$(date +%Y%m%d)-$(git rev-parse --short HEAD).zip * echo "artifactName=MiniDexed_$GITHUB_RUN_NUMBER_$(date +%Y-%m-%d)-$(git rev-parse --short HEAD)" >> $GITHUB_ENV cd - + - name: Hardware configration files + run: | + cd hwconfig + sh -ex ./customize.sh + cd - + mkdir -p ./sdcard/hardware/ + cp -r ./hwconfig/minidexed_* ./sdcard/minidexed.ini ./sdcard/hardware/ - uses: actions/upload-artifact@v3 with: name: ${{ env.artifactName }} # Exported above diff --git a/.gitignore b/.gitignore index 6ad1469..42431b6 100644 --- a/.gitignore +++ b/.gitignore @@ -49,4 +49,5 @@ sdcard CMSIS_5/** Synth_Dexed/** circle-stdlib/** -.vscode/ \ No newline at end of file +.vscode/ +minidexed_* \ No newline at end of file diff --git a/README.md b/README.md index 68cdb02..81bd3b5 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ![minidexed](https://user-images.githubusercontent.com/2480569/161813414-bb156a1c-efec-44c0-802a-8926412a08e0.jpg) -MiniDexed is a FM synthesizer closely modeled on the famous DX7 by a well-known Japanese manufacturer running on a bare metal Raspberry Pi (without a Linux kernel or operating system). On Raspberry Pi 2 and larger, it can run 8 tone generators, not unlike the TX816/TX802 (8 DX7 instances without the keyboard in one box). [Featured by HACKADAY](https://hackaday.com/2022/04/19/bare-metal-gives-this-pi-some-classic-synths/), [Adafruit](https://blog.adafruit.com/2022/04/25/free-yamaha-dx7-synth-emulator-on-a-raspberry-pi/), and [Synth Geekery](https://www.youtube.com/watch?v=TDSy5nnm0jA). +MiniDexed is a FM synthesizer closely modeled on the famous DX7 by a well-known Japanese manufacturer running on a bare metal Raspberry Pi (without a Linux kernel or operating system). On Raspberry Pi 2 and larger, it can run 8 tone generators, not unlike the TX816/TX802 (8 DX7 instances without the keyboard in one box). [Featured by HACKADAY](https://hackaday.com/2022/04/19/bare-metal-gives-this-pi-some-classic-synths/), [Adafruit](https://blog.adafruit.com/2022/04/25/free-yamaha-dx7-synth-emulator-on-a-raspberry-pi/), [The MagPi magazine](https://magpi.raspberrypi.com/articles/mini-dexed) (Issue 142 June 2024, [PDF](https://magpi.raspberrypi.com/issues/142)) and [Synth Geekery](https://www.youtube.com/watch?v=TDSy5nnm0jA). ## Demo songs diff --git a/hwconfig/DT-DX.override b/hwconfig/DT-DX.override new file mode 100644 index 0000000..1e6ba75 --- /dev/null +++ b/hwconfig/DT-DX.override @@ -0,0 +1,46 @@ +# DTronics DT-DX +# https://www.dtronics.nl/dt-dx + +SoundDevice=i2s +SampleRate=22000 +ChunkSize=256 +DACI2CAddress=0x0 +ChannelsSwapped=1 + +LCDEnabled=1 +LCDPinEnable=17 +LCDPinRegisterSelect=27 +LCDPinReadWrite=16 +LCDPinData4=22 +LCDPinData5=23 +LCDPinData6=24 +LCDPinData7=25 +LCDI2CAddress=0x00 + +SSD1306LCDI2CAddress=0x00 +SSD1306LCDWidth=128 +SSD1306LCDHeight=32 +SSD1306LCDRotate=0 +SSD1306LCDMirror=0 + +LCDColumns=16 +LCDRows=2 + +ButtonPinPrev=0 +ButtonActionPrev=0 +ButtonPinNext=0 +ButtonActionNext=0 +ButtonPinBack=26 +ButtonActionBack=longpress +ButtonPinSelect=26 +ButtonActionSelect=click +ButtonPinHome=26 +ButtonActionHome=doubleclick +ButtonPinShortcut=26 + +DoubleClickTimeout=400 +LongPressTimeout=400 + +EncoderEnabled=1 +EncoderPinClock=6 +EncoderPinData=5 \ No newline at end of file diff --git a/hwconfig/customize.sh b/hwconfig/customize.sh new file mode 100755 index 0000000..687b568 --- /dev/null +++ b/hwconfig/customize.sh @@ -0,0 +1,33 @@ +#!/bin/sh + +# This script creates a set of ini files from the *.override files +# to provide customized configurations for well-known hardware + +# Find all files named *.override, and run the following on each of them +for file in *.override; do + # Copy the file minidexed.ini to the name of this file but with .ini extension instead + name_of_ini_file=minidexed_$(echo "$file" | sed 's/\.override$/.ini/') + cp ../src/minidexed.ini "$name_of_ini_file" + + # Change the values in the ini file, leaving the rest of the file unchanged + while IFS='=' read -r key value; do + # Skip empty lines and comments + if [ -z "$key" ] || [ "${key#\#}" != "$key" ]; then + continue + fi + value=$(echo "$value" | tr -d '\r') + if [ -n "$value" ]; then + sed -i "s/^$key=.*/$key=$value/" "$name_of_ini_file" + fi + done < "$file" + + # Process the last line of the override file separately, if it doesn't end with a newline + if [ -n "$key" ]; then + value=$(echo "$value" | tr -d '\r') + if [ -n "$value" ]; then + sed -i "s/^$key=.*/$key=$value/" "$name_of_ini_file" + fi + fi + + echo "Created $name_of_ini_file" +done diff --git a/hwconfig/pirate_audio.override b/hwconfig/pirate_audio.override new file mode 100644 index 0000000..680f3fe --- /dev/null +++ b/hwconfig/pirate_audio.override @@ -0,0 +1,32 @@ +# Pimoroni Pirate Audio (screen, buttons and audio output) +# https://shop.pimoroni.com/search?q=pirate%20audio + +SoundDevice=i2s +LCDEnabled=1 + +SPIBus=0 +ST7789Enabled=1 +ST7789Data=9 +ST7789Select=1 +ST7789Reset= +ST7789Backlight=13 +ST7789Width=240 +ST7789Height=240 +ST7789Rotation=90 + +LCDColumns=15 +LCDRows=2 + +ButtonPinPrev=5 +ButtonActionPrev=click +ButtonPinNext=6 +ButtonActionNext=click +ButtonPinBack=16 +ButtonActionBack=click +ButtonPinSelect=24 +ButtonActionSelect=click +ButtonPinHome=16 +ButtonActionHome=doubleclick +ButtonPinShortcut=0 + +EncoderEnabled=0 \ No newline at end of file diff --git a/src/config.cpp b/src/config.cpp index 70c76f3..21c2473 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -164,11 +164,15 @@ void CConfig::Load (void) m_nButtonPinPgmUp = m_Properties.GetNumber ("ButtonPinPgmUp", 0); m_nButtonPinPgmDown = m_Properties.GetNumber ("ButtonPinPgmDown", 0); + m_nButtonPinBankUp = m_Properties.GetNumber ("ButtonPinBankUp", 0); + m_nButtonPinBankDown = m_Properties.GetNumber ("ButtonPinBankDown", 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_ButtonActionBankUp = m_Properties.GetString ("ButtonActionBankUp", ""); + m_ButtonActionBankDown = m_Properties.GetString ("ButtonActionBankDown", ""); m_ButtonActionTGUp = m_Properties.GetString ("ButtonActionTGUp", ""); m_ButtonActionTGDown = m_Properties.GetString ("ButtonActionTGDown", ""); @@ -182,6 +186,8 @@ void CConfig::Load (void) m_nMIDIButtonPgmUp = m_Properties.GetNumber ("MIDIButtonPgmUp", 0); m_nMIDIButtonPgmDown = m_Properties.GetNumber ("MIDIButtonPgmDown", 0); + m_nMIDIButtonBankUp = m_Properties.GetNumber ("MIDIButtonBankUp", 0); + m_nMIDIButtonBankDown = m_Properties.GetNumber ("MIDIButtonBankDown", 0); m_nMIDIButtonTGUp = m_Properties.GetNumber ("MIDIButtonTGUp", 0); m_nMIDIButtonTGDown = m_Properties.GetNumber ("MIDIButtonTGDown", 0); @@ -571,6 +577,16 @@ unsigned CConfig::GetButtonPinPgmDown (void) const return m_nButtonPinPgmDown; } +unsigned CConfig::GetButtonPinBankUp (void) const +{ + return m_nButtonPinBankUp; +} + +unsigned CConfig::GetButtonPinBankDown (void) const +{ + return m_nButtonPinBankDown; +} + unsigned CConfig::GetButtonPinTGUp (void) const { return m_nButtonPinTGUp; @@ -591,6 +607,16 @@ const char *CConfig::GetButtonActionPgmDown (void) const return m_ButtonActionPgmDown.c_str(); } +const char *CConfig::GetButtonActionBankUp (void) const +{ + return m_ButtonActionBankUp.c_str(); +} + +const char *CConfig::GetButtonActionBankDown (void) const +{ + return m_ButtonActionBankDown.c_str(); +} + const char *CConfig::GetButtonActionTGUp (void) const { return m_ButtonActionTGUp.c_str(); @@ -646,6 +672,16 @@ unsigned CConfig::GetMIDIButtonPgmDown (void) const return m_nMIDIButtonPgmDown; } +unsigned CConfig::GetMIDIButtonBankUp (void) const +{ + return m_nMIDIButtonBankUp; +} + +unsigned CConfig::GetMIDIButtonBankDown (void) const +{ + return m_nMIDIButtonBankDown; +} + unsigned CConfig::GetMIDIButtonTGUp (void) const { return m_nMIDIButtonTGUp; diff --git a/src/config.h b/src/config.h index 3103fca..b87a94c 100644 --- a/src/config.h +++ b/src/config.h @@ -195,12 +195,16 @@ public: // GPIO pin numbers are chip numbers, not header positions unsigned GetButtonPinPgmUp (void) const; unsigned GetButtonPinPgmDown (void) const; + unsigned GetButtonPinBankUp (void) const; + unsigned GetButtonPinBankDown (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 *GetButtonActionBankUp (void) const; + const char *GetButtonActionBankDown (void) const; const char *GetButtonActionTGUp (void) const; const char *GetButtonActionTGDown (void) const; @@ -216,6 +220,8 @@ public: // MIDI Button Program and TG Selection unsigned GetMIDIButtonPgmUp (void) const; unsigned GetMIDIButtonPgmDown (void) const; + unsigned GetMIDIButtonBankUp (void) const; + unsigned GetMIDIButtonBankDown (void) const; unsigned GetMIDIButtonTGUp (void) const; unsigned GetMIDIButtonTGDown (void) const; @@ -314,6 +320,8 @@ private: unsigned m_nButtonPinShortcut; unsigned m_nButtonPinPgmUp; unsigned m_nButtonPinPgmDown; + unsigned m_nButtonPinBankUp; + unsigned m_nButtonPinBankDown; unsigned m_nButtonPinTGUp; unsigned m_nButtonPinTGDown; @@ -324,6 +332,8 @@ private: std::string m_ButtonActionHome; std::string m_ButtonActionPgmUp; std::string m_ButtonActionPgmDown; + std::string m_ButtonActionBankUp; + std::string m_ButtonActionBankDown; std::string m_ButtonActionTGUp; std::string m_ButtonActionTGDown; @@ -339,6 +349,8 @@ private: unsigned m_nMIDIButtonHome; unsigned m_nMIDIButtonPgmUp; unsigned m_nMIDIButtonPgmDown; + unsigned m_nMIDIButtonBankUp; + unsigned m_nMIDIButtonBankDown; unsigned m_nMIDIButtonTGUp; unsigned m_nMIDIButtonTGDown; diff --git a/src/minidexed.ini b/src/minidexed.ini index 41c5a12..3c03327 100644 --- a/src/minidexed.ini +++ b/src/minidexed.ini @@ -95,12 +95,16 @@ ButtonActionHome=doubleclick ButtonPinShortcut=11 # (Shortcut doesn't have an action) -# GPIO Program/TG Selection +# GPIO Program/Bank/TG Selection # Any buttons set to 0 will be ignored ButtonPinPgmUp=0 ButtonActionPgmUp= ButtonPinPgmDown=0 ButtonActionPgmDown= +ButtonPinBankUp=0 +ButtonActionBankUp= +ButtonPinBankDown=0 +ButtonActionBankDown= ButtonPinTGUp=0 ButtonActionTGUp= ButtonPinTGDown=0 @@ -125,6 +129,8 @@ MIDIButtonSelect=0 MIDIButtonHome=0 MIDIButtonPgmUp=0 MIDIButtonPgmDown=0 +MIDIButtonBankUp=0 +MIDIButtonBankDown=0 MIDIButtonTGUp=0 MIDIButtonTGDown=0 diff --git a/src/uibuttons.cpp b/src/uibuttons.cpp index 0e361ae..ae206dc 100644 --- a/src/uibuttons.cpp +++ b/src/uibuttons.cpp @@ -257,50 +257,8 @@ CUIButton::BtnTrigger CUIButton::triggerTypeFromString(const char* triggerString } -CUIButtons::CUIButtons ( - unsigned prevPin, const char *prevAction, - unsigned nextPin, const char *nextAction, - 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 pgmUpMidi, unsigned pgmDownMidi, unsigned TGUpMidi, unsigned TGDownMidi -) -: m_doubleClickTimeout(doubleClickTimeout), - m_longPressTimeout(longPressTimeout), - m_prevPin(prevPin), - m_prevAction(CUIButton::triggerTypeFromString(prevAction)), - m_nextPin(nextPin), - m_nextAction(CUIButton::triggerTypeFromString(nextAction)), - m_backPin(backPin), - m_backAction(CUIButton::triggerTypeFromString(backAction)), - m_selectPin(selectPin), - 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)), +CUIButtons::CUIButtons (CConfig *pConfig) +: m_pConfig(pConfig), m_eventHandler (0), m_lastTick (0) { @@ -312,6 +270,46 @@ CUIButtons::~CUIButtons (void) boolean CUIButtons::Initialize (void) { + assert (m_pConfig); + + // Read the button configuration + m_doubleClickTimeout = m_pConfig->GetDoubleClickTimeout (); + m_longPressTimeout = m_pConfig->GetLongPressTimeout (); + m_prevPin = m_pConfig->GetButtonPinPrev (); + m_prevAction = CUIButton::triggerTypeFromString( m_pConfig->GetButtonActionPrev ()); + m_nextPin = m_pConfig->GetButtonPinNext (); + m_nextAction = CUIButton::triggerTypeFromString( m_pConfig->GetButtonActionNext ()); + m_backPin = m_pConfig->GetButtonPinBack (); + m_backAction = CUIButton::triggerTypeFromString( m_pConfig->GetButtonActionBack ()); + m_selectPin = m_pConfig->GetButtonPinSelect (); + m_selectAction = CUIButton::triggerTypeFromString( m_pConfig->GetButtonActionSelect ()); + m_homePin = m_pConfig->GetButtonPinHome (); + m_homeAction = CUIButton::triggerTypeFromString( m_pConfig->GetButtonActionHome ()); + m_pgmUpPin = m_pConfig->GetButtonPinPgmUp (); + m_pgmUpAction = CUIButton::triggerTypeFromString( m_pConfig->GetButtonActionPgmUp ()); + m_pgmDownPin = m_pConfig->GetButtonPinPgmDown (); + m_pgmDownAction = CUIButton::triggerTypeFromString( m_pConfig->GetButtonActionPgmDown ()); + m_BankUpPin = m_pConfig->GetButtonPinBankUp (); + m_BankUpAction = CUIButton::triggerTypeFromString( m_pConfig->GetButtonActionBankUp ()); + m_BankDownPin = m_pConfig->GetButtonPinBankDown (); + m_BankDownAction = CUIButton::triggerTypeFromString( m_pConfig->GetButtonActionBankDown ()); + m_TGUpPin = m_pConfig->GetButtonPinTGUp (); + m_TGUpAction = CUIButton::triggerTypeFromString( m_pConfig->GetButtonActionTGUp ()); + m_TGDownPin = m_pConfig->GetButtonPinTGDown (); + m_TGDownAction = CUIButton::triggerTypeFromString( m_pConfig->GetButtonActionTGDown ()); + m_notesMidi = ccToMidiPin( m_pConfig->GetMIDIButtonNotes ()); + m_prevMidi = ccToMidiPin( m_pConfig->GetMIDIButtonPrev ()); + m_nextMidi = ccToMidiPin( m_pConfig->GetMIDIButtonNext ()); + m_backMidi = ccToMidiPin( m_pConfig->GetMIDIButtonBack ()); + m_selectMidi = ccToMidiPin( m_pConfig->GetMIDIButtonSelect ()); + m_homeMidi = ccToMidiPin( m_pConfig->GetMIDIButtonHome ()); + m_pgmUpMidi = ccToMidiPin( m_pConfig->GetMIDIButtonPgmUp ()); + m_pgmDownMidi = ccToMidiPin( m_pConfig->GetMIDIButtonPgmDown ()); + m_BankUpMidi = ccToMidiPin( m_pConfig->GetMIDIButtonBankUp ()); + m_BankDownMidi = ccToMidiPin( m_pConfig->GetMIDIButtonBankDown ()); + m_TGUpMidi = ccToMidiPin( m_pConfig->GetMIDIButtonTGUp ()); + m_TGDownMidi = ccToMidiPin( m_pConfig->GetMIDIButtonTGDown ()); + // First sanity check and convert the timeouts: // Internally values are in tenths of a millisecond, but config values // are in milliseconds @@ -332,16 +330,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_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 + m_prevPin, m_nextPin, m_backPin, m_selectPin, m_homePin, m_pgmUpPin, m_pgmDownPin, m_BankUpPin, m_BankDownPin, m_TGUpPin, m_TGDownPin, + m_prevMidi, m_nextMidi, m_backMidi, m_selectMidi, m_homeMidi, m_pgmUpMidi, m_pgmDownMidi, m_BankUpMidi, m_BankDownMidi, 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, + m_pgmUpAction, m_pgmDownAction, m_BankUpAction, m_BankDownAction, 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::BtnTriggerClick }; CUIButton::BtnEvent events[MAX_BUTTONS] = { // Normal buttons @@ -352,6 +350,8 @@ boolean CUIButtons::Initialize (void) CUIButton::BtnEventHome, CUIButton::BtnEventPgmUp, CUIButton::BtnEventPgmDown, + CUIButton::BtnEventBankUp, + CUIButton::BtnEventBankDown, CUIButton::BtnEventTGUp, CUIButton::BtnEventTGDown, // MIDI buttons @@ -362,6 +362,8 @@ boolean CUIButtons::Initialize (void) CUIButton::BtnEventHome, CUIButton::BtnEventPgmUp, CUIButton::BtnEventPgmDown, + CUIButton::BtnEventBankUp, + CUIButton::BtnEventBankDown, CUIButton::BtnEventTGUp, CUIButton::BtnEventTGDown }; diff --git a/src/uibuttons.h b/src/uibuttons.h index 44dcca0..be17934 100644 --- a/src/uibuttons.h +++ b/src/uibuttons.h @@ -27,8 +27,8 @@ #define BUTTONS_UPDATE_NUM_TICKS 100 #define DEBOUNCE_TIME 20 -#define MAX_GPIO_BUTTONS 9 // 5 UI buttons, 4 Program/TG Select buttons -#define MAX_MIDI_BUTTONS 9 +#define MAX_GPIO_BUTTONS 11 // 5 UI buttons, 6 Program/Bank/TG Select buttons +#define MAX_MIDI_BUTTONS 11 #define MAX_BUTTONS (MAX_GPIO_BUTTONS+MAX_MIDI_BUTTONS) class CUIButtons; @@ -54,9 +54,11 @@ public: BtnEventHome = 5, BtnEventPgmUp = 6, BtnEventPgmDown = 7, - BtnEventTGUp = 8, - BtnEventTGDown = 9, - BtnEventUnknown = 10 + BtnEventBankUp = 8, + BtnEventBankDown = 9, + BtnEventTGUp = 10, + BtnEventTGDown = 11, + BtnEventUnknown = 12 }; CUIButton (void); @@ -111,20 +113,7 @@ public: typedef void BtnEventHandler (CUIButton::BtnEvent Event, void *param); public: - CUIButtons ( - unsigned prevPin, const char *prevAction, - unsigned nextPin, const char *nextAction, - 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 pgmUpMidi, unsigned pgmDownMidi, unsigned TGUpMidi, unsigned TGDownMidi - ); + CUIButtons (CConfig *pConfig); ~CUIButtons (void); boolean Initialize (void); @@ -138,6 +127,8 @@ public: void BtnMIDICmdHandler (unsigned nMidiCmd, unsigned nMidiData1, unsigned nMidiData2); private: + CConfig *m_pConfig; + // Array of normal GPIO buttons and "MIDI buttons" CUIButton m_buttons[MAX_BUTTONS]; @@ -163,6 +154,10 @@ private: CUIButton::BtnTrigger m_pgmUpAction; unsigned m_pgmDownPin; CUIButton::BtnTrigger m_pgmDownAction; + unsigned m_BankUpPin; + CUIButton::BtnTrigger m_BankUpAction; + unsigned m_BankDownPin; + CUIButton::BtnTrigger m_BankDownAction; unsigned m_TGUpPin; CUIButton::BtnTrigger m_TGUpAction; unsigned m_TGDownPin; @@ -178,6 +173,8 @@ private: unsigned m_pgmUpMidi; unsigned m_pgmDownMidi; + unsigned m_BankUpMidi; + unsigned m_BankDownMidi; unsigned m_TGUpMidi; unsigned m_TGDownMidi; diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 8b72425..ed36cd4 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -431,6 +431,11 @@ void CUIMenu::EventHandler (TMenuEvent Event) PgmUpDownHandler(Event); break; + case MenuEventBankUp: + case MenuEventBankDown: + BankUpDownHandler(Event); + break; + case MenuEventTGUp: case MenuEventTGDown: TGUpDownHandler(Event); @@ -1375,6 +1380,87 @@ void CUIMenu::PgmUpDownHandler (TMenuEvent Event) } } +void CUIMenu::BankUpDownHandler (TMenuEvent Event) +{ + if (m_pMiniDexed->GetParameter (CMiniDexed::ParameterPerformanceSelectChannel) != CMIDIDevice::Disabled) + { + // Bank Up/Down acts on performances + unsigned nLastPerformanceBank = m_pMiniDexed->GetLastPerformanceBank(); + unsigned nPerformanceBank = m_nSelectedPerformanceBankID; + unsigned nStartBank = nPerformanceBank; + //LOGNOTE("Performance Bank actual=%d, last=%d", nPerformanceBank, nLastPerformanceBank); + if (Event == MenuEventBankDown) + { + do + { + if (nPerformanceBank == 0) + { + // Wrap around + nPerformanceBank = nLastPerformanceBank; + } + else if (nPerformanceBank > 0) + { + --nPerformanceBank; + } + } while ((m_pMiniDexed->IsValidPerformanceBank(nPerformanceBank) != true) && (nPerformanceBank != nStartBank)); + m_nSelectedPerformanceBankID = nPerformanceBank; + // Switch to the new bank and select the first performance voice + m_pMiniDexed->SetParameter (CMiniDexed::ParameterPerformanceBank, nPerformanceBank); + m_pMiniDexed->SetFirstPerformance(); + //LOGNOTE("Performance Bank new=%d, last=%d", m_nSelectedPerformanceBankID, nLastPerformanceBank); + } + else // MenuEventBankUp + { + do + { + if (nPerformanceBank == nLastPerformanceBank) + { + // Wrap around + nPerformanceBank = 0; + } + else if (nPerformanceBank < nLastPerformanceBank) + { + ++nPerformanceBank; + } + } while ((m_pMiniDexed->IsValidPerformanceBank(nPerformanceBank) != true) && (nPerformanceBank != nStartBank)); + m_nSelectedPerformanceBankID = nPerformanceBank; + m_pMiniDexed->SetParameter (CMiniDexed::ParameterPerformanceBank, nPerformanceBank); + m_pMiniDexed->SetFirstPerformance(); + //LOGNOTE("Performance Bank new=%d, last=%d", m_nSelectedPerformanceBankID, nLastPerformanceBank); + } + } + else + { + // Bank Up/Down acts on voices within a TG. + + // If we're not in the root menu, then see if we are already in a TG menu, + // then find the current TG number. Otherwise assume TG1 (nTG=0). + unsigned nTG = 0; + if (m_MenuStackMenu[0] == s_MainMenu && (m_pCurrentMenu == s_TGMenu) || (m_MenuStackMenu[1] == s_TGMenu)) { + nTG = m_nMenuStackSelection[0]; + } + assert (nTG < CConfig::AllToneGenerators); + if (nTG < m_nToneGenerators) + { + int nBank = m_pMiniDexed->GetTGParameter (CMiniDexed::TGParameterVoiceBank, nTG); + + assert (Event == MenuEventBankDown || Event == MenuEventBankUp); + if (Event == MenuEventBankDown) + { + //LOGNOTE("BankDown"); + nBank = m_pMiniDexed->GetSysExFileLoader ()->GetNextBankDown(nBank); + m_pMiniDexed->SetTGParameter (CMiniDexed::TGParameterVoiceBank, nBank, nTG); + } + else + { + //LOGNOTE("BankUp"); + nBank = m_pMiniDexed->GetSysExFileLoader ()->GetNextBankUp(nBank); + m_pMiniDexed->SetTGParameter (CMiniDexed::TGParameterVoiceBank, nBank, nTG); + } + } + } +} + void CUIMenu::TGUpDownHandler (TMenuEvent Event) { // This will update the menus to position it for the next TG up or down diff --git a/src/uimenu.h b/src/uimenu.h index 0034278..d9dc3ee 100644 --- a/src/uimenu.h +++ b/src/uimenu.h @@ -48,6 +48,8 @@ public: MenuEventPressAndStepUp, MenuEventPgmUp, MenuEventPgmDown, + MenuEventBankUp, + MenuEventBankDown, MenuEventTGUp, MenuEventTGDown, MenuEventUnknown @@ -119,6 +121,7 @@ private: void OPShortcutHandler (TMenuEvent Event); void PgmUpDownHandler (TMenuEvent Event); + void BankUpDownHandler (TMenuEvent Event); void TGUpDownHandler (TMenuEvent Event); static void TimerHandler (TKernelTimerHandle hTimer, void *pParam, void *pContext); diff --git a/src/userinterface.cpp b/src/userinterface.cpp index aa46f9e..32222a1 100644 --- a/src/userinterface.cpp +++ b/src/userinterface.cpp @@ -162,37 +162,7 @@ bool CUserInterface::Initialize (void) LOGDBG ("LCD initialized"); } - m_pUIButtons = new CUIButtons ( m_pConfig->GetButtonPinPrev (), - m_pConfig->GetButtonActionPrev (), - m_pConfig->GetButtonPinNext (), - m_pConfig->GetButtonActionNext (), - m_pConfig->GetButtonPinBack (), - m_pConfig->GetButtonActionBack (), - m_pConfig->GetButtonPinSelect (), - 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 (), - m_pConfig->GetMIDIButtonPrev (), - m_pConfig->GetMIDIButtonNext (), - m_pConfig->GetMIDIButtonBack (), - m_pConfig->GetMIDIButtonSelect (), - m_pConfig->GetMIDIButtonHome (), - m_pConfig->GetMIDIButtonPgmUp (), - m_pConfig->GetMIDIButtonPgmDown (), - m_pConfig->GetMIDIButtonTGUp (), - m_pConfig->GetMIDIButtonTGDown () - ); + m_pUIButtons = new CUIButtons ( m_pConfig ); assert (m_pUIButtons); if (!m_pUIButtons->Initialize ()) @@ -397,6 +367,14 @@ void CUserInterface::UIButtonsEventHandler (CUIButton::BtnEvent Event) m_Menu.EventHandler (CUIMenu::MenuEventPgmDown); break; + case CUIButton::BtnEventBankUp: + m_Menu.EventHandler (CUIMenu::MenuEventBankUp); + break; + + case CUIButton::BtnEventBankDown: + m_Menu.EventHandler (CUIMenu::MenuEventBankDown); + break; + case CUIButton::BtnEventTGUp: m_Menu.EventHandler (CUIMenu::MenuEventTGUp); break;