diff --git a/CMSIS_5 b/CMSIS_5
index 18205c6..8a64562 160000
--- a/CMSIS_5
+++ b/CMSIS_5
@@ -1 +1 @@
-Subproject commit 18205c6c2b68e7e96f40dc941c47efdbdd9f7d01
+Subproject commit 8a64562247485159a090ec4a01588f44f8d10311
diff --git a/Synth_Dexed b/Synth_Dexed
index e40f29d..8c677ce 160000
--- a/Synth_Dexed
+++ b/Synth_Dexed
@@ -1 +1 @@
-Subproject commit e40f29dc0ab6b70d57fc6a0c0d30130adfbc903d
+Subproject commit 8c677ceb4b3fb73f8643e30ff6cf4158dc8b9e53
diff --git a/src/mididevice.cpp b/src/mididevice.cpp
index 47f3f11..a6f5375 100644
--- a/src/mididevice.cpp
+++ b/src/mididevice.cpp
@@ -20,12 +20,16 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
//
+
+#include
#include "mididevice.h"
#include "minidexed.h"
#include "config.h"
#include
#include
+LOGMODULE ("mididevice");
+
#define MIDI_NOTE_OFF 0b1000
#define MIDI_NOTE_ON 0b1001
#define MIDI_AFTERTOUCH 0b1010 // TODO
@@ -45,6 +49,7 @@
#define MIDI_PROGRAM_CHANGE 0b1100
#define MIDI_PITCH_BEND 0b1110
+#define MIDI_SYSTEM_EXCLUSIVE 0xF0
#define MIDI_TIMING_CLOCK 0xF8
#define MIDI_ACTIVE_SENSING 0xFE
@@ -79,8 +84,6 @@ u8 CMIDIDevice::GetChannel (unsigned nTG) const
void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsigned nCable)
{
- assert (m_pSynthesizer != 0);
-
// The packet contents are just normal MIDI data - see
// https://www.midi.org/specifications/item/table-1-summary-of-midi-message
@@ -106,6 +109,25 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign
(unsigned) pMessage[0], (unsigned) pMessage[1],
(unsigned) pMessage[2]);
break;
+ default:
+ switch(pMessage[0])
+ {
+ case MIDI_SYSTEM_EXCLUSIVE:
+ printf("SysEx data length: [%d]\n",uint16_t(nLength));
+ printf("SysEx data:\n");
+ for (uint16_t i = 0; i < nLength; i++)
+ {
+ if((i % 8) == 0)
+ printf("%04d:",i);
+ printf(" 0x%02x",pMessage[i]);
+ if((i % 8) == 0)
+ printf("\n");
+ }
+ break;
+ default:
+ printf("Unhandled MIDI event type %0x02x\n",pMessage[0]);
+ }
+ break;
}
}
@@ -130,126 +152,142 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign
u8 ucChannel = ucStatus & 0x0F;
u8 ucType = ucStatus >> 4;
- for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++)
+ // GLOBAL MIDI SYSEX
+ if (pMessage[0] == MIDI_SYSTEM_EXCLUSIVE && pMessage[3] == 0x04 && pMessage[4] == 0x01 && pMessage[nLength-1] == 0xF7) // MASTER VOLUME
+ {
+ float32_t nMasterVolume=(pMessage[5] & (pMessage[6]<<7))/(1<<14);
+ LOGNOTE("Master volume: %f",nMasterVolume);
+ // TODO: Handle global master volume
+ }
+ else
{
- if ( m_ChannelMap[nTG] == ucChannel
- || m_ChannelMap[nTG] == OmniMode)
+ for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++)
{
- switch (ucType)
+ // MIDI SYSEX per MIDI channel
+ if (ucStatus == MIDI_SYSTEM_EXCLUSIVE && m_ChannelMap[nTG] == pMessage[2] & 0x07)
+ HandleSystemExclusive(pMessage, nLength, nTG);
+ else
{
- case MIDI_NOTE_ON:
- if (nLength < 3)
- {
- break;
- }
-
- if (pMessage[2] > 0)
+ if ( m_ChannelMap[nTG] == ucChannel
+ || m_ChannelMap[nTG] == OmniMode)
{
- if (pMessage[2] <= 127)
- {
- m_pSynthesizer->keydown (pMessage[1],
- pMessage[2], nTG);
- }
- }
- else
- {
- m_pSynthesizer->keyup (pMessage[1], nTG);
- }
- break;
-
- case MIDI_NOTE_OFF:
- if (nLength < 3)
- {
- break;
- }
-
- m_pSynthesizer->keyup (pMessage[1], nTG);
- break;
-
- case MIDI_CONTROL_CHANGE:
- if (nLength < 3)
- {
- break;
- }
-
- switch (pMessage[1])
- {
- case MIDI_CC_MODULATION:
- m_pSynthesizer->setModWheel (pMessage[2], nTG);
- m_pSynthesizer->ControllersRefresh (nTG);
- break;
-
- case MIDI_CC_VOLUME:
- m_pSynthesizer->SetVolume (pMessage[2], nTG);
- break;
-
- case MIDI_CC_PAN_POSITION:
- m_pSynthesizer->SetPan (pMessage[2], nTG);
- break;
-
- case MIDI_CC_BANK_SELECT_LSB:
- m_pSynthesizer->BankSelectLSB (pMessage[2], nTG);
- break;
-
- case MIDI_CC_BANK_SUSTAIN:
- m_pSynthesizer->setSustain (pMessage[2] >= 64, nTG);
- break;
-
- case MIDI_CC_RESONANCE:
- m_pSynthesizer->SetResonance (maplong (pMessage[2], 0, 127, 0, 99), nTG);
- break;
-
- case MIDI_CC_FREQUENCY_CUTOFF:
- m_pSynthesizer->SetCutoff (maplong (pMessage[2], 0, 127, 0, 99), nTG);
- break;
-
- case MIDI_CC_REVERB_LEVEL:
- m_pSynthesizer->SetReverbSend (maplong (pMessage[2], 0, 127, 0, 99), nTG);
- break;
-
- case MIDI_CC_DETUNE_LEVEL:
- if (pMessage[2] == 0)
- {
- // "0 to 127, with 0 being no celeste (detune) effect applied at all."
- m_pSynthesizer->SetMasterTune (0, nTG);
- }
- else
+ switch (ucType)
{
- m_pSynthesizer->SetMasterTune (maplong (pMessage[2], 1, 127, -99, 99), nTG);
+ case MIDI_NOTE_ON:
+ if (nLength < 3)
+ {
+ break;
+ }
+
+ if (pMessage[2] > 0)
+ {
+ if (pMessage[2] <= 127)
+ {
+ m_pSynthesizer->keydown (pMessage[1],
+ pMessage[2], nTG);
+ }
+ }
+ else
+ {
+ m_pSynthesizer->keyup (pMessage[1], nTG);
+ }
+ break;
+
+ case MIDI_NOTE_OFF:
+ if (nLength < 3)
+ {
+ break;
+ }
+
+ m_pSynthesizer->keyup (pMessage[1], nTG);
+ break;
+
+ case MIDI_CONTROL_CHANGE:
+ if (nLength < 3)
+ {
+ break;
+ }
+
+ switch (pMessage[1])
+ {
+ case MIDI_CC_MODULATION:
+ m_pSynthesizer->setModWheel (pMessage[2], nTG);
+ m_pSynthesizer->ControllersRefresh (nTG);
+ break;
+
+ case MIDI_CC_VOLUME:
+ m_pSynthesizer->SetVolume (pMessage[2], nTG);
+ break;
+
+ case MIDI_CC_PAN_POSITION:
+ m_pSynthesizer->SetPan (pMessage[2], nTG);
+ break;
+
+ case MIDI_CC_BANK_SELECT_LSB:
+ m_pSynthesizer->BankSelectLSB (pMessage[2], nTG);
+ break;
+
+ case MIDI_CC_BANK_SUSTAIN:
+ m_pSynthesizer->setSustain (pMessage[2] >= 64, nTG);
+ break;
+
+ case MIDI_CC_RESONANCE:
+ m_pSynthesizer->SetResonance (maplong (pMessage[2], 0, 127, 0, 99), nTG);
+ break;
+
+ case MIDI_CC_FREQUENCY_CUTOFF:
+ m_pSynthesizer->SetCutoff (maplong (pMessage[2], 0, 127, 0, 99), nTG);
+ break;
+
+ case MIDI_CC_REVERB_LEVEL:
+ m_pSynthesizer->SetReverbSend (maplong (pMessage[2], 0, 127, 0, 99), nTG);
+ break;
+
+ case MIDI_CC_DETUNE_LEVEL:
+ if (pMessage[2] == 0)
+ {
+ // "0 to 127, with 0 being no celeste (detune) effect applied at all."
+ m_pSynthesizer->SetMasterTune (0, nTG);
+ }
+ else
+ {
+ m_pSynthesizer->SetMasterTune (maplong (pMessage[2], 1, 127, -99, 99), nTG);
+ }
+ break;
+
+ case MIDI_CC_ALL_SOUND_OFF:
+ m_pSynthesizer->panic (pMessage[2], nTG);
+ break;
+
+ case MIDI_CC_ALL_NOTES_OFF:
+ m_pSynthesizer->notesOff (pMessage[2], nTG);
+ break;
+ }
+ break;
+
+ case MIDI_PROGRAM_CHANGE:
+ // do program change only if enabled in config
+ if( m_pConfig->GetMIDIRXProgramChange() )
+ m_pSynthesizer->ProgramChange (pMessage[1], nTG);
+ break;
+
+ case MIDI_PITCH_BEND: {
+ if (nLength < 3)
+ {
+ break;
+ }
+
+ s16 nValue = pMessage[1];
+ nValue |= (s16) pMessage[2] << 7;
+ nValue -= 0x2000;
+
+ m_pSynthesizer->setPitchbend (nValue, nTG);
+ } break;
+
+ default:
+ break;
}
- break;
-
- case MIDI_CC_ALL_SOUND_OFF:
- m_pSynthesizer->panic (pMessage[2], nTG);
- break;
-
- case MIDI_CC_ALL_NOTES_OFF:
- m_pSynthesizer->notesOff (pMessage[2], nTG);
- break;
- }
- break;
-
- case MIDI_PROGRAM_CHANGE:
- // do program change only if enabled in config
- if( m_pConfig->GetMIDIRXProgramChange() )
- m_pSynthesizer->ProgramChange (pMessage[1], nTG);
- break;
-
- case MIDI_PITCH_BEND: {
- if (nLength < 3)
- {
- break;
}
-
- s16 nValue = pMessage[1];
- nValue |= (s16) pMessage[2] << 7;
- nValue -= 0x2000;
-
- m_pSynthesizer->setPitchbend (nValue, nTG);
- } break;
-
- default:
- break;
}
}
}
@@ -265,3 +303,119 @@ 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)
+{
+ int16_t sysex_return;
+
+ sysex_return = m_pSynthesizer->checkSystemExclusive(pMessage, nLength, nTG);
+ LOGDBG("SYSEX handler return value: %d", sysex_return);
+
+ switch (sysex_return)
+ {
+ case -1:
+ LOGERR("SysEx end status byte not detected.");
+ break;
+ case -2:
+ LOGERR("E: SysEx vendor not Yamaha.");
+ break;
+ case -3:
+ LOGERR("E: Unknown SysEx parameter change.");
+ break;
+ case -4:
+ LOGERR(" Unknown SysEx voice or function.");
+ break;
+ case -5:
+ LOGERR("E: Not a SysEx voice bulk upload.");
+ break;
+ case -6:
+ LOGERR("E: Wrong length for SysEx voice bulk upload (not 155).");
+ break;
+ case -7:
+ LOGERR("E: Checksum error for one voice.");
+ break;
+ case -8:
+ LOGERR("E: Not a SysEx bank bulk upload.");
+ break;
+ case -9:
+ LOGERR("E: Wrong length for SysEx bank bulk upload (not 4096).");
+ case -10:
+ LOGERR("E: Checksum error for bank.");
+ break;
+ case -11:
+ LOGERR("E: Unknown SysEx message.");
+ break;
+ case 64:
+ LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
+ m_pSynthesizer->setMonoMode(pMessage[5],nTG);
+ break;
+ case 65:
+ LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
+ m_pSynthesizer->setPitchbendRange(pMessage[5],nTG);
+ break;
+ case 66:
+ LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
+ m_pSynthesizer->setPitchbendStep(pMessage[5],nTG);
+ break;
+ case 67:
+ LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
+ m_pSynthesizer->setPortamentoMode(pMessage[5],nTG);
+ break;
+ case 68:
+ LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
+ m_pSynthesizer->setPortamentoGlissando(pMessage[5],nTG);
+ break;
+ case 69:
+ LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
+ m_pSynthesizer->setPortamentoTime(pMessage[5],nTG);
+ break;
+ case 70:
+ LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
+ m_pSynthesizer->setModWheelRange(pMessage[5],nTG);
+ break;
+ case 71:
+ LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
+ m_pSynthesizer->setModWheelTarget(pMessage[5],nTG);
+ break;
+ case 72:
+ LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
+ m_pSynthesizer->setFootControllerRange(pMessage[5],nTG);
+ break;
+ case 73:
+ LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
+ m_pSynthesizer->setFootControllerTarget(pMessage[5],nTG);
+ break;
+ case 74:
+ LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
+ m_pSynthesizer->setBreathControllerRange(pMessage[5],nTG);
+ break;
+ case 75:
+ LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
+ m_pSynthesizer->setBreathControllerTarget(pMessage[5],nTG);
+ break;
+ case 76:
+ LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
+ m_pSynthesizer->setAftertouchRange(pMessage[5],nTG);
+ break;
+ case 77:
+ LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
+ m_pSynthesizer->setAftertouchTarget(pMessage[5],nTG);
+ break;
+ case 100:
+ // load sysex-data into voice memory
+ LOGDBG("One Voice bulk upload");
+ m_pSynthesizer->loadVoiceParameters(pMessage,nTG);
+
+ break;
+ case 200:
+ LOGDBG("Bank bulk upload.");
+ //TODO: add code for storing a bank bulk upload
+ 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);
+ break;
+ }
+}
+
diff --git a/src/mididevice.h b/src/mididevice.h
index d4e3079..0b116d1 100644
--- a/src/mididevice.h
+++ b/src/mididevice.h
@@ -55,6 +55,8 @@ protected:
void AddDevice (const char *pDeviceName);
+ void HandleSystemExclusive(const uint8_t* pMessage, const size_t nLength, const uint8_t nTG);
+
private:
CMiniDexed *m_pSynthesizer;
CConfig *m_pConfig;
diff --git a/src/minidexed.cpp b/src/minidexed.cpp
index 68908bf..45baf96 100644
--- a/src/minidexed.cpp
+++ b/src/minidexed.cpp
@@ -23,6 +23,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -255,6 +256,7 @@ void CMiniDexed::Process (bool bPlugAndPlayUpdated)
if (m_bUseSerial)
{
m_SerialMIDI.Process ();
+ m_SerialMIDI.Process ();
}
m_UI.Process ();
@@ -940,3 +942,179 @@ bool CMiniDexed::SavePerformance (void)
return m_PerformanceConfig.Save ();
}
+
+void CMiniDexed::setMonoMode(uint8_t mono, uint8_t nTG)
+{
+ assert (nTG < CConfig::ToneGenerators);
+ assert (m_pTG[nTG]);
+
+ m_pTG[nTG]->setMonoMode(constrain(mono, 0, 1));
+ m_pTG[nTG]->doRefreshVoice();
+ m_UI.ParameterChanged ();
+}
+
+void CMiniDexed::setPitchbendRange(uint8_t range, uint8_t nTG)
+{
+ assert (nTG < CConfig::ToneGenerators);
+ assert (m_pTG[nTG]);
+
+ m_pTG[nTG]->setPitchbendRange(constrain(range, 0, 12));
+ m_pTG[nTG]->ControllersRefresh();
+ m_UI.ParameterChanged ();
+}
+
+void CMiniDexed::setPitchbendStep(uint8_t step, uint8_t nTG)
+{
+ assert (nTG < CConfig::ToneGenerators);
+ assert (m_pTG[nTG]);
+
+ m_pTG[nTG]->setPitchbendStep(constrain(step, 0, 12));
+ m_pTG[nTG]->ControllersRefresh();
+ m_UI.ParameterChanged ();
+}
+
+void CMiniDexed::setPortamentoMode(uint8_t mode, uint8_t nTG)
+{
+ assert (nTG < CConfig::ToneGenerators);
+ assert (m_pTG[nTG]);
+
+ m_pTG[nTG]->setPortamentoMode(constrain(mode, 0, 1));
+ m_pTG[nTG]->ControllersRefresh();
+ m_UI.ParameterChanged ();
+}
+
+void CMiniDexed::setPortamentoGlissando(uint8_t glissando, uint8_t nTG)
+{
+ assert (nTG < CConfig::ToneGenerators);
+ assert (m_pTG[nTG]);
+
+ m_pTG[nTG]->setPortamentoGlissando(constrain(glissando, 0, 1));
+ m_pTG[nTG]->ControllersRefresh();
+ m_UI.ParameterChanged ();
+}
+
+void CMiniDexed::setPortamentoTime(uint8_t time, uint8_t nTG)
+{
+ assert (nTG < CConfig::ToneGenerators);
+ assert (m_pTG[nTG]);
+
+ m_pTG[nTG]->setPortamentoTime(constrain(time, 0, 99));
+ m_pTG[nTG]->ControllersRefresh();
+ m_UI.ParameterChanged ();
+}
+
+void CMiniDexed::setModWheelRange(uint8_t range, uint8_t nTG)
+{
+ assert (nTG < CConfig::ToneGenerators);
+ assert (m_pTG[nTG]);
+
+ m_pTG[nTG]->setModWheelRange(constrain(range, 0, 99));
+ m_pTG[nTG]->ControllersRefresh();
+ m_UI.ParameterChanged ();
+}
+
+void CMiniDexed::setModWheelTarget(uint8_t target, uint8_t nTG)
+{
+ assert (nTG < CConfig::ToneGenerators);
+ assert (m_pTG[nTG]);
+
+ m_pTG[nTG]->setModWheelTarget(constrain(target, 0, 7));
+ m_pTG[nTG]->ControllersRefresh();
+ m_UI.ParameterChanged ();
+}
+
+void CMiniDexed::setFootControllerRange(uint8_t range, uint8_t nTG)
+{
+ assert (nTG < CConfig::ToneGenerators);
+ assert (m_pTG[nTG]);
+
+ m_pTG[nTG]->setFootControllerRange(constrain(range, 0, 99));
+ m_pTG[nTG]->ControllersRefresh();
+ m_UI.ParameterChanged ();
+}
+
+void CMiniDexed::setFootControllerTarget(uint8_t target, uint8_t nTG)
+{
+ assert (nTG < CConfig::ToneGenerators);
+ assert (m_pTG[nTG]);
+
+ m_pTG[nTG]->setFootControllerTarget(constrain(target, 0, 7));
+ m_pTG[nTG]->ControllersRefresh();
+ m_UI.ParameterChanged ();
+}
+
+void CMiniDexed::setBreathControllerRange(uint8_t range, uint8_t nTG)
+{
+ assert (nTG < CConfig::ToneGenerators);
+ assert (m_pTG[nTG]);
+
+ m_pTG[nTG]->setBreathControllerRange(constrain(range, 0, 99));
+ m_pTG[nTG]->ControllersRefresh();
+ m_UI.ParameterChanged ();
+}
+
+void CMiniDexed::setBreathControllerTarget(uint8_t target, uint8_t nTG)
+{
+ assert (nTG < CConfig::ToneGenerators);
+ assert (m_pTG[nTG]);
+
+ m_pTG[nTG]->setBreathControllerTarget(constrain(target, 0, 7));
+ m_pTG[nTG]->ControllersRefresh();
+ m_UI.ParameterChanged ();
+}
+
+void CMiniDexed::setAftertouchRange(uint8_t range, uint8_t nTG)
+{
+ assert (nTG < CConfig::ToneGenerators);
+ assert (m_pTG[nTG]);
+
+ m_pTG[nTG]->setAftertouchRange(constrain(range, 0, 99));
+ m_pTG[nTG]->ControllersRefresh();
+ m_UI.ParameterChanged ();
+}
+
+void CMiniDexed::setAftertouchTarget(uint8_t target, uint8_t nTG)
+{
+ assert (nTG < CConfig::ToneGenerators);
+ assert (m_pTG[nTG]);
+
+ m_pTG[nTG]->setAftertouchTarget(constrain(target, 0, 7));
+ m_pTG[nTG]->ControllersRefresh();
+ m_UI.ParameterChanged ();
+}
+
+void CMiniDexed::loadVoiceParameters(const uint8_t* data, uint8_t nTG)
+{
+ assert (nTG < CConfig::ToneGenerators);
+ assert (m_pTG[nTG]);
+
+ uint8_t voice[161];
+
+ memcpy(voice, data, sizeof(uint8_t)*161);
+
+ // fix voice name
+ for (uint8_t i = 0; i < 10; i++)
+ {
+ if (voice[151 + i] > 126) // filter characters
+ voice[151 + i] = 32;
+ }
+
+ m_pTG[nTG]->loadVoiceParameters(&voice[6]);
+ m_pTG[nTG]->doRefreshVoice();
+ m_UI.ParameterChanged ();
+}
+
+void CMiniDexed::setVoiceDataElement(uint8_t data, uint8_t number, uint8_t nTG)
+{
+ assert (nTG < CConfig::ToneGenerators);
+ assert (m_pTG[nTG]);
+
+ m_pTG[nTG]->setVoiceDataElement(constrain(data, 0, 155),constrain(number, 0, 99));
+ //m_pTG[nTG]->doRefreshVoice();
+ m_UI.ParameterChanged ();
+}
+
+int16_t CMiniDexed::checkSystemExclusive(const uint8_t* pMessage,const uint16_t nLength, uint8_t nTG)
+{
+ return(m_pTG[nTG]->checkSystemExclusive(pMessage, nLength));
+}
diff --git a/src/minidexed.h b/src/minidexed.h
index 1292e53..4aeb42f 100644
--- a/src/minidexed.h
+++ b/src/minidexed.h
@@ -84,6 +84,25 @@ public:
void SetReverbSend (unsigned nReverbSend, unsigned nTG); // 0 .. 127
+ void setMonoMode(uint8_t mono, uint8_t nTG);
+ void setPitchbendRange(uint8_t range, uint8_t nTG);
+ void setPitchbendStep(uint8_t step, uint8_t nTG);
+ void setPortamentoMode(uint8_t mode, uint8_t nTG);
+ void setPortamentoGlissando(uint8_t glissando, uint8_t nTG);
+ void setPortamentoTime(uint8_t time, uint8_t nTG);
+ void setModWheelRange(uint8_t range, uint8_t nTG);
+ void setModWheelTarget(uint8_t target, uint8_t nTG);
+ void setFootControllerRange(uint8_t range, uint8_t nTG);
+ void setFootControllerTarget(uint8_t target, uint8_t nTG);
+ void setBreathControllerRange(uint8_t range, uint8_t nTG);
+ void setBreathControllerTarget(uint8_t target, uint8_t nTG);
+ void setAftertouchRange(uint8_t range, uint8_t nTG);
+ 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);
+
+ int16_t checkSystemExclusive(const uint8_t* pMessage, const uint16_t nLength, uint8_t nTG);
+
enum TParameter
{
ParameterCompressorEnable,
diff --git a/src/serialmididevice.cpp b/src/serialmididevice.cpp
index b03dfad..6c484cf 100644
--- a/src/serialmididevice.cpp
+++ b/src/serialmididevice.cpp
@@ -20,6 +20,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
//
+#include
#include "serialmididevice.h"
#include
@@ -29,12 +30,14 @@ CSerialMIDIDevice::CSerialMIDIDevice (CMiniDexed *pSynthesizer, CInterruptSystem
m_pConfig (pConfig),
m_Serial (pInterrupt, TRUE),
m_nSerialState (0),
+ m_nSysEx (0),
m_SendBuffer (&m_Serial)
{
AddDevice ("ttyS1");
}
CSerialMIDIDevice::~CSerialMIDIDevice (void)
+
{
m_nSerialState = 255;
}
@@ -57,6 +60,21 @@ void CSerialMIDIDevice::Process (void)
return;
}
+ if (m_pConfig->GetMIDIDumpEnabled ())
+ {
+ printf("Incoming MIDI data:\n");
+ for (uint16_t i = 0; i < nResult; i++)
+ {
+ if((i % 8) == 0)
+ printf("%04d:",i);
+ printf(" 0x%02x",Buffer[i]);
+ if((i > 1 ) && (i % 8) == 0)
+ printf("\n");
+ }
+ if((nResult % 8) != 0)
+ printf("\n");
+ }
+
// Process MIDI messages
// See: https://www.midi.org/specifications/item/table-1-summary-of-midi-message
// "Running status" see: https://www.lim.di.unimi.it/IEEE/MIDI/SOT5.HTM#Running-
@@ -65,54 +83,70 @@ void CSerialMIDIDevice::Process (void)
{
u8 uchData = Buffer[i];
- switch (m_nSerialState)
+ if(uchData == 0xF0)
{
- case 0:
- MIDIRestart:
- if ( (uchData & 0x80) == 0x80 // status byte, all channels
- && (uchData & 0xF0) != 0xF0) // ignore system messages
- {
- m_SerialMessage[m_nSerialState++] = uchData;
- }
- break;
-
- case 1:
- case 2:
- DATABytes:
- if (uchData & 0x80) // got status when parameter expected
- {
- m_nSerialState = 0;
-
- goto MIDIRestart;
- }
-
- m_SerialMessage[m_nSerialState++] = uchData;
-
- if ( (m_SerialMessage[0] & 0xE0) == 0xC0
- || m_nSerialState == 3) // message is complete
- {
- MIDIMessageHandler (m_SerialMessage, m_nSerialState);
+ // SYSEX found
+ m_SerialMessage[m_nSysEx++]=uchData;
+ continue;
+ }
- m_nSerialState = 4; // State 4 for test if 4th byte is a status byte or a data byte
- }
- break;
- case 4:
-
- if ((uchData & 0x80) == 0) // true data byte, false status byte
+ if(m_nSysEx > 0)
+ {
+ m_SerialMessage[m_nSysEx++]=uchData;
+ if ((uchData & 0x80) == 0x80 || m_nSysEx >= MAX_MIDI_MESSAGE)
{
- m_nSerialState = 1;
- goto DATABytes;
+ if(uchData == 0xF7)
+ MIDIMessageHandler (m_SerialMessage, m_nSysEx);
+ m_nSysEx = 0;
}
- else
+ continue;
+ }
+ else
+ {
+ switch (m_nSerialState)
{
- m_nSerialState = 0;
- goto MIDIRestart;
+ case 0:
+ MIDIRestart:
+ if ( (uchData & 0x80) == 0x80 // status byte, all channels
+ && (uchData & 0xF0) != 0xF0) // ignore system messages
+ {
+ m_SerialMessage[m_nSerialState++] = uchData;
+ }
+ break;
+
+ case 1:
+ case 2:
+ DATABytes:
+ if (uchData & 0x80) // got status when parameter expected
+ {
+ m_nSerialState = 0;
+
+ goto MIDIRestart;
+ }
+
+ m_SerialMessage[m_nSerialState++] = uchData;
+
+ if ( (m_SerialMessage[0] & 0xE0) == 0xC0
+ || m_nSerialState == 3) // message is complete
+ {
+ MIDIMessageHandler (m_SerialMessage, m_nSerialState);
+
+ m_nSerialState = 4; // State 4 for test if 4th byte is a status byte or a data byte
+ }
+
+ break;
+ case 4:
+
+ if ((uchData & 0x80) == 0) // true data byte, false status byte
+ {
+ m_nSerialState = 1;
+ goto DATABytes;
+ }
+ break;
+ default:
+ assert (0);
+ break;
}
- break;
-
- default:
- assert (0);
- break;
}
}
}
diff --git a/src/serialmididevice.h b/src/serialmididevice.h
index 0e6d9f5..1f3619e 100644
--- a/src/serialmididevice.h
+++ b/src/serialmididevice.h
@@ -30,6 +30,9 @@
#include
#include
+#define MAX_DX7_SYSEX_LENGTH 4104
+#define MAX_MIDI_MESSAGE MAX_DX7_SYSEX_LENGTH
+
class CMiniDexed;
class CSerialMIDIDevice : public CMIDIDevice
@@ -49,7 +52,8 @@ private:
CSerialDevice m_Serial;
unsigned m_nSerialState;
- u8 m_SerialMessage[3];
+ unsigned m_nSysEx;
+ u8 m_SerialMessage[MAX_MIDI_MESSAGE];
CWriteBufferDevice m_SendBuffer;
};