From 2f044b6fcb550eec08ee6f57285f8849a2523ed5 Mon Sep 17 00:00:00 2001 From: probonopd Date: Sat, 21 May 2022 19:01:47 +0000 Subject: [PATCH 1/4] Fix Save Performance (#238) Closes #151 Thanks @rsta2 --- src/minidexed.cpp | 17 ++++++++++++++++- src/minidexed.h | 3 +++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 21e79f1..3eba164 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -49,7 +49,8 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, #endif m_GetChunkTimer ("GetChunk", 1000000U * pConfig->GetChunkSize ()/2 / pConfig->GetSampleRate ()), - m_bProfileEnabled (m_pConfig->GetProfileEnabled ()) + m_bProfileEnabled (m_pConfig->GetProfileEnabled ()), + m_bSavePerformance (false) { assert (m_pConfig); @@ -270,6 +271,13 @@ void CMiniDexed::Process (bool bPlugAndPlayUpdated) m_UI.Process (); + if (m_bSavePerformance) + { + DoSavePerformance (); + + m_bSavePerformance = false; + } + if (m_bProfileEnabled) { m_GetChunkTimer.Dump (); @@ -933,6 +941,13 @@ void CMiniDexed::ProcessSound (void) #endif bool CMiniDexed::SavePerformance (void) +{ + m_bSavePerformance = true; + + return true; +} + +bool CMiniDexed::DoSavePerformance (void) { for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++) { diff --git a/src/minidexed.h b/src/minidexed.h index 66beb35..7acf52f 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -149,6 +149,7 @@ public: std::string GetVoiceName (unsigned nTG); bool SavePerformance (void); + bool DoSavePerformance (void); private: int16_t ApplyNoteLimits (int16_t pitch, unsigned nTG); // returns < 0 to ignore note @@ -222,6 +223,8 @@ private: AudioStereoMixer* reverb_send_mixer; CSpinLock m_ReverbSpinLock; + + bool m_bSavePerformance; }; #endif From c00ed093984bc4eb60ffa1806170eb95e5400df2 Mon Sep 17 00:00:00 2001 From: Holger Date: Tue, 24 May 2022 19:11:23 +0200 Subject: [PATCH 2/4] Fixes for SYSEX channel messages / Added master volume method (also for SYSEX) (#249) * Fix for using the right MIDI channel for SYSEX. Fix for SYSEX MIDI dump output. * Small fixes for recognizing MIDI channel in SYSEX. Disabled printing of MIDI data in incoming serial data. Added some mor debug output. * Reenabled showing incomfing MIDI data when MIDI-DUmp is enabled. Fix for using MIDI channel for SYSEX. * Several fixes for SYSEX handling. * Code for sending a voice dump via MIDI started. * Fix for sending SYSEX voice dump to all interfaces. * Sending voice data via SYSEX when voice is changed. Adding master volume and changing master volume when SYSEX master volume is triggered. * Forgot to initialize nMasterVolume - just added it. * Merge. * Added a SpinLock around MIDI message processing. * Added notesOff() when changing algorithm parameter (can be extended later for other parameters). Co-authored-by: Holger Wirtz --- src/mididevice.cpp | 106 +++++++++++++++++++++------- src/mididevice.h | 9 +-- src/minidexed.cpp | 144 +++++++++++++++++++++++++++------------ src/minidexed.h | 5 ++ src/serialmididevice.cpp | 16 +++-- 5 files changed, 199 insertions(+), 81 deletions(-) diff --git a/src/mididevice.cpp b/src/mididevice.cpp index 5daacc1..d96d089 100644 --- a/src/mididevice.cpp +++ b/src/mididevice.cpp @@ -114,24 +114,37 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign switch(pMessage[0]) { case MIDI_SYSTEM_EXCLUSIVE_BEGIN: - printf("SysEx data length: [%d]\n",uint16_t(nLength)); - printf("SysEx data:\n"); + printf("MIDI%u: SysEx data length: [%d]:",nCable, uint16_t(nLength)); for (uint16_t i = 0; i < nLength; i++) { - if((i % 8) == 0) - printf("%04d:",i); + if((i % 16) == 0) + printf("\n%04d:",i); printf(" 0x%02x",pMessage[i]); - if((i % 8) == 0) - printf("\n"); } + printf("\n"); break; default: - printf("Unhandled MIDI event type %0x02x\n",pMessage[0]); + printf("MIDI%u: Unhandled MIDI event type %0x02x\n",nCable,pMessage[0]); } break; } } + // Only for debugging: +/* + if(pMessage[0]==MIDI_SYSTEM_EXCLUSIVE_BEGIN) + { + printf("MIDI%u: SysEx data length: [%d]:",nCable, uint16_t(nLength)); + for (uint16_t i = 0; i < nLength; i++) + { + if((i % 16) == 0) + printf("\n%04d:",i); + printf(" 0x%02x",pMessage[i]); + } + printf("\n"); + } +*/ + // Handle MIDI Thru if (m_DeviceName.compare (m_pConfig->GetMIDIThruIn ()) == 0) { @@ -150,6 +163,8 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign return; } + m_MIDISpinLock.Acquire (); + u8 ucStatus = pMessage[0]; u8 ucChannel = ucStatus & 0x0F; u8 ucType = ucStatus >> 4; @@ -157,17 +172,24 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign // GLOBAL MIDI SYSEX if (pMessage[0] == MIDI_SYSTEM_EXCLUSIVE_BEGIN && pMessage[3] == 0x04 && pMessage[4] == 0x01 && pMessage[nLength-1] == MIDI_SYSTEM_EXCLUSIVE_END) // MASTER VOLUME { - float32_t nMasterVolume=(pMessage[5] & (pMessage[6]<<7))/(1<<14); + float32_t nMasterVolume=((pMessage[5] & 0x7c) & ((pMessage[6] & 0x7c) <<7))/(1<<14); LOGNOTE("Master volume: %f",nMasterVolume); - // TODO: Handle global master volume + m_pSynthesizer->setMasterVolume(nMasterVolume); } else { for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++) { - // MIDI SYSEX per MIDI channel - if (ucStatus == MIDI_SYSTEM_EXCLUSIVE_BEGIN && m_ChannelMap[nTG] == pMessage[2] & 0x07) - HandleSystemExclusive(pMessage, nLength, nTG); + if (ucStatus == MIDI_SYSTEM_EXCLUSIVE_BEGIN) + { + // MIDI SYSEX per MIDI channel + uint8_t ucSysExChannel = (pMessage[2] & 0x07); + if (m_ChannelMap[nTG] == ucSysExChannel || m_ChannelMap[nTG] == OmniMode) + { + LOGNOTE("MIDI-SYSEX: channel: %u, len: %u, TG: %u",m_ChannelMap[nTG],nLength,nTG); + HandleSystemExclusive(pMessage, nLength, nCable, nTG); + } + } else { if ( m_ChannelMap[nTG] == ucChannel @@ -293,6 +315,7 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign } } } + m_MIDISpinLock.Release (); } void CMIDIDevice::AddDevice (const char *pDeviceName) @@ -306,7 +329,7 @@ void CMIDIDevice::AddDevice (const char *pDeviceName) s_DeviceMap.insert (std::pair (pDeviceName, this)); } -void CMIDIDevice::HandleSystemExclusive(const uint8_t* pMessage, const size_t nLength, const uint8_t nTG) +void CMIDIDevice::HandleSystemExclusive(const uint8_t* pMessage, const size_t nLength, const unsigned nCable, const uint8_t nTG) { int16_t sysex_return; @@ -319,33 +342,33 @@ void CMIDIDevice::HandleSystemExclusive(const uint8_t* pMessage, const size_t nL LOGERR("SysEx end status byte not detected."); break; case -2: - LOGERR("E: SysEx vendor not Yamaha."); + LOGERR("SysEx vendor not Yamaha."); break; case -3: - LOGERR("E: Unknown SysEx parameter change."); + LOGERR("Unknown SysEx parameter change."); break; case -4: - LOGERR(" Unknown SysEx voice or function."); + LOGERR("Unknown SysEx voice or function."); break; case -5: - LOGERR("E: Not a SysEx voice bulk upload."); + LOGERR("Not a SysEx voice bulk upload."); break; case -6: - LOGERR("E: Wrong length for SysEx voice bulk upload (not 155)."); + LOGERR("Wrong length for SysEx voice bulk upload (not 155)."); break; case -7: - LOGERR("E: Checksum error for one voice."); + LOGERR("Checksum error for one voice."); break; case -8: - LOGERR("E: Not a SysEx bank bulk upload."); + LOGERR("Not a SysEx bank bulk upload."); break; case -9: - LOGERR("E: Wrong length for SysEx bank bulk upload (not 4096)."); + LOGERR("Wrong length for SysEx bank bulk upload (not 4096)."); case -10: - LOGERR("E: Checksum error for bank."); + LOGERR("Checksum error for bank."); break; case -11: - LOGERR("E: Unknown SysEx message."); + LOGERR("Unknown SysEx message."); break; case 64: LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]); @@ -407,7 +430,6 @@ void CMIDIDevice::HandleSystemExclusive(const uint8_t* pMessage, const size_t nL // load sysex-data into voice memory LOGDBG("One Voice bulk upload"); m_pSynthesizer->loadVoiceParameters(pMessage,nTG); - break; case 200: LOGDBG("Bank bulk upload."); @@ -415,9 +437,41 @@ void CMIDIDevice::HandleSystemExclusive(const uint8_t* pMessage, const size_t nL LOGNOTE("Currently code for storing a bulk bank upload is missing!"); break; default: - LOGDBG("SysEx voice parameter change: %d value: %d",pMessage[4] + ((pMessage[3] & 0x03) * 128), pMessage[5]); - m_pSynthesizer->setVoiceDataElement(pMessage[4] + ((pMessage[3] & 0x03) * 128), pMessage[5],nTG); + if(sysex_return >= 300 && sysex_return < 500) + { + LOGDBG("SysEx voice parameter change: Parameter %d value: %d",pMessage[4] + ((pMessage[3] & 0x03) * 128), pMessage[5]); + m_pSynthesizer->setVoiceDataElement(pMessage[4] + ((pMessage[3] & 0x03) * 128), pMessage[5],nTG); + switch(pMessage[4] + ((pMessage[3] & 0x03) * 128)) + { + case 134: + m_pSynthesizer->notesOff(0,nTG); + break; + } + } + else if(sysex_return >= 500 && sysex_return < 600) + { + LOGDBG("SysEx send voice %u request",sysex_return-500); + SendSystemExclusiveVoice(sysex_return-500, nCable, nTG); + } break; } } +void CMIDIDevice::SendSystemExclusiveVoice(uint8_t nVoice, const unsigned nCable, uint8_t nTG) +{ + uint8_t voicedump[163]; + + LOGDBG("Sending SysEx voice %u ",nVoice); + + // Get voice sysex dump from TG + m_pSynthesizer->getSysExVoiceDump(voicedump, nTG); + + TDeviceMap::const_iterator Iterator; + + // send voice dump to all MIDI interfaces + for(Iterator = s_DeviceMap.begin(); Iterator != s_DeviceMap.end(); ++Iterator) + { + Iterator->second->Send (voicedump, sizeof(voicedump)*sizeof(uint8_t), nCable); + LOGNOTE("Send SYSEX voice dump to \"%s\"\n",Iterator->first); + } +} diff --git a/src/mididevice.h b/src/mididevice.h index 0b116d1..1bd5396 100644 --- a/src/mididevice.h +++ b/src/mididevice.h @@ -27,6 +27,7 @@ #include #include #include +#include class CMiniDexed; @@ -49,14 +50,12 @@ public: u8 GetChannel (unsigned nTG) const; virtual void Send (const u8 *pMessage, size_t nLength, unsigned nCable = 0) {} + virtual void SendSystemExclusiveVoice(uint8_t nVoice, const unsigned nCable, uint8_t nTG); protected: void MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsigned nCable = 0); - void AddDevice (const char *pDeviceName); - - void HandleSystemExclusive(const uint8_t* pMessage, const size_t nLength, const uint8_t nTG); - + void HandleSystemExclusive(const uint8_t* pMessage, const size_t nLength, const unsigned nCable, const uint8_t nTG); private: CMiniDexed *m_pSynthesizer; CConfig *m_pConfig; @@ -67,6 +66,8 @@ private: typedef std::unordered_map TDeviceMap; static TDeviceMap s_DeviceMap; + + CSpinLock m_MIDISpinLock; }; #endif diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 3eba164..5e685e2 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -125,6 +125,8 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, } #endif + setMasterVolume(1.0); + // BEGIN setup tg_mixer tg_mixer = new AudioStereoMixer(pConfig->GetChunkSize()/2); // END setup tgmixer @@ -371,6 +373,7 @@ void CMiniDexed::ProgramChange (unsigned nProgram, unsigned nTG) assert (m_pTG[nTG]); m_pTG[nTG]->loadVoiceParameters (Buffer); + m_SerialMIDI.SendSystemExclusiveVoice(nProgram,0,nTG); m_UI.ParameterChanged (); } @@ -875,56 +878,70 @@ void CMiniDexed::ProcessSound (void) } // BEGIN TG mixing - for (uint8_t i = 0; i < CConfig::ToneGenerators; i++) - { - tg_mixer->doAddMix(i,m_OutputLevel[i]); - reverb_send_mixer->doAddMix(i,m_OutputLevel[i]); - } - // END TG mixing - - // BEGIN create SampleBuffer for holding audio data - float32_t SampleBuffer[2][nFrames]; - // END create SampleBuffer for holding audio data - - // get the mix of all TGs - tg_mixer->getMix(SampleBuffer[indexL], SampleBuffer[indexR]); + float32_t tmp_float[nFrames*2]; + int16_t tmp_int[nFrames*2]; - // BEGIN adding reverb - if (m_nParameter[ParameterReverbEnable]) + if(nMasterVolume > 0.0) { - float32_t ReverbBuffer[2][nFrames]; - float32_t ReverbSendBuffer[2][nFrames]; - - arm_fill_f32(0.0f, ReverbBuffer[indexL], nFrames); - arm_fill_f32(0.0f, ReverbBuffer[indexR], nFrames); - arm_fill_f32(0.0f, ReverbSendBuffer[indexR], nFrames); - arm_fill_f32(0.0f, ReverbSendBuffer[indexL], nFrames); - - m_ReverbSpinLock.Acquire (); - - reverb_send_mixer->getMix(ReverbSendBuffer[indexL], ReverbSendBuffer[indexR]); - reverb->doReverb(ReverbSendBuffer[indexL],ReverbSendBuffer[indexR],ReverbBuffer[indexL], ReverbBuffer[indexR],nFrames); + for (uint8_t i = 0; i < CConfig::ToneGenerators; i++) + { + tg_mixer->doAddMix(i,m_OutputLevel[i]); + reverb_send_mixer->doAddMix(i,m_OutputLevel[i]); + } + // END TG mixing + + // BEGIN create SampleBuffer for holding audio data + float32_t SampleBuffer[2][nFrames]; + // END create SampleBuffer for holding audio data - // scale down and add left reverb buffer by reverb level - arm_scale_f32(ReverbBuffer[indexL], reverb->get_level(), ReverbBuffer[indexL], nFrames); - arm_add_f32(SampleBuffer[indexL], ReverbBuffer[indexL], SampleBuffer[indexL], nFrames); - // scale down and add right reverb buffer by reverb level - arm_scale_f32(ReverbBuffer[indexR], reverb->get_level(), ReverbBuffer[indexR], nFrames); - arm_add_f32(SampleBuffer[indexR], ReverbBuffer[indexR], SampleBuffer[indexR], nFrames); + // get the mix of all TGs + tg_mixer->getMix(SampleBuffer[indexL], SampleBuffer[indexR]); - m_ReverbSpinLock.Release (); - } - // END adding reverb + // BEGIN adding reverb + if (m_nParameter[ParameterReverbEnable]) + { + float32_t ReverbBuffer[2][nFrames]; + float32_t ReverbSendBuffer[2][nFrames]; - // Convert dual float array (left, right) to single int16 array (left/right) - float32_t tmp_float[nFrames*2]; - int16_t tmp_int[nFrames*2]; - for(uint16_t i=0; igetMix(ReverbSendBuffer[indexL], ReverbSendBuffer[indexR]); + reverb->doReverb(ReverbSendBuffer[indexL],ReverbSendBuffer[indexR],ReverbBuffer[indexL], ReverbBuffer[indexR],nFrames); + + // scale down and add left reverb buffer by reverb level + arm_scale_f32(ReverbBuffer[indexL], reverb->get_level(), ReverbBuffer[indexL], nFrames); + arm_add_f32(SampleBuffer[indexL], ReverbBuffer[indexL], SampleBuffer[indexL], nFrames); + // scale down and add right reverb buffer by reverb level + arm_scale_f32(ReverbBuffer[indexR], reverb->get_level(), ReverbBuffer[indexR], nFrames); + arm_add_f32(SampleBuffer[indexR], ReverbBuffer[indexR], SampleBuffer[indexR], nFrames); + + m_ReverbSpinLock.Release (); + } + // END adding reverb + + // Convert dual float array (left, right) to single int16 array (left/right) + for(uint16_t i=0; i0.0 && nMasterVolume <1.0) + { + tmp_float[i*2]=SampleBuffer[indexL][i] * nMasterVolume; + tmp_float[(i*2)+1]=SampleBuffer[indexR][i] * nMasterVolume; + } + else if(nMasterVolume == 1.0) + { + tmp_float[i*2]=SampleBuffer[indexL][i]; + tmp_float[(i*2)+1]=SampleBuffer[indexR][i]; + } + } + arm_float_to_q15(tmp_float,tmp_int,nFrames*2); } - arm_float_to_q15(tmp_float,tmp_int,nFrames*2); + else + arm_fill_q15(0, tmp_int, nFrames * 2); if (m_pSoundDevice->Write (tmp_int, sizeof(tmp_int)) != (int) sizeof(tmp_int)) { @@ -1168,5 +1185,44 @@ void CMiniDexed::setVoiceDataElement(uint8_t data, uint8_t number, uint8_t nTG) int16_t CMiniDexed::checkSystemExclusive(const uint8_t* pMessage,const uint16_t nLength, uint8_t nTG) { + assert (nTG < CConfig::ToneGenerators); + assert (m_pTG[nTG]); + return(m_pTG[nTG]->checkSystemExclusive(pMessage, nLength)); } + +void CMiniDexed::getSysExVoiceDump(uint8_t* dest, uint8_t nTG) +{ + uint8_t checksum = 0; + uint8_t data[155]; + + assert (nTG < CConfig::ToneGenerators); + assert (m_pTG[nTG]); + + m_pTG[nTG]->getVoiceData(data); + + dest[0] = 0xF0; // SysEx start + dest[1] = 0x43; // ID=Yamaha + dest[2] = GetTGParameter(TGParameterMIDIChannel, nTG); // Sub-status and MIDI channel + dest[3] = 0x00; // Format number (0=1 voice) + dest[4] = 0x01; // Byte count MSB + dest[5] = 0x1B; // Byte count LSB + for (uint8_t n = 0; n < 155; n++) + { + checksum -= data[n]; + dest[6 + n] = data[n]; + } + dest[161] = checksum & 0x7f; // Checksum + dest[162] = 0xF7; // SysEx end +} + +void CMiniDexed::setMasterVolume (float32_t vol) +{ + if(vol < 0.0) + vol = 0.0; + else if(vol > 1.0) + vol = 1.0; + + nMasterVolume=vol; +} + diff --git a/src/minidexed.h b/src/minidexed.h index 7acf52f..0c8b575 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -100,6 +100,7 @@ public: void setAftertouchTarget(uint8_t target, uint8_t nTG); void loadVoiceParameters(const uint8_t* data, uint8_t nTG); void setVoiceDataElement(uint8_t data, uint8_t number, uint8_t nTG); + void getSysExVoiceDump(uint8_t* dest, uint8_t nTG); int16_t checkSystemExclusive(const uint8_t* pMessage, const uint16_t nLength, uint8_t nTG); @@ -151,6 +152,8 @@ public: bool SavePerformance (void); bool DoSavePerformance (void); + void setMasterVolume (float32_t vol); + private: int16_t ApplyNoteLimits (int16_t pitch, unsigned nTG); // returns < 0 to ignore note uint8_t m_uchOPMask[CConfig::ToneGenerators]; @@ -195,6 +198,8 @@ private: unsigned m_nReverbSend[CConfig::ToneGenerators]; + float32_t nMasterVolume; + CUserInterface m_UI; CSysExFileLoader m_SysExFileLoader; CPerformanceConfig m_PerformanceConfig; diff --git a/src/serialmididevice.cpp b/src/serialmididevice.cpp index ec819d0..aed64a6 100644 --- a/src/serialmididevice.cpp +++ b/src/serialmididevice.cpp @@ -20,10 +20,14 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . // + +#include #include #include "serialmididevice.h" #include +LOGMODULE("serialmididevice"); + CSerialMIDIDevice::CSerialMIDIDevice (CMiniDexed *pSynthesizer, CInterruptSystem *pInterrupt, CConfig *pConfig) : CMIDIDevice (pSynthesizer, pConfig), @@ -58,23 +62,20 @@ void CSerialMIDIDevice::Process (void) if (nResult <= 0) { if(nResult!=0) - printf("Serial-Read: %d\n",nResult); + LOGERR("Serial.Read() error: %d\n",nResult); return; } if (m_pConfig->GetMIDIDumpEnabled ()) { - printf("Incoming MIDI data:\n"); + printf("Incoming MIDI data:"); for (uint16_t i = 0; i < nResult; i++) { if((i % 8) == 0) - printf("%04d:",i); + printf("\n%04d:",i); printf(" 0x%02x",Buffer[i]); - if((i > 1 ) && (i % 8) == 0) - printf("\n"); } - if((nResult % 8) != 0) - printf("\n"); + printf("\n"); } // Process MIDI messages @@ -157,6 +158,7 @@ void CSerialMIDIDevice::Process (void) } } } + void CSerialMIDIDevice::Send (const u8 *pMessage, size_t nLength, unsigned nCable) { m_SendBuffer.Write (pMessage, nLength); From 60ab4a562b38cf9ac3e05b85462d61193bddef27 Mon Sep 17 00:00:00 2001 From: arsamus Date: Sat, 28 May 2022 03:08:17 -0300 Subject: [PATCH 3/4] 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); From 0a5ec7d5290910b1f2879b5afa891edb67065363 Mon Sep 17 00:00:00 2001 From: Holger Date: Sun, 5 Jun 2022 11:23:53 +0200 Subject: [PATCH 4/4] Fix for garbled device name in debug output, closes #265 Thanks @dcoredump --- src/mididevice.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/mididevice.cpp b/src/mididevice.cpp index d96d089..4e15cf1 100644 --- a/src/mididevice.cpp +++ b/src/mididevice.cpp @@ -461,8 +461,6 @@ void CMIDIDevice::SendSystemExclusiveVoice(uint8_t nVoice, const unsigned nCable { uint8_t voicedump[163]; - LOGDBG("Sending SysEx voice %u ",nVoice); - // Get voice sysex dump from TG m_pSynthesizer->getSysExVoiceDump(voicedump, nTG); @@ -471,7 +469,7 @@ void CMIDIDevice::SendSystemExclusiveVoice(uint8_t nVoice, const unsigned nCable // send voice dump to all MIDI interfaces for(Iterator = s_DeviceMap.begin(); Iterator != s_DeviceMap.end(); ++Iterator) { - Iterator->second->Send (voicedump, sizeof(voicedump)*sizeof(uint8_t), nCable); - LOGNOTE("Send SYSEX voice dump to \"%s\"\n",Iterator->first); + Iterator->second->Send (voicedump, sizeof(voicedump)*sizeof(uint8_t)); + LOGDBG("Send SYSEX voice dump %u to \"%s\"",nVoice,Iterator->first.c_str()); } }