From f6ebd7871d0bc055224cf1b72278589a6be386ac Mon Sep 17 00:00:00 2001 From: Kevin <68612569+diyelectromusic@users.noreply.github.com> Date: Mon, 5 Aug 2024 08:39:32 +0100 Subject: [PATCH] Another attempt to support configuration TGs and polyphony (#690) * Initial commit for configuration TGs and polyphony across RPI1-5. * Ensure unused TGs in a performance are MIDI disabled. Set polyphony to higher defaults on Pi 4 and 5. * Actually, can just default to MIDI "disabled" directly in performance config if not present. * Fix issue with choosing max polyphony --- src/config.cpp | 56 ++++++++ src/config.h | 48 ++++++- src/mididevice.cpp | 10 +- src/mididevice.h | 2 +- src/minidexed.cpp | 284 +++++++++++++++++++++++++++----------- src/minidexed.h | 69 ++++----- src/performanceconfig.cpp | 126 +++++++++-------- src/performanceconfig.h | 62 +++++---- src/sysexfileloader.cpp | 17 +++ src/sysexfileloader.h | 1 + src/uimenu.cpp | 233 +++++++++++++++++++------------ src/uimenu.h | 6 +- src/userinterface.cpp | 2 +- 13 files changed, 618 insertions(+), 298 deletions(-) diff --git a/src/config.cpp b/src/config.cpp index 884d7cc..15a37ad 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -36,6 +36,20 @@ void CConfig::Load (void) { m_Properties.Load (); + // Number of Tone Generators and Polyphony + m_nToneGenerators = m_Properties.GetNumber ("ToneGenerators", DefToneGenerators); + m_nPolyphony = m_Properties.GetNumber ("Polyphony", DefaultNotes); + // At present there are only two options for tone generators: min or max + // and for the Pi 1,2,3 these are the same anyway. + if ((m_nToneGenerators != MinToneGenerators) && (m_nToneGenerators != AllToneGenerators)) + { + m_nToneGenerators = DefToneGenerators; + } + if (m_nPolyphony > MaxNotes) + { + m_nPolyphony = DefaultNotes; + } + m_bUSBGadget = m_Properties.GetNumber ("USBGadget", 0) != 0; m_nUSBGadgetPin = m_Properties.GetNumber ("USBGadgetPin", 0); // Default OFF SetUSBGadgetMode(m_bUSBGadget); // Might get overriden later by USBGadgetPin state @@ -177,6 +191,48 @@ void CConfig::Load (void) m_bPerformanceSelectChannel = m_Properties.GetNumber ("PerformanceSelectChannel", 0); } +unsigned CConfig::GetToneGenerators (void) const +{ + return m_nToneGenerators; +} + +unsigned CConfig::GetPolyphony (void) const +{ + return m_nPolyphony; +} + +unsigned CConfig::GetTGsCore1 (void) const +{ +#ifndef ARM_ALLOW_MULTI_CORE + return 0; +#else + if (m_nToneGenerators > MinToneGenerators) + { + return TGsCore1 + TGsCore1Opt; + } + else + { + return TGsCore1; + } +#endif +} + +unsigned CConfig::GetTGsCore23 (void) const +{ +#ifndef ARM_ALLOW_MULTI_CORE + return 0; +#else + if (m_nToneGenerators > MinToneGenerators) + { + return TGsCore23 + TGsCore23Opt; + } + else + { + return TGsCore23; + } +#endif +} + bool CConfig::GetUSBGadget (void) const { return m_bUSBGadget; diff --git a/src/config.h b/src/config.h index 7497c21..166c4bb 100644 --- a/src/config.h +++ b/src/config.h @@ -35,18 +35,49 @@ class CConfig // Configuration for MiniDexed { public: +// Set maximum, minimum and default numbers of tone generators, depending on Pi version. +// Actual number in can be changed via config settings for some Pis. #ifndef ARM_ALLOW_MULTI_CORE - static const unsigned ToneGenerators = 1; + // Pi V1 or Zero (single core) + static const unsigned MinToneGenerators = 1; + static const unsigned AllToneGenerators = 1; + static const unsigned DefToneGenerators = AllToneGenerators; #else +#if (RASPPI==4 || RASPPI==5) + // Pi 4 and 5 quad core + // These are max values, default is to support 8 in total with optional 16 TGs static const unsigned TGsCore1 = 2; // process 2 TGs on core 1 static const unsigned TGsCore23 = 3; // process 3 TGs on core 2 and 3 each - static const unsigned ToneGenerators = TGsCore1 + 2*TGsCore23; + static const unsigned TGsCore1Opt = 2; // process optional additional 2 TGs on core 1 + static const unsigned TGsCore23Opt = 3; // process optional additional 3 TGs on core 2 and 3 each + static const unsigned MinToneGenerators = TGsCore1 + 2*TGsCore23; + static const unsigned AllToneGenerators = TGsCore1 + TGsCore1Opt + 2*TGsCore23 + 2*TGsCore23Opt; + static const unsigned DefToneGenerators = MinToneGenerators; +#else + // Pi 2 or 3 quad core + static const unsigned TGsCore1 = 2; // process 2 TGs on core 1 + static const unsigned TGsCore23 = 3; // process 3 TGs on core 2 and 3 each + static const unsigned TGsCore1Opt = 0; + static const unsigned TGsCore23Opt = 0; + static const unsigned MinToneGenerators = TGsCore1 + 2*TGsCore23; + static const unsigned AllToneGenerators = MinToneGenerators; + static const unsigned DefToneGenerators = AllToneGenerators; #endif - +#endif + +// Set maximum polyphony, depending on PI version. This can be changed via config settings #if RASPPI == 1 - static const unsigned MaxNotes = 8; // polyphony + static const unsigned MaxNotes = 8; + static const unsigned DefaultNotes = 8; +#elif RASPPI == 4 + static const unsigned MaxNotes = 32; + static const unsigned DefaultNotes = 24; +#elif RASPPI == 5 + static const unsigned MaxNotes = 32; + static const unsigned DefaultNotes = 32; #else static const unsigned MaxNotes = 16; + static const unsigned DefaultNotes = 16; #endif static const unsigned MaxChunkSize = 4096; @@ -67,6 +98,12 @@ public: void Load (void); + // TGs and Polyphony + unsigned GetToneGenerators (void) const; + unsigned GetPolyphony (void) const; + unsigned GetTGsCore1 (void) const; + unsigned GetTGsCore23 (void) const; + // USB Mode bool GetUSBGadget (void) const; unsigned GetUSBGadgetPin (void) const; @@ -195,6 +232,9 @@ public: private: CPropertiesFatFsFile m_Properties; + unsigned m_nToneGenerators; + unsigned m_nPolyphony; + bool m_bUSBGadget; unsigned m_nUSBGadgetPin; bool m_bUSBGadgetMode; diff --git a/src/mididevice.cpp b/src/mididevice.cpp index 81314ba..504423e 100644 --- a/src/mididevice.cpp +++ b/src/mididevice.cpp @@ -65,7 +65,7 @@ CMIDIDevice::CMIDIDevice (CMiniDexed *pSynthesizer, CConfig *pConfig, CUserInter m_pConfig (pConfig), m_pUI (pUI) { - for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++) + for (unsigned nTG = 0; nTG < CConfig::AllToneGenerators; nTG++) { m_ChannelMap[nTG] = Disabled; } @@ -78,13 +78,13 @@ CMIDIDevice::~CMIDIDevice (void) void CMIDIDevice::SetChannel (u8 ucChannel, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); m_ChannelMap[nTG] = ucChannel; } u8 CMIDIDevice::GetChannel (unsigned nTG) const { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); return m_ChannelMap[nTG]; } @@ -238,8 +238,8 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign break; } - // Process MIDI for each Tone Generator - for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++) + // Process MIDI for each active Tone Generator + for (unsigned nTG = 0; nTG < m_pConfig->GetToneGenerators(); nTG++) { if (ucStatus == MIDI_SYSTEM_EXCLUSIVE_BEGIN) { diff --git a/src/mididevice.h b/src/mididevice.h index 0fc027c..b7e7fe7 100644 --- a/src/mididevice.h +++ b/src/mididevice.h @@ -65,7 +65,7 @@ private: CConfig *m_pConfig; CUserInterface *m_pUI; - u8 m_ChannelMap[CConfig::ToneGenerators]; + u8 m_ChannelMap[CConfig::AllToneGenerators]; std::string m_DeviceName; diff --git a/src/minidexed.cpp b/src/minidexed.cpp index da9e598..2e45f46 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -46,7 +46,7 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, m_pSoundDevice (0), m_bChannelsSwapped (pConfig->GetChannelsSwapped ()), #ifdef ARM_ALLOW_MULTI_CORE - m_nActiveTGsLog2 (0), +// m_nActiveTGsLog2 (0), #endif m_GetChunkTimer ("GetChunk", 1000000U * pConfig->GetChunkSize ()/2 / pConfig->GetSampleRate ()), @@ -61,8 +61,12 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, m_bLoadPerformanceBankBusy(false) { assert (m_pConfig); + + m_nToneGenerators = m_pConfig->GetToneGenerators(); + m_nPolyphony = m_pConfig->GetPolyphony(); + LOGNOTE("Tone Generators=%d, Polyphony=%d", m_nToneGenerators, m_nPolyphony); - for (unsigned i = 0; i < CConfig::ToneGenerators; i++) + for (unsigned i = 0; i < CConfig::AllToneGenerators; i++) { m_nVoiceBankID[i] = 0; m_nVoiceBankIDMSB[i] = 0; @@ -93,15 +97,20 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, m_nAftertouchTarget[i]=0; m_nReverbSend[i] = 0; - m_uchOPMask[i] = 0b111111; // All operators on - m_pTG[i] = new CDexedAdapter (CConfig::MaxNotes, pConfig->GetSampleRate ()); - assert (m_pTG[i]); - - m_pTG[i]->setEngineType(pConfig->GetEngineType ()); - m_pTG[i]->activate (); + // Active the required number of active TGs + if (iGetSampleRate ()); + assert (m_pTG[i]); + + m_pTG[i]->setEngineType(pConfig->GetEngineType ()); + m_pTG[i]->activate (); + } } - + unsigned nUSBGadgetPin = pConfig->GetUSBGadgetPin(); bool bUSBGadget = pConfig->GetUSBGadget(); bool bUSBGadgetMode = pConfig->GetUSBGadgetMode(); @@ -156,6 +165,11 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, // Quad DAC 8-channel mono only an option for RPI 5 m_bQuadDAC8Chan = pConfig->GetQuadDAC8Chan (); #endif + if (m_bQuadDAC8Chan && (m_nToneGenerators != 8)) + { + LOGNOTE("ERROR: Quad DAC Mode is only valid when number of TGs = 8. Defaulting to non-Quad DAC mode,"); + m_bQuadDAC8Chan = false; + } if (m_bQuadDAC8Chan) { LOGNOTE ("Configured for Quad DAC 8-channel Mono audio"); m_pSoundDevice = new CI2SSoundBaseDevice (pInterrupt, pConfig->GetSampleRate (), @@ -206,11 +220,11 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, setMasterVolume(1.0); // BEGIN setup tg_mixer - tg_mixer = new AudioStereoMixer(pConfig->GetChunkSize()/2); + tg_mixer = new AudioStereoMixer(pConfig->GetChunkSize()/2); // END setup tgmixer // BEGIN setup reverb - reverb_send_mixer = new AudioStereoMixer(pConfig->GetChunkSize()/2); + reverb_send_mixer = new AudioStereoMixer(pConfig->GetChunkSize()/2); reverb = new AudioEffectPlateReverb(pConfig->GetSampleRate()); SetParameter (ParameterReverbEnable, 1); SetParameter (ParameterReverbSize, 70); @@ -261,7 +275,7 @@ bool CMiniDexed::Initialize (void) LOGNOTE("Program Change: Disabled"); } - for (unsigned i = 0; i < CConfig::ToneGenerators; i++) + for (unsigned i = 0; i < m_nToneGenerators; i++) { assert (m_pTG[i]); @@ -283,7 +297,7 @@ bool CMiniDexed::Initialize (void) reverb_send_mixer->gain(i,mapfloat(m_nReverbSend[i],0,99,0.0f,1.0f)); } - m_PerformanceConfig.Init(); + m_PerformanceConfig.Init(m_nToneGenerators); if (m_PerformanceConfig.Load ()) { LoadPerformanceParameters(); @@ -453,12 +467,16 @@ void CMiniDexed::Run (unsigned nCore) // process the TGs, assigned to this core (2 or 3) - assert (m_nFramesToProcess <= CConfig::MaxChunkSize); - unsigned nTG = CConfig::TGsCore1 + (nCore-2)*CConfig::TGsCore23; - for (unsigned i = 0; i < CConfig::TGsCore23; i++, nTG++) + assert (m_nFramesToProcess <= m_pConfig->MaxChunkSize); + unsigned nTG = m_pConfig->GetTGsCore1() + (nCore-2)*m_pConfig->GetTGsCore23(); + for (unsigned i = 0; i < m_pConfig->GetTGsCore23(); i++, nTG++) { - assert (m_pTG[nTG]); - m_pTG[nTG]->getSamples (m_OutputLevel[nTG],m_nFramesToProcess); + assert (nTG < CConfig::AllToneGenerators); + if (nTG < m_pConfig->GetToneGenerators()) + { + assert (m_pTG[nTG]); + m_pTG[nTG]->getSamples (m_OutputLevel[nTG],m_nFramesToProcess); + } } } } @@ -480,7 +498,8 @@ void CMiniDexed::BankSelect (unsigned nBank, unsigned nTG) { nBank=constrain((int)nBank,0,16383); - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG if (GetSysExFileLoader ()->IsValidBank(nBank)) { @@ -509,7 +528,9 @@ void CMiniDexed::BankSelectMSB (unsigned nBankMSB, unsigned nTG) { nBankMSB=constrain((int)nBankMSB,0,127); - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + // MIDI Spec 1.0 "BANK SELECT" states: // "The transmitter must transmit the MSB and LSB as a pair, // and the Program Change must be sent immediately after @@ -530,7 +551,9 @@ void CMiniDexed::BankSelectLSB (unsigned nBankLSB, unsigned nTG) { nBankLSB=constrain((int)nBankLSB,0,127); - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + unsigned nBank = m_nVoiceBankID[nTG]; unsigned nBankMSB = m_nVoiceBankIDMSB[nTG]; nBank = (nBankMSB << 7) + nBankLSB; @@ -578,7 +601,9 @@ void CMiniDexed::ProgramChange (unsigned nProgram, unsigned nTG) nProgram=constrain((int)nProgram,0,31); } - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + m_nProgram[nTG] = nProgram; uint8_t Buffer[156]; @@ -617,7 +642,9 @@ void CMiniDexed::SetVolume (unsigned nVolume, unsigned nTG) { nVolume=constrain((int)nVolume,0,127); - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + m_nVolume[nTG] = nVolume; assert (m_pTG[nTG]); @@ -630,7 +657,9 @@ void CMiniDexed::SetPan (unsigned nPan, unsigned nTG) { nPan=constrain((int)nPan,0,127); - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + m_nPan[nTG] = nPan; tg_mixer->pan(nTG,mapfloat(nPan,0,127,0.0f,1.0f)); @@ -643,7 +672,9 @@ void CMiniDexed::SetReverbSend (unsigned nReverbSend, unsigned nTG) { nReverbSend=constrain((int)nReverbSend,0,99); - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + m_nReverbSend[nTG] = nReverbSend; reverb_send_mixer->gain(nTG,mapfloat(nReverbSend,0,99,0.0f,1.0f)); @@ -655,7 +686,9 @@ void CMiniDexed::SetMasterTune (int nMasterTune, unsigned nTG) { nMasterTune=constrain((int)nMasterTune,-99,99); - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + m_nMasterTune[nTG] = nMasterTune; assert (m_pTG[nTG]); @@ -668,7 +701,9 @@ void CMiniDexed::SetCutoff (int nCutoff, unsigned nTG) { nCutoff = constrain (nCutoff, 0, 99); - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + m_nCutoff[nTG] = nCutoff; assert (m_pTG[nTG]); @@ -681,7 +716,9 @@ void CMiniDexed::SetResonance (int nResonance, unsigned nTG) { nResonance = constrain (nResonance, 0, 99); - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + m_nResonance[nTG] = nResonance; assert (m_pTG[nTG]); @@ -694,7 +731,9 @@ void CMiniDexed::SetResonance (int nResonance, unsigned nTG) void CMiniDexed::SetMIDIChannel (uint8_t uchChannel, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + assert (uchChannel < CMIDIDevice::ChannelUnknown); m_nMIDIChannel[nTG] = uchChannel; @@ -713,6 +752,7 @@ void CMiniDexed::SetMIDIChannel (uint8_t uchChannel, unsigned nTG) } #ifdef ARM_ALLOW_MULTI_CORE +/* This doesn't appear to be used anywhere... unsigned nActiveTGs = 0; for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++) { @@ -725,6 +765,7 @@ void CMiniDexed::SetMIDIChannel (uint8_t uchChannel, unsigned nTG) assert (nActiveTGs <= 8); static const unsigned Log2[] = {0, 0, 1, 2, 2, 3, 3, 3, 3}; m_nActiveTGsLog2 = Log2[nActiveTGs]; +*/ #endif m_UI.ParameterChanged (); @@ -732,7 +773,9 @@ void CMiniDexed::SetMIDIChannel (uint8_t uchChannel, unsigned nTG) void CMiniDexed::keyup (int16_t pitch, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + assert (m_pTG[nTG]); pitch = ApplyNoteLimits (pitch, nTG); @@ -744,7 +787,9 @@ void CMiniDexed::keyup (int16_t pitch, unsigned nTG) void CMiniDexed::keydown (int16_t pitch, uint8_t velocity, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + assert (m_pTG[nTG]); pitch = ApplyNoteLimits (pitch, nTG); @@ -756,7 +801,8 @@ void CMiniDexed::keydown (int16_t pitch, uint8_t velocity, unsigned nTG) int16_t CMiniDexed::ApplyNoteLimits (int16_t pitch, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return -1; // Not an active TG if ( pitch < (int16_t) m_nNoteLimitLow[nTG] || pitch > (int16_t) m_nNoteLimitHigh[nTG]) @@ -777,14 +823,18 @@ int16_t CMiniDexed::ApplyNoteLimits (int16_t pitch, unsigned nTG) void CMiniDexed::setSustain(bool sustain, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + assert (m_pTG[nTG]); m_pTG[nTG]->setSustain (sustain); } void CMiniDexed::panic(uint8_t value, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + assert (m_pTG[nTG]); if (value == 0) { m_pTG[nTG]->panic (); @@ -793,7 +843,9 @@ void CMiniDexed::panic(uint8_t value, unsigned nTG) void CMiniDexed::notesOff(uint8_t value, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + assert (m_pTG[nTG]); if (value == 0) { m_pTG[nTG]->notesOff (); @@ -802,7 +854,9 @@ void CMiniDexed::notesOff(uint8_t value, unsigned nTG) void CMiniDexed::setModWheel (uint8_t value, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + assert (m_pTG[nTG]); m_pTG[nTG]->setModWheel (value); } @@ -810,35 +864,45 @@ void CMiniDexed::setModWheel (uint8_t value, unsigned nTG) void CMiniDexed::setFootController (uint8_t value, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + assert (m_pTG[nTG]); m_pTG[nTG]->setFootController (value); } void CMiniDexed::setBreathController (uint8_t value, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + assert (m_pTG[nTG]); m_pTG[nTG]->setBreathController (value); } void CMiniDexed::setAftertouch (uint8_t value, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + assert (m_pTG[nTG]); m_pTG[nTG]->setAftertouch (value); } void CMiniDexed::setPitchbend (int16_t value, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + assert (m_pTG[nTG]); m_pTG[nTG]->setPitchbend (value); } void CMiniDexed::ControllersRefresh (unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + assert (m_pTG[nTG]); m_pTG[nTG]->ControllersRefresh (); } @@ -853,7 +917,7 @@ void CMiniDexed::SetParameter (TParameter Parameter, int nValue) switch (Parameter) { case ParameterCompressorEnable: - for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++) + for (unsigned nTG = 0; nTG < m_nToneGenerators; nTG++) { assert (m_pTG[nTG]); m_pTG[nTG]->setCompressor (!!nValue); @@ -931,7 +995,8 @@ int CMiniDexed::GetParameter (TParameter Parameter) void CMiniDexed::SetTGParameter (TTGParameter Parameter, int nValue, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG switch (Parameter) { @@ -986,7 +1051,7 @@ void CMiniDexed::SetTGParameter (TTGParameter Parameter, int nValue, unsigned nT int CMiniDexed::GetTGParameter (TTGParameter Parameter, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); switch (Parameter) { @@ -1037,7 +1102,9 @@ int CMiniDexed::GetTGParameter (TTGParameter Parameter, unsigned nTG) void CMiniDexed::SetVoiceParameter (uint8_t uchOffset, uint8_t uchValue, unsigned nOP, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + assert (m_pTG[nTG]); assert (nOP <= 6); @@ -1070,7 +1137,9 @@ void CMiniDexed::SetVoiceParameter (uint8_t uchOffset, uint8_t uchValue, unsigne uint8_t CMiniDexed::GetVoiceParameter (uint8_t uchOffset, unsigned nOP, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return 0; // Not an active TG + assert (m_pTG[nTG]); assert (nOP <= 6); @@ -1094,13 +1163,15 @@ std::string CMiniDexed::GetVoiceName (unsigned nTG) { char VoiceName[11]; memset (VoiceName, 0, sizeof VoiceName); + VoiceName[0] = 32; // space + assert (nTG < CConfig::AllToneGenerators); - assert (nTG < CConfig::ToneGenerators); - assert (m_pTG[nTG]); - m_pTG[nTG]->setName (VoiceName); - + if (nTG < m_nToneGenerators) + { + assert (m_pTG[nTG]); + m_pTG[nTG]->setName (VoiceName); + } std::string Result (VoiceName); - return Result; } @@ -1142,6 +1213,7 @@ void CMiniDexed::ProcessSound (void) void CMiniDexed::ProcessSound (void) { assert (m_pSoundDevice); + assert (m_pConfig); unsigned nFrames = m_nQueueSizeFrames - m_pSoundDevice->GetQueueFramesAvail (); if (nFrames >= m_nQueueSizeFrames/2) @@ -1162,7 +1234,7 @@ void CMiniDexed::ProcessSound (void) // process the TGs assigned to core 1 assert (nFrames <= CConfig::MaxChunkSize); - for (unsigned i = 0; i < CConfig::TGsCore1; i++) + for (unsigned i = 0; i < m_pConfig->GetTGsCore1(); i++) { assert (m_pTG[i]); m_pTG[i]->getSamples (m_OutputLevel[i], nFrames); @@ -1181,9 +1253,10 @@ void CMiniDexed::ProcessSound (void) // Audio signal path after tone generators starts here // - assert (CConfig::ToneGenerators == 8); - if (m_bQuadDAC8Chan) { + // This is only supported when there are 8 TGs + assert (m_nToneGenerators == 8); + // No mixing is performed by MiniDexed, sound is output in 8 channels. // Note: one TG per audio channel; output=mono; no processing. const int Channels = 8; // One TG per channel @@ -1233,7 +1306,7 @@ void CMiniDexed::ProcessSound (void) if(nMasterVolume > 0.0) { - for (uint8_t i = 0; i < CConfig::ToneGenerators; i++) + for (uint8_t i = 0; i < m_nToneGenerators; i++) { tg_mixer->doAddMix(i,m_OutputLevel[i]); reverb_send_mixer->doAddMix(i,m_OutputLevel[i]); @@ -1358,7 +1431,7 @@ bool CMiniDexed::SavePerformance (bool bSaveAsDeault) bool CMiniDexed::DoSavePerformance (void) { - for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++) + for (unsigned nTG = 0; nTG < CConfig::AllToneGenerators; nTG++) { m_PerformanceConfig.SetBankNumber (m_nVoiceBankID[nTG], nTG); m_PerformanceConfig.SetVoiceNumber (m_nProgram[nTG], nTG); @@ -1377,8 +1450,14 @@ bool CMiniDexed::DoSavePerformance (void) m_PerformanceConfig.SetNoteLimitLow (m_nNoteLimitLow[nTG], nTG); m_PerformanceConfig.SetNoteLimitHigh (m_nNoteLimitHigh[nTG], nTG); m_PerformanceConfig.SetNoteShift (m_nNoteShift[nTG], nTG); - m_pTG[nTG]->getVoiceData(m_nRawVoiceData); - m_PerformanceConfig.SetVoiceDataToTxt (m_nRawVoiceData, nTG); + if (nTG < m_pConfig->GetToneGenerators()) + { + m_pTG[nTG]->getVoiceData(m_nRawVoiceData); + } else { + // Not an active TG so provide default voice by asking for an invalid voice ID. + m_SysExFileLoader.GetVoice(CSysExFileLoader::MaxVoiceBankID, CSysExFileLoader::VoicesPerBank+1, m_nRawVoiceData); + } + m_PerformanceConfig.SetVoiceDataToTxt (m_nRawVoiceData, nTG); m_PerformanceConfig.SetMonoMode (m_bMonoMode[nTG], nTG); m_PerformanceConfig.SetModulationWheelRange (m_nModulationWheelRange[nTG], nTG); @@ -1412,7 +1491,9 @@ bool CMiniDexed::DoSavePerformance (void) void CMiniDexed::setMonoMode(uint8_t mono, uint8_t nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + assert (m_pTG[nTG]); m_bMonoMode[nTG]= mono != 0; m_pTG[nTG]->setMonoMode(constrain(mono, 0, 1)); @@ -1423,7 +1504,9 @@ void CMiniDexed::setMonoMode(uint8_t mono, uint8_t nTG) void CMiniDexed::setPitchbendRange(uint8_t range, uint8_t nTG) { range = constrain (range, 0, 12); - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + assert (m_pTG[nTG]); m_nPitchBendRange[nTG] = range; @@ -1435,7 +1518,9 @@ void CMiniDexed::setPitchbendRange(uint8_t range, uint8_t nTG) void CMiniDexed::setPitchbendStep(uint8_t step, uint8_t nTG) { step= constrain (step, 0, 12); - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + assert (m_pTG[nTG]); m_nPitchBendStep[nTG] = step; @@ -1448,7 +1533,9 @@ void CMiniDexed::setPortamentoMode(uint8_t mode, uint8_t nTG) { mode= constrain (mode, 0, 1); - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + assert (m_pTG[nTG]); m_nPortamentoMode[nTG] = mode; @@ -1460,7 +1547,9 @@ void CMiniDexed::setPortamentoMode(uint8_t mode, uint8_t nTG) void CMiniDexed::setPortamentoGlissando(uint8_t glissando, uint8_t nTG) { glissando = constrain (glissando, 0, 1); - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + assert (m_pTG[nTG]); m_nPortamentoGlissando[nTG] = glissando; @@ -1472,7 +1561,9 @@ void CMiniDexed::setPortamentoGlissando(uint8_t glissando, uint8_t nTG) void CMiniDexed::setPortamentoTime(uint8_t time, uint8_t nTG) { time = constrain (time, 0, 99); - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + assert (m_pTG[nTG]); m_nPortamentoTime[nTG] = time; @@ -1483,7 +1574,9 @@ void CMiniDexed::setPortamentoTime(uint8_t time, uint8_t nTG) void CMiniDexed::setModWheelRange(uint8_t range, uint8_t nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + assert (m_pTG[nTG]); m_nModulationWheelRange[nTG] = range; @@ -1496,7 +1589,9 @@ void CMiniDexed::setModWheelRange(uint8_t range, uint8_t nTG) void CMiniDexed::setModWheelTarget(uint8_t target, uint8_t nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + assert (m_pTG[nTG]); m_nModulationWheelTarget[nTG] = target; @@ -1508,7 +1603,9 @@ void CMiniDexed::setModWheelTarget(uint8_t target, uint8_t nTG) void CMiniDexed::setFootControllerRange(uint8_t range, uint8_t nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + assert (m_pTG[nTG]); m_nFootControlRange[nTG]=range; @@ -1521,7 +1618,9 @@ void CMiniDexed::setFootControllerRange(uint8_t range, uint8_t nTG) void CMiniDexed::setFootControllerTarget(uint8_t target, uint8_t nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + assert (m_pTG[nTG]); m_nFootControlTarget[nTG] = target; @@ -1533,7 +1632,9 @@ void CMiniDexed::setFootControllerTarget(uint8_t target, uint8_t nTG) void CMiniDexed::setBreathControllerRange(uint8_t range, uint8_t nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + assert (m_pTG[nTG]); m_nBreathControlRange[nTG]=range; @@ -1546,7 +1647,9 @@ void CMiniDexed::setBreathControllerRange(uint8_t range, uint8_t nTG) void CMiniDexed::setBreathControllerTarget(uint8_t target, uint8_t nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + assert (m_pTG[nTG]); m_nBreathControlTarget[nTG]=target; @@ -1558,7 +1661,9 @@ void CMiniDexed::setBreathControllerTarget(uint8_t target, uint8_t nTG) void CMiniDexed::setAftertouchRange(uint8_t range, uint8_t nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + assert (m_pTG[nTG]); m_nAftertouchRange[nTG]=range; @@ -1571,7 +1676,9 @@ void CMiniDexed::setAftertouchRange(uint8_t range, uint8_t nTG) void CMiniDexed::setAftertouchTarget(uint8_t target, uint8_t nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + assert (m_pTG[nTG]); m_nAftertouchTarget[nTG]=target; @@ -1583,7 +1690,9 @@ void CMiniDexed::setAftertouchTarget(uint8_t target, uint8_t nTG) void CMiniDexed::loadVoiceParameters(const uint8_t* data, uint8_t nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + assert (m_pTG[nTG]); uint8_t voice[161]; @@ -1604,7 +1713,9 @@ void CMiniDexed::loadVoiceParameters(const uint8_t* data, uint8_t nTG) void CMiniDexed::setVoiceDataElement(uint8_t data, uint8_t number, uint8_t nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + assert (m_pTG[nTG]); m_pTG[nTG]->setVoiceDataElement(constrain(data, 0, 155),constrain(number, 0, 99)); @@ -1614,7 +1725,9 @@ void CMiniDexed::setVoiceDataElement(uint8_t data, uint8_t number, uint8_t nTG) int16_t CMiniDexed::checkSystemExclusive(const uint8_t* pMessage,const uint16_t nLength, uint8_t nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return 0; // Not an active TG + assert (m_pTG[nTG]); return(m_pTG[nTG]->checkSystemExclusive(pMessage, nLength)); @@ -1625,10 +1738,17 @@ void CMiniDexed::getSysExVoiceDump(uint8_t* dest, uint8_t nTG) uint8_t checksum = 0; uint8_t data[155]; - assert (nTG < CConfig::ToneGenerators); - assert (m_pTG[nTG]); - - m_pTG[nTG]->getVoiceData(data); + assert (nTG < CConfig::AllToneGenerators); + if (nTG < m_nToneGenerators) + { + assert (m_pTG[nTG]); + m_pTG[nTG]->getVoiceData(data); + } + else + { + // Not an active TG so grab a default voice + m_SysExFileLoader.GetVoice(CSysExFileLoader::MaxVoiceBankID, CSysExFileLoader::VoicesPerBank+1, data); + } dest[0] = 0xF0; // SysEx start dest[1] = 0x43; // ID=Yamaha @@ -1791,7 +1911,7 @@ bool CMiniDexed::DoSavePerformanceNewFile (void) void CMiniDexed::LoadPerformanceParameters(void) { - for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++) + for (unsigned nTG = 0; nTG < CConfig::AllToneGenerators; nTG++) { BankSelect (m_PerformanceConfig.GetBankNumber (nTG), nTG); @@ -1865,7 +1985,9 @@ bool CMiniDexed::IsValidPerformanceBank(unsigned nBankID) void CMiniDexed::SetVoiceName (std::string VoiceName, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + assert (m_pTG[nTG]); char Name[11]; strncpy(Name, VoiceName.c_str(),10); diff --git a/src/minidexed.h b/src/minidexed.h index 6e5e012..69dcf9c 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -230,7 +230,7 @@ public: private: int16_t ApplyNoteLimits (int16_t pitch, unsigned nTG); // returns < 0 to ignore note - uint8_t m_uchOPMask[CConfig::ToneGenerators]; + uint8_t m_uchOPMask[CConfig::AllToneGenerators]; void LoadPerformanceParameters(void); void ProcessSound (void); @@ -249,41 +249,44 @@ private: CConfig *m_pConfig; int m_nParameter[ParameterUnknown]; // global (non-TG) parameters + + unsigned m_nToneGenerators; + unsigned m_nPolyphony; - CDexedAdapter *m_pTG[CConfig::ToneGenerators]; + CDexedAdapter *m_pTG[CConfig::AllToneGenerators]; - unsigned m_nVoiceBankID[CConfig::ToneGenerators]; - unsigned m_nVoiceBankIDMSB[CConfig::ToneGenerators]; + unsigned m_nVoiceBankID[CConfig::AllToneGenerators]; + unsigned m_nVoiceBankIDMSB[CConfig::AllToneGenerators]; unsigned m_nVoiceBankIDPerformance; unsigned m_nVoiceBankIDMSBPerformance; - unsigned m_nProgram[CConfig::ToneGenerators]; - unsigned m_nVolume[CConfig::ToneGenerators]; - unsigned m_nPan[CConfig::ToneGenerators]; - int m_nMasterTune[CConfig::ToneGenerators]; - int m_nCutoff[CConfig::ToneGenerators]; - int m_nResonance[CConfig::ToneGenerators]; - unsigned m_nMIDIChannel[CConfig::ToneGenerators]; - unsigned m_nPitchBendRange[CConfig::ToneGenerators]; - unsigned m_nPitchBendStep[CConfig::ToneGenerators]; - unsigned m_nPortamentoMode[CConfig::ToneGenerators]; - unsigned m_nPortamentoGlissando[CConfig::ToneGenerators]; - unsigned m_nPortamentoTime[CConfig::ToneGenerators]; - bool m_bMonoMode[CConfig::ToneGenerators]; + unsigned m_nProgram[CConfig::AllToneGenerators]; + unsigned m_nVolume[CConfig::AllToneGenerators]; + unsigned m_nPan[CConfig::AllToneGenerators]; + int m_nMasterTune[CConfig::AllToneGenerators]; + int m_nCutoff[CConfig::AllToneGenerators]; + int m_nResonance[CConfig::AllToneGenerators]; + unsigned m_nMIDIChannel[CConfig::AllToneGenerators]; + unsigned m_nPitchBendRange[CConfig::AllToneGenerators]; + unsigned m_nPitchBendStep[CConfig::AllToneGenerators]; + unsigned m_nPortamentoMode[CConfig::AllToneGenerators]; + unsigned m_nPortamentoGlissando[CConfig::AllToneGenerators]; + unsigned m_nPortamentoTime[CConfig::AllToneGenerators]; + bool m_bMonoMode[CConfig::AllToneGenerators]; - unsigned m_nModulationWheelRange[CConfig::ToneGenerators]; - unsigned m_nModulationWheelTarget[CConfig::ToneGenerators]; - unsigned m_nFootControlRange[CConfig::ToneGenerators]; - unsigned m_nFootControlTarget[CConfig::ToneGenerators]; - unsigned m_nBreathControlRange[CConfig::ToneGenerators]; - unsigned m_nBreathControlTarget[CConfig::ToneGenerators]; - unsigned m_nAftertouchRange[CConfig::ToneGenerators]; - unsigned m_nAftertouchTarget[CConfig::ToneGenerators]; + unsigned m_nModulationWheelRange[CConfig::AllToneGenerators]; + unsigned m_nModulationWheelTarget[CConfig::AllToneGenerators]; + unsigned m_nFootControlRange[CConfig::AllToneGenerators]; + unsigned m_nFootControlTarget[CConfig::AllToneGenerators]; + unsigned m_nBreathControlRange[CConfig::AllToneGenerators]; + unsigned m_nBreathControlTarget[CConfig::AllToneGenerators]; + unsigned m_nAftertouchRange[CConfig::AllToneGenerators]; + unsigned m_nAftertouchTarget[CConfig::AllToneGenerators]; - unsigned m_nNoteLimitLow[CConfig::ToneGenerators]; - unsigned m_nNoteLimitHigh[CConfig::ToneGenerators]; - int m_nNoteShift[CConfig::ToneGenerators]; + unsigned m_nNoteLimitLow[CConfig::AllToneGenerators]; + unsigned m_nNoteLimitHigh[CConfig::AllToneGenerators]; + int m_nNoteShift[CConfig::AllToneGenerators]; - unsigned m_nReverbSend[CConfig::ToneGenerators]; + unsigned m_nReverbSend[CConfig::AllToneGenerators]; uint8_t m_nRawVoiceData[156]; @@ -305,18 +308,18 @@ private: unsigned m_nQueueSizeFrames; #ifdef ARM_ALLOW_MULTI_CORE - unsigned m_nActiveTGsLog2; +// unsigned m_nActiveTGsLog2; volatile TCoreStatus m_CoreStatus[CORES]; volatile unsigned m_nFramesToProcess; - float32_t m_OutputLevel[CConfig::ToneGenerators][CConfig::MaxChunkSize]; + float32_t m_OutputLevel[CConfig::AllToneGenerators][CConfig::MaxChunkSize]; #endif CPerformanceTimer m_GetChunkTimer; bool m_bProfileEnabled; AudioEffectPlateReverb* reverb; - AudioStereoMixer* tg_mixer; - AudioStereoMixer* reverb_send_mixer; + AudioStereoMixer* tg_mixer; + AudioStereoMixer* reverb_send_mixer; CSpinLock m_ReverbSpinLock; diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index 8cd6275..8a182e7 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -45,8 +45,20 @@ CPerformanceConfig::~CPerformanceConfig (void) { } -bool CPerformanceConfig::Init (void) +bool CPerformanceConfig::Init (unsigned nToneGenerators) { + // Different versions of Pi allow different TG configurations. + // On loading, performances will load up to the number of + // supported/active TGs. + // + // On saving, the active/supported number of TGs is used. + // + // This means that if an 8TG performance is loaded into + // a 16 TG system and then saved, the saved performance + // will include all 16 TG configurations. + // + m_nToneGenerators = nToneGenerators; + // Check intermal performance directory exists DIR Directory; FRESULT Result; @@ -95,7 +107,7 @@ bool CPerformanceConfig::Load (void) bool bResult = false; - for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++) + for (unsigned nTG = 0; nTG < CConfig::AllToneGenerators; nTG++) { CString PropertyName; @@ -110,7 +122,7 @@ bool CPerformanceConfig::Load (void) } PropertyName.Format ("MIDIChannel%u", nTG+1); - unsigned nMIDIChannel = m_Properties.GetNumber (PropertyName, 255); + unsigned nMIDIChannel = m_Properties.GetNumber (PropertyName, 0); if (nMIDIChannel == 0) { m_nMIDIChannel[nTG] = CMIDIDevice::Disabled; @@ -217,7 +229,7 @@ bool CPerformanceConfig::Save (void) { m_Properties.RemoveAll (); - for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++) + for (unsigned nTG = 0; nTG < m_nToneGenerators; nTG++) { CString PropertyName; @@ -333,145 +345,145 @@ bool CPerformanceConfig::Save (void) unsigned CPerformanceConfig::GetBankNumber (unsigned nTG) const { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); return m_nBankNumber[nTG]; } unsigned CPerformanceConfig::GetVoiceNumber (unsigned nTG) const { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); return m_nVoiceNumber[nTG]; } unsigned CPerformanceConfig::GetMIDIChannel (unsigned nTG) const { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); return m_nMIDIChannel[nTG]; } unsigned CPerformanceConfig::GetVolume (unsigned nTG) const { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); return m_nVolume[nTG]; } unsigned CPerformanceConfig::GetPan (unsigned nTG) const { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); return m_nPan[nTG]; } int CPerformanceConfig::GetDetune (unsigned nTG) const { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); return m_nDetune[nTG]; } unsigned CPerformanceConfig::GetCutoff (unsigned nTG) const { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); return m_nCutoff[nTG]; } unsigned CPerformanceConfig::GetResonance (unsigned nTG) const { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); return m_nResonance[nTG]; } unsigned CPerformanceConfig::GetNoteLimitLow (unsigned nTG) const { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); return m_nNoteLimitLow[nTG]; } unsigned CPerformanceConfig::GetNoteLimitHigh (unsigned nTG) const { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); return m_nNoteLimitHigh[nTG]; } int CPerformanceConfig::GetNoteShift (unsigned nTG) const { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); return m_nNoteShift[nTG]; } unsigned CPerformanceConfig::GetReverbSend (unsigned nTG) const { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); return m_nReverbSend[nTG]; } void CPerformanceConfig::SetBankNumber (unsigned nValue, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); m_nBankNumber[nTG] = nValue; } void CPerformanceConfig::SetVoiceNumber (unsigned nValue, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); m_nVoiceNumber[nTG] = nValue; } void CPerformanceConfig::SetMIDIChannel (unsigned nValue, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); m_nMIDIChannel[nTG] = nValue; } void CPerformanceConfig::SetVolume (unsigned nValue, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); m_nVolume[nTG] = nValue; } void CPerformanceConfig::SetPan (unsigned nValue, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); m_nPan[nTG] = nValue; } void CPerformanceConfig::SetDetune (int nValue, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); m_nDetune[nTG] = nValue; } void CPerformanceConfig::SetCutoff (unsigned nValue, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); m_nCutoff[nTG] = nValue; } void CPerformanceConfig::SetResonance (unsigned nValue, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); m_nResonance[nTG] = nValue; } void CPerformanceConfig::SetNoteLimitLow (unsigned nValue, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); m_nNoteLimitLow[nTG] = nValue; } void CPerformanceConfig::SetNoteLimitHigh (unsigned nValue, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); m_nNoteLimitHigh[nTG] = nValue; } void CPerformanceConfig::SetNoteShift (int nValue, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); m_nNoteShift[nTG] = nValue; } void CPerformanceConfig::SetReverbSend (unsigned nValue, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); m_nReverbSend[nTG] = nValue; } @@ -557,71 +569,71 @@ void CPerformanceConfig::SetReverbLevel (unsigned nValue) // Pitch bender and portamento: void CPerformanceConfig::SetPitchBendRange (unsigned nValue, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); m_nPitchBendRange[nTG] = nValue; } unsigned CPerformanceConfig::GetPitchBendRange (unsigned nTG) const { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); return m_nPitchBendRange[nTG]; } void CPerformanceConfig::SetPitchBendStep (unsigned nValue, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); m_nPitchBendStep[nTG] = nValue; } unsigned CPerformanceConfig::GetPitchBendStep (unsigned nTG) const { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); return m_nPitchBendStep[nTG]; } void CPerformanceConfig::SetPortamentoMode (unsigned nValue, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); m_nPortamentoMode[nTG] = nValue; } unsigned CPerformanceConfig::GetPortamentoMode (unsigned nTG) const { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); return m_nPortamentoMode[nTG]; } void CPerformanceConfig::SetPortamentoGlissando (unsigned nValue, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); m_nPortamentoGlissando[nTG] = nValue; } unsigned CPerformanceConfig::GetPortamentoGlissando (unsigned nTG) const { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); return m_nPortamentoGlissando[nTG]; } void CPerformanceConfig::SetPortamentoTime (unsigned nValue, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); m_nPortamentoTime[nTG] = nValue; } unsigned CPerformanceConfig::GetPortamentoTime (unsigned nTG) const { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); return m_nPortamentoTime[nTG]; } void CPerformanceConfig::SetMonoMode (bool bValue, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); m_bMonoMode[nTG] = bValue; } @@ -632,103 +644,103 @@ bool CPerformanceConfig::GetMonoMode (unsigned nTG) const void CPerformanceConfig::SetModulationWheelRange (unsigned nValue, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); m_nModulationWheelRange[nTG] = nValue; } unsigned CPerformanceConfig::GetModulationWheelRange (unsigned nTG) const { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); return m_nModulationWheelRange[nTG]; } void CPerformanceConfig::SetModulationWheelTarget (unsigned nValue, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); m_nModulationWheelTarget[nTG] = nValue; } unsigned CPerformanceConfig::GetModulationWheelTarget (unsigned nTG) const { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); return m_nModulationWheelTarget[nTG]; } void CPerformanceConfig::SetFootControlRange (unsigned nValue, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); m_nFootControlRange[nTG] = nValue; } unsigned CPerformanceConfig::GetFootControlRange (unsigned nTG) const { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); return m_nFootControlRange[nTG]; } void CPerformanceConfig::SetFootControlTarget (unsigned nValue, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); m_nFootControlTarget[nTG] = nValue; } unsigned CPerformanceConfig::GetFootControlTarget (unsigned nTG) const { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); return m_nFootControlTarget[nTG]; } void CPerformanceConfig::SetBreathControlRange (unsigned nValue, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); m_nBreathControlRange[nTG] = nValue; } unsigned CPerformanceConfig::GetBreathControlRange (unsigned nTG) const { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); return m_nBreathControlRange[nTG]; } void CPerformanceConfig::SetBreathControlTarget (unsigned nValue, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); m_nBreathControlTarget[nTG] = nValue; } unsigned CPerformanceConfig::GetBreathControlTarget (unsigned nTG) const { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); return m_nBreathControlTarget[nTG]; } void CPerformanceConfig::SetAftertouchRange (unsigned nValue, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); m_nAftertouchRange[nTG] = nValue; } unsigned CPerformanceConfig::GetAftertouchRange (unsigned nTG) const { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); return m_nAftertouchRange[nTG]; } void CPerformanceConfig::SetAftertouchTarget (unsigned nValue, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); m_nAftertouchTarget[nTG] = nValue; } unsigned CPerformanceConfig::GetAftertouchTarget (unsigned nTG) const { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); return m_nAftertouchTarget[nTG]; } void CPerformanceConfig::SetVoiceDataToTxt (const uint8_t *pData, unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); m_nVoiceDataTxt[nTG] = ""; char nDtoH[]="0123456789ABCDEF"; for (int i = 0; i < NUM_VOICE_PARAM; i++) @@ -744,7 +756,7 @@ void CPerformanceConfig::SetVoiceDataToTxt (const uint8_t *pData, unsigned nTG) uint8_t *CPerformanceConfig::GetVoiceDataFromTxt (unsigned nTG) { - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); static uint8_t pData[NUM_VOICE_PARAM]; std::string nHtoD="0123456789ABCDEF"; diff --git a/src/performanceconfig.h b/src/performanceconfig.h index 0d50daa..c9c4b27 100644 --- a/src/performanceconfig.h +++ b/src/performanceconfig.h @@ -36,7 +36,7 @@ public: CPerformanceConfig (FATFS *pFileSystem); ~CPerformanceConfig (void); - bool Init (void); + bool Init (unsigned nToneGenerators); bool Load (void); @@ -151,35 +151,37 @@ public: private: CPropertiesFatFsFile m_Properties; - - unsigned m_nBankNumber[CConfig::ToneGenerators]; - unsigned m_nVoiceNumber[CConfig::ToneGenerators]; - unsigned m_nMIDIChannel[CConfig::ToneGenerators]; - unsigned m_nVolume[CConfig::ToneGenerators]; - unsigned m_nPan[CConfig::ToneGenerators]; - int m_nDetune[CConfig::ToneGenerators]; - unsigned m_nCutoff[CConfig::ToneGenerators]; - unsigned m_nResonance[CConfig::ToneGenerators]; - unsigned m_nNoteLimitLow[CConfig::ToneGenerators]; - unsigned m_nNoteLimitHigh[CConfig::ToneGenerators]; - int m_nNoteShift[CConfig::ToneGenerators]; - int m_nReverbSend[CConfig::ToneGenerators]; - unsigned m_nPitchBendRange[CConfig::ToneGenerators]; - unsigned m_nPitchBendStep[CConfig::ToneGenerators]; - unsigned m_nPortamentoMode[CConfig::ToneGenerators]; - unsigned m_nPortamentoGlissando[CConfig::ToneGenerators]; - unsigned m_nPortamentoTime[CConfig::ToneGenerators]; - std::string m_nVoiceDataTxt[CConfig::ToneGenerators]; - bool m_bMonoMode[CConfig::ToneGenerators]; - - unsigned m_nModulationWheelRange[CConfig::ToneGenerators]; - unsigned m_nModulationWheelTarget[CConfig::ToneGenerators]; - unsigned m_nFootControlRange[CConfig::ToneGenerators]; - unsigned m_nFootControlTarget[CConfig::ToneGenerators]; - unsigned m_nBreathControlRange[CConfig::ToneGenerators]; - unsigned m_nBreathControlTarget[CConfig::ToneGenerators]; - unsigned m_nAftertouchRange[CConfig::ToneGenerators]; - unsigned m_nAftertouchTarget[CConfig::ToneGenerators]; + + unsigned m_nToneGenerators; + + unsigned m_nBankNumber[CConfig::AllToneGenerators]; + unsigned m_nVoiceNumber[CConfig::AllToneGenerators]; + unsigned m_nMIDIChannel[CConfig::AllToneGenerators]; + unsigned m_nVolume[CConfig::AllToneGenerators]; + unsigned m_nPan[CConfig::AllToneGenerators]; + int m_nDetune[CConfig::AllToneGenerators]; + unsigned m_nCutoff[CConfig::AllToneGenerators]; + unsigned m_nResonance[CConfig::AllToneGenerators]; + unsigned m_nNoteLimitLow[CConfig::AllToneGenerators]; + unsigned m_nNoteLimitHigh[CConfig::AllToneGenerators]; + int m_nNoteShift[CConfig::AllToneGenerators]; + int m_nReverbSend[CConfig::AllToneGenerators]; + unsigned m_nPitchBendRange[CConfig::AllToneGenerators]; + unsigned m_nPitchBendStep[CConfig::AllToneGenerators]; + unsigned m_nPortamentoMode[CConfig::AllToneGenerators]; + unsigned m_nPortamentoGlissando[CConfig::AllToneGenerators]; + unsigned m_nPortamentoTime[CConfig::AllToneGenerators]; + std::string m_nVoiceDataTxt[CConfig::AllToneGenerators]; + bool m_bMonoMode[CConfig::AllToneGenerators]; + + unsigned m_nModulationWheelRange[CConfig::AllToneGenerators]; + unsigned m_nModulationWheelTarget[CConfig::AllToneGenerators]; + unsigned m_nFootControlRange[CConfig::AllToneGenerators]; + unsigned m_nFootControlTarget[CConfig::AllToneGenerators]; + unsigned m_nBreathControlRange[CConfig::AllToneGenerators]; + unsigned m_nBreathControlTarget[CConfig::AllToneGenerators]; + unsigned m_nAftertouchRange[CConfig::AllToneGenerators]; + unsigned m_nAftertouchTarget[CConfig::AllToneGenerators]; unsigned m_nLastPerformance; unsigned m_nActualPerformance = 0; diff --git a/src/sysexfileloader.cpp b/src/sysexfileloader.cpp index ea5ba5c..6b83f5b 100644 --- a/src/sysexfileloader.cpp +++ b/src/sysexfileloader.cpp @@ -273,6 +273,23 @@ std::string CSysExFileLoader::GetBankName (unsigned nBankID) return "NO NAME"; } +std::string CSysExFileLoader::GetVoiceName (unsigned nBankID, unsigned nVoiceID) +{ + if ((nBankID <= MaxVoiceBankID) && (nVoiceID < VoicesPerBank)) + { + if (IsValidBank(nBankID)) + { + // The name is the last 10 characters of the voice data + char sVoiceName[11]; + strncpy (sVoiceName, (char *)((char *)&(m_pVoiceBank[nBankID]->Voice[nVoiceID]) + SizePackedVoice - 10), 10); + sVoiceName[10] = 0; + std::string result(sVoiceName); + return result; + } + } + return "INIT VOICE"; +} + unsigned CSysExFileLoader::GetNextBankUp (unsigned nBankID) { // Find the next loaded bank "up" from the provided bank ID diff --git a/src/sysexfileloader.h b/src/sysexfileloader.h index 4918db6..272d775 100644 --- a/src/sysexfileloader.h +++ b/src/sysexfileloader.h @@ -60,6 +60,7 @@ public: void Load (bool bHeaderlessSysExVoices = false); std::string GetBankName (unsigned nBankID); // 0 .. MaxVoiceBankID + std::string GetVoiceName (unsigned nBankID, unsigned nVoice); // 0 .. MaxVoiceBankID, 0 .. VoicesPerBank-1 unsigned GetNumHighestBank (); // 0 .. MaxVoiceBankID bool IsValidBank (unsigned nBankID); unsigned GetNextBankUp (unsigned nBankID); diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 82a426a..8b72425 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -51,6 +51,16 @@ const CUIMenu::TMenuItem CUIMenu::s_MainMenu[] = {"TG6", MenuHandler, s_TGMenu, 5}, {"TG7", MenuHandler, s_TGMenu, 6}, {"TG8", MenuHandler, s_TGMenu, 7}, +#if (RASPPI==4 || RASPPI==5) + {"TG9", MenuHandler, s_TGMenu, 8}, + {"TG10", MenuHandler, s_TGMenu, 9}, + {"TG11", MenuHandler, s_TGMenu, 10}, + {"TG12", MenuHandler, s_TGMenu, 11}, + {"TG13", MenuHandler, s_TGMenu, 12}, + {"TG14", MenuHandler, s_TGMenu, 13}, + {"TG15", MenuHandler, s_TGMenu, 14}, + {"TG16", MenuHandler, s_TGMenu, 15}, +#endif #endif {"Effects", MenuHandler, s_EffectsMenu}, {"Performance", MenuHandler, s_PerformanceMenu}, @@ -334,9 +344,10 @@ const CUIMenu::TMenuItem CUIMenu::s_PerformanceMenu[] = }; -CUIMenu::CUIMenu (CUserInterface *pUI, CMiniDexed *pMiniDexed) +CUIMenu::CUIMenu (CUserInterface *pUI, CMiniDexed *pMiniDexed, CConfig *pConfig) : m_pUI (pUI), m_pMiniDexed (pMiniDexed), + m_pConfig (pConfig), m_pParentMenu (s_MenuRoot), m_pCurrentMenu (s_MainMenu), m_nCurrentMenuItem (0), @@ -344,23 +355,27 @@ CUIMenu::CUIMenu (CUserInterface *pUI, CMiniDexed *pMiniDexed) m_nCurrentParameter (0), m_nCurrentMenuDepth (0) { -#ifndef ARM_ALLOW_MULTI_CORE - // If there is just one core, then there is only a single - // tone generator so start on the TG1 menu... - m_pParentMenu = s_MainMenu; - m_pCurrentMenu = s_TGMenu; - m_nCurrentMenuItem = 0; - m_nCurrentSelection = 0; - m_nCurrentParameter = 0; - m_nCurrentMenuDepth = 1; + assert (m_pConfig); + m_nToneGenerators = m_pConfig->GetToneGenerators(); - // Place the "root" menu at the top of the stack - m_MenuStackParent[0] = s_MenuRoot; - m_MenuStackMenu[0] = s_MainMenu; - m_nMenuStackItem[0] = 0; - m_nMenuStackSelection[0] = 0; - m_nMenuStackParameter[0] = 0; -#endif + if (m_nToneGenerators == 1) + { + // If there is just one core, then there is only a single + // tone generator so start on the TG1 menu... + m_pParentMenu = s_MainMenu; + m_pCurrentMenu = s_TGMenu; + m_nCurrentMenuItem = 0; + m_nCurrentSelection = 0; + m_nCurrentParameter = 0; + m_nCurrentMenuDepth = 1; + + // Place the "root" menu at the top of the stack + m_MenuStackParent[0] = s_MenuRoot; + m_MenuStackMenu[0] = s_MainMenu; + m_nMenuStackItem[0] = 0; + m_nMenuStackSelection[0] = 0; + m_nMenuStackParameter[0] = 0; + } } void CUIMenu::EventHandler (TMenuEvent Event) @@ -383,28 +398,31 @@ void CUIMenu::EventHandler (TMenuEvent Event) break; case MenuEventHome: -#ifdef ARM_ALLOW_MULTI_CORE - m_pParentMenu = s_MenuRoot; - m_pCurrentMenu = s_MainMenu; - m_nCurrentMenuItem = 0; - m_nCurrentSelection = 0; - m_nCurrentParameter = 0; - m_nCurrentMenuDepth = 0; -#else - // "Home" is the TG0 menu if only one TG active - m_pParentMenu = s_MainMenu; - m_pCurrentMenu = s_TGMenu; - m_nCurrentMenuItem = 0; - m_nCurrentSelection = 0; - m_nCurrentParameter = 0; - m_nCurrentMenuDepth = 1; - // Place the "root" menu at the top of the stack - m_MenuStackParent[0] = s_MenuRoot; - m_MenuStackMenu[0] = s_MainMenu; - m_nMenuStackItem[0] = 0; - m_nMenuStackSelection[0] = 0; - m_nMenuStackParameter[0] = 0; -#endif + if (m_nToneGenerators == 1) + { + // "Home" is the TG0 menu if only one TG active + m_pParentMenu = s_MainMenu; + m_pCurrentMenu = s_TGMenu; + m_nCurrentMenuItem = 0; + m_nCurrentSelection = 0; + m_nCurrentParameter = 0; + m_nCurrentMenuDepth = 1; + // Place the "root" menu at the top of the stack + m_MenuStackParent[0] = s_MenuRoot; + m_MenuStackMenu[0] = s_MainMenu; + m_nMenuStackItem[0] = 0; + m_nMenuStackSelection[0] = 0; + m_nMenuStackParameter[0] = 0; + } + else + { + m_pParentMenu = s_MenuRoot; + m_pCurrentMenu = s_MainMenu; + m_nCurrentMenuItem = 0; + m_nCurrentSelection = 0; + m_nCurrentParameter = 0; + m_nCurrentMenuDepth = 0; + } EventHandler (MenuEventUpdate); break; @@ -453,7 +471,30 @@ void CUIMenu::MenuHandler (CUIMenu *pUIMenu, TMenuEvent Event) break; case MenuEventStepDown: - if (pUIMenu->m_nCurrentSelection > 0) + if (pUIMenu->m_nCurrentSelection == 0) + { + // If in main mennu, wrap around + if (pUIMenu->m_pCurrentMenu == s_MainMenu) + { + // Find last entry with a name + while (pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection+1].Name) + { + pUIMenu->m_nCurrentSelection++; + } + } + } + else if (pUIMenu->m_nCurrentSelection > 0) + { + pUIMenu->m_nCurrentSelection--; + } + // Might need to trim menu if number of TGs is configured to be less than the maximum supported + while ((pUIMenu->m_pCurrentMenu == s_MainMenu) && (pUIMenu->m_nCurrentSelection > 0) && + ( // Skip any unused menus + (pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].MenuItem == s_TGMenu) && + (pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].Parameter >= pUIMenu->m_nToneGenerators) && + (pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].Parameter < CConfig::AllToneGenerators) + ) + ) { pUIMenu->m_nCurrentSelection--; } @@ -463,7 +504,27 @@ void CUIMenu::MenuHandler (CUIMenu *pUIMenu, TMenuEvent Event) ++pUIMenu->m_nCurrentSelection; if (!pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].Name) // more entries? { - pUIMenu->m_nCurrentSelection--; + if (pUIMenu->m_pCurrentMenu == s_MainMenu) + { + // If in main mennu, wrap around + pUIMenu->m_nCurrentSelection = 0; + } + else + { + // Return to last known good item + pUIMenu->m_nCurrentSelection--; + } + } + // Might need to trim menu if number of TGs is configured to be less than the maximum supported + while ((pUIMenu->m_pCurrentMenu == s_MainMenu) && (pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection+1].Name) && + ( // Skip any unused TG menus + (pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].MenuItem == s_TGMenu) && + (pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].Parameter >= pUIMenu->m_nToneGenerators) && + (pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].Parameter < CConfig::AllToneGenerators) + ) + ) + { + pUIMenu->m_nCurrentSelection++; } break; @@ -1151,7 +1212,7 @@ 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 (nTG < CConfig::AllToneGenerators); assert (m_nMenuStackItem[1] == nTG); assert (m_nMenuStackParameter[1] == nTG); @@ -1166,7 +1227,7 @@ void CUIMenu::TGShortcutHandler (TMenuEvent Event) nTG++; } - if (nTG < CConfig::ToneGenerators) + if (nTG < m_nToneGenerators) { m_nMenuStackSelection[0] = nTG; m_nMenuStackItem[1] = nTG; @@ -1262,51 +1323,53 @@ void CUIMenu::PgmUpDownHandler (TMenuEvent Event) if (m_MenuStackMenu[0] == s_MainMenu && (m_pCurrentMenu == s_TGMenu) || (m_MenuStackMenu[1] == s_TGMenu)) { nTG = m_nMenuStackSelection[0]; } - assert (nTG < CConfig::ToneGenerators); - - int nPgm = m_pMiniDexed->GetTGParameter (CMiniDexed::TGParameterProgram, nTG); - - assert (Event == MenuEventPgmDown || Event == MenuEventPgmUp); - if (Event == MenuEventPgmDown) + assert (nTG < CConfig::AllToneGenerators); + if (nTG < m_nToneGenerators) { - //LOGNOTE("PgmDown"); - if (--nPgm < 0) + int nPgm = m_pMiniDexed->GetTGParameter (CMiniDexed::TGParameterProgram, nTG); + + assert (Event == MenuEventPgmDown || Event == MenuEventPgmUp); + if (Event == MenuEventPgmDown) { - // 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); + //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); } - m_pMiniDexed->SetTGParameter (CMiniDexed::TGParameterProgram, nPgm, nTG); - } - else - { - //LOGNOTE("PgmUp"); - if (++nPgm > (int) CSysExFileLoader::VoicesPerBank-1) + else { - // 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); + //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); } - 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); + // 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); + } } } } @@ -1317,7 +1380,7 @@ 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) { + if (m_nToneGenerators <= 1) { // Nothing to do if only a single TG return; } @@ -1328,7 +1391,7 @@ void CUIMenu::TGUpDownHandler (TMenuEvent Event) nTG = m_nMenuStackSelection[0]; } - assert (nTG < CConfig::ToneGenerators); + assert (nTG < CConfig::AllToneGenerators); assert (Event == MenuEventTGDown || Event == MenuEventTGUp); if (Event == MenuEventTGDown) { @@ -1340,7 +1403,7 @@ void CUIMenu::TGUpDownHandler (TMenuEvent Event) else { //LOGNOTE("TGUp"); - if (nTG < CConfig::ToneGenerators - 1) { + if (nTG < m_nToneGenerators - 1) { nTG++; } } diff --git a/src/uimenu.h b/src/uimenu.h index d5b48dc..0034278 100644 --- a/src/uimenu.h +++ b/src/uimenu.h @@ -25,6 +25,7 @@ #include #include +#include "config.h" class CMiniDexed; class CUserInterface; @@ -53,7 +54,7 @@ public: }; public: - CUIMenu (CUserInterface *pUI, CMiniDexed *pMiniDexed); + CUIMenu (CUserInterface *pUI, CMiniDexed *pMiniDexed, CConfig *pConfig); void EventHandler (TMenuEvent Event); @@ -128,6 +129,9 @@ private: private: CUserInterface *m_pUI; CMiniDexed *m_pMiniDexed; + CConfig *m_pConfig; + + unsigned m_nToneGenerators; const TMenuItem *m_pParentMenu; const TMenuItem *m_pCurrentMenu; diff --git a/src/userinterface.cpp b/src/userinterface.cpp index 9e7c112..aa46f9e 100644 --- a/src/userinterface.cpp +++ b/src/userinterface.cpp @@ -38,7 +38,7 @@ CUserInterface::CUserInterface (CMiniDexed *pMiniDexed, CGPIOManager *pGPIOManag m_pUIButtons (0), m_pRotaryEncoder (0), m_bSwitchPressed (false), - m_Menu (this, pMiniDexed) + m_Menu (this, pMiniDexed, pConfig) { }