diff --git a/src/minidexed.cpp b/src/minidexed.cpp index b22ab12..66c6151 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -61,6 +61,7 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, for (unsigned i = 0; i < CConfig::ToneGenerators; i++) { m_nVoiceBankID[i] = 0; + m_nVoiceBankIDMSB[i] = 0; m_nProgram[i] = 0; m_nVolume[i] = 100; m_nPan[i] = 64; @@ -371,10 +372,9 @@ void CMiniDexed::BankSelect (unsigned nBank, unsigned nTG) assert (nTG < CConfig::ToneGenerators); - unsigned nHighestBank = GetSysExFileLoader ()->GetNumHighestBank(); - - if (nBank <= nHighestBank) + if (GetSysExFileLoader ()->IsValidBank(nBank)) { + // Only change if we have the bank loaded m_nVoiceBankID[nTG] = nBank; m_UI.ParameterChanged (); @@ -386,11 +386,14 @@ void CMiniDexed::BankSelectMSB (unsigned nBankMSB, unsigned nTG) nBankMSB=constrain((int)nBankMSB,0,127); assert (nTG < CConfig::ToneGenerators); - unsigned nBank = m_nVoiceBankID[nTG]; - unsigned nBankLSB = nBank & 0x7F; - nBank = (nBankMSB << 7) + nBankLSB; - - BankSelect(nBank, nTG); + // 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 + // the Bank Select pair." + // + // So it isn't possible to validate the selected bank ID until + // we receive both MSB and LSB so just store the MSB for now. + m_nVoiceBankIDMSB[nTG] = nBankMSB; } void CMiniDexed::BankSelectLSB (unsigned nBankLSB, unsigned nTG) @@ -399,9 +402,10 @@ void CMiniDexed::BankSelectLSB (unsigned nBankLSB, unsigned nTG) assert (nTG < CConfig::ToneGenerators); unsigned nBank = m_nVoiceBankID[nTG]; - unsigned nBankMSB = nBank >> 7; + unsigned nBankMSB = m_nVoiceBankIDMSB[nTG]; nBank = (nBankMSB << 7) + nBankLSB; + // Now should have both MSB and LSB so enable the BankSelect BankSelect(nBank, nTG); } diff --git a/src/minidexed.h b/src/minidexed.h index 895a733..8e8deaf 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -231,6 +231,7 @@ private: CDexedAdapter *m_pTG[CConfig::ToneGenerators]; unsigned m_nVoiceBankID[CConfig::ToneGenerators]; + unsigned m_nVoiceBankIDMSB[CConfig::ToneGenerators]; unsigned m_nProgram[CConfig::ToneGenerators]; unsigned m_nVolume[CConfig::ToneGenerators]; unsigned m_nPan[CConfig::ToneGenerators]; diff --git a/src/sysexfileloader.cpp b/src/sysexfileloader.cpp index 82d7a49..c50e9a3 100644 --- a/src/sysexfileloader.cpp +++ b/src/sysexfileloader.cpp @@ -192,6 +192,68 @@ std::string CSysExFileLoader::GetBankName (unsigned nBankID) return "NO NAME"; } +unsigned CSysExFileLoader::GetNextBankUp (unsigned nBankID) +{ + // Find the next loaded bank "up" from the provided bank ID + for (unsigned id=nBankID+1; id <= m_nNumHighestBank; id++) + { + if (IsValidBank(id)) + { + return id; + } + } + + // Handle wrap-around + for (unsigned id=0; id= 0; id--) + { + if (IsValidBank((unsigned)id)) + { + return id; + } + } + + // Handle wrap-around + for (unsigned id=m_nNumHighestBank; id>nBankID; id--) + { + if (IsValidBank(id)) + { + return id; + } + } + + // If we get here there are no other banks! + return nBankID; +} + +bool CSysExFileLoader::IsValidBank (unsigned nBankID) +{ + // Use a valid "status start/end" as an indicator of a loaded bank + if ((m_pVoiceBank[nBankID]->StatusStart == 0xF0) && + (m_pVoiceBank[nBankID]->StatusEnd == 0xF7)) + { + return true; + } + else + { + return false; + } +} + unsigned CSysExFileLoader::GetNumHighestBank (void) { return m_nNumHighestBank; diff --git a/src/sysexfileloader.h b/src/sysexfileloader.h index 9b78546..3c20d0f 100644 --- a/src/sysexfileloader.h +++ b/src/sysexfileloader.h @@ -58,6 +58,9 @@ public: std::string GetBankName (unsigned nBankID); // 0 .. MaxVoiceBankID unsigned GetNumHighestBank (); // 0 .. MaxVoiceBankID + bool IsValidBank (unsigned nBankID); + unsigned GetNextBankUp (unsigned nBankID); + unsigned GetNextBankDown (unsigned nBankID); void GetVoice (unsigned nBankID, // 0 .. MaxVoiceBankID unsigned nVoiceID, // 0 .. 31 diff --git a/src/uimenu.cpp b/src/uimenu.cpp index ba41dcc..bcea3e0 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -486,7 +486,6 @@ void CUIMenu::EditGlobalParameter (CUIMenu *pUIMenu, TMenuEvent Event) void CUIMenu::EditVoiceBankNumber (CUIMenu *pUIMenu, TMenuEvent Event) { unsigned nTG = pUIMenu->m_nMenuStackParameter[pUIMenu->m_nCurrentMenuDepth-1]; - int nHighestBank = pUIMenu->m_pMiniDexed->GetSysExFileLoader ()->GetNumHighestBank(); int nValue = pUIMenu->m_pMiniDexed->GetTGParameter (CMiniDexed::TGParameterVoiceBank, nTG); @@ -496,19 +495,13 @@ void CUIMenu::EditVoiceBankNumber (CUIMenu *pUIMenu, TMenuEvent Event) break; case MenuEventStepDown: - if (--nValue < 0) - { - nValue = 0; - } + nValue = pUIMenu->m_pMiniDexed->GetSysExFileLoader ()->GetNextBankDown(nValue); pUIMenu->m_pMiniDexed->SetTGParameter ( CMiniDexed::TGParameterVoiceBank, nValue, nTG); break; case MenuEventStepUp: - if (++nValue > (int) nHighestBank) - { - nValue = nHighestBank; - } + nValue = pUIMenu->m_pMiniDexed->GetSysExFileLoader ()->GetNextBankUp(nValue); pUIMenu->m_pMiniDexed->SetTGParameter ( CMiniDexed::TGParameterVoiceBank, nValue, nTG); break;