From 494005102baeb92e6fa5ef94a9038e40227c53fe Mon Sep 17 00:00:00 2001 From: Kevin <68612569+diyelectromusic@users.noreply.github.com> Date: Mon, 4 Dec 2023 13:36:26 -0800 Subject: [PATCH 01/15] Initial update in performance file handling. This change makes the 6-digit number in the filename indicate a performance "voice number" in MiniDexed. The external filename numbers will now match any Program Change messages using the common MIDI concept of user selecting 1..128 whilst internally they are treated as 0..127. Note: in the case of performances, performance 1 (index 0) is the Default "performance.ini" file for backwards compatibility. Also note that in this version, new performances, when saved, cannot occupy free slots between other performances - they are added to the end. Even though the filename standard gives 6 digit numbers, the actual number of performances is still limited to 256. --- src/minidexed.cpp | 10 ++- src/minidexed.h | 1 + src/performanceconfig.cpp | 160 ++++++++++++++++++++++++++------------ src/performanceconfig.h | 3 +- src/uimenu.cpp | 32 ++++++-- 5 files changed, 145 insertions(+), 61 deletions(-) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 71b72476..b11f8b44 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -489,10 +489,7 @@ void CMiniDexed::ProgramChangePerformance (unsigned nProgram) if (m_nParameter[ParameterPerformanceSelectChannel] != CMIDIDevice::Disabled) { // Program Change messages change Performances. - unsigned nLastPerformance = m_PerformanceConfig.GetLastPerformance(); - - // GetLastPerformance actually returns 1-indexed, number of performances - if (nProgram < nLastPerformance - 1) + if (m_PerformanceConfig.IsValidPerformance(nProgram)) { SetNewPerformance(nProgram); } @@ -1631,6 +1628,11 @@ void CMiniDexed::SetNewPerformanceName(std::string nName) m_PerformanceConfig.SetNewPerformanceName(nName); } +bool CMiniDexed::IsValidPerformance(unsigned nID) +{ + return m_PerformanceConfig.IsValidPerformance(nID); +} + void CMiniDexed::SetVoiceName (std::string VoiceName, unsigned nTG) { assert (nTG < CConfig::ToneGenerators); diff --git a/src/minidexed.h b/src/minidexed.h index 1aa30966..d56c228d 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -128,6 +128,7 @@ class CMiniDexed bool SavePerformance (bool bSaveAsDeault); unsigned GetPerformanceSelectChannel (void); void SetPerformanceSelectChannel (unsigned uCh); + bool IsValidPerformance(unsigned nID); // Must match the order in CUIMenu::TParameter enum TParameter diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index 853ccf51..1382f34f 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -28,8 +28,10 @@ LOGMODULE ("Performance"); +#define DEFAULT_PERFORMANCE_FILENAME "performance.ini" + CPerformanceConfig::CPerformanceConfig (FATFS *pFileSystem) -: m_Properties ("performance.ini", pFileSystem) +: m_Properties (DEFAULT_PERFORMANCE_FILENAME, pFileSystem) { m_pFileSystem = pFileSystem; } @@ -715,19 +717,44 @@ bool CPerformanceConfig::VoiceDataFilled(unsigned nTG) std::string CPerformanceConfig::GetPerformanceFileName(unsigned nID) { - return m_nPerformanceFileName[nID]; -} - -std::string CPerformanceConfig::GetPerformanceName(unsigned nID) -{ - if(nID == 0) // in order to assure retrocompatibility + assert (nID < NUM_PERFORMANCES); + std::string FileN = ""; + if (nID == 0) // in order to assure retrocompatibility { - return "Default"; + FileN += DEFAULT_PERFORMANCE_FILENAME; } else { - return m_nPerformanceFileName[nID].substr(0,m_nPerformanceFileName[nID].length()-4).substr(7,14); + // Build up from the index, "_", performance name, and ".ini" + // NB: Index on disk = index in memory + 1 + std::string nIndex = "000000"; + nIndex += std::to_string(nID+1); + nIndex = nIndex.substr(nIndex.length()-6,6); + FileN += nIndex; + FileN += "_"; + FileN += m_nPerformanceFileName[nID]; + FileN += ".ini"; + } + return FileN; +} + +std::string CPerformanceConfig::GetPerformanceFullFilePath(unsigned nID) +{ + assert (nID < NUM_PERFORMANCES); + std::string FileN = ""; + if (nID != 0) + { + FileN += PERFORMANCE_DIR; + FileN += "/"; } + FileN += GetPerformanceFileName(nID); + return FileN; +} + +std::string CPerformanceConfig::GetPerformanceName(unsigned nID) +{ + assert (nID < NUM_PERFORMANCES); + return m_nPerformanceFileName[nID]; } unsigned CPerformanceConfig::GetLastPerformance() @@ -742,6 +769,7 @@ unsigned CPerformanceConfig::GetActualPerformanceID() void CPerformanceConfig::SetActualPerformanceID(unsigned nID) { + assert (nID < NUM_PERFORMANCES); nActualPerformance = nID; } @@ -750,6 +778,20 @@ bool CPerformanceConfig::GetInternalFolderOk() return nInternalFolderOk; } +bool CPerformanceConfig::IsValidPerformance(unsigned nID) +{ + if (nID < NUM_PERFORMANCES) + { + if (!m_nPerformanceFileName[nID].empty()) + { + return true; + } + } + + return false; +} + + bool CPerformanceConfig::CheckFreePerformanceSlot(void) { if (nLastPerformance < NUM_PERFORMANCES) @@ -774,10 +816,11 @@ bool CPerformanceConfig::CreateNewPerformanceFile(void) std::string sPerformanceName = NewPerformanceName; NewPerformanceName=""; nActualPerformance=nLastPerformance; + unsigned nNewPerformance = nLastPerformance + 1; std::string nFileName; std::string nPath; std::string nIndex = "000000"; - nIndex += std::to_string(++nLastFileIndex); + nIndex += std::to_string(nNewPerformance+1); // Index on disk = index in memory+1 nIndex = nIndex.substr(nIndex.length()-6,6); @@ -793,7 +836,7 @@ bool CPerformanceConfig::CreateNewPerformanceFile(void) nFileName +=sPerformanceName.substr(0,14); } nFileName += ".ini"; - m_nPerformanceFileName[nLastPerformance]= nFileName; + m_nPerformanceFileName[nNewPerformance]= sPerformanceName; nPath = "SD:/" ; nPath += PERFORMANCE_DIR; @@ -804,17 +847,17 @@ bool CPerformanceConfig::CreateNewPerformanceFile(void) FRESULT Result = f_open (&File, nFileName.c_str(), FA_WRITE | FA_CREATE_ALWAYS); if (Result != FR_OK) { - m_nPerformanceFileName[nLastPerformance]=nullptr; + m_nPerformanceFileName[nNewPerformance]=nullptr; return false; } if (f_close (&File) != FR_OK) { - m_nPerformanceFileName[nLastPerformance]=nullptr; + m_nPerformanceFileName[nNewPerformance]=nullptr; return false; } - nLastPerformance++; + nLastPerformance = nNewPerformance; new (&m_Properties) CPropertiesFatFsFile(nFileName.c_str(), m_pFileSystem); return true; @@ -825,8 +868,7 @@ bool CPerformanceConfig::ListPerformances() nInternalFolderOk=false; nExternalFolderOk=false; // for future USB implementation nLastPerformance=0; - nLastFileIndex=0; - m_nPerformanceFileName[nLastPerformance++]="performance.ini"; // in order to assure retrocompatibility + m_nPerformanceFileName[0]="Default"; // in order to assure retrocompatibility unsigned nPIndex; DIR Directory; @@ -848,7 +890,7 @@ bool CPerformanceConfig::ListPerformances() if (nInternalFolderOk) { - Result = f_findfirst (&Directory, &FileInfo, "SD:/" PERFORMANCE_DIR, "*.ini"); + Result = f_findfirst (&Directory, &FileInfo, "SD:/" PERFORMANCE_DIR, "*.ini"); for (unsigned i = 0; Result == FR_OK && FileInfo.fname[0]; i++) { if (nLastPerformance >= NUM_PERFORMANCES) { @@ -856,31 +898,56 @@ bool CPerformanceConfig::ListPerformances() } else { if (!(FileInfo.fattrib & (AM_HID | AM_SYS))) { - std::string FileName = FileInfo.fname; - size_t nLen = FileName.length(); - if ( nLen > 8 && nLen <26 && strcmp(FileName.substr(6,1).c_str(), "_")==0) - { - nPIndex=stoi(FileName.substr(0,6)); - if(nPIndex > nLastFileIndex) + std::string OriFileName = FileInfo.fname; + size_t nLen = OriFileName.length(); + if ( nLen > 8 && nLen <26 && strcmp(OriFileName.substr(6,1).c_str(), "_")==0) + { + // Note: nLastPerformance - refers to the number (index) of the last performance in memory, + // which includes a default performance. + // + // Filenames on the disk start from 1 to match what the user might see in MIDI. + // So this means that actually file 000001_ will correspond to index position [0] + // which is the default performance. Consequently file-loaded performances + // will start from index position 000002. + // m_nPerformanceFileName[0] = default performance (file 000001) + // m_nPerformanceFileName[1] = first available on-disk performance (file 000002) + // + // Note2: filenames assume 6 digits, underscore, name, finally ".ini" + // i.e. 123456_Performance Name.ini + // + nPIndex=stoi(OriFileName.substr(0,6)); + if ((nPIndex < 2) || (nPIndex >= (NUM_PERFORMANCES+1))) { - nLastFileIndex=nPIndex; + // Index is out of range - skip to next file + continue; } + // Convert from "user facing" 1..indexed number to internal 0..indexed + nPIndex = nPIndex-1; + if (m_nPerformanceFileName[nPIndex].empty()) + { + if(nPIndex > nLastPerformance) + { + nLastPerformance=nPIndex; + } - m_nPerformanceFileName[nLastPerformance++]= FileName; + std::string FileName = OriFileName.substr(0,OriFileName.length()-4).substr(7,14); + + m_nPerformanceFileName[nPIndex] = FileName; + //LOGNOTE ("Loading performance %s (%d, %s)", OriFileName.c_str(), nPIndex, FileName.c_str()); + } + else + { + LOGNOTE ("Duplicate performance %s", OriFileName.c_str()); + } } } } Result = f_findnext (&Directory, &FileInfo); } - // sort by performance number-name - if (nLastPerformance > 2) - { - sort (m_nPerformanceFileName+1, m_nPerformanceFileName + nLastPerformance); // default is always on first place. %%%%%%%%%%%%%%%% - } } - LOGNOTE ("Number of Performances: %d", nLastPerformance); + LOGNOTE ("Last Performance: %d", nLastPerformance + 1); // Show "user facing" index return nInternalFolderOk; } @@ -888,22 +955,17 @@ bool CPerformanceConfig::ListPerformances() void CPerformanceConfig::SetNewPerformance (unsigned nID) { - nActualPerformance=nID; - std::string FileN = ""; - if (nID != 0) // in order to assure retrocompatibility - { - FileN += PERFORMANCE_DIR; - FileN += "/"; - } - FileN += m_nPerformanceFileName[nID]; - new (&m_Properties) CPropertiesFatFsFile(FileN.c_str(), m_pFileSystem); - + assert (nID < NUM_PERFORMANCES); + nActualPerformance=nID; + std::string FileN = GetPerformanceFullFilePath(nID); + + new (&m_Properties) CPropertiesFatFsFile(FileN.c_str(), m_pFileSystem); } std::string CPerformanceConfig::GetNewPerformanceDefaultName(void) { std::string nIndex = "000000"; - nIndex += std::to_string(nLastFileIndex+1); + nIndex += std::to_string(nLastPerformance+1+1); // Convert from internal 0.. index to a file-based 1.. index to show the user nIndex = nIndex.substr(nIndex.length()-6,6); return "Perf" + nIndex; } @@ -930,24 +992,24 @@ bool CPerformanceConfig::DeletePerformance(unsigned nID) std::string FileN = "SD:/"; FileN += PERFORMANCE_DIR; - - FRESULT Result = f_findfirst (&Directory, &FileInfo, FileN.c_str(), m_nPerformanceFileName[nID].c_str()); + FRESULT Result = f_findfirst (&Directory, &FileInfo, FileN.c_str(), GetPerformanceFileName(nID).c_str()); if (Result == FR_OK && FileInfo.fname[0]) { FileN += "/"; - FileN += m_nPerformanceFileName[nID]; + FileN += GetPerformanceFileName(nID); Result=f_unlink (FileN.c_str()); if (Result == FR_OK) { SetNewPerformance(0); nActualPerformance =0; //nMenuSelectedPerformance=0; - m_nPerformanceFileName[nID]="ZZZZZZ"; - sort (m_nPerformanceFileName+1, m_nPerformanceFileName + nLastPerformance); // test si va con -1 o no - --nLastPerformance; - m_nPerformanceFileName[nLastPerformance]=nullptr; + m_nPerformanceFileName[nID].clear(); bOK=true; } + else + { + LOGNOTE ("Failed to delete %s", FileN.c_str()); + } } return bOK; } diff --git a/src/performanceconfig.h b/src/performanceconfig.h index c151c7aa..1815e7c4 100644 --- a/src/performanceconfig.h +++ b/src/performanceconfig.h @@ -123,6 +123,7 @@ class CPerformanceConfig // Performance configuration //std::string m_DirName; void SetNewPerformance (unsigned nID); std::string GetPerformanceFileName(unsigned nID); + std::string GetPerformanceFullFilePath(unsigned nID); std::string GetPerformanceName(unsigned nID); unsigned GetLastPerformance(); void SetActualPerformanceID(unsigned nID); @@ -133,6 +134,7 @@ class CPerformanceConfig // Performance configuration void SetNewPerformanceName(std::string nName); bool DeletePerformance(unsigned nID); bool CheckFreePerformanceSlot(void); + bool IsValidPerformance(unsigned nID); private: CPropertiesFatFsFile m_Properties; @@ -167,7 +169,6 @@ class CPerformanceConfig // Performance configuration unsigned m_nAftertouchTarget[CConfig::ToneGenerators]; unsigned nLastPerformance; - unsigned nLastFileIndex; unsigned nActualPerformance = 0; //unsigned nMenuSelectedPerformance = 0; std::string m_nPerformanceFileName[NUM_PERFORMANCES]; diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 93e6b0ea..1f710c9a 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -1366,7 +1366,9 @@ void CUIMenu::TimerHandlerNoBack (TKernelTimerHandle hTimer, void *pParam, void void CUIMenu::PerformanceMenu (CUIMenu *pUIMenu, TMenuEvent Event) { bool bPerformanceSelectToLoad = pUIMenu->m_pMiniDexed->GetPerformanceSelectToLoad(); + unsigned nLastPerformance = pUIMenu->m_pMiniDexed->GetLastPerformance(); unsigned nValue = pUIMenu->m_nSelectedPerformanceID; + unsigned nStart = nValue; std::string Value; if (Event == MenuEventUpdate) @@ -1380,17 +1382,25 @@ void CUIMenu::PerformanceMenu (CUIMenu *pUIMenu, TMenuEvent Event) } if(!pUIMenu->m_bPerformanceDeleteMode) - { + { switch (Event) { case MenuEventUpdate: break; case MenuEventStepDown: - if (nValue > 0) + do { - --nValue; - } + if (nValue == 0) + { + // Wrap around + nValue = nLastPerformance; + } + else if (nValue > 0) + { + --nValue; + } + } while ((pUIMenu->m_pMiniDexed->IsValidPerformance(nValue) != true) && (nValue != nStart)); pUIMenu->m_nSelectedPerformanceID = nValue; if (!bPerformanceSelectToLoad && pUIMenu->m_nCurrentParameter==0) { @@ -1399,10 +1409,18 @@ void CUIMenu::PerformanceMenu (CUIMenu *pUIMenu, TMenuEvent Event) break; case MenuEventStepUp: - if (++nValue > (unsigned) pUIMenu->m_pMiniDexed->GetLastPerformance()-1) + do { - nValue = pUIMenu->m_pMiniDexed->GetLastPerformance()-1; - } + if (nValue == nLastPerformance) + { + // Wrap around + nValue = 0; + } + else if (nValue < nLastPerformance) + { + ++nValue; + } + } while ((pUIMenu->m_pMiniDexed->IsValidPerformance(nValue) != true) && (nValue != nStart)); pUIMenu->m_nSelectedPerformanceID = nValue; if (!bPerformanceSelectToLoad && pUIMenu->m_nCurrentParameter==0) { From a02515360d28df8605333c6a8f05f7051ac8e399 Mon Sep 17 00:00:00 2001 From: Kevin <68612569+diyelectromusic@users.noreply.github.com> Date: Sat, 9 Dec 2023 11:03:03 -0800 Subject: [PATCH 02/15] Start of subdirectory implementation for performance banks. --- src/mididevice.cpp | 24 +++++++- src/minidexed.cpp | 34 +++++++++++ src/minidexed.h | 5 ++ src/performanceconfig.cpp | 121 ++++++++++++++++++++++++++++++++++++++ src/performanceconfig.h | 9 +++ 5 files changed, 192 insertions(+), 1 deletion(-) diff --git a/src/mididevice.cpp b/src/mididevice.cpp index 5f231d63..b5959bff 100644 --- a/src/mididevice.cpp +++ b/src/mididevice.cpp @@ -184,9 +184,31 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign else { // Perform any MiniDexed level MIDI handling before specific Tone Generators + unsigned nPerfCh = m_pSynthesizer->GetPerformanceSelectChannel(); switch (ucType) { case MIDI_CONTROL_CHANGE: + // Check for performance PC messages + if (nPerfCh != Disabled) + { + if ((ucChannel == nPerfCh) || (nPerfCh == OmniMode)) + { + if (pMessage[1] == MIDI_CC_BANK_SELECT_MSB) + { + m_pSynthesizer->BankSelectMSBPerformance (pMessage[2]); + } + else if (pMessage[1] == MIDI_CC_BANK_SELECT_LSB) + { + m_pSynthesizer->BankSelectLSBPerformance (pMessage[2]); + } + else + { + // Ignore any other CC messages at this time + } + } + } + break; + case MIDI_NOTE_OFF: case MIDI_NOTE_ON: if (nLength < 3) @@ -195,11 +217,11 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign } m_pUI->UIMIDICmdHandler (ucChannel, ucStatus & 0xF0, pMessage[1], pMessage[2]); break; + case MIDI_PROGRAM_CHANGE: // Check for performance PC messages if( m_pConfig->GetMIDIRXProgramChange() ) { - unsigned nPerfCh = m_pSynthesizer->GetPerformanceSelectChannel(); if( nPerfCh != Disabled) { if ((ucChannel == nPerfCh) || (nPerfCh == OmniMode)) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index b11f8b44..e9c4dbc9 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -407,6 +407,22 @@ void CMiniDexed::BankSelect (unsigned nBank, unsigned nTG) } } +void CMiniDexed::BankSelectPerformance (unsigned nBank) +{ + nBank=constrain((int)nBank,0,16383); + + if (m_nParameter[ParameterPerformanceSelectChannel] != CMIDIDevice::Disabled) + { + // if (GetSysExFileLoader ()->IsValidBank(nBank)) + { + // Only change if we have the bank loaded + m_nVoiceBankIDPerformance = nBank; + + m_UI.ParameterChanged (); + } + } +} + void CMiniDexed::BankSelectMSB (unsigned nBankMSB, unsigned nTG) { nBankMSB=constrain((int)nBankMSB,0,127); @@ -422,6 +438,12 @@ void CMiniDexed::BankSelectMSB (unsigned nBankMSB, unsigned nTG) m_nVoiceBankIDMSB[nTG] = nBankMSB; } +void CMiniDexed::BankSelectMSBPerformance (unsigned nBankMSB) +{ + nBankMSB=constrain((int)nBankMSB,0,127); + m_nVoiceBankIDMSBPerformance = nBankMSB; +} + void CMiniDexed::BankSelectLSB (unsigned nBankLSB, unsigned nTG) { nBankLSB=constrain((int)nBankLSB,0,127); @@ -435,6 +457,18 @@ void CMiniDexed::BankSelectLSB (unsigned nBankLSB, unsigned nTG) BankSelect(nBank, nTG); } +void CMiniDexed::BankSelectLSBPerformance (unsigned nBankLSB) +{ + nBankLSB=constrain((int)nBankLSB,0,127); + + unsigned nBank = m_nVoiceBankIDPerformance; + unsigned nBankMSB = m_nVoiceBankIDMSBPerformance; + nBank = (nBankMSB << 7) + nBankLSB; + + // Now should have both MSB and LSB so enable the BankSelect + BankSelectPerformance(nBank); +} + void CMiniDexed::ProgramChange (unsigned nProgram, unsigned nTG) { assert (m_pConfig); diff --git a/src/minidexed.h b/src/minidexed.h index d56c228d..c2852632 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -64,8 +64,11 @@ class CMiniDexed CSysExFileLoader *GetSysExFileLoader (void); void BankSelect (unsigned nBank, unsigned nTG); + void BankSelectPerformance (unsigned nBank); void BankSelectMSB (unsigned nBankMSB, unsigned nTG); + void BankSelectMSBPerformance (unsigned nBankMSB); void BankSelectLSB (unsigned nBankLSB, unsigned nTG); + void BankSelectLSBPerformance (unsigned nBankLSB); void ProgramChange (unsigned nProgram, unsigned nTG); void ProgramChangePerformance (unsigned nProgram); void SetVolume (unsigned nVolume, unsigned nTG); @@ -239,6 +242,8 @@ class CMiniDexed unsigned m_nVoiceBankID[CConfig::ToneGenerators]; unsigned m_nVoiceBankIDMSB[CConfig::ToneGenerators]; + unsigned m_nVoiceBankIDPerformance; + unsigned m_nVoiceBankIDMSBPerformance; unsigned m_nProgram[CConfig::ToneGenerators]; unsigned m_nVolume[CConfig::ToneGenerators]; unsigned m_nPan[CConfig::ToneGenerators]; diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index 1382f34f..2f36b096 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -949,6 +949,8 @@ bool CPerformanceConfig::ListPerformances() LOGNOTE ("Last Performance: %d", nLastPerformance + 1); // Show "user facing" index + ListPerformanceBanks(); + return nInternalFolderOk; } @@ -1013,3 +1015,122 @@ bool CPerformanceConfig::DeletePerformance(unsigned nID) } return bOK; } + +bool CPerformanceConfig::ListPerformanceBanks() +{ + // Open performance directory + DIR Directory; + FILINFO FileInfo; + FRESULT Result; + Result = f_opendir (&Directory, "SD:/" PERFORMANCE_DIR); + if (Result != FR_OK) + { + // No performance directory, so no performance banks. + // So nothing else to do here + return false; + } + + LOGNOTE ("Performance Directory Found"); + + unsigned nNumBanks = 0; + unsigned nHighestBank = 0; + + // List directories with names in format 01_Perf Bank Name + Result = f_findfirst (&Directory, &FileInfo, "SD:/" PERFORMANCE_DIR, "*"); + for (unsigned i = 0; Result == FR_OK && FileInfo.fname[0]; i++) + { + // Check to see if it is a directory + if ((FileInfo.fattrib & AM_DIR) != 0) + { + // Looking for Performance banks of the form: 01_Perf Bank Name + // So positions 0,1 = decimal digit + // position 2 = "_" + // positions 3.. = actual name + // + std::string OriFileName = FileInfo.fname; + size_t nLen = OriFileName.length(); + if ( nLen > 3 && nLen <26 && strcmp(OriFileName.substr(2,1).c_str(), "_")==0) + { + unsigned nBankIndex = stoi(OriFileName.substr(0,2)); + // Recall user index numbered 01..NUM_PERFORMANCE_BANKS + if ((nBankIndex > 0) && (nBankIndex <= NUM_PERFORMANCE_BANKS)) + { + // Convert from "user facing" 1..indexed number to internal 0..indexed + nBankIndex = nBankIndex-1; + if (m_nPerformanceBankName[nBankIndex].empty()) + { + std::string BankName = OriFileName.substr(3,nLen); + + m_nPerformanceBankName[nBankIndex] = BankName; + //LOGNOTE ("Found performance bank %s (%d, %s)", OriFileName.c_str(), nBankIndex, BankName.c_str()); + nNumBanks++; + if (nBankIndex > nHighestBank) + { + nHighestBank = nBankIndex; + } + } + else + { + LOGNOTE ("Duplicate Performance Bank: %s", FileInfo.fname); + } + } + else + { + LOGNOTE ("Performance Bank number out of range: %s", FileInfo.fname); + } + } + else + { + //LOGNOTE ("Skipping: %s", FileInfo.fname); + } + } + + Result = f_findnext (&Directory, &FileInfo); + } + + if (nNumBanks > 0) + { + LOGNOTE ("Number of Performance Banks: %d (last = %d)", nNumBanks, nHighestBank+1); + } + return true; +} + +void CPerformanceConfig::SetPerformanceBank(unsigned nBankID) +{ + assert (nBankID < NUM_PERFORMANCE_BANKS); + if (IsValidPerformanceBank(nBankID)) + { + // Construct performance bank directory name + // Change directory + // Reload performances from that directory + nPerformanceBank = nBankID; + } +} + +unsigned CPerformanceConfig::GetPerformanceBank(void) +{ + return nPerformanceBank; +} + +std::string CPerformanceConfig::GetPerformanceBankName(unsigned nBankID) +{ + assert (nBankID < NUM_PERFORMANCE_BANKS); + if (IsValidPerformanceBank(nBankID)) + { + return m_nPerformanceBankName[nBankID]; + } + else + { + return "Default"; + } +} + +bool CPerformanceConfig::IsValidPerformanceBank(unsigned nBankID) +{ + assert (nBankID < NUM_PERFORMANCE_BANKS); + if (m_nPerformanceBankName[nBankID].empty()) + { + return false; + } + return true; +} diff --git a/src/performanceconfig.h b/src/performanceconfig.h index 1815e7c4..77e508e1 100644 --- a/src/performanceconfig.h +++ b/src/performanceconfig.h @@ -29,6 +29,7 @@ #define NUM_VOICE_PARAM 156 #define PERFORMANCE_DIR "performance" #define NUM_PERFORMANCES 256 +#define NUM_PERFORMANCE_BANKS 8 class CPerformanceConfig // Performance configuration { @@ -136,6 +137,12 @@ class CPerformanceConfig // Performance configuration bool CheckFreePerformanceSlot(void); bool IsValidPerformance(unsigned nID); + bool ListPerformanceBanks(void); + void SetPerformanceBank(unsigned nBankID); + unsigned GetPerformanceBank(void); + std::string GetPerformanceBankName(unsigned nBankID); + bool IsValidPerformanceBank(unsigned nBankID); + private: CPropertiesFatFsFile m_Properties; @@ -170,8 +177,10 @@ class CPerformanceConfig // Performance configuration unsigned nLastPerformance; unsigned nActualPerformance = 0; + unsigned nPerformanceBank; //unsigned nMenuSelectedPerformance = 0; std::string m_nPerformanceFileName[NUM_PERFORMANCES]; + std::string m_nPerformanceBankName[NUM_PERFORMANCE_BANKS]; FATFS *m_pFileSystem; bool nInternalFolderOk=false; From 36d138f3daee7cfc90b8ebffdd73fcb8baa9785e Mon Sep 17 00:00:00 2001 From: Kevin <68612569+diyelectromusic@users.noreply.github.com> Date: Sat, 16 Dec 2023 08:07:50 -0800 Subject: [PATCH 03/15] Initial version with performance banks, selectable over MIDI only. --- src/minidexed.cpp | 15 +-- src/minidexed.h | 1 + src/performanceconfig.cpp | 255 ++++++++++++++++++++++++++------------ src/performanceconfig.h | 19 +-- 4 files changed, 194 insertions(+), 96 deletions(-) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index e9c4dbc9..57c55bc4 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -227,6 +227,7 @@ bool CMiniDexed::Initialize (void) reverb_send_mixer->gain(i,mapfloat(m_nReverbSend[i],0,99,0.0f,1.0f)); } + m_PerformanceConfig.Init(); if (m_PerformanceConfig.Load ()) { LoadPerformanceParameters(); @@ -236,12 +237,6 @@ bool CMiniDexed::Initialize (void) SetMIDIChannel (CMIDIDevice::OmniMode, 0); } - // load performances file list, and attempt to create the performance folder - if (!m_PerformanceConfig.ListPerformances()) - { - LOGERR ("Cannot create internal Performance folder, new performances can't be created"); - } - // setup and start the sound device if (!m_pSoundDevice->AllocateQueueFrames (m_pConfig->GetChunkSize ())) { @@ -392,6 +387,11 @@ CSysExFileLoader *CMiniDexed::GetSysExFileLoader (void) return &m_SysExFileLoader; } +CPerformanceConfig *CMiniDexed::GetPerformanceConfig (void) +{ + return &m_PerformanceConfig; +} + void CMiniDexed::BankSelect (unsigned nBank, unsigned nTG) { nBank=constrain((int)nBank,0,16383); @@ -413,10 +413,11 @@ void CMiniDexed::BankSelectPerformance (unsigned nBank) if (m_nParameter[ParameterPerformanceSelectChannel] != CMIDIDevice::Disabled) { - // if (GetSysExFileLoader ()->IsValidBank(nBank)) + if (GetPerformanceConfig ()->IsValidPerformanceBank(nBank)) { // Only change if we have the bank loaded m_nVoiceBankIDPerformance = nBank; + GetPerformanceConfig ()->SetPerformanceBank (nBank); m_UI.ParameterChanged (); } diff --git a/src/minidexed.h b/src/minidexed.h index c2852632..323f856f 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -62,6 +62,7 @@ class CMiniDexed #endif CSysExFileLoader *GetSysExFileLoader (void); + CPerformanceConfig *GetPerformanceConfig (void); void BankSelect (unsigned nBank, unsigned nTG); void BankSelectPerformance (unsigned nBank); diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index 2f36b096..45bcf522 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -28,7 +28,10 @@ LOGMODULE ("Performance"); +#define PERFORMANCE_DIR "performance" #define DEFAULT_PERFORMANCE_FILENAME "performance.ini" +#define DEFAULT_PERFORMANCE_NAME "Default" +#define DEFAULT_PERFORMANCE_BANK_NAME "Default" CPerformanceConfig::CPerformanceConfig (FATFS *pFileSystem) : m_Properties (DEFAULT_PERFORMANCE_FILENAME, pFileSystem) @@ -40,6 +43,45 @@ CPerformanceConfig::~CPerformanceConfig (void) { } +bool CPerformanceConfig::Init (void) +{ + // Check intermal performance directory exists + DIR Directory; + FRESULT Result; + //Check if internal "performance" directory exists + Result = f_opendir (&Directory, "SD:/" PERFORMANCE_DIR); + if (Result == FR_OK) + { + m_bPerformanceDirectoryExists=true; + Result = f_closedir (&Directory); + } + else + { + m_bPerformanceDirectoryExists = false; + } + + // List banks if present + ListPerformanceBanks(); + + LOGNOTE("Testing loading of banks"); + for (unsigned i=0; i= NUM_PERFORMANCES) { + if (m_nLastPerformance >= NUM_PERFORMANCES) { // No space left for new performances LOGWARN ("No space left for new performance"); return false; } + + // Note: New performances are created at the end of the currently selected bank. + // Sould we default to a new bank just for user-performances? + // + // There is the possibility of MIDI changing the Bank Number and the user + // not spotting the bank has changed... + // + // Another option would be to find empty slots in the current bank + // rather than always add at the end. + // + // Sorting this out is left for a future update. std::string sPerformanceName = NewPerformanceName; NewPerformanceName=""; - nActualPerformance=nLastPerformance; - unsigned nNewPerformance = nLastPerformance + 1; + m_nActualPerformance=m_nLastPerformance; + unsigned nNewPerformance = m_nLastPerformance + 1; std::string nFileName; std::string nPath; std::string nIndex = "000000"; @@ -836,10 +895,11 @@ bool CPerformanceConfig::CreateNewPerformanceFile(void) nFileName +=sPerformanceName.substr(0,14); } nFileName += ".ini"; - m_nPerformanceFileName[nNewPerformance]= sPerformanceName; + m_PerformanceFileName[nNewPerformance]= sPerformanceName; nPath = "SD:/" ; nPath += PERFORMANCE_DIR; + nPath += AddPerformanceBankDirName(m_nPerformanceBank); nPath += "/"; nFileName = nPath + nFileName; @@ -847,17 +907,17 @@ bool CPerformanceConfig::CreateNewPerformanceFile(void) FRESULT Result = f_open (&File, nFileName.c_str(), FA_WRITE | FA_CREATE_ALWAYS); if (Result != FR_OK) { - m_nPerformanceFileName[nNewPerformance]=nullptr; + m_PerformanceFileName[nNewPerformance]=nullptr; return false; } if (f_close (&File) != FR_OK) { - m_nPerformanceFileName[nNewPerformance]=nullptr; + m_PerformanceFileName[nNewPerformance]=nullptr; return false; } - nLastPerformance = nNewPerformance; + m_nLastPerformance = nNewPerformance; new (&m_Properties) CPropertiesFatFsFile(nFileName.c_str(), m_pFileSystem); return true; @@ -865,35 +925,36 @@ bool CPerformanceConfig::CreateNewPerformanceFile(void) bool CPerformanceConfig::ListPerformances() { - nInternalFolderOk=false; - nExternalFolderOk=false; // for future USB implementation - nLastPerformance=0; - m_nPerformanceFileName[0]="Default"; // in order to assure retrocompatibility - - unsigned nPIndex; - DIR Directory; - FILINFO FileInfo; - FRESULT Result; - //Check if internal "performance" directory exists - Result = f_opendir (&Directory, "SD:/" PERFORMANCE_DIR); - if (Result == FR_OK) + // Clear any existing lists of performances + for (unsigned i=0; i= NUM_PERFORMANCES) { + if (m_nLastPerformance >= NUM_PERFORMANCES) { LOGNOTE ("Skipping performance %s", FileInfo.fname); } else { if (!(FileInfo.fattrib & (AM_HID | AM_SYS))) @@ -902,38 +963,37 @@ bool CPerformanceConfig::ListPerformances() size_t nLen = OriFileName.length(); if ( nLen > 8 && nLen <26 && strcmp(OriFileName.substr(6,1).c_str(), "_")==0) { - // Note: nLastPerformance - refers to the number (index) of the last performance in memory, + // Note: m_nLastPerformance - refers to the number (index) of the last performance in memory, // which includes a default performance. // // Filenames on the disk start from 1 to match what the user might see in MIDI. - // So this means that actually file 000001_ will correspond to index position [0] - // which is the default performance. Consequently file-loaded performances - // will start from index position 000002. - // m_nPerformanceFileName[0] = default performance (file 000001) - // m_nPerformanceFileName[1] = first available on-disk performance (file 000002) + // So this means that actually file 000001_ will correspond to index position [0]. + // For the default bank though, ID 1 is the default performance, so will already exist. + // m_PerformanceFileName[0] = default performance (file 000001) + // m_PerformanceFileName[1] = first available on-disk performance (file 000002) // // Note2: filenames assume 6 digits, underscore, name, finally ".ini" // i.e. 123456_Performance Name.ini // nPIndex=stoi(OriFileName.substr(0,6)); - if ((nPIndex < 2) || (nPIndex >= (NUM_PERFORMANCES+1))) + if ((nPIndex < 1) || (nPIndex >= (NUM_PERFORMANCES+1))) { // Index is out of range - skip to next file continue; } // Convert from "user facing" 1..indexed number to internal 0..indexed nPIndex = nPIndex-1; - if (m_nPerformanceFileName[nPIndex].empty()) + if (m_PerformanceFileName[nPIndex].empty()) { - if(nPIndex > nLastPerformance) + if(nPIndex > m_nLastPerformance) { - nLastPerformance=nPIndex; + m_nLastPerformance=nPIndex; } std::string FileName = OriFileName.substr(0,OriFileName.length()-4).substr(7,14); - m_nPerformanceFileName[nPIndex] = FileName; - //LOGNOTE ("Loading performance %s (%d, %s)", OriFileName.c_str(), nPIndex, FileName.c_str()); + m_PerformanceFileName[nPIndex] = FileName; + LOGNOTE ("Loading performance %s (%d, %s)", OriFileName.c_str(), nPIndex, FileName.c_str()); } else { @@ -945,29 +1005,26 @@ bool CPerformanceConfig::ListPerformances() Result = f_findnext (&Directory, &FileInfo); } + f_closedir (&Directory); } - LOGNOTE ("Last Performance: %d", nLastPerformance + 1); // Show "user facing" index - - ListPerformanceBanks(); - - return nInternalFolderOk; -} - + return true; +} void CPerformanceConfig::SetNewPerformance (unsigned nID) { assert (nID < NUM_PERFORMANCES); - nActualPerformance=nID; + m_nActualPerformance=nID; std::string FileN = GetPerformanceFullFilePath(nID); new (&m_Properties) CPropertiesFatFsFile(FileN.c_str(), m_pFileSystem); + LOGNOTE("Selecting Performance: %d (%s)", nID+1, FileN.c_str()); } std::string CPerformanceConfig::GetNewPerformanceDefaultName(void) { std::string nIndex = "000000"; - nIndex += std::to_string(nLastPerformance+1+1); // Convert from internal 0.. index to a file-based 1.. index to show the user + nIndex += std::to_string(m_nLastPerformance+1+1); // Convert from internal 0.. index to a file-based 1.. index to show the user nIndex = nIndex.substr(nIndex.length()-6,6); return "Perf" + nIndex; } @@ -988,12 +1045,13 @@ void CPerformanceConfig::SetNewPerformanceName(std::string nName) bool CPerformanceConfig::DeletePerformance(unsigned nID) { bool bOK = false; - if(nID == 0){return bOK;} // default (performance.ini at root directory) can't be deleted + if((m_nPerformanceBank == 0) && (nID == 0)){return bOK;} // default (performance.ini at root directory) can't be deleted DIR Directory; FILINFO FileInfo; std::string FileN = "SD:/"; FileN += PERFORMANCE_DIR; - + FileN += AddPerformanceBankDirName(m_nPerformanceBank); + FRESULT Result = f_findfirst (&Directory, &FileInfo, FileN.c_str(), GetPerformanceFileName(nID).c_str()); if (Result == FR_OK && FileInfo.fname[0]) { @@ -1003,9 +1061,9 @@ bool CPerformanceConfig::DeletePerformance(unsigned nID) if (Result == FR_OK) { SetNewPerformance(0); - nActualPerformance =0; + m_nActualPerformance =0; //nMenuSelectedPerformance=0; - m_nPerformanceFileName[nID].clear(); + m_PerformanceFileName[nID].clear(); bOK=true; } else @@ -1019,7 +1077,7 @@ bool CPerformanceConfig::DeletePerformance(unsigned nID) bool CPerformanceConfig::ListPerformanceBanks() { // Open performance directory - DIR Directory; + DIR Directory; FILINFO FileInfo; FRESULT Result; Result = f_opendir (&Directory, "SD:/" PERFORMANCE_DIR); @@ -1030,10 +1088,13 @@ bool CPerformanceConfig::ListPerformanceBanks() return false; } - LOGNOTE ("Performance Directory Found"); - unsigned nNumBanks = 0; unsigned nHighestBank = 0; + + // Add in the default performance directory as the first bank + m_PerformanceBankName[0] = DEFAULT_PERFORMANCE_BANK_NAME; + nNumBanks = 1; + nHighestBank = 0; // List directories with names in format 01_Perf Bank Name Result = f_findfirst (&Directory, &FileInfo, "SD:/" PERFORMANCE_DIR, "*"); @@ -1052,17 +1113,18 @@ bool CPerformanceConfig::ListPerformanceBanks() if ( nLen > 3 && nLen <26 && strcmp(OriFileName.substr(2,1).c_str(), "_")==0) { unsigned nBankIndex = stoi(OriFileName.substr(0,2)); - // Recall user index numbered 01..NUM_PERFORMANCE_BANKS + // Recall user index numbered 02..NUM_PERFORMANCE_BANKS + // NB: Bank 01 is reserved for the default performance directory if ((nBankIndex > 0) && (nBankIndex <= NUM_PERFORMANCE_BANKS)) { // Convert from "user facing" 1..indexed number to internal 0..indexed nBankIndex = nBankIndex-1; - if (m_nPerformanceBankName[nBankIndex].empty()) + if (m_PerformanceBankName[nBankIndex].empty()) { std::string BankName = OriFileName.substr(3,nLen); - m_nPerformanceBankName[nBankIndex] = BankName; - //LOGNOTE ("Found performance bank %s (%d, %s)", OriFileName.c_str(), nBankIndex, BankName.c_str()); + m_PerformanceBankName[nBankIndex] = BankName; + LOGNOTE ("Found performance bank %s (%d, %s)", OriFileName.c_str(), nBankIndex, BankName.c_str()); nNumBanks++; if (nBankIndex > nHighestBank) { @@ -1072,6 +1134,10 @@ bool CPerformanceConfig::ListPerformanceBanks() else { LOGNOTE ("Duplicate Performance Bank: %s", FileInfo.fname); + if (nBankIndex==0) + { + LOGNOTE ("(Bank 01 is the default performance directory)"); + } } } else @@ -1092,6 +1158,8 @@ bool CPerformanceConfig::ListPerformanceBanks() { LOGNOTE ("Number of Performance Banks: %d (last = %d)", nNumBanks, nHighestBank+1); } + + f_closedir (&Directory); return true; } @@ -1100,16 +1168,15 @@ void CPerformanceConfig::SetPerformanceBank(unsigned nBankID) assert (nBankID < NUM_PERFORMANCE_BANKS); if (IsValidPerformanceBank(nBankID)) { - // Construct performance bank directory name - // Change directory - // Reload performances from that directory - nPerformanceBank = nBankID; + LOGNOTE("Selecting Performance Bank: %d", nBankID+1); + m_nPerformanceBank = nBankID; + ListPerformances(); } } unsigned CPerformanceConfig::GetPerformanceBank(void) { - return nPerformanceBank; + return m_nPerformanceBank; } std::string CPerformanceConfig::GetPerformanceBankName(unsigned nBankID) @@ -1117,18 +1184,46 @@ std::string CPerformanceConfig::GetPerformanceBankName(unsigned nBankID) assert (nBankID < NUM_PERFORMANCE_BANKS); if (IsValidPerformanceBank(nBankID)) { - return m_nPerformanceBankName[nBankID]; + return m_PerformanceBankName[nBankID]; + } + else + { + return DEFAULT_PERFORMANCE_BANK_NAME; + } +} + +std::string CPerformanceConfig::AddPerformanceBankDirName(unsigned nBankID) +{ + assert (nBankID < NUM_PERFORMANCE_BANKS); + if (IsValidPerformanceBank(nBankID)) + { + // Performance Banks directories in format "01_Bank Name" + std::string Index; + if (nBankID == 0) + { + // Legacy: Bank 1 is the default performance directory + return ""; + } + if (nBankID < 9) + { + Index = "0" + std::to_string(nBankID+1); + } + else + { + Index = std::to_string(nBankID+1); + } + return "/" + Index + "_" + m_PerformanceBankName[nBankID]; } else { - return "Default"; + return ""; } } bool CPerformanceConfig::IsValidPerformanceBank(unsigned nBankID) { assert (nBankID < NUM_PERFORMANCE_BANKS); - if (m_nPerformanceBankName[nBankID].empty()) + if (m_PerformanceBankName[nBankID].empty()) { return false; } diff --git a/src/performanceconfig.h b/src/performanceconfig.h index 77e508e1..18b2cf00 100644 --- a/src/performanceconfig.h +++ b/src/performanceconfig.h @@ -27,15 +27,16 @@ #include #include #define NUM_VOICE_PARAM 156 -#define PERFORMANCE_DIR "performance" #define NUM_PERFORMANCES 256 -#define NUM_PERFORMANCE_BANKS 8 +#define NUM_PERFORMANCE_BANKS 64 class CPerformanceConfig // Performance configuration { public: CPerformanceConfig (FATFS *pFileSystem); ~CPerformanceConfig (void); + + bool Init (void); bool Load (void); @@ -135,6 +136,7 @@ class CPerformanceConfig // Performance configuration void SetNewPerformanceName(std::string nName); bool DeletePerformance(unsigned nID); bool CheckFreePerformanceSlot(void); + std::string AddPerformanceBankDirName(unsigned nBankID); bool IsValidPerformance(unsigned nID); bool ListPerformanceBanks(void); @@ -175,16 +177,15 @@ class CPerformanceConfig // Performance configuration unsigned m_nAftertouchRange[CConfig::ToneGenerators]; unsigned m_nAftertouchTarget[CConfig::ToneGenerators]; - unsigned nLastPerformance; - unsigned nActualPerformance = 0; - unsigned nPerformanceBank; + unsigned m_nLastPerformance; + unsigned m_nActualPerformance = 0; + unsigned m_nPerformanceBank; + bool m_bPerformanceDirectoryExists; //unsigned nMenuSelectedPerformance = 0; - std::string m_nPerformanceFileName[NUM_PERFORMANCES]; - std::string m_nPerformanceBankName[NUM_PERFORMANCE_BANKS]; + std::string m_PerformanceFileName[NUM_PERFORMANCES]; + std::string m_PerformanceBankName[NUM_PERFORMANCE_BANKS]; FATFS *m_pFileSystem; - bool nInternalFolderOk=false; - bool nExternalFolderOk=false; // for future USB implementation std::string NewPerformanceName=""; bool m_bCompressorEnable; From 2109b576e30b3eed422a5fbe64839fad11de023f Mon Sep 17 00:00:00 2001 From: Kevin <68612569+diyelectromusic@users.noreply.github.com> Date: Wed, 20 Dec 2023 03:47:17 -0800 Subject: [PATCH 04/15] Initial implementation of performance bank switching in the UI menu. --- src/minidexed.cpp | 23 +++++++++++ src/minidexed.h | 4 ++ src/performanceconfig.cpp | 31 +++++++++++--- src/performanceconfig.h | 3 ++ src/uimenu.cpp | 85 ++++++++++++++++++++++++++++++++++++++- src/uimenu.h | 2 + 6 files changed, 141 insertions(+), 7 deletions(-) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 57c55bc4..cdd293c1 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -170,6 +170,8 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, SetParameter (ParameterCompressorEnable, 1); SetPerformanceSelectChannel(m_pConfig->GetPerformanceSelectChannel()); + + SetParameter (ParameterPerformanceBank, 0); }; bool CMiniDexed::Initialize (void) @@ -832,6 +834,10 @@ void CMiniDexed::SetParameter (TParameter Parameter, int nValue) // Nothing more to do break; + case ParameterPerformanceBank: + BankSelectPerformance(nValue); + break; + default: assert (0); break; @@ -1533,6 +1539,11 @@ unsigned CMiniDexed::GetLastPerformance() return m_PerformanceConfig.GetLastPerformance(); } +unsigned CMiniDexed::GetLastPerformanceBank() +{ + return m_PerformanceConfig.GetLastPerformanceBank(); +} + unsigned CMiniDexed::GetActualPerformanceID() { return m_PerformanceConfig.GetActualPerformanceID(); @@ -1551,6 +1562,13 @@ bool CMiniDexed::SetNewPerformance(unsigned nID) return true; } +unsigned CMiniDexed::SetFirstPerformance(void) +{ + unsigned nID = m_PerformanceConfig.FindFirstPerformance(); + SetNewPerformance(nID); + return nID; +} + bool CMiniDexed::DoSetNewPerformance (void) { m_bLoadPerformanceBusy = true; @@ -1668,6 +1686,11 @@ bool CMiniDexed::IsValidPerformance(unsigned nID) return m_PerformanceConfig.IsValidPerformance(nID); } +bool CMiniDexed::IsValidPerformanceBank(unsigned nBankID) +{ + return m_PerformanceConfig.IsValidPerformanceBank(nBankID); +} + void CMiniDexed::SetVoiceName (std::string VoiceName, unsigned nTG) { assert (nTG < CConfig::ToneGenerators); diff --git a/src/minidexed.h b/src/minidexed.h index 323f856f..14aa88bc 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -121,9 +121,11 @@ class CMiniDexed std::string GetPerformanceFileName(unsigned nID); std::string GetPerformanceName(unsigned nID); unsigned GetLastPerformance(); + unsigned GetLastPerformanceBank(); unsigned GetActualPerformanceID(); void SetActualPerformanceID(unsigned nID); bool SetNewPerformance(unsigned nID); + unsigned SetFirstPerformance(void); bool SavePerformanceNewFile (); bool DoSavePerformanceNewFile (void); @@ -133,6 +135,7 @@ class CMiniDexed unsigned GetPerformanceSelectChannel (void); void SetPerformanceSelectChannel (unsigned uCh); bool IsValidPerformance(unsigned nID); + bool IsValidPerformanceBank(unsigned nBankID); // Must match the order in CUIMenu::TParameter enum TParameter @@ -146,6 +149,7 @@ class CMiniDexed ParameterReverbDiffusion, ParameterReverbLevel, ParameterPerformanceSelectChannel, + ParameterPerformanceBank, ParameterUnknown }; diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index 45bcf522..02a2b388 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -1,3 +1,4 @@ + // // performanceconfig.cpp // @@ -46,7 +47,7 @@ CPerformanceConfig::~CPerformanceConfig (void) bool CPerformanceConfig::Init (void) { // Check intermal performance directory exists - DIR Directory; + DIR Directory; FRESULT Result; //Check if internal "performance" directory exists Result = f_opendir (&Directory, "SD:/" PERFORMANCE_DIR); @@ -810,6 +811,11 @@ unsigned CPerformanceConfig::GetLastPerformance() return m_nLastPerformance; } +unsigned CPerformanceConfig::GetLastPerformanceBank() +{ + return m_nLastPerformanceBank; +} + unsigned CPerformanceConfig::GetActualPerformanceID() { return m_nActualPerformance; @@ -1021,6 +1027,19 @@ void CPerformanceConfig::SetNewPerformance (unsigned nID) LOGNOTE("Selecting Performance: %d (%s)", nID+1, FileN.c_str()); } +unsigned CPerformanceConfig::FindFirstPerformance (void) +{ + for (int nID=0; nID < NUM_PERFORMANCES; nID++) + { + if (IsValidPerformance(nID)) + { + return nID; + } + } + + return 0; // Even though 0 is a valid performance, not much else to do +} + std::string CPerformanceConfig::GetNewPerformanceDefaultName(void) { std::string nIndex = "000000"; @@ -1089,12 +1108,12 @@ bool CPerformanceConfig::ListPerformanceBanks() } unsigned nNumBanks = 0; - unsigned nHighestBank = 0; + m_nLastPerformanceBank = 0; // Add in the default performance directory as the first bank m_PerformanceBankName[0] = DEFAULT_PERFORMANCE_BANK_NAME; nNumBanks = 1; - nHighestBank = 0; + m_nLastPerformanceBank = 0; // List directories with names in format 01_Perf Bank Name Result = f_findfirst (&Directory, &FileInfo, "SD:/" PERFORMANCE_DIR, "*"); @@ -1126,9 +1145,9 @@ bool CPerformanceConfig::ListPerformanceBanks() m_PerformanceBankName[nBankIndex] = BankName; LOGNOTE ("Found performance bank %s (%d, %s)", OriFileName.c_str(), nBankIndex, BankName.c_str()); nNumBanks++; - if (nBankIndex > nHighestBank) + if (nBankIndex > m_nLastPerformanceBank) { - nHighestBank = nBankIndex; + m_nLastPerformanceBank = nBankIndex; } } else @@ -1156,7 +1175,7 @@ bool CPerformanceConfig::ListPerformanceBanks() if (nNumBanks > 0) { - LOGNOTE ("Number of Performance Banks: %d (last = %d)", nNumBanks, nHighestBank+1); + LOGNOTE ("Number of Performance Banks: %d (last = %d)", nNumBanks, m_nLastPerformanceBank+1); } f_closedir (&Directory); diff --git a/src/performanceconfig.h b/src/performanceconfig.h index 18b2cf00..8960f852 100644 --- a/src/performanceconfig.h +++ b/src/performanceconfig.h @@ -124,10 +124,12 @@ class CPerformanceConfig // Performance configuration bool ListPerformances(); //std::string m_DirName; void SetNewPerformance (unsigned nID); + unsigned FindFirstPerformance (void); std::string GetPerformanceFileName(unsigned nID); std::string GetPerformanceFullFilePath(unsigned nID); std::string GetPerformanceName(unsigned nID); unsigned GetLastPerformance(); + unsigned GetLastPerformanceBank(); void SetActualPerformanceID(unsigned nID); unsigned GetActualPerformanceID(); bool CreateNewPerformanceFile(void); @@ -180,6 +182,7 @@ class CPerformanceConfig // Performance configuration unsigned m_nLastPerformance; unsigned m_nActualPerformance = 0; unsigned m_nPerformanceBank; + unsigned m_nLastPerformanceBank; bool m_bPerformanceDirectoryExists; //unsigned nMenuSelectedPerformance = 0; std::string m_PerformanceFileName[NUM_PERFORMANCES]; diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 1f710c9a..02653d14 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -214,7 +214,8 @@ const CUIMenu::TParameter CUIMenu::s_GlobalParameter[CMiniDexed::ParameterUnknow {0, 99, 1}, // ParameterReverbLowPass {0, 99, 1}, // ParameterReverbDiffusion {0, 99, 1}, // ParameterReverbLevel - {0, CMIDIDevice::ChannelUnknown-1, 1, ToMIDIChannel} // ParameterPerformanceSelectChannel + {0, CMIDIDevice::ChannelUnknown-1, 1, ToMIDIChannel}, // ParameterPerformanceSelectChannel + {0, NUM_PERFORMANCE_BANKS, 1} // ParameterPerformanceBank }; // must match CMiniDexed::TTGParameter @@ -327,6 +328,7 @@ const CUIMenu::TMenuItem CUIMenu::s_PerformanceMenu[] = {"Load", PerformanceMenu, 0, 0}, {"Save", MenuHandler, s_SaveMenu}, {"Delete", PerformanceMenu, 0, 1}, + {"Bank", EditPerformanceBankNumber, 0, 0}, {"PCCH", EditGlobalParameter, 0, CMiniDexed::ParameterPerformanceSelectChannel}, {0} }; @@ -1510,6 +1512,87 @@ void CUIMenu::PerformanceMenu (CUIMenu *pUIMenu, TMenuEvent Event) } } +void CUIMenu::EditPerformanceBankNumber (CUIMenu *pUIMenu, TMenuEvent Event) +{ + bool bPerformanceSelectToLoad = pUIMenu->m_pMiniDexed->GetPerformanceSelectToLoad(); + unsigned nLastPerformanceBank = pUIMenu->m_pMiniDexed->GetLastPerformanceBank(); + unsigned nValue = pUIMenu->m_nSelectedPerformanceBankID; + unsigned nStart = nValue; + std::string Value; + + switch (Event) + { + case MenuEventUpdate: + break; + + case MenuEventStepDown: + do + { + if (nValue == 0) + { + // Wrap around + nValue = nLastPerformanceBank; + } + else if (nValue > 0) + { + --nValue; + } + } while ((pUIMenu->m_pMiniDexed->IsValidPerformanceBank(nValue) != true) && (nValue != nStart)); + pUIMenu->m_nSelectedPerformanceBankID = nValue; + if (!bPerformanceSelectToLoad) + { + // Switch to the new bank and select the first performance voice + pUIMenu->m_pMiniDexed->SetParameter (CMiniDexed::ParameterPerformanceBank, nValue); + pUIMenu->m_nSelectedPerformanceID = pUIMenu->m_pMiniDexed->SetFirstPerformance(); + } + break; + + case MenuEventStepUp: + do + { + if (nValue == nLastPerformanceBank) + { + // Wrap around + nValue = 0; + } + else if (nValue < nLastPerformanceBank) + { + ++nValue; + } + } while ((pUIMenu->m_pMiniDexed->IsValidPerformanceBank(nValue) != true) && (nValue != nStart)); + pUIMenu->m_nSelectedPerformanceBankID = nValue; + if (!bPerformanceSelectToLoad) + { + pUIMenu->m_pMiniDexed->SetParameter (CMiniDexed::ParameterPerformanceBank, nValue); + pUIMenu->m_nSelectedPerformanceID = pUIMenu->m_pMiniDexed->SetFirstPerformance(); + } + break; + + case MenuEventSelect: + if (bPerformanceSelectToLoad) + { + pUIMenu->m_pMiniDexed->SetParameter (CMiniDexed::ParameterPerformanceBank, nValue); + pUIMenu->m_nSelectedPerformanceID = pUIMenu->m_pMiniDexed->SetFirstPerformance(); + } + break; + + default: + return; + } + + Value = pUIMenu->m_pMiniDexed->GetPerformanceConfig ()->GetPerformanceBankName(nValue); + std::string nPSelected = ""; + if(nValue == (unsigned)pUIMenu->m_pMiniDexed->GetParameter (CMiniDexed::ParameterPerformanceBank)) + { + nPSelected= "[L]"; + } + + pUIMenu->m_pUI->DisplayWrite (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, nPSelected.c_str(), + Value.c_str (), + nValue > 0, + nValue < pUIMenu->m_pMiniDexed->GetLastPerformanceBank()-1); +} + void CUIMenu::InputTxt (CUIMenu *pUIMenu, TMenuEvent Event) { unsigned nTG=0; diff --git a/src/uimenu.h b/src/uimenu.h index b66d65c5..d5b48dcb 100644 --- a/src/uimenu.h +++ b/src/uimenu.h @@ -91,6 +91,7 @@ class CUIMenu static void EditTGParameterModulation (CUIMenu *pUIMenu, TMenuEvent Event); static void PerformanceMenu (CUIMenu *pUIMenu, TMenuEvent Event); static void SavePerformanceNewFile (CUIMenu *pUIMenu, TMenuEvent Event); + static void EditPerformanceBankNumber (CUIMenu *pUIMenu, TMenuEvent Event); static std::string GetGlobalValueString (unsigned nParameter, int nValue); static std::string GetTGValueString (unsigned nTGParameter, int nValue); @@ -169,6 +170,7 @@ class CUIMenu bool m_bPerformanceDeleteMode=false; bool m_bConfirmDeletePerformance=false; unsigned m_nSelectedPerformanceID =0; + unsigned m_nSelectedPerformanceBankID =0; bool m_bSplashShow=false; }; From d5819608c57a437cb7a99a3fd259889339fee368 Mon Sep 17 00:00:00 2001 From: Kevin <68612569+diyelectromusic@users.noreply.github.com> Date: Sat, 30 Dec 2023 07:34:12 -0800 Subject: [PATCH 05/15] Remove debug information, fix few bugs, including PgmUpDown handling and performance numbers out of range. --- src/performanceconfig.cpp | 83 +++++++++++++++++++++++++-------------- src/performanceconfig.h | 4 +- src/uimenu.cpp | 45 +++++++++++++++------ 3 files changed, 88 insertions(+), 44 deletions(-) diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index 02a2b388..340edf32 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -29,6 +29,8 @@ LOGMODULE ("Performance"); +//#define VERBOSE_DEBUG + #define PERFORMANCE_DIR "performance" #define DEFAULT_PERFORMANCE_FILENAME "performance.ini" #define DEFAULT_PERFORMANCE_NAME "Default" @@ -63,7 +65,9 @@ bool CPerformanceConfig::Init (void) // List banks if present ListPerformanceBanks(); - + +#ifdef VERBOSE_DEBUG +#warning "PerformanceConfig in verbose debug printing mode" LOGNOTE("Testing loading of banks"); for (unsigned i=0; i= (NUM_PERFORMANCES+1))) { // Index is out of range - skip to next file - continue; + LOGNOTE ("Performance number out of range: %s (%d to %d)", FileInfo.fname, 1, NUM_PERFORMANCES); } - // Convert from "user facing" 1..indexed number to internal 0..indexed - nPIndex = nPIndex-1; - if (m_PerformanceFileName[nPIndex].empty()) + else { - if(nPIndex > m_nLastPerformance) + // Convert from "user facing" 1..indexed number to internal 0..indexed + nPIndex = nPIndex-1; + if (m_PerformanceFileName[nPIndex].empty()) { - m_nLastPerformance=nPIndex; - } + if(nPIndex > m_nLastPerformance) + { + m_nLastPerformance=nPIndex; + } - std::string FileName = OriFileName.substr(0,OriFileName.length()-4).substr(7,14); + std::string FileName = OriFileName.substr(0,OriFileName.length()-4).substr(7,14); - m_PerformanceFileName[nPIndex] = FileName; - LOGNOTE ("Loading performance %s (%d, %s)", OriFileName.c_str(), nPIndex, FileName.c_str()); - } - else - { - LOGNOTE ("Duplicate performance %s", OriFileName.c_str()); + m_PerformanceFileName[nPIndex] = FileName; +#ifdef VERBOSE_DEBUG + LOGNOTE ("Loading performance %s (%d, %s)", OriFileName.c_str(), nPIndex, FileName.c_str()); +#endif + } + else + { + LOGNOTE ("Duplicate performance %s", OriFileName.c_str()); + } } - } + } } } @@ -1024,7 +1035,9 @@ void CPerformanceConfig::SetNewPerformance (unsigned nID) std::string FileN = GetPerformanceFullFilePath(nID); new (&m_Properties) CPropertiesFatFsFile(FileN.c_str(), m_pFileSystem); +#ifdef VERBOSE_DEBUG LOGNOTE("Selecting Performance: %d (%s)", nID+1, FileN.c_str()); +#endif } unsigned CPerformanceConfig::FindFirstPerformance (void) @@ -1123,27 +1136,29 @@ bool CPerformanceConfig::ListPerformanceBanks() if ((FileInfo.fattrib & AM_DIR) != 0) { // Looking for Performance banks of the form: 01_Perf Bank Name - // So positions 0,1 = decimal digit - // position 2 = "_" - // positions 3.. = actual name + // So positions 0,1,2 = decimal digit + // position 3 = "_" + // positions 4.. = actual name // std::string OriFileName = FileInfo.fname; size_t nLen = OriFileName.length(); - if ( nLen > 3 && nLen <26 && strcmp(OriFileName.substr(2,1).c_str(), "_")==0) + if ( nLen > 4 && nLen <26 && strcmp(OriFileName.substr(3,1).c_str(), "_")==0) { - unsigned nBankIndex = stoi(OriFileName.substr(0,2)); - // Recall user index numbered 02..NUM_PERFORMANCE_BANKS - // NB: Bank 01 is reserved for the default performance directory + unsigned nBankIndex = stoi(OriFileName.substr(0,3)); + // Recall user index numbered 002..NUM_PERFORMANCE_BANKS + // NB: Bank 001 is reserved for the default performance directory if ((nBankIndex > 0) && (nBankIndex <= NUM_PERFORMANCE_BANKS)) { // Convert from "user facing" 1..indexed number to internal 0..indexed nBankIndex = nBankIndex-1; if (m_PerformanceBankName[nBankIndex].empty()) { - std::string BankName = OriFileName.substr(3,nLen); + std::string BankName = OriFileName.substr(4,nLen); m_PerformanceBankName[nBankIndex] = BankName; +#ifdef VERBOSE_DEBUG LOGNOTE ("Found performance bank %s (%d, %s)", OriFileName.c_str(), nBankIndex, BankName.c_str()); +#endif nNumBanks++; if (nBankIndex > m_nLastPerformanceBank) { @@ -1155,18 +1170,20 @@ bool CPerformanceConfig::ListPerformanceBanks() LOGNOTE ("Duplicate Performance Bank: %s", FileInfo.fname); if (nBankIndex==0) { - LOGNOTE ("(Bank 01 is the default performance directory)"); + LOGNOTE ("(Bank 001 is the default performance directory)"); } } } else { - LOGNOTE ("Performance Bank number out of range: %s", FileInfo.fname); + LOGNOTE ("Performance Bank number out of range: %s (%d to %d)", FileInfo.fname, 1, NUM_PERFORMANCE_BANKS); } } else { - //LOGNOTE ("Skipping: %s", FileInfo.fname); +#ifdef VERBOSE_DEBUG + LOGNOTE ("Skipping: %s", FileInfo.fname); +#endif } } @@ -1187,7 +1204,9 @@ void CPerformanceConfig::SetPerformanceBank(unsigned nBankID) assert (nBankID < NUM_PERFORMANCE_BANKS); if (IsValidPerformanceBank(nBankID)) { +#ifdef VERBOSE_DEBUG LOGNOTE("Selecting Performance Bank: %d", nBankID+1); +#endif m_nPerformanceBank = nBankID; ListPerformances(); } @@ -1216,14 +1235,19 @@ std::string CPerformanceConfig::AddPerformanceBankDirName(unsigned nBankID) assert (nBankID < NUM_PERFORMANCE_BANKS); if (IsValidPerformanceBank(nBankID)) { - // Performance Banks directories in format "01_Bank Name" + // Performance Banks directories in format "001_Bank Name" std::string Index; if (nBankID == 0) { // Legacy: Bank 1 is the default performance directory return ""; } + if (nBankID < 9) + { + Index = "00" + std::to_string(nBankID+1); + } + else if (nBankID < 99) { Index = "0" + std::to_string(nBankID+1); } @@ -1231,6 +1255,7 @@ std::string CPerformanceConfig::AddPerformanceBankDirName(unsigned nBankID) { Index = std::to_string(nBankID+1); } + return "/" + Index + "_" + m_PerformanceBankName[nBankID]; } else diff --git a/src/performanceconfig.h b/src/performanceconfig.h index 8960f852..df019499 100644 --- a/src/performanceconfig.h +++ b/src/performanceconfig.h @@ -27,8 +27,8 @@ #include #include #define NUM_VOICE_PARAM 156 -#define NUM_PERFORMANCES 256 -#define NUM_PERFORMANCE_BANKS 64 +#define NUM_PERFORMANCES 128 +#define NUM_PERFORMANCE_BANKS 128 class CPerformanceConfig // Performance configuration { diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 02653d14..129c1d5b 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -1213,24 +1213,43 @@ void CUIMenu::PgmUpDownHandler (TMenuEvent Event) // Program Up/Down acts on performances unsigned nLastPerformance = m_pMiniDexed->GetLastPerformance(); unsigned nPerformance = m_pMiniDexed->GetActualPerformanceID(); + unsigned nStart = nPerformance; //LOGNOTE("Performance actual=%d, last=%d", nPerformance, nLastPerformance); if (Event == MenuEventPgmDown) { - if (nPerformance > 0) + do { - m_nSelectedPerformanceID = nPerformance-1; - m_pMiniDexed->SetNewPerformance(m_nSelectedPerformanceID); - //LOGNOTE("Performance new=%d, last=%d", m_nSelectedPerformanceID, nLastPerformance); - } + if (nPerformance == 0) + { + // Wrap around + nPerformance = nLastPerformance; + } + else if (nPerformance > 0) + { + --nPerformance; + } + } while ((m_pMiniDexed->IsValidPerformance(nPerformance) != true) && (nPerformance != nStart)); + m_nSelectedPerformanceID = nPerformance; + m_pMiniDexed->SetNewPerformance(m_nSelectedPerformanceID); + //LOGNOTE("Performance new=%d, last=%d", m_nSelectedPerformanceID, nLastPerformance); } - else + else // MenuEventPgmUp { - if (nPerformance < nLastPerformance-1) + do { - m_nSelectedPerformanceID = nPerformance+1; - m_pMiniDexed->SetNewPerformance(m_nSelectedPerformanceID); - //LOGNOTE("Performance new=%d, last=%d", m_nSelectedPerformanceID, nLastPerformance); - } + if (nPerformance == nLastPerformance) + { + // Wrap around + nPerformance = 0; + } + else if (nPerformance < nLastPerformance) + { + ++nPerformance; + } + } while ((m_pMiniDexed->IsValidPerformance(nPerformance) != true) && (nPerformance != nStart)); + m_nSelectedPerformanceID = nPerformance; + m_pMiniDexed->SetNewPerformance(m_nSelectedPerformanceID); + //LOGNOTE("Performance new=%d, last=%d", m_nSelectedPerformanceID, nLastPerformance); } } else @@ -1503,8 +1522,8 @@ void CUIMenu::PerformanceMenu (CUIMenu *pUIMenu, TMenuEvent Event) } pUIMenu->m_pUI->DisplayWrite (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, nPSelected.c_str(), - Value.c_str (), - (int) nValue > 0, (int) nValue < (int) pUIMenu->m_pMiniDexed->GetLastPerformance()-1); + Value.c_str (), true, true); +// (int) nValue > 0, (int) nValue < (int) pUIMenu->m_pMiniDexed->GetLastPerformance()); } else { From 5e910a52011b2f63c67b5ceca5c6b2f94cafb7e2 Mon Sep 17 00:00:00 2001 From: Kevin <68612569+diyelectromusic@users.noreply.github.com> Date: Sat, 30 Dec 2023 09:03:43 -0800 Subject: [PATCH 06/15] Bugfixes for legacy cases when no performance directory exists plus some extra checks for saving and deleting performances. --- src/minidexed.cpp | 26 ++++++++++++++---- src/performanceconfig.cpp | 58 +++++++++++++++++++++++++++++++++------ src/uimenu.cpp | 2 +- 3 files changed, 71 insertions(+), 15 deletions(-) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index cdd293c1..2395aa2a 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -1219,10 +1219,17 @@ void CMiniDexed::SetPerformanceSelectChannel (unsigned uCh) bool CMiniDexed::SavePerformance (bool bSaveAsDeault) { - m_bSavePerformance = true; - m_bSaveAsDeault=bSaveAsDeault; + if (m_PerformanceConfig.GetInternalFolderOk()) + { + m_bSavePerformance = true; + m_bSaveAsDeault=bSaveAsDeault; - return true; + return true; + } + else + { + return false; + } } bool CMiniDexed::DoSavePerformance (void) @@ -1702,10 +1709,17 @@ void CMiniDexed::SetVoiceName (std::string VoiceName, unsigned nTG) bool CMiniDexed::DeletePerformance(unsigned nID) { - m_bDeletePerformance = true; - m_nDeletePerformanceID = nID; + if (m_PerformanceConfig.IsValidPerformance(nID) && m_PerformanceConfig.GetInternalFolderOk()) + { + m_bDeletePerformance = true; + m_nDeletePerformanceID = nID; - return true; + return true; + } + else + { + return false; + } } bool CMiniDexed::DoDeletePerformance(void) diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index 340edf32..8af5255b 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -29,7 +29,7 @@ LOGMODULE ("Performance"); -//#define VERBOSE_DEBUG +#define VERBOSE_DEBUG #define PERFORMANCE_DIR "performance" #define DEFAULT_PERFORMANCE_FILENAME "performance.ini" @@ -796,10 +796,13 @@ std::string CPerformanceConfig::GetPerformanceFullFilePath(unsigned nID) } else { - FileN += PERFORMANCE_DIR; - FileN += AddPerformanceBankDirName(m_nPerformanceBank); - FileN += "/"; - FileN += GetPerformanceFileName(nID); + if (m_bPerformanceDirectoryExists) + { + FileN += PERFORMANCE_DIR; + FileN += AddPerformanceBankDirName(m_nPerformanceBank); + FileN += "/"; + FileN += GetPerformanceFileName(nID); + } } return FileN; } @@ -807,7 +810,14 @@ std::string CPerformanceConfig::GetPerformanceFullFilePath(unsigned nID) std::string CPerformanceConfig::GetPerformanceName(unsigned nID) { assert (nID < NUM_PERFORMANCES); - return m_PerformanceFileName[nID]; + if ((m_nPerformanceBank==0) && (nID == 0)) // in order to assure retrocompatibility + { + return DEFAULT_PERFORMANCE_NAME; + } + else + { + return m_PerformanceFileName[nID]; + } } unsigned CPerformanceConfig::GetLastPerformance() @@ -852,7 +862,7 @@ bool CPerformanceConfig::IsValidPerformance(unsigned nID) bool CPerformanceConfig::CheckFreePerformanceSlot(void) { - if (m_nLastPerformance < NUM_PERFORMANCES) + if (m_nLastPerformance < NUM_PERFORMANCES-1) { // There is a free slot... return true; @@ -865,6 +875,12 @@ bool CPerformanceConfig::CheckFreePerformanceSlot(void) bool CPerformanceConfig::CreateNewPerformanceFile(void) { + if (!m_bPerformanceDirectoryExists) + { + // Nothing can be done if there is no performance directory + LOGNOTE("Performance directory does not exist"); + return false; + } if (m_nLastPerformance >= NUM_PERFORMANCES) { // No space left for new performances LOGWARN ("No space left for new performance"); @@ -1076,6 +1092,12 @@ void CPerformanceConfig::SetNewPerformanceName(std::string nName) bool CPerformanceConfig::DeletePerformance(unsigned nID) { + if (!m_bPerformanceDirectoryExists) + { + // Nothing can be done if there is no performance directory + LOGNOTE("Performance directory does not exist"); + return false; + } bool bOK = false; if((m_nPerformanceBank == 0) && (nID == 0)){return bOK;} // default (performance.ini at root directory) can't be deleted DIR Directory; @@ -1096,6 +1118,15 @@ bool CPerformanceConfig::DeletePerformance(unsigned nID) m_nActualPerformance =0; //nMenuSelectedPerformance=0; m_PerformanceFileName[nID].clear(); + // If this was the last performance in the bank... + if (nID == m_nLastPerformance) + { + do + { + // Find the new last performance + m_nLastPerformance--; + } while (!IsValidPerformance(m_nLastPerformance) && (m_nLastPerformance > 0)); + } bOK=true; } else @@ -1108,6 +1139,10 @@ bool CPerformanceConfig::DeletePerformance(unsigned nID) bool CPerformanceConfig::ListPerformanceBanks() { + m_nPerformanceBank = 0; + m_nLastPerformance = 0; + m_nLastPerformanceBank = 0; + // Open performance directory DIR Directory; FILINFO FileInfo; @@ -1117,11 +1152,12 @@ bool CPerformanceConfig::ListPerformanceBanks() { // No performance directory, so no performance banks. // So nothing else to do here + LOGNOTE ("No performance banks detected"); + m_bPerformanceDirectoryExists = false; return false; } unsigned nNumBanks = 0; - m_nLastPerformanceBank = 0; // Add in the default performance directory as the first bank m_PerformanceBankName[0] = DEFAULT_PERFORMANCE_BANK_NAME; @@ -1210,6 +1246,12 @@ void CPerformanceConfig::SetPerformanceBank(unsigned nBankID) m_nPerformanceBank = nBankID; ListPerformances(); } + else + { +#ifdef VERBOSE_DEBUG + LOGNOTE("Not selecting invalid Performance Bank: %d", nBankID+1); +#endif + } } unsigned CPerformanceConfig::GetPerformanceBank(void) diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 129c1d5b..a7f241c0 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -1460,7 +1460,7 @@ void CUIMenu::PerformanceMenu (CUIMenu *pUIMenu, TMenuEvent Event) break; case 1: - if (pUIMenu->m_nSelectedPerformanceID != 0) + if (pUIMenu->m_pMiniDexed->IsValidPerformance(pUIMenu->m_nSelectedPerformanceID)) { pUIMenu->m_bPerformanceDeleteMode=true; pUIMenu->m_bConfirmDeletePerformance=false; From 7a9dd25786b7e7e4c86e88c435680e3ddc0a6cb8 Mon Sep 17 00:00:00 2001 From: Kevin <68612569+diyelectromusic@users.noreply.github.com> Date: Sat, 30 Dec 2023 09:06:12 -0800 Subject: [PATCH 07/15] Remove verbose debug options (doh!) --- src/performanceconfig.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index 8af5255b..d6f59bdb 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -29,7 +29,7 @@ LOGMODULE ("Performance"); -#define VERBOSE_DEBUG +//#define VERBOSE_DEBUG #define PERFORMANCE_DIR "performance" #define DEFAULT_PERFORMANCE_FILENAME "performance.ini" From e49a410d7eb858350e10ccaf64e3374f6bffcec8 Mon Sep 17 00:00:00 2001 From: Kevin <68612569+diyelectromusic@users.noreply.github.com> Date: Sat, 30 Dec 2023 09:20:22 -0800 Subject: [PATCH 08/15] Fix a minor off-by-one error found in review. --- src/performanceconfig.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index d6f59bdb..b36dfea0 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -1,4 +1,3 @@ - // // performanceconfig.cpp // @@ -982,7 +981,7 @@ bool CPerformanceConfig::ListPerformances() Result = f_findfirst (&Directory, &FileInfo, PerfDir.c_str(), "*.ini"); for (unsigned i = 0; Result == FR_OK && FileInfo.fname[0]; i++) { - if (m_nLastPerformance >= NUM_PERFORMANCES) { + if (m_nLastPerformance >= NUM_PERFORMANCES - 1) { LOGNOTE ("Skipping performance %s", FileInfo.fname); } else { if (!(FileInfo.fattrib & (AM_HID | AM_SYS))) From 692f57ae9e54150d97301ebea39ccbd4d061f271 Mon Sep 17 00:00:00 2001 From: Kevin <68612569+diyelectromusic@users.noreply.github.com> Date: Sun, 31 Dec 2023 01:52:55 -0800 Subject: [PATCH 09/15] Bugfix - removed redundant legacy check that results in out of order performance files being skipped on load. --- src/performanceconfig.cpp | 78 +++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 41 deletions(-) diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index b36dfea0..168a0e0d 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -981,55 +981,51 @@ bool CPerformanceConfig::ListPerformances() Result = f_findfirst (&Directory, &FileInfo, PerfDir.c_str(), "*.ini"); for (unsigned i = 0; Result == FR_OK && FileInfo.fname[0]; i++) { - if (m_nLastPerformance >= NUM_PERFORMANCES - 1) { - LOGNOTE ("Skipping performance %s", FileInfo.fname); - } else { - if (!(FileInfo.fattrib & (AM_HID | AM_SYS))) + if (!(FileInfo.fattrib & (AM_HID | AM_SYS))) + { + std::string OriFileName = FileInfo.fname; + size_t nLen = OriFileName.length(); + if ( nLen > 8 && nLen <26 && strcmp(OriFileName.substr(6,1).c_str(), "_")==0) { - std::string OriFileName = FileInfo.fname; - size_t nLen = OriFileName.length(); - if ( nLen > 8 && nLen <26 && strcmp(OriFileName.substr(6,1).c_str(), "_")==0) + // Note: m_nLastPerformance - refers to the number (index) of the last performance in memory, + // which includes a default performance. + // + // Filenames on the disk start from 1 to match what the user might see in MIDI. + // So this means that actually file 000001_ will correspond to index position [0]. + // For the default bank though, ID 1 is the default performance, so will already exist. + // m_PerformanceFileName[0] = default performance (file 000001) + // m_PerformanceFileName[1] = first available on-disk performance (file 000002) + // + // Note2: filenames assume 6 digits, underscore, name, finally ".ini" + // i.e. 123456_Performance Name.ini + // + nPIndex=stoi(OriFileName.substr(0,6)); + if ((nPIndex < 1) || (nPIndex >= (NUM_PERFORMANCES+1))) { - // Note: m_nLastPerformance - refers to the number (index) of the last performance in memory, - // which includes a default performance. - // - // Filenames on the disk start from 1 to match what the user might see in MIDI. - // So this means that actually file 000001_ will correspond to index position [0]. - // For the default bank though, ID 1 is the default performance, so will already exist. - // m_PerformanceFileName[0] = default performance (file 000001) - // m_PerformanceFileName[1] = first available on-disk performance (file 000002) - // - // Note2: filenames assume 6 digits, underscore, name, finally ".ini" - // i.e. 123456_Performance Name.ini - // - nPIndex=stoi(OriFileName.substr(0,6)); - if ((nPIndex < 1) || (nPIndex >= (NUM_PERFORMANCES+1))) - { - // Index is out of range - skip to next file - LOGNOTE ("Performance number out of range: %s (%d to %d)", FileInfo.fname, 1, NUM_PERFORMANCES); - } - else + // Index is out of range - skip to next file + LOGNOTE ("Performance number out of range: %s (%d to %d)", FileInfo.fname, 1, NUM_PERFORMANCES); + } + else + { + // Convert from "user facing" 1..indexed number to internal 0..indexed + nPIndex = nPIndex-1; + if (m_PerformanceFileName[nPIndex].empty()) { - // Convert from "user facing" 1..indexed number to internal 0..indexed - nPIndex = nPIndex-1; - if (m_PerformanceFileName[nPIndex].empty()) + if(nPIndex > m_nLastPerformance) { - if(nPIndex > m_nLastPerformance) - { - m_nLastPerformance=nPIndex; - } + m_nLastPerformance=nPIndex; + } - std::string FileName = OriFileName.substr(0,OriFileName.length()-4).substr(7,14); + std::string FileName = OriFileName.substr(0,OriFileName.length()-4).substr(7,14); - m_PerformanceFileName[nPIndex] = FileName; + m_PerformanceFileName[nPIndex] = FileName; #ifdef VERBOSE_DEBUG - LOGNOTE ("Loading performance %s (%d, %s)", OriFileName.c_str(), nPIndex, FileName.c_str()); + LOGNOTE ("Loading performance %s (%d, %s)", OriFileName.c_str(), nPIndex, FileName.c_str()); #endif - } - else - { - LOGNOTE ("Duplicate performance %s", OriFileName.c_str()); - } + } + else + { + LOGNOTE ("Duplicate performance %s", OriFileName.c_str()); } } } From 7c6d5440083e46478923c54b6612babe910adf7f Mon Sep 17 00:00:00 2001 From: Kevin <68612569+diyelectromusic@users.noreply.github.com> Date: Wed, 3 Jan 2024 15:43:17 -0800 Subject: [PATCH 10/15] Fix bug in MIDI button handling commands. --- src/mididevice.cpp | 4 ++++ src/userinterface.cpp | 3 +++ 2 files changed, 7 insertions(+) diff --git a/src/mididevice.cpp b/src/mididevice.cpp index b5959bff..81314ba3 100644 --- a/src/mididevice.cpp +++ b/src/mididevice.cpp @@ -207,6 +207,10 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign } } } + if (nLength == 3) + { + m_pUI->UIMIDICmdHandler (ucChannel, ucStatus & 0xF0, pMessage[1], pMessage[2]); + } break; case MIDI_NOTE_OFF: diff --git a/src/userinterface.cpp b/src/userinterface.cpp index 1c0716ed..a2d78f18 100644 --- a/src/userinterface.cpp +++ b/src/userinterface.cpp @@ -388,13 +388,16 @@ void CUserInterface::UISetMIDIButtonChannel (unsigned uCh) if (uCh == 0) { m_nMIDIButtonCh = CMIDIDevice::Disabled; + LOGNOTE("MIDI Button channel not set"); } else if (uCh < CMIDIDevice::Channels) { m_nMIDIButtonCh = uCh - 1; + LOGNOTE("MIDI Button channel set to: %d", m_nMIDIButtonCh); } else { m_nMIDIButtonCh = CMIDIDevice::OmniMode; + LOGNOTE("MIDI Button channel set to: OMNI"); } } \ No newline at end of file From 726470abfd8549b609c702551e5a58a6dc00e08d Mon Sep 17 00:00:00 2001 From: Kevin <68612569+diyelectromusic@users.noreply.github.com> Date: Mon, 8 Jan 2024 09:02:46 -0800 Subject: [PATCH 11/15] Fix for issue where wrong performance is selected [L] on new save. --- src/performanceconfig.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index 168a0e0d..ed98796d 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -899,7 +899,6 @@ bool CPerformanceConfig::CreateNewPerformanceFile(void) std::string sPerformanceName = NewPerformanceName; NewPerformanceName=""; - m_nActualPerformance=m_nLastPerformance; unsigned nNewPerformance = m_nLastPerformance + 1; std::string nFileName; std::string nPath; @@ -943,6 +942,7 @@ bool CPerformanceConfig::CreateNewPerformanceFile(void) } m_nLastPerformance = nNewPerformance; + m_nActualPerformance = nNewPerformance; new (&m_Properties) CPropertiesFatFsFile(nFileName.c_str(), m_pFileSystem); return true; From 66409c6739589b6e7301049f55ebc1e8c8c03a7b Mon Sep 17 00:00:00 2001 From: Kevin <68612569+diyelectromusic@users.noreply.github.com> Date: Mon, 8 Jan 2024 09:51:44 -0800 Subject: [PATCH 12/15] Suggested update to UI to show bank/performance numbers. --- src/minidexed.cpp | 5 +++++ src/minidexed.h | 1 + src/uimenu.cpp | 20 +++++++++++++++----- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 2395aa2a..cdad60a4 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -1546,6 +1546,11 @@ unsigned CMiniDexed::GetLastPerformance() return m_PerformanceConfig.GetLastPerformance(); } +unsigned CMiniDexed::GetPerformanceBank() +{ + return m_PerformanceConfig.GetPerformanceBank(); +} + unsigned CMiniDexed::GetLastPerformanceBank() { return m_PerformanceConfig.GetLastPerformanceBank(); diff --git a/src/minidexed.h b/src/minidexed.h index 14aa88bc..38f98418 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -121,6 +121,7 @@ class CMiniDexed std::string GetPerformanceFileName(unsigned nID); std::string GetPerformanceName(unsigned nID); unsigned GetLastPerformance(); + unsigned GetPerformanceBank(); unsigned GetLastPerformanceBank(); unsigned GetActualPerformanceID(); void SetActualPerformanceID(unsigned nID); diff --git a/src/uimenu.cpp b/src/uimenu.cpp index a7f241c0..2bacb682 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -1513,12 +1513,19 @@ void CUIMenu::PerformanceMenu (CUIMenu *pUIMenu, TMenuEvent Event) if(!pUIMenu->m_bPerformanceDeleteMode) { Value = pUIMenu->m_pMiniDexed->GetPerformanceName(nValue); + unsigned nBankNum = pUIMenu->m_pMiniDexed->GetPerformanceBank(); - - std::string nPSelected = ""; + std::string nPSelected = "000"; + nPSelected += std::to_string(nBankNum+1); // Convert to user-facing bank number rather than index + nPSelected = nPSelected.substr(nPSelected.length()-3,3); + std::string nPPerf = "000"; + nPPerf += std::to_string(nValue+1); // Convert to user-facing performance number rather than index + nPPerf = nPPerf.substr(nPPerf.length()-3,3); + + nPSelected += ":"+nPPerf; if(nValue == pUIMenu->m_pMiniDexed->GetActualPerformanceID()) { - nPSelected= "[L]"; + nPSelected += " [L]"; } pUIMenu->m_pUI->DisplayWrite (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, nPSelected.c_str(), @@ -1600,10 +1607,13 @@ void CUIMenu::EditPerformanceBankNumber (CUIMenu *pUIMenu, TMenuEvent Event) } Value = pUIMenu->m_pMiniDexed->GetPerformanceConfig ()->GetPerformanceBankName(nValue); - std::string nPSelected = ""; + std::string nPSelected = "000"; + nPSelected += std::to_string(nValue+1); // Convert to user-facing number rather than index + nPSelected = nPSelected.substr(nPSelected.length()-3,3); + if(nValue == (unsigned)pUIMenu->m_pMiniDexed->GetParameter (CMiniDexed::ParameterPerformanceBank)) { - nPSelected= "[L]"; + nPSelected += " [L]"; } pUIMenu->m_pUI->DisplayWrite (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, nPSelected.c_str(), From 07cdafc1f295dd33e51e5e9d8489fc822448c597 Mon Sep 17 00:00:00 2001 From: Kevin <68612569+diyelectromusic@users.noreply.github.com> Date: Sun, 14 Jan 2024 13:09:53 -0800 Subject: [PATCH 13/15] Make performance bank select asynchronous to MIDI and UI to stop corruptions on loading performances. --- src/minidexed.cpp | 71 ++++++++++++++++++++++++++++++++++----- src/minidexed.h | 11 +++++- src/performanceconfig.cpp | 18 ++++++++-- src/performanceconfig.h | 5 ++- src/uimenu.cpp | 6 ++-- 5 files changed, 95 insertions(+), 16 deletions(-) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index cdad60a4..8ce5ca26 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -53,8 +53,11 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, m_bSavePerformance (false), m_bSavePerformanceNewFile (false), m_bSetNewPerformance (false), + m_bSetNewPerformanceBank (false), + m_bSetFirstPerformance (false), m_bDeletePerformance (false), - m_bLoadPerformanceBusy(false) + m_bLoadPerformanceBusy(false), + m_bLoadPerformanceBankBusy(false) { assert (m_pConfig); @@ -302,14 +305,30 @@ void CMiniDexed::Process (bool bPlugAndPlayUpdated) m_bSavePerformanceNewFile = false; } - if (m_bSetNewPerformance && !m_bLoadPerformanceBusy) + if (m_bSetNewPerformanceBank && !m_bLoadPerformanceBusy && !m_bLoadPerformanceBankBusy) + { + DoSetNewPerformanceBank (); + if (m_nSetNewPerformanceBankID == GetActualPerformanceBankID()) + { + m_bSetNewPerformanceBank = false; + } + + // If there is no pending SetNewPerformance already, then see if we need to find the first performance to load + // NB: If called from the UI, then there will not be a SetNewPerformance, so load the first existing one. + // If called from MIDI, there will probably be a SetNewPerformance alongside the Bank select. + if (!m_bSetNewPerformance && m_bSetFirstPerformance) + { + DoSetFirstPerformance(); + } + } + + if (m_bSetNewPerformance && !m_bSetNewPerformanceBank && !m_bLoadPerformanceBusy && !m_bLoadPerformanceBankBusy) { DoSetNewPerformance (); if (m_nSetNewPerformanceID == GetActualPerformanceID()) { m_bSetNewPerformance = false; } - } if(m_bDeletePerformance) @@ -419,7 +438,7 @@ void CMiniDexed::BankSelectPerformance (unsigned nBank) { // Only change if we have the bank loaded m_nVoiceBankIDPerformance = nBank; - GetPerformanceConfig ()->SetPerformanceBank (nBank); + SetNewPerformanceBank (nBank); m_UI.ParameterChanged (); } @@ -1566,6 +1585,16 @@ void CMiniDexed::SetActualPerformanceID(unsigned nID) m_PerformanceConfig.SetActualPerformanceID(nID); } +unsigned CMiniDexed::GetActualPerformanceBankID() +{ + return m_PerformanceConfig.GetActualPerformanceBankID(); +} + +void CMiniDexed::SetActualPerformanceBankID(unsigned nBankID) +{ + m_PerformanceConfig.SetActualPerformanceBankID(nBankID); +} + bool CMiniDexed::SetNewPerformance(unsigned nID) { m_bSetNewPerformance = true; @@ -1574,11 +1603,18 @@ bool CMiniDexed::SetNewPerformance(unsigned nID) return true; } -unsigned CMiniDexed::SetFirstPerformance(void) +bool CMiniDexed::SetNewPerformanceBank(unsigned nBankID) { - unsigned nID = m_PerformanceConfig.FindFirstPerformance(); - SetNewPerformance(nID); - return nID; + m_bSetNewPerformanceBank = true; + m_nSetNewPerformanceBankID = nBankID; + + return true; +} + +void CMiniDexed::SetFirstPerformance(void) +{ + m_bSetFirstPerformance = true; + return; } bool CMiniDexed::DoSetNewPerformance (void) @@ -1602,6 +1638,25 @@ bool CMiniDexed::DoSetNewPerformance (void) } } +bool CMiniDexed::DoSetNewPerformanceBank (void) +{ + m_bLoadPerformanceBankBusy = true; + + unsigned nBankID = m_nSetNewPerformanceBankID; + m_PerformanceConfig.SetNewPerformanceBank(nBankID); + + m_bLoadPerformanceBankBusy = false; + return true; +} + +void CMiniDexed::DoSetFirstPerformance(void) +{ + unsigned nID = m_PerformanceConfig.FindFirstPerformance(); + SetNewPerformance(nID); + m_bSetFirstPerformance = false; + return; +} + bool CMiniDexed::SavePerformanceNewFile () { m_bSavePerformanceNewFile = m_PerformanceConfig.GetInternalFolderOk() && m_PerformanceConfig.CheckFreePerformanceSlot(); diff --git a/src/minidexed.h b/src/minidexed.h index 38f98418..407d5db8 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -125,12 +125,17 @@ class CMiniDexed unsigned GetLastPerformanceBank(); unsigned GetActualPerformanceID(); void SetActualPerformanceID(unsigned nID); + unsigned GetActualPerformanceBankID(); + void SetActualPerformanceBankID(unsigned nBankID); bool SetNewPerformance(unsigned nID); - unsigned SetFirstPerformance(void); + bool SetNewPerformanceBank(unsigned nBankID); + void SetFirstPerformance(void); + void DoSetFirstPerformance(void); bool SavePerformanceNewFile (); bool DoSavePerformanceNewFile (void); bool DoSetNewPerformance (void); + bool DoSetNewPerformanceBank (void); bool GetPerformanceSelectToLoad(void); bool SavePerformance (bool bSaveAsDeault); unsigned GetPerformanceSelectChannel (void); @@ -317,9 +322,13 @@ class CMiniDexed bool m_bSavePerformanceNewFile; bool m_bSetNewPerformance; unsigned m_nSetNewPerformanceID; + bool m_bSetNewPerformanceBank; + unsigned m_nSetNewPerformanceBankID; + bool m_bSetFirstPerformance; bool m_bDeletePerformance; unsigned m_nDeletePerformanceID; bool m_bLoadPerformanceBusy; + bool m_bLoadPerformanceBankBusy; bool m_bSaveAsDeault; }; diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index ed98796d..193766a6 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -72,13 +72,13 @@ bool CPerformanceConfig::Init (void) { if (!m_PerformanceBankName[i].empty()) { - SetPerformanceBank(i); + SetNewPerformanceBank(i); SetNewPerformance(0); } } #endif // Set to default initial bank - SetPerformanceBank(0); + SetNewPerformanceBank(0); SetNewPerformance(0); LOGNOTE ("Loaded Default Performance Bank - Last Performance: %d", m_nLastPerformance + 1); // Show "user facing" index @@ -840,6 +840,17 @@ void CPerformanceConfig::SetActualPerformanceID(unsigned nID) m_nActualPerformance = nID; } +unsigned CPerformanceConfig::GetActualPerformanceBankID() +{ + return m_nActualPerformanceBank; +} + +void CPerformanceConfig::SetActualPerformanceBankID(unsigned nBankID) +{ + assert (nBankID < NUM_PERFORMANCE_BANKS); + m_nActualPerformanceBank = nBankID; +} + bool CPerformanceConfig::GetInternalFolderOk() { return m_bPerformanceDirectoryExists; @@ -1230,7 +1241,7 @@ bool CPerformanceConfig::ListPerformanceBanks() return true; } -void CPerformanceConfig::SetPerformanceBank(unsigned nBankID) +void CPerformanceConfig::SetNewPerformanceBank(unsigned nBankID) { assert (nBankID < NUM_PERFORMANCE_BANKS); if (IsValidPerformanceBank(nBankID)) @@ -1239,6 +1250,7 @@ void CPerformanceConfig::SetPerformanceBank(unsigned nBankID) LOGNOTE("Selecting Performance Bank: %d", nBankID+1); #endif m_nPerformanceBank = nBankID; + m_nActualPerformanceBank = nBankID; ListPerformances(); } else diff --git a/src/performanceconfig.h b/src/performanceconfig.h index df019499..0d50daa8 100644 --- a/src/performanceconfig.h +++ b/src/performanceconfig.h @@ -132,6 +132,8 @@ class CPerformanceConfig // Performance configuration unsigned GetLastPerformanceBank(); void SetActualPerformanceID(unsigned nID); unsigned GetActualPerformanceID(); + void SetActualPerformanceBankID(unsigned nBankID); + unsigned GetActualPerformanceBankID(); bool CreateNewPerformanceFile(void); bool GetInternalFolderOk(); std::string GetNewPerformanceDefaultName(void); @@ -142,7 +144,7 @@ class CPerformanceConfig // Performance configuration bool IsValidPerformance(unsigned nID); bool ListPerformanceBanks(void); - void SetPerformanceBank(unsigned nBankID); + void SetNewPerformanceBank(unsigned nBankID); unsigned GetPerformanceBank(void); std::string GetPerformanceBankName(unsigned nBankID); bool IsValidPerformanceBank(unsigned nBankID); @@ -181,6 +183,7 @@ class CPerformanceConfig // Performance configuration unsigned m_nLastPerformance; unsigned m_nActualPerformance = 0; + unsigned m_nActualPerformanceBank = 0; unsigned m_nPerformanceBank; unsigned m_nLastPerformanceBank; bool m_bPerformanceDirectoryExists; diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 2bacb682..e09e3016 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -1569,7 +1569,7 @@ void CUIMenu::EditPerformanceBankNumber (CUIMenu *pUIMenu, TMenuEvent Event) { // Switch to the new bank and select the first performance voice pUIMenu->m_pMiniDexed->SetParameter (CMiniDexed::ParameterPerformanceBank, nValue); - pUIMenu->m_nSelectedPerformanceID = pUIMenu->m_pMiniDexed->SetFirstPerformance(); + pUIMenu->m_pMiniDexed->SetFirstPerformance(); } break; @@ -1590,7 +1590,7 @@ void CUIMenu::EditPerformanceBankNumber (CUIMenu *pUIMenu, TMenuEvent Event) if (!bPerformanceSelectToLoad) { pUIMenu->m_pMiniDexed->SetParameter (CMiniDexed::ParameterPerformanceBank, nValue); - pUIMenu->m_nSelectedPerformanceID = pUIMenu->m_pMiniDexed->SetFirstPerformance(); + pUIMenu->m_pMiniDexed->SetFirstPerformance(); } break; @@ -1598,7 +1598,7 @@ void CUIMenu::EditPerformanceBankNumber (CUIMenu *pUIMenu, TMenuEvent Event) if (bPerformanceSelectToLoad) { pUIMenu->m_pMiniDexed->SetParameter (CMiniDexed::ParameterPerformanceBank, nValue); - pUIMenu->m_nSelectedPerformanceID = pUIMenu->m_pMiniDexed->SetFirstPerformance(); + pUIMenu->m_pMiniDexed->SetFirstPerformance(); } break; From 7d18461d099ee619623d8610b772e74e42f4679c Mon Sep 17 00:00:00 2001 From: Kevin <68612569+diyelectromusic@users.noreply.github.com> Date: Mon, 15 Jan 2024 08:58:20 -0800 Subject: [PATCH 14/15] Fix an assert that should be a run-time test. --- src/performanceconfig.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index 193766a6..53a3eeba 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -1,3 +1,4 @@ + // // performanceconfig.cpp // @@ -1315,7 +1316,9 @@ std::string CPerformanceConfig::AddPerformanceBankDirName(unsigned nBankID) bool CPerformanceConfig::IsValidPerformanceBank(unsigned nBankID) { - assert (nBankID < NUM_PERFORMANCE_BANKS); + if (nBankID >= NUM_PERFORMANCE_BANKS) { + return false; + } if (m_PerformanceBankName[nBankID].empty()) { return false; From aeac944ff0907ce1d89b62d29d529602f9a5bf6f Mon Sep 17 00:00:00 2001 From: Kevin <68612569+diyelectromusic@users.noreply.github.com> Date: Tue, 23 Jan 2024 14:46:52 -0800 Subject: [PATCH 15/15] Ensure bank selection works when PCCH is not enabled, and that UI remains consistent when changing banks. --- src/minidexed.cpp | 13 +++++-------- src/performanceconfig.cpp | 1 - src/uimenu.cpp | 6 ++++++ 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 8ce5ca26..968320ab 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -432,16 +432,13 @@ void CMiniDexed::BankSelectPerformance (unsigned nBank) { nBank=constrain((int)nBank,0,16383); - if (m_nParameter[ParameterPerformanceSelectChannel] != CMIDIDevice::Disabled) + if (GetPerformanceConfig ()->IsValidPerformanceBank(nBank)) { - if (GetPerformanceConfig ()->IsValidPerformanceBank(nBank)) - { - // Only change if we have the bank loaded - m_nVoiceBankIDPerformance = nBank; - SetNewPerformanceBank (nBank); + // Only change if we have the bank loaded + m_nVoiceBankIDPerformance = nBank; + SetNewPerformanceBank (nBank); - m_UI.ParameterChanged (); - } + m_UI.ParameterChanged (); } } diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index 53a3eeba..8cd62757 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -1,4 +1,3 @@ - // // performanceconfig.cpp // diff --git a/src/uimenu.cpp b/src/uimenu.cpp index e09e3016..82a426a8 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -1390,6 +1390,12 @@ void CUIMenu::PerformanceMenu (CUIMenu *pUIMenu, TMenuEvent Event) unsigned nLastPerformance = pUIMenu->m_pMiniDexed->GetLastPerformance(); unsigned nValue = pUIMenu->m_nSelectedPerformanceID; unsigned nStart = nValue; + if (pUIMenu->m_pMiniDexed->IsValidPerformance(nValue) != true) + { + // A bank change has left the selected performance out of sync + nValue = pUIMenu->m_pMiniDexed->GetActualPerformanceID(); + pUIMenu->m_nSelectedPerformanceID = nValue; + } std::string Value; if (Event == MenuEventUpdate)