Merge remote-tracking branch 'upstream/main' into steve_buttongpio

pull/274/head
Stephen Brown 3 years ago
commit 5c9bab0612
  1. 104
      src/mididevice.cpp
  2. 9
      src/mididevice.h
  3. 355
      src/minidexed.cpp
  4. 32
      src/minidexed.h
  5. 9
      src/performance.ini
  6. 217
      src/performanceconfig.cpp
  7. 31
      src/performanceconfig.h
  8. 16
      src/serialmididevice.cpp
  9. 81
      src/uimenu.cpp
  10. 5
      src/uimenu.h

@ -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<std::string, CMIDIDevice *> (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,39 @@ 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];
// 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));
LOGDBG("Send SYSEX voice dump %u to \"%s\"",nVoice,Iterator->first.c_str());
}
}

@ -27,6 +27,7 @@
#include <string>
#include <unordered_map>
#include <circle/types.h>
#include <circle/spinlock.h>
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<std::string, CMIDIDevice *> TDeviceMap;
static TDeviceMap s_DeviceMap;
CSpinLock m_MIDISpinLock;
};
#endif

@ -49,7 +49,10 @@ 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),
m_bSavePerformanceNewFile (false),
m_bSetNewPerformance (false)
{
assert (m_pConfig);
@ -124,6 +127,8 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt,
}
#endif
setMasterVolume(1.0);
// BEGIN setup tg_mixer
tg_mixer = new AudioStereoMixer<CConfig::ToneGenerators>(pConfig->GetChunkSize()/2);
// END setup tgmixer
@ -182,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 ()))
{
@ -270,6 +250,25 @@ void CMiniDexed::Process (bool bPlugAndPlayUpdated)
m_UI.Process ();
if (m_bSavePerformance)
{
DoSavePerformance ();
m_bSavePerformance = false;
}
if (m_bSavePerformanceNewFile)
{
DoSavePerformanceNewFile ();
m_bSavePerformanceNewFile = false;
}
if (m_bSetNewPerformance)
{
DoSetNewPerformance ();
m_bSetNewPerformance = false;
}
if (m_bProfileEnabled)
{
m_GetChunkTimer.Dump ();
@ -363,6 +362,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 ();
}
@ -867,56 +867,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; i<nFrames;i++)
{
tmp_float[i*2]=SampleBuffer[indexL][i];
tmp_float[(i*2)+1]=SampleBuffer[indexR][i];
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);
// 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; i<nFrames;i++)
{
if(nMasterVolume >0.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))
{
@ -933,6 +947,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++)
{
@ -953,7 +974,9 @@ bool CMiniDexed::SavePerformance (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);
}
@ -1153,5 +1176,179 @@ 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;
}
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 ());
}

@ -100,9 +100,23 @@ 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);
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,
@ -149,11 +163,14 @@ public:
std::string GetVoiceName (unsigned nTG);
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];
void LoadPerformanceParameters(void);
void ProcessSound (void);
#ifdef ARM_ALLOW_MULTI_CORE
@ -193,6 +210,17 @@ 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;
@ -222,6 +250,8 @@ private:
AudioStereoMixer<CConfig::ToneGenerators>* reverb_send_mixer;
CSpinLock m_ReverbSpinLock;
bool m_bSavePerformance;
};
#endif

@ -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

@ -22,10 +22,13 @@
//
#include "performanceconfig.h"
#include "mididevice.h"
#include <cstring>
#include <algorithm>
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<NUM_VOICE_PARAM * 3; i=i+3)
{
pData[i/3] = ((nHtoD.find(toupper(m_nVoiceDataTxt[nTG][i]),0) * 16 + nHtoD.find(toupper(m_nVoiceDataTxt[nTG][i+1]),0))) & 0xFF ;
}
return pData;
}
bool CPerformanceConfig::VoiceDataFilled(unsigned nTG)
{
return (strcmp(m_nVoiceDataTxt[nTG].c_str(),"") != 0) ;
}
std::string CPerformanceConfig::GetPerformanceFileName(unsigned nID)
{
return m_nPerformanceFileName[nID];
}
std::string CPerformanceConfig::GetPerformanceName(unsigned nID)
{
if(nID == 0) // in order to assure retrocompatibility
{
return "Default";
}
else
{
return m_nPerformanceFileName[nID].substr(0,m_nPerformanceFileName[nID].length()-4).substr(7,14);
}
}
unsigned CPerformanceConfig::GetLastPerformance()
{
return nLastPerformance;
}
unsigned CPerformanceConfig::GetActualPerformanceID()
{
return nActualPerformance;
}
void CPerformanceConfig::SetActualPerformanceID(unsigned nID)
{
nActualPerformance = nID;
}
unsigned CPerformanceConfig::GetMenuSelectedPerformanceID()
{
return nMenuSelectedPerformance;
}
void CPerformanceConfig::SetMenuSelectedPerformanceID(unsigned nID)
{
nMenuSelectedPerformance = nID;
}
bool CPerformanceConfig::GetInternalFolderOk()
{
return nInternalFolderOk;
}
bool CPerformanceConfig::CreateNewPerformanceFile(std::string sPerformanceName)
{
// sPerformanceName for future improvements when user can enter a name via UI
nActualPerformance=nLastPerformance;
std::string nFileName;
std::string nPath;
std::string nIndex = "000000";
nIndex += std::to_string(++nLastFileIndex);
nIndex = nIndex.substr(nIndex.length()-6,6);
nFileName = nIndex;
nFileName += "_";
if (strcmp(sPerformanceName.c_str(),"") == 0)
{
nFileName += "Perf";
nFileName += nIndex;
}
else
{
nFileName +=sPerformanceName.substr(0,14);
}
nFileName += ".ini";
m_nPerformanceFileName[nLastPerformance]= nFileName;
nPath = "SD:/" ;
nPath += PERFORMANCE_DIR;
nPath += "/";
nFileName = nPath + nFileName;
FIL File;
FRESULT Result = f_open (&File, nFileName.c_str(), FA_WRITE | FA_CREATE_ALWAYS);
if (Result != FR_OK)
{
m_nPerformanceFileName[nLastPerformance]=nullptr;
return false;
}
if (f_close (&File) != FR_OK)
{
m_nPerformanceFileName[nLastPerformance]=nullptr;
return false;
}
nLastPerformance++;
new (&m_Properties) CPropertiesFatFsFile(nFileName.c_str(), m_pFileSystem);
return true;
}
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
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)
{
nInternalFolderOk=true;
// Result = f_closedir (&Directory);
}
else
{
// attenpt to create the folder
Result = f_mkdir("SD:/" PERFORMANCE_DIR);
nInternalFolderOk = (Result == FR_OK);
}
if (nInternalFolderOk)
{
Result = f_findfirst (&Directory, &FileInfo, "SD:/" PERFORMANCE_DIR, "*.ini");
for (unsigned i = 0; Result == FR_OK && FileInfo.fname[0]; i++)
{
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)
{
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);
}

@ -26,6 +26,8 @@
#include "config.h"
#include <fatfs/ff.h>
#include <Properties/propertiesfatfsfile.h>
#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;

@ -20,10 +20,14 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
#include <circle/logger.h>
#include <cstring>
#include "serialmididevice.h"
#include <assert.h>
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);

@ -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);
}

@ -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);

Loading…
Cancel
Save