From 63bf2e47cea7c2e79dddaed6ff1e3751886db67b Mon Sep 17 00:00:00 2001 From: Rene Stange Date: Sat, 19 Mar 2022 09:14:41 +0100 Subject: [PATCH] Configure MIDI mapping from UI * ui: New menu item "MIDI" for configures assigned MIDI channel * ui: Holding switch for at least one second returns to menu home * ui: Do not show TG instance, if there is only one * By default TG1 is in omni mode, all other TGs are not assigned * config: Default chunk size is 1024 without multi-core --- src/config.cpp | 4 + src/mididevice.cpp | 185 ++++++++++++++++++++---------------------- src/mididevice.h | 14 ++++ src/minidexed.cpp | 22 +++++ src/minidexed.h | 1 + src/userinterface.cpp | 47 ++++++++++- src/userinterface.h | 4 + 7 files changed, 181 insertions(+), 96 deletions(-) diff --git a/src/config.cpp b/src/config.cpp index a31e1a4..0242548 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -38,7 +38,11 @@ void CConfig::Load (void) m_SoundDevice = m_Properties.GetString ("SoundDevice", "pwm"); m_nSampleRate = m_Properties.GetNumber ("SampleRate", 48000); +#ifdef ARM_ALLOW_MULTI_CORE m_nChunkSize = m_Properties.GetNumber ("ChunkSize", m_SoundDevice == "hdmi" ? 384*6 : 256); +#else + m_nChunkSize = m_Properties.GetNumber ("ChunkSize", m_SoundDevice == "hdmi" ? 384*6 : 1024); +#endif m_nDACI2CAddress = m_Properties.GetNumber ("DACI2CAddress", 0); m_nMIDIBaudRate = m_Properties.GetNumber ("MIDIBaudRate", 31250); diff --git a/src/mididevice.cpp b/src/mididevice.cpp index 5d2ebc4..33032ac 100644 --- a/src/mididevice.cpp +++ b/src/mididevice.cpp @@ -45,6 +45,10 @@ CMIDIDevice::CMIDIDevice (CMiniDexed *pSynthesizer, CConfig *pConfig) : m_pSynthesizer (pSynthesizer), m_pConfig (pConfig) { + for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++) + { + m_ChannelMap[nTG] = Disabled; + } } CMIDIDevice::~CMIDIDevice (void) @@ -52,6 +56,18 @@ CMIDIDevice::~CMIDIDevice (void) m_pSynthesizer = 0; } +void CMIDIDevice::SetChannel (u8 ucChannel, unsigned nTG) +{ + assert (nTG < CConfig::ToneGenerators); + m_ChannelMap[nTG] = ucChannel; +} + +u8 CMIDIDevice::GetChannel (unsigned nTG) const +{ + assert (nTG < CConfig::ToneGenerators); + return m_ChannelMap[nTG]; +} + void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsigned nCable) { assert (m_pSynthesizer != 0); @@ -67,17 +83,17 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign if ( pMessage[0] != MIDI_TIMING_CLOCK && pMessage[0] != MIDI_ACTIVE_SENSING) { - printf ("MIDI %u: %02X\n", nCable, (unsigned) pMessage[0]); + printf ("MIDI%u: %02X\n", nCable, (unsigned) pMessage[0]); } break; case 2: - printf ("MIDI %u: %02X %02X\n", nCable, + printf ("MIDI%u: %02X %02X\n", nCable, (unsigned) pMessage[0], (unsigned) pMessage[1]); break; case 3: - printf ("MIDI %u: %02X %02X %02X\n", nCable, + printf ("MIDI%u: %02X %02X %02X\n", nCable, (unsigned) pMessage[0], (unsigned) pMessage[1], (unsigned) pMessage[2]); break; @@ -89,114 +105,93 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign return; } - u8 ucStatus = pMessage[0]; - // TODO: u8 ucChannel = ucStatus & 0x0F; - u8 ucType = ucStatus >> 4; - u8 ucKeyNumber = pMessage[1]; - u8 ucVelocity = pMessage[2]; + u8 ucStatus = pMessage[0]; + u8 ucChannel = ucStatus & 0x0F; + u8 ucType = ucStatus >> 4; - switch (ucType) + for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++) { - case MIDI_NOTE_ON: - if (nLength < 3) + if ( m_ChannelMap[nTG] == ucChannel + || m_ChannelMap[nTG] == OmniMode) { - break; - } - - if (ucVelocity > 0) - { - if (ucVelocity <= 127) + switch (ucType) { - for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++) + case MIDI_NOTE_ON: + if (nLength < 3) { - m_pSynthesizer->keydown (ucKeyNumber, ucVelocity, nTG); + break; } - } - } - else - { - for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++) - { - m_pSynthesizer->keyup (ucKeyNumber, nTG); - } - } - break; - - case MIDI_NOTE_OFF: - if (nLength < 3) - { - break; - } - for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++) - { - m_pSynthesizer->keyup (ucKeyNumber, nTG); - } - 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_CONTROL_CHANGE: - if (nLength < 3) - { - break; - } + case MIDI_NOTE_OFF: + if (nLength < 3) + { + break; + } - switch (pMessage[1]) - { - case MIDI_CC_MODULATION: - for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++) - { - m_pSynthesizer->setModWheel (pMessage[2], nTG); - m_pSynthesizer->ControllersRefresh (nTG); - } - break; + m_pSynthesizer->keyup (pMessage[1], nTG); + break; - case MIDI_CC_VOLUME: - for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++) - { - m_pSynthesizer->SetVolume (pMessage[2], nTG); - } - break; + case MIDI_CONTROL_CHANGE: + if (nLength < 3) + { + break; + } - case MIDI_CC_BANK_SELECT_LSB: - for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++) - { - m_pSynthesizer->BankSelectLSB (pMessage[2], nTG); - } - 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_BANK_SELECT_LSB: + m_pSynthesizer->BankSelectLSB (pMessage[2], nTG); + break; + + case MIDI_CC_BANK_SUSTAIN: + m_pSynthesizer->setSustain (pMessage[2] >= 64, nTG); + break; + } + break; - case MIDI_CC_BANK_SUSTAIN: - for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++) - { - m_pSynthesizer->setSustain (pMessage[2] >= 64, nTG); - } - break; - } - break; + case MIDI_PROGRAM_CHANGE: + m_pSynthesizer->ProgramChange (pMessage[1], nTG); + break; - case MIDI_PROGRAM_CHANGE: - for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++) - { - m_pSynthesizer->ProgramChange (pMessage[1], nTG); - } - break; + case MIDI_PITCH_BEND: { + if (nLength < 3) + { + break; + } - case MIDI_PITCH_BEND: { - if (nLength < 3) - { - break; - } + s16 nValue = pMessage[1]; + nValue |= (s16) pMessage[2] << 7; + nValue -= 0x2000; - s16 nValue = pMessage[1]; - nValue |= (s16) pMessage[2] << 7; - nValue -= 0x2000; + m_pSynthesizer->setPitchbend (nValue, nTG); + } break; - for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++) - { - m_pSynthesizer->setPitchbend (nValue, nTG); + default: + break; + } } - } break; - - default: - break; } } diff --git a/src/mididevice.h b/src/mididevice.h index a595d1e..166351d 100644 --- a/src/mididevice.h +++ b/src/mididevice.h @@ -30,16 +30,30 @@ class CMiniDexed; class CMIDIDevice { +public: + enum TChannel + { + Channels = 16, + OmniMode = Channels, + Disabled, + ChannelUnknown + }; + public: CMIDIDevice (CMiniDexed *pSynthesizer, CConfig *pConfig); ~CMIDIDevice (void); + void SetChannel (u8 ucChannel, unsigned nTG); + u8 GetChannel (unsigned nTG) const; + protected: void MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsigned nCable = 0); private: CMiniDexed *m_pSynthesizer; CConfig *m_pConfig; + + u8 m_ChannelMap[CConfig::ToneGenerators]; }; #endif diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 3cc44e8..762cf3d 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -128,6 +128,8 @@ bool CMiniDexed::Initialize (void) m_pTG[i]->setMWController (99, 7, 0); } + SetMIDIChannel (CMIDIDevice::OmniMode, 0); + // setup and start the sound device if (!m_pSoundDevice->AllocateQueueFrames (m_pConfig->GetChunkSize ())) { @@ -289,6 +291,26 @@ void CMiniDexed::SetVolume (unsigned nVolume, unsigned nTG) m_UI.VolumeChanged (nVolume, nTG); } +void CMiniDexed::SetMIDIChannel (uint8_t uchChannel, unsigned nTG) +{ + assert (nTG < CConfig::ToneGenerators); + + for (unsigned i = 0; i < CConfig::MaxUSBMIDIDevices; i++) + { + assert (m_pMIDIKeyboard[i]); + m_pMIDIKeyboard[i]->SetChannel (uchChannel, nTG); + } + + m_PCKeyboard.SetChannel (uchChannel, nTG); + + if (m_bUseSerial) + { + m_SerialMIDI.SetChannel (uchChannel, nTG); + } + + m_UI.MIDIChannelChanged (uchChannel, nTG); +} + void CMiniDexed::keyup (int16_t pitch, unsigned nTG) { assert (nTG < CConfig::ToneGenerators); diff --git a/src/minidexed.h b/src/minidexed.h index c9c4cc8..144e53b 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -59,6 +59,7 @@ public: void BankSelectLSB (unsigned nBankLSB, unsigned nTG); void ProgramChange (unsigned nProgram, unsigned nTG); void SetVolume (unsigned nVolume, unsigned nTG); + void SetMIDIChannel (uint8_t uchChannel, unsigned nTG); void keyup (int16_t pitch, unsigned nTG); void keydown (int16_t pitch, uint8_t velocity, unsigned nTG); diff --git a/src/userinterface.cpp b/src/userinterface.cpp index 2ce76f6..ee9bf4b 100644 --- a/src/userinterface.cpp +++ b/src/userinterface.cpp @@ -44,6 +44,7 @@ CUserInterface::CUserInterface (CMiniDexed *pMiniDexed, CGPIOManager *pGPIOManag m_nBank[nTG] = 0; m_nProgram[nTG] = 0; m_nVolume[nTG] = 0; + m_uchMIDIChannel[nTG] = CMIDIDevice::Disabled; } } @@ -183,6 +184,32 @@ void CUserInterface::VolumeChanged (unsigned nVolume, unsigned nTG) } } +void CUserInterface::MIDIChannelChanged (uint8_t uchChannel, unsigned nTG) +{ + assert (nTG < CConfig::ToneGenerators); + m_uchMIDIChannel[nTG] = uchChannel; + + if ( m_UIMode == UIModeMIDI + && m_nTG == nTG) + { + CString TG; + TG.Format ("TG%u", nTG+1); + + CString String; + switch (uchChannel) + { + case CMIDIDevice::OmniMode: String = "OMNI"; break; + case CMIDIDevice::Disabled: String = "OFF"; break; + + default: + String.Format ("%u", (unsigned) uchChannel+1); + break; + } + + DisplayWrite (TG, "MIDI", "CHANNEL", (const char *) String); + } +} + void CUserInterface::DisplayWrite (const char *pInstance, const char *pMenu, const char *pParam, const char *pValue) { @@ -190,6 +217,12 @@ void CUserInterface::DisplayWrite (const char *pInstance, const char *pMenu, assert (pMenu); assert (pParam); + // Do not show instance, if there is only one. + if (CConfig::ToneGenerators == 1) + { + pInstance = ""; + } + CString Msg ("\x1B[H"); // cursor home // first line @@ -268,7 +301,12 @@ void CUserInterface::EncoderEventHandler (CKY040::TEvent Event) reboot (); } - return; + else + { + m_UIMode = UIModeStart; + m_nTG = 0; + } + break; default: return; @@ -306,6 +344,13 @@ void CUserInterface::EncoderEventHandler (CKY040::TEvent Event) m_pMiniDexed->SetVolume (nVolume, m_nTG); } break; + case UIModeMIDI: + if ((uint8_t) (m_uchMIDIChannel[m_nTG] + nStep) < CMIDIDevice::ChannelUnknown) + { + m_pMiniDexed->SetMIDIChannel (m_uchMIDIChannel[m_nTG] + nStep, m_nTG); + } + break; + default: break; } diff --git a/src/userinterface.h b/src/userinterface.h index 972d2ec..05d7d61 100644 --- a/src/userinterface.h +++ b/src/userinterface.h @@ -25,6 +25,7 @@ #include #include #include +#include class CMiniDexed; @@ -41,6 +42,7 @@ public: void BankSelected (unsigned nBankLSB, unsigned nTG); // 0 .. 127 void ProgramChanged (unsigned nProgram, unsigned nTG); // 0 .. 127 void VolumeChanged (unsigned nVolume, unsigned nTG); // 0 .. 127 + void MIDIChannelChanged (uint8_t uchChannel, unsigned nTG); private: // Print to display in this format: @@ -63,6 +65,7 @@ private: UIModeVoiceSelect = UIModeStart, UIModeBankSelect, UIModeVolume, + UIModeMIDI, UIModeUnknown }; @@ -82,6 +85,7 @@ private: unsigned m_nBank[CConfig::ToneGenerators]; unsigned m_nProgram[CConfig::ToneGenerators]; unsigned m_nVolume[CConfig::ToneGenerators]; + uint8_t m_uchMIDIChannel[CConfig::ToneGenerators]; }; #endif