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
pull/50/head
Rene Stange 3 years ago
parent ca380d0740
commit 63bf2e47ce
  1. 4
      src/config.cpp
  2. 185
      src/mididevice.cpp
  3. 14
      src/mididevice.h
  4. 22
      src/minidexed.cpp
  5. 1
      src/minidexed.h
  6. 47
      src/userinterface.cpp
  7. 4
      src/userinterface.h

@ -38,7 +38,11 @@ void CConfig::Load (void)
m_SoundDevice = m_Properties.GetString ("SoundDevice", "pwm"); m_SoundDevice = m_Properties.GetString ("SoundDevice", "pwm");
m_nSampleRate = m_Properties.GetNumber ("SampleRate", 48000); m_nSampleRate = m_Properties.GetNumber ("SampleRate", 48000);
#ifdef ARM_ALLOW_MULTI_CORE
m_nChunkSize = m_Properties.GetNumber ("ChunkSize", m_SoundDevice == "hdmi" ? 384*6 : 256); 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_nDACI2CAddress = m_Properties.GetNumber ("DACI2CAddress", 0);
m_nMIDIBaudRate = m_Properties.GetNumber ("MIDIBaudRate", 31250); m_nMIDIBaudRate = m_Properties.GetNumber ("MIDIBaudRate", 31250);

@ -45,6 +45,10 @@ CMIDIDevice::CMIDIDevice (CMiniDexed *pSynthesizer, CConfig *pConfig)
: m_pSynthesizer (pSynthesizer), : m_pSynthesizer (pSynthesizer),
m_pConfig (pConfig) m_pConfig (pConfig)
{ {
for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++)
{
m_ChannelMap[nTG] = Disabled;
}
} }
CMIDIDevice::~CMIDIDevice (void) CMIDIDevice::~CMIDIDevice (void)
@ -52,6 +56,18 @@ CMIDIDevice::~CMIDIDevice (void)
m_pSynthesizer = 0; 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) void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsigned nCable)
{ {
assert (m_pSynthesizer != 0); assert (m_pSynthesizer != 0);
@ -67,17 +83,17 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign
if ( pMessage[0] != MIDI_TIMING_CLOCK if ( pMessage[0] != MIDI_TIMING_CLOCK
&& pMessage[0] != MIDI_ACTIVE_SENSING) && pMessage[0] != MIDI_ACTIVE_SENSING)
{ {
printf ("MIDI %u: %02X\n", nCable, (unsigned) pMessage[0]); printf ("MIDI%u: %02X\n", nCable, (unsigned) pMessage[0]);
} }
break; break;
case 2: case 2:
printf ("MIDI %u: %02X %02X\n", nCable, printf ("MIDI%u: %02X %02X\n", nCable,
(unsigned) pMessage[0], (unsigned) pMessage[1]); (unsigned) pMessage[0], (unsigned) pMessage[1]);
break; break;
case 3: 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[0], (unsigned) pMessage[1],
(unsigned) pMessage[2]); (unsigned) pMessage[2]);
break; break;
@ -89,114 +105,93 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign
return; return;
} }
u8 ucStatus = pMessage[0]; u8 ucStatus = pMessage[0];
// TODO: u8 ucChannel = ucStatus & 0x0F; u8 ucChannel = ucStatus & 0x0F;
u8 ucType = ucStatus >> 4; u8 ucType = ucStatus >> 4;
u8 ucKeyNumber = pMessage[1];
u8 ucVelocity = pMessage[2];
switch (ucType) for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++)
{ {
case MIDI_NOTE_ON: if ( m_ChannelMap[nTG] == ucChannel
if (nLength < 3) || m_ChannelMap[nTG] == OmniMode)
{ {
break; switch (ucType)
}
if (ucVelocity > 0)
{
if (ucVelocity <= 127)
{ {
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++) if (pMessage[2] > 0)
{ {
m_pSynthesizer->keyup (ucKeyNumber, nTG); if (pMessage[2] <= 127)
} {
break; m_pSynthesizer->keydown (pMessage[1],
pMessage[2], nTG);
}
}
else
{
m_pSynthesizer->keyup (pMessage[1], nTG);
}
break;
case MIDI_CONTROL_CHANGE: case MIDI_NOTE_OFF:
if (nLength < 3) if (nLength < 3)
{ {
break; break;
} }
switch (pMessage[1]) m_pSynthesizer->keyup (pMessage[1], nTG);
{ break;
case MIDI_CC_MODULATION:
for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++)
{
m_pSynthesizer->setModWheel (pMessage[2], nTG);
m_pSynthesizer->ControllersRefresh (nTG);
}
break;
case MIDI_CC_VOLUME: case MIDI_CONTROL_CHANGE:
for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++) if (nLength < 3)
{ {
m_pSynthesizer->SetVolume (pMessage[2], nTG); break;
} }
break;
case MIDI_CC_BANK_SELECT_LSB: switch (pMessage[1])
for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++) {
{ case MIDI_CC_MODULATION:
m_pSynthesizer->BankSelectLSB (pMessage[2], nTG); m_pSynthesizer->setModWheel (pMessage[2], nTG);
} m_pSynthesizer->ControllersRefresh (nTG);
break; 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: case MIDI_PROGRAM_CHANGE:
for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++) m_pSynthesizer->ProgramChange (pMessage[1], nTG);
{ break;
m_pSynthesizer->setSustain (pMessage[2] >= 64, nTG);
}
break;
}
break;
case MIDI_PROGRAM_CHANGE: case MIDI_PITCH_BEND: {
for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++) if (nLength < 3)
{ {
m_pSynthesizer->ProgramChange (pMessage[1], nTG); break;
} }
break;
case MIDI_PITCH_BEND: { s16 nValue = pMessage[1];
if (nLength < 3) nValue |= (s16) pMessage[2] << 7;
{ nValue -= 0x2000;
break;
}
s16 nValue = pMessage[1]; m_pSynthesizer->setPitchbend (nValue, nTG);
nValue |= (s16) pMessage[2] << 7; } break;
nValue -= 0x2000;
for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++) default:
{ break;
m_pSynthesizer->setPitchbend (nValue, nTG); }
} }
} break;
default:
break;
} }
} }

@ -30,16 +30,30 @@ class CMiniDexed;
class CMIDIDevice class CMIDIDevice
{ {
public:
enum TChannel
{
Channels = 16,
OmniMode = Channels,
Disabled,
ChannelUnknown
};
public: public:
CMIDIDevice (CMiniDexed *pSynthesizer, CConfig *pConfig); CMIDIDevice (CMiniDexed *pSynthesizer, CConfig *pConfig);
~CMIDIDevice (void); ~CMIDIDevice (void);
void SetChannel (u8 ucChannel, unsigned nTG);
u8 GetChannel (unsigned nTG) const;
protected: protected:
void MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsigned nCable = 0); void MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsigned nCable = 0);
private: private:
CMiniDexed *m_pSynthesizer; CMiniDexed *m_pSynthesizer;
CConfig *m_pConfig; CConfig *m_pConfig;
u8 m_ChannelMap[CConfig::ToneGenerators];
}; };
#endif #endif

@ -128,6 +128,8 @@ bool CMiniDexed::Initialize (void)
m_pTG[i]->setMWController (99, 7, 0); m_pTG[i]->setMWController (99, 7, 0);
} }
SetMIDIChannel (CMIDIDevice::OmniMode, 0);
// setup and start the sound device // setup and start the sound device
if (!m_pSoundDevice->AllocateQueueFrames (m_pConfig->GetChunkSize ())) if (!m_pSoundDevice->AllocateQueueFrames (m_pConfig->GetChunkSize ()))
{ {
@ -289,6 +291,26 @@ void CMiniDexed::SetVolume (unsigned nVolume, unsigned nTG)
m_UI.VolumeChanged (nVolume, 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) void CMiniDexed::keyup (int16_t pitch, unsigned nTG)
{ {
assert (nTG < CConfig::ToneGenerators); assert (nTG < CConfig::ToneGenerators);

@ -59,6 +59,7 @@ public:
void BankSelectLSB (unsigned nBankLSB, unsigned nTG); void BankSelectLSB (unsigned nBankLSB, unsigned nTG);
void ProgramChange (unsigned nProgram, unsigned nTG); void ProgramChange (unsigned nProgram, unsigned nTG);
void SetVolume (unsigned nVolume, unsigned nTG); void SetVolume (unsigned nVolume, unsigned nTG);
void SetMIDIChannel (uint8_t uchChannel, unsigned nTG);
void keyup (int16_t pitch, unsigned nTG); void keyup (int16_t pitch, unsigned nTG);
void keydown (int16_t pitch, uint8_t velocity, unsigned nTG); void keydown (int16_t pitch, uint8_t velocity, unsigned nTG);

@ -44,6 +44,7 @@ CUserInterface::CUserInterface (CMiniDexed *pMiniDexed, CGPIOManager *pGPIOManag
m_nBank[nTG] = 0; m_nBank[nTG] = 0;
m_nProgram[nTG] = 0; m_nProgram[nTG] = 0;
m_nVolume[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, void CUserInterface::DisplayWrite (const char *pInstance, const char *pMenu,
const char *pParam, const char *pValue) const char *pParam, const char *pValue)
{ {
@ -190,6 +217,12 @@ void CUserInterface::DisplayWrite (const char *pInstance, const char *pMenu,
assert (pMenu); assert (pMenu);
assert (pParam); assert (pParam);
// Do not show instance, if there is only one.
if (CConfig::ToneGenerators == 1)
{
pInstance = "";
}
CString Msg ("\x1B[H"); // cursor home CString Msg ("\x1B[H"); // cursor home
// first line // first line
@ -268,7 +301,12 @@ void CUserInterface::EncoderEventHandler (CKY040::TEvent Event)
reboot (); reboot ();
} }
return; else
{
m_UIMode = UIModeStart;
m_nTG = 0;
}
break;
default: default:
return; return;
@ -306,6 +344,13 @@ void CUserInterface::EncoderEventHandler (CKY040::TEvent Event)
m_pMiniDexed->SetVolume (nVolume, m_nTG); m_pMiniDexed->SetVolume (nVolume, m_nTG);
} break; } 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: default:
break; break;
} }

@ -25,6 +25,7 @@
#include <display/hd44780device.h> #include <display/hd44780device.h>
#include <circle/gpiomanager.h> #include <circle/gpiomanager.h>
#include <circle/writebuffer.h> #include <circle/writebuffer.h>
#include <stdint.h>
class CMiniDexed; class CMiniDexed;
@ -41,6 +42,7 @@ public:
void BankSelected (unsigned nBankLSB, unsigned nTG); // 0 .. 127 void BankSelected (unsigned nBankLSB, unsigned nTG); // 0 .. 127
void ProgramChanged (unsigned nProgram, unsigned nTG); // 0 .. 127 void ProgramChanged (unsigned nProgram, unsigned nTG); // 0 .. 127
void VolumeChanged (unsigned nVolume, unsigned nTG); // 0 .. 127 void VolumeChanged (unsigned nVolume, unsigned nTG); // 0 .. 127
void MIDIChannelChanged (uint8_t uchChannel, unsigned nTG);
private: private:
// Print to display in this format: // Print to display in this format:
@ -63,6 +65,7 @@ private:
UIModeVoiceSelect = UIModeStart, UIModeVoiceSelect = UIModeStart,
UIModeBankSelect, UIModeBankSelect,
UIModeVolume, UIModeVolume,
UIModeMIDI,
UIModeUnknown UIModeUnknown
}; };
@ -82,6 +85,7 @@ private:
unsigned m_nBank[CConfig::ToneGenerators]; unsigned m_nBank[CConfig::ToneGenerators];
unsigned m_nProgram[CConfig::ToneGenerators]; unsigned m_nProgram[CConfig::ToneGenerators];
unsigned m_nVolume[CConfig::ToneGenerators]; unsigned m_nVolume[CConfig::ToneGenerators];
uint8_t m_uchMIDIChannel[CConfig::ToneGenerators];
}; };
#endif #endif

Loading…
Cancel
Save