From 60ab4a562b38cf9ac3e05b85462d61193bddef27 Mon Sep 17 00:00:00 2001 From: arsamus Date: Sat, 28 May 2022 03:08:17 -0300 Subject: [PATCH] Switchable performance files and saving all voice data parameters. (#228) --- src/minidexed.cpp | 196 ++++++++++++++++++++++++++++------ src/minidexed.h | 26 ++++- src/performance.ini | 9 ++ src/performanceconfig.cpp | 217 ++++++++++++++++++++++++++++++++++++++ src/performanceconfig.h | 31 +++++- src/uimenu.cpp | 81 +++++++++++++- src/uimenu.h | 5 +- 7 files changed, 525 insertions(+), 40 deletions(-) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 5e685e2..c09eb42 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -50,7 +50,9 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, m_GetChunkTimer ("GetChunk", 1000000U * pConfig->GetChunkSize ()/2 / pConfig->GetSampleRate ()), m_bProfileEnabled (m_pConfig->GetProfileEnabled ()), - m_bSavePerformance (false) + m_bSavePerformance (false), + m_bSavePerformanceNewFile (false), + m_bSetNewPerformance (false) { assert (m_pConfig); @@ -185,44 +187,19 @@ bool CMiniDexed::Initialize (void) if (m_PerformanceConfig.Load ()) { - for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++) - { - BankSelectLSB (m_PerformanceConfig.GetBankNumber (nTG), nTG); - ProgramChange (m_PerformanceConfig.GetVoiceNumber (nTG), nTG); - SetMIDIChannel (m_PerformanceConfig.GetMIDIChannel (nTG), nTG); - SetVolume (m_PerformanceConfig.GetVolume (nTG), nTG); - SetPan (m_PerformanceConfig.GetPan (nTG), nTG); - SetMasterTune (m_PerformanceConfig.GetDetune (nTG), nTG); - SetCutoff (m_PerformanceConfig.GetCutoff (nTG), nTG); - SetResonance (m_PerformanceConfig.GetResonance (nTG), nTG); - setPitchbendRange (m_PerformanceConfig.GetPitchBendRange (nTG), nTG); - setPitchbendStep (m_PerformanceConfig.GetPitchBendStep (nTG), nTG); - setPortamentoMode (m_PerformanceConfig.GetPortamentoMode (nTG), nTG); - setPortamentoGlissando (m_PerformanceConfig.GetPortamentoGlissando (nTG), nTG); - setPortamentoTime (m_PerformanceConfig.GetPortamentoTime (nTG), nTG); - - m_nNoteLimitLow[nTG] = m_PerformanceConfig.GetNoteLimitLow (nTG); - m_nNoteLimitHigh[nTG] = m_PerformanceConfig.GetNoteLimitHigh (nTG); - m_nNoteShift[nTG] = m_PerformanceConfig.GetNoteShift (nTG); - - SetReverbSend (m_PerformanceConfig.GetReverbSend (nTG), nTG); - } - - // Effects - SetParameter (ParameterCompressorEnable, m_PerformanceConfig.GetCompressorEnable () ? 1 : 0); - SetParameter (ParameterReverbEnable, m_PerformanceConfig.GetReverbEnable () ? 1 : 0); - SetParameter (ParameterReverbSize, m_PerformanceConfig.GetReverbSize ()); - SetParameter (ParameterReverbHighDamp, m_PerformanceConfig.GetReverbHighDamp ()); - SetParameter (ParameterReverbLowDamp, m_PerformanceConfig.GetReverbLowDamp ()); - SetParameter (ParameterReverbLowPass, m_PerformanceConfig.GetReverbLowPass ()); - SetParameter (ParameterReverbDiffusion, m_PerformanceConfig.GetReverbDiffusion ()); - SetParameter (ParameterReverbLevel, m_PerformanceConfig.GetReverbLevel ()); + LoadPerformanceParameters(); } else { 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 ())) { @@ -280,6 +257,18 @@ void CMiniDexed::Process (bool bPlugAndPlayUpdated) m_bSavePerformance = false; } + if (m_bSavePerformanceNewFile) + { + DoSavePerformanceNewFile (); + m_bSavePerformanceNewFile = false; + } + + if (m_bSetNewPerformance) + { + DoSetNewPerformance (); + m_bSetNewPerformance = false; + } + if (m_bProfileEnabled) { m_GetChunkTimer.Dump (); @@ -985,7 +974,9 @@ bool CMiniDexed::DoSavePerformance (void) m_PerformanceConfig.SetNoteLimitLow (m_nNoteLimitLow[nTG], nTG); m_PerformanceConfig.SetNoteLimitHigh (m_nNoteLimitHigh[nTG], nTG); m_PerformanceConfig.SetNoteShift (m_nNoteShift[nTG], nTG); - + m_pTG[nTG]->getVoiceData(m_nRawVoiceData); + m_PerformanceConfig.SetVoiceDataToTxt (m_nRawVoiceData, nTG); + m_PerformanceConfig.SetReverbSend (m_nReverbSend[nTG], nTG); } @@ -1226,3 +1217,138 @@ void CMiniDexed::setMasterVolume (float32_t vol) nMasterVolume=vol; } +std::string CMiniDexed::GetPerformanceFileName(unsigned nID) +{ + return m_PerformanceConfig.GetPerformanceFileName(nID); +} + +std::string CMiniDexed::GetPerformanceName(unsigned nID) +{ + return m_PerformanceConfig.GetPerformanceName(nID); +} + +unsigned CMiniDexed::GetLastPerformance() +{ + return m_PerformanceConfig.GetLastPerformance(); +} + + + +unsigned CMiniDexed::GetActualPerformanceID() +{ + return m_PerformanceConfig.GetActualPerformanceID(); +} + +void CMiniDexed::SetActualPerformanceID(unsigned nID) +{ + m_PerformanceConfig.SetActualPerformanceID(nID); +} + +unsigned CMiniDexed::GetMenuSelectedPerformanceID() +{ + return m_PerformanceConfig.GetMenuSelectedPerformanceID(); +} + +void CMiniDexed::SetMenuSelectedPerformanceID(unsigned nID) +{ + m_PerformanceConfig.SetMenuSelectedPerformanceID(nID); +} + + +bool CMiniDexed::SetNewPerformance(unsigned nID) +{ + m_bSetNewPerformance = true; + m_nSetNewPerformanceID = nID; + + return true; +} + +bool CMiniDexed::DoSetNewPerformance (void) +{ + unsigned nID = m_nSetNewPerformanceID; + m_PerformanceConfig.SetNewPerformance(nID); + + if (m_PerformanceConfig.Load ()) + { + LoadPerformanceParameters(); + return true; + } + else + { + SetMIDIChannel (CMIDIDevice::OmniMode, 0); + return false; + } +} + +bool CMiniDexed::SavePerformanceNewFile () +{ + m_bSavePerformanceNewFile = m_PerformanceConfig.GetInternalFolderOk(); + return m_bSavePerformanceNewFile; +} + +bool CMiniDexed::DoSavePerformanceNewFile (void) +{ + std::string nPerformanceName=""; // for future enhacements: capability to write performance name + if (m_PerformanceConfig.CreateNewPerformanceFile(nPerformanceName)) + { + if(SavePerformance()) + { + return true; + } + else + { + return false; + } + } + else + { + return false; + } + +} + + +void CMiniDexed::LoadPerformanceParameters(void) +{ + for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++) + { + + BankSelectLSB (m_PerformanceConfig.GetBankNumber (nTG), nTG); + ProgramChange (m_PerformanceConfig.GetVoiceNumber (nTG), nTG); + SetMIDIChannel (m_PerformanceConfig.GetMIDIChannel (nTG), nTG); + SetVolume (m_PerformanceConfig.GetVolume (nTG), nTG); + SetPan (m_PerformanceConfig.GetPan (nTG), nTG); + SetMasterTune (m_PerformanceConfig.GetDetune (nTG), nTG); + SetCutoff (m_PerformanceConfig.GetCutoff (nTG), nTG); + SetResonance (m_PerformanceConfig.GetResonance (nTG), nTG); + setPitchbendRange (m_PerformanceConfig.GetPitchBendRange (nTG), nTG); + setPitchbendStep (m_PerformanceConfig.GetPitchBendStep (nTG), nTG); + setPortamentoMode (m_PerformanceConfig.GetPortamentoMode (nTG), nTG); + setPortamentoGlissando (m_PerformanceConfig.GetPortamentoGlissando (nTG), nTG); + setPortamentoTime (m_PerformanceConfig.GetPortamentoTime (nTG), nTG); + + m_nNoteLimitLow[nTG] = m_PerformanceConfig.GetNoteLimitLow (nTG); + m_nNoteLimitHigh[nTG] = m_PerformanceConfig.GetNoteLimitHigh (nTG); + m_nNoteShift[nTG] = m_PerformanceConfig.GetNoteShift (nTG); + + if(m_PerformanceConfig.VoiceDataFilled(nTG)) + { + uint8_t* tVoiceData = m_PerformanceConfig.GetVoiceDataFromTxt(nTG); + m_pTG[nTG]->loadVoiceParameters(tVoiceData); + } + + SetReverbSend (m_PerformanceConfig.GetReverbSend (nTG), nTG); + + } + + // Effects + SetParameter (ParameterCompressorEnable, m_PerformanceConfig.GetCompressorEnable () ? 1 : 0); + SetParameter (ParameterReverbEnable, m_PerformanceConfig.GetReverbEnable () ? 1 : 0); + SetParameter (ParameterReverbSize, m_PerformanceConfig.GetReverbSize ()); + SetParameter (ParameterReverbHighDamp, m_PerformanceConfig.GetReverbHighDamp ()); + SetParameter (ParameterReverbLowDamp, m_PerformanceConfig.GetReverbLowDamp ()); + SetParameter (ParameterReverbLowPass, m_PerformanceConfig.GetReverbLowPass ()); + SetParameter (ParameterReverbDiffusion, m_PerformanceConfig.GetReverbDiffusion ()); + SetParameter (ParameterReverbLevel, m_PerformanceConfig.GetReverbLevel ()); +} + diff --git a/src/minidexed.h b/src/minidexed.h index 0c8b575..6945845 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -104,6 +104,19 @@ public: int16_t checkSystemExclusive(const uint8_t* pMessage, const uint16_t nLength, uint8_t nTG); + std::string GetPerformanceFileName(unsigned nID); + std::string GetPerformanceName(unsigned nID); + unsigned GetLastPerformance(); + unsigned GetActualPerformanceID(); + void SetActualPerformanceID(unsigned nID); + bool SetNewPerformance(unsigned nID); + bool SavePerformanceNewFile (); + unsigned GetMenuSelectedPerformanceID(); + void SetMenuSelectedPerformanceID(unsigned nID); + + bool DoSavePerformanceNewFile (void); + bool DoSetNewPerformance (void); + enum TParameter { ParameterCompressorEnable, @@ -157,7 +170,7 @@ public: private: int16_t ApplyNoteLimits (int16_t pitch, unsigned nTG); // returns < 0 to ignore note uint8_t m_uchOPMask[CConfig::ToneGenerators]; - + void LoadPerformanceParameters(void); void ProcessSound (void); #ifdef ARM_ALLOW_MULTI_CORE @@ -197,9 +210,18 @@ private: int m_nNoteShift[CConfig::ToneGenerators]; unsigned m_nReverbSend[CConfig::ToneGenerators]; - + + uint8_t m_nRawVoiceData[156]; + + + bool m_bSavePerformanceNewFile; + bool m_bSetNewPerformance; + unsigned m_nSetNewPerformanceID; + float32_t nMasterVolume; + + CUserInterface m_UI; CSysExFileLoader m_SysExFileLoader; CPerformanceConfig m_PerformanceConfig; diff --git a/src/performance.ini b/src/performance.ini index bdd3d66..1ab54b2 100644 --- a/src/performance.ini +++ b/src/performance.ini @@ -20,6 +20,7 @@ #PortamentoMode#=0 # 0 .. 1 #PortamentoGlissando#=0 # 0 .. 1 #PortamentoTime#=0 # 0 .. 99 +#VoiceData#= # space separated hex numbers of 156 voice parameters. Example: 5F 1D 14 32 63 [....] 20 55 # TG1 BankNumber1=0 @@ -39,6 +40,7 @@ PitchBendStep1=0 PortamentoMode1=0 PortamentoGlissando1=0 PortamentoTime1=0 +VoiceData1= # TG2 BankNumber2=0 @@ -58,6 +60,7 @@ PitchBendStep2=0 PortamentoMode2=0 PortamentoGlissando2=0 PortamentoTime2=0 +VoiceData2= # TG3 BankNumber3=0 @@ -77,6 +80,7 @@ PitchBendStep3=0 PortamentoMode3=0 PortamentoGlissando3=0 PortamentoTime3=0 +VoiceData3= # TG4 BankNumber4=0 @@ -96,6 +100,7 @@ PitchBendStep4=0 PortamentoMode4=0 PortamentoGlissando4=0 PortamentoTime4=0 +VoiceData4= # TG5 BankNumber5=0 @@ -115,6 +120,7 @@ PitchBendStep5=0 PortamentoMode5=0 PortamentoGlissando5=0 PortamentoTime5=0 +VoiceData5= # TG6 BankNumber6=0 @@ -134,6 +140,7 @@ PitchBendStep6=0 PortamentoMode6=0 PortamentoGlissando6=0 PortamentoTime6=0 +VoiceData6= # TG7 BankNumber7=0 @@ -153,6 +160,7 @@ PitchBendStep7=0 PortamentoMode7=0 PortamentoGlissando7=0 PortamentoTime7=0 +VoiceData7= # TG8 BankNumber8=0 @@ -172,6 +180,7 @@ PitchBendStep8=0 PortamentoMode8=0 PortamentoGlissando8=0 PortamentoTime8=0 +VoiceData8= # Effects #CompressorEnable=1 # 0: off, 1: on diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index 5c381ec..c477248 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -22,10 +22,13 @@ // #include "performanceconfig.h" #include "mididevice.h" +#include +#include CPerformanceConfig::CPerformanceConfig (FATFS *pFileSystem) : m_Properties ("performance.ini", pFileSystem) { + m_pFileSystem = pFileSystem; } CPerformanceConfig::~CPerformanceConfig (void) @@ -113,6 +116,9 @@ bool CPerformanceConfig::Load (void) PropertyName.Format ("PortamentoTime%u", nTG+1); m_nPortamentoTime[nTG] = m_Properties.GetNumber (PropertyName, 0); + + PropertyName.Format ("VoiceData%u", nTG+1); + m_nVoiceDataTxt[nTG] = m_Properties.GetString (PropertyName, ""); } m_bCompressorEnable = m_Properties.GetNumber ("CompressorEnable", 1) != 0; @@ -199,6 +205,10 @@ bool CPerformanceConfig::Save (void) PropertyName.Format ("PortamentoTime%u", nTG+1); m_Properties.SetNumber (PropertyName, m_nPortamentoTime[nTG]); + + PropertyName.Format ("VoiceData%u", nTG+1); + char *cstr = &m_nVoiceDataTxt[nTG][0]; + m_Properties.SetString (PropertyName, cstr); } m_Properties.SetNumber ("CompressorEnable", m_bCompressorEnable ? 1 : 0); @@ -501,3 +511,210 @@ unsigned CPerformanceConfig::GetPortamentoTime (unsigned nTG) const assert (nTG < CConfig::ToneGenerators); return m_nPortamentoTime[nTG]; } + +void CPerformanceConfig::SetVoiceDataToTxt (const uint8_t *pData, unsigned nTG) +{ + assert (nTG < CConfig::ToneGenerators); + m_nVoiceDataTxt[nTG] = ""; + char nDtoH[]="0123456789ABCDEF"; + for (int i = 0; i < NUM_VOICE_PARAM; i++) + { + m_nVoiceDataTxt[nTG] += nDtoH[(pData[i] & 0xF0)/16]; + m_nVoiceDataTxt[nTG] += nDtoH[pData[i] & 0x0F] ; + if ( i < (NUM_VOICE_PARAM-1) ) + { + m_nVoiceDataTxt[nTG] += " "; + } + } +} + +uint8_t *CPerformanceConfig::GetVoiceDataFromTxt (unsigned nTG) +{ + assert (nTG < CConfig::ToneGenerators); + static uint8_t pData[NUM_VOICE_PARAM]; + std::string nHtoD="0123456789ABCDEF"; + + for (int i=0; i 8 && nLen <26 && strcmp(FileName.substr(6,1).c_str(), "_")==0) + { + nPIndex=stoi(FileName.substr(0,6)); + if(nPIndex > nLastFileIndex) + { + nLastFileIndex=nPIndex; + } + + m_nPerformanceFileName[nLastPerformance++]= FileName; + } + } + + Result = f_findnext (&Directory, &FileInfo); + } + // sort by performance number-name + if (nLastPerformance > 2) + { + sort (m_nPerformanceFileName+1, m_nPerformanceFileName + nLastPerformance - 1); // default is always on first place. + } + } + + return nInternalFolderOk; +} + + +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); + +} diff --git a/src/performanceconfig.h b/src/performanceconfig.h index bf7617a..2110e34 100644 --- a/src/performanceconfig.h +++ b/src/performanceconfig.h @@ -26,6 +26,8 @@ #include "config.h" #include #include +#define NUM_VOICE_PARAM 156 +#define PERFORMANCE_DIR "performance" class CPerformanceConfig // Performance configuration { @@ -73,7 +75,9 @@ public: void SetPortamentoMode (unsigned nValue, unsigned nTG); void SetPortamentoGlissando (unsigned nValue, unsigned nTG); void SetPortamentoTime (unsigned nValue, unsigned nTG); - + void SetVoiceDataToTxt (const uint8_t *pData, unsigned nTG); + uint8_t *GetVoiceDataFromTxt (unsigned nTG); + // Effects bool GetCompressorEnable (void) const; bool GetReverbEnable (void) const; @@ -93,6 +97,20 @@ public: void SetReverbDiffusion (unsigned nValue); void SetReverbLevel (unsigned nValue); + bool VoiceDataFilled(unsigned nTG); + bool ListPerformances(); + //std::string m_DirName; + void SetNewPerformance (unsigned nID); + std::string GetPerformanceFileName(unsigned nID); + std::string GetPerformanceName(unsigned nID); + unsigned GetLastPerformance(); + void SetActualPerformanceID(unsigned nID); + unsigned GetActualPerformanceID(); + void SetMenuSelectedPerformanceID(unsigned nID); + unsigned GetMenuSelectedPerformanceID(); + bool CreateNewPerformanceFile(std::string sPerformanceName); + bool GetInternalFolderOk(); + private: CPropertiesFatFsFile m_Properties; @@ -113,6 +131,17 @@ private: unsigned m_nPortamentoMode[CConfig::ToneGenerators]; unsigned m_nPortamentoGlissando[CConfig::ToneGenerators]; unsigned m_nPortamentoTime[CConfig::ToneGenerators]; + std::string m_nVoiceDataTxt[CConfig::ToneGenerators]; + + unsigned nLastPerformance; + unsigned nLastFileIndex; + unsigned nActualPerformance = 0; + unsigned nMenuSelectedPerformance = 0; + std::string m_nPerformanceFileName[40]; + FATFS *m_pFileSystem; + + bool nInternalFolderOk=false; + bool nExternalFolderOk=false; // for future USB implementation bool m_bCompressorEnable; bool m_bReverbEnable; diff --git a/src/uimenu.cpp b/src/uimenu.cpp index c12bd39..6191add 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -52,6 +52,7 @@ const CUIMenu::TMenuItem CUIMenu::s_MainMenu[] = {"TG8", MenuHandler, s_TGMenu, 7}, #endif {"Effects", MenuHandler, s_EffectsMenu}, + {"Performance", PerformanceMenu}, {"Save", MenuHandler, s_SaveMenu}, {0} }; @@ -175,7 +176,8 @@ const CUIMenu::TMenuItem CUIMenu::s_OperatorMenu[] = const CUIMenu::TMenuItem CUIMenu::s_SaveMenu[] = { - {"Performance", SavePerformance}, + {"Overwrite", SavePerformance}, + {"New", SavePerformanceNewFile}, {0} }; @@ -1085,3 +1087,80 @@ void CUIMenu::TimerHandler (TKernelTimerHandle hTimer, void *pParam, void *pCont pThis->EventHandler (MenuEventBack); } + +void CUIMenu::PerformanceMenu (CUIMenu *pUIMenu, TMenuEvent Event) +{ + + unsigned nValue = pUIMenu->m_pMiniDexed->GetMenuSelectedPerformanceID(); + + switch (Event) + { + case MenuEventUpdate: + break; + + case MenuEventStepDown: + if (nValue > 0) + { + --nValue; + } + pUIMenu->m_pMiniDexed->SetMenuSelectedPerformanceID (nValue); + break; + + case MenuEventStepUp: + if (++nValue > (unsigned) pUIMenu->m_pMiniDexed->GetLastPerformance()-1) + { + nValue = pUIMenu->m_pMiniDexed->GetLastPerformance()-1; + } + pUIMenu->m_pMiniDexed->SetMenuSelectedPerformanceID (nValue); + break; + + case MenuEventSelect: + pUIMenu->m_pMiniDexed->SetNewPerformance(nValue); + + break; + + + case MenuEventPressAndStepDown: + case MenuEventPressAndStepUp: + pUIMenu->TGShortcutHandler (Event); + return; + + default: + return; + } + + string Value = pUIMenu->m_pMiniDexed->GetPerformanceName(nValue); + + + std::string nPSelected = ""; + if(nValue == pUIMenu->m_pMiniDexed->GetActualPerformanceID()) + { + nPSelected="[Ld]"; + } + + 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); + +} + +void CUIMenu::SavePerformanceNewFile (CUIMenu *pUIMenu, TMenuEvent Event) +{ + if (Event != MenuEventUpdate) + { + return; + } + + bool bOK = pUIMenu->m_pMiniDexed->SavePerformanceNewFile (); + + const char *pMenuName = + pUIMenu->m_MenuStackParent[pUIMenu->m_nCurrentMenuDepth-1] + [pUIMenu->m_nMenuStackItem[pUIMenu->m_nCurrentMenuDepth-1]].Name; + + pUIMenu->m_pUI->DisplayWrite (pMenuName, + pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, + bOK ? "Completed" : "Error", + false, false); + + CTimer::Get ()->StartKernelTimer (MSEC2HZ (1500), TimerHandler, 0, pUIMenu); +} diff --git a/src/uimenu.h b/src/uimenu.h index b130e4c..d5935af 100644 --- a/src/uimenu.h +++ b/src/uimenu.h @@ -84,7 +84,10 @@ private: static void EditOPParameter (CUIMenu *pUIMenu, TMenuEvent Event); static void SavePerformance (CUIMenu *pUIMenu, TMenuEvent Event); static void EditTGParameter2 (CUIMenu *pUIMenu, TMenuEvent Event); - + + static void PerformanceMenu (CUIMenu *pUIMenu, TMenuEvent Event); + static void SavePerformanceNewFile (CUIMenu *pUIMenu, TMenuEvent Event); + static std::string GetGlobalValueString (unsigned nParameter, int nValue); static std::string GetTGValueString (unsigned nTGParameter, int nValue); static std::string GetVoiceValueString (unsigned nVoiceParameter, int nValue);