Initial implementation of system-level, i.e. all TG, MIDI control maps (#704)

* Initial implementation of system-level, i.e. all TG, MIDI control maps

* Ensure msg only handled once by the first TG with a matching receiving MIDI channel.

* Optimise system CC handling esp when unrecognised CCs are received.

* Update in optimisation of System CC handling.
pull/746/head 2024-09-29
Kevin 2 months ago committed by GitHub
parent 6c56960888
commit 8c18e60e51
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 23
      src/config.cpp
  2. 10
      src/config.h
  3. 104
      src/mididevice.cpp
  4. 9
      src/mididevice.h

@ -109,6 +109,10 @@ void CConfig::Load (void)
m_bHeaderlessSysExVoices = m_Properties.GetNumber ("HeaderlessSysExVoices", 0) != 0; m_bHeaderlessSysExVoices = m_Properties.GetNumber ("HeaderlessSysExVoices", 0) != 0;
m_bExpandPCAcrossBanks = m_Properties.GetNumber ("ExpandPCAcrossBanks", 1) != 0; m_bExpandPCAcrossBanks = m_Properties.GetNumber ("ExpandPCAcrossBanks", 1) != 0;
m_nMIDISystemCCVol = m_Properties.GetNumber ("MIDISystemCCVol", 0);
m_nMIDISystemCCPan = m_Properties.GetNumber ("MIDISystemCCPan", 0);
m_nMIDISystemCCDetune = m_Properties.GetNumber ("MIDISystemCCDetune", 0);
m_bLCDEnabled = m_Properties.GetNumber ("LCDEnabled", 0) != 0; m_bLCDEnabled = m_Properties.GetNumber ("LCDEnabled", 0) != 0;
m_nLCDPinEnable = m_Properties.GetNumber ("LCDPinEnable", 4); m_nLCDPinEnable = m_Properties.GetNumber ("LCDPinEnable", 4);
m_nLCDPinRegisterSelect = m_Properties.GetNumber ("LCDPinRegisterSelect", 27); m_nLCDPinRegisterSelect = m_Properties.GetNumber ("LCDPinRegisterSelect", 27);
@ -283,6 +287,11 @@ unsigned CConfig::GetEngineType (void) const
return m_EngineType; return m_EngineType;
} }
bool CConfig::GetQuadDAC8Chan (void) const
{
return m_bQuadDAC8Chan;
}
unsigned CConfig::GetMIDIBaudRate (void) const unsigned CConfig::GetMIDIBaudRate (void) const
{ {
return m_nMIDIBaudRate; return m_nMIDIBaudRate;
@ -323,9 +332,19 @@ bool CConfig::GetExpandPCAcrossBanks (void) const
return m_bExpandPCAcrossBanks; return m_bExpandPCAcrossBanks;
} }
bool CConfig::GetQuadDAC8Chan (void) const unsigned CConfig::GetMIDISystemCCVol (void) const
{ {
return m_bQuadDAC8Chan; return m_nMIDISystemCCVol;
}
unsigned CConfig::GetMIDISystemCCPan (void) const
{
return m_nMIDISystemCCPan;
}
unsigned CConfig::GetMIDISystemCCDetune (void) const
{
return m_nMIDISystemCCDetune;
} }
bool CConfig::GetLCDEnabled (void) const bool CConfig::GetLCDEnabled (void) const

@ -117,6 +117,7 @@ public:
unsigned GetDACI2CAddress (void) const; // 0 for auto probing unsigned GetDACI2CAddress (void) const; // 0 for auto probing
bool GetChannelsSwapped (void) const; bool GetChannelsSwapped (void) const;
unsigned GetEngineType (void) const; unsigned GetEngineType (void) const;
bool GetQuadDAC8Chan (void) const; // false if not specified
// MIDI // MIDI
unsigned GetMIDIBaudRate (void) const; unsigned GetMIDIBaudRate (void) const;
@ -127,7 +128,9 @@ public:
bool GetMIDIAutoVoiceDumpOnPC (void) const; // false if not specified bool GetMIDIAutoVoiceDumpOnPC (void) const; // false if not specified
bool GetHeaderlessSysExVoices (void) const; // false if not specified bool GetHeaderlessSysExVoices (void) const; // false if not specified
bool GetExpandPCAcrossBanks (void) const; // true if not specified bool GetExpandPCAcrossBanks (void) const; // true if not specified
bool GetQuadDAC8Chan (void) const; // false if not specified unsigned GetMIDISystemCCVol (void) const;
unsigned GetMIDISystemCCPan (void) const;
unsigned GetMIDISystemCCDetune (void) const;
// HD44780 LCD // HD44780 LCD
// GPIO pin numbers are chip numbers, not header positions // GPIO pin numbers are chip numbers, not header positions
@ -245,6 +248,7 @@ private:
unsigned m_nDACI2CAddress; unsigned m_nDACI2CAddress;
bool m_bChannelsSwapped; bool m_bChannelsSwapped;
unsigned m_EngineType; unsigned m_EngineType;
bool m_bQuadDAC8Chan;
unsigned m_nMIDIBaudRate; unsigned m_nMIDIBaudRate;
std::string m_MIDIThruIn; std::string m_MIDIThruIn;
@ -254,7 +258,9 @@ private:
bool m_bMIDIAutoVoiceDumpOnPC; bool m_bMIDIAutoVoiceDumpOnPC;
bool m_bHeaderlessSysExVoices; bool m_bHeaderlessSysExVoices;
bool m_bExpandPCAcrossBanks; bool m_bExpandPCAcrossBanks;
bool m_bQuadDAC8Chan; unsigned m_nMIDISystemCCVol;
unsigned m_nMIDISystemCCPan;
unsigned m_nMIDISystemCCDetune;
bool m_bLCDEnabled; bool m_bLCDEnabled;
unsigned m_nLCDPinEnable; unsigned m_nLCDPinEnable;

@ -53,6 +53,21 @@ LOGMODULE ("mididevice");
#define MIDI_PROGRAM_CHANGE 0b1100 #define MIDI_PROGRAM_CHANGE 0b1100
#define MIDI_PITCH_BEND 0b1110 #define MIDI_PITCH_BEND 0b1110
// MIDI "System" level (i.e. all TG) custom CC maps
// Note: Even if number of TGs is not 8, there are only 8
// available to be used in the mappings here.
#define NUM_MIDI_CC_MAPS 8
const unsigned MIDISystemCCMap[NUM_MIDI_CC_MAPS][8] = {
{0,0,0,0,0,0,0,0}, // 0 = disabled
{16,17,18,19,80,81,82,83}, // 1 = General Purpose Controllers 1-8
{20,21,22,23,24,25,26,27},
{52,53,54,55,56,57,58,59},
{102,103,104,105,106,107,108,109},
{110,111,112,113,114,115,116,117},
{3,9,14,15,28,29,30,31},
{35,41,46,47,60,61,62,63}
};
#define MIDI_SYSTEM_EXCLUSIVE_BEGIN 0xF0 #define MIDI_SYSTEM_EXCLUSIVE_BEGIN 0xF0
#define MIDI_SYSTEM_EXCLUSIVE_END 0xF7 #define MIDI_SYSTEM_EXCLUSIVE_END 0xF7
#define MIDI_TIMING_CLOCK 0xF8 #define MIDI_TIMING_CLOCK 0xF8
@ -69,6 +84,34 @@ CMIDIDevice::CMIDIDevice (CMiniDexed *pSynthesizer, CConfig *pConfig, CUserInter
{ {
m_ChannelMap[nTG] = Disabled; m_ChannelMap[nTG] = Disabled;
} }
m_nMIDISystemCCVol = m_pConfig->GetMIDISystemCCVol();
m_nMIDISystemCCPan = m_pConfig->GetMIDISystemCCPan();
m_nMIDISystemCCDetune = m_pConfig->GetMIDISystemCCDetune();
m_MIDISystemCCBitmap[0] = 0;
m_MIDISystemCCBitmap[1] = 0;
m_MIDISystemCCBitmap[2] = 0;
m_MIDISystemCCBitmap[3] = 0;
for (int tg=0; tg<8; tg++)
{
if (m_nMIDISystemCCVol != 0) {
u8 cc = MIDISystemCCMap[m_nMIDISystemCCVol][tg];
m_MIDISystemCCBitmap[cc>>5] |= (1<<(cc%32));
}
if (m_nMIDISystemCCPan != 0) {
u8 cc = MIDISystemCCMap[m_nMIDISystemCCPan][tg];
m_MIDISystemCCBitmap[cc>>5] |= (1<<(cc%32));
}
if (m_nMIDISystemCCDetune != 0) {
u8 cc = MIDISystemCCMap[m_nMIDISystemCCDetune][tg];
m_MIDISystemCCBitmap[cc>>5] |= (1<<(cc%32));
}
}
if (m_pConfig->GetMIDIDumpEnabled ()) {
LOGNOTE("MIDI System CC Map: %08X %08X %08X %08X", m_MIDISystemCCBitmap[3],m_MIDISystemCCBitmap[2],m_MIDISystemCCBitmap[1],m_MIDISystemCCBitmap[0]);
}
} }
CMIDIDevice::~CMIDIDevice (void) CMIDIDevice::~CMIDIDevice (void)
@ -239,7 +282,9 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign
} }
// Process MIDI for each active Tone Generator // Process MIDI for each active Tone Generator
for (unsigned nTG = 0; nTG < m_pConfig->GetToneGenerators(); nTG++) bool bSystemCCHandled = false;
bool bSystemCCChecked = false;
for (unsigned nTG = 0; nTG < m_pConfig->GetToneGenerators() && !bSystemCCHandled; nTG++)
{ {
if (ucStatus == MIDI_SYSTEM_EXCLUSIVE_BEGIN) if (ucStatus == MIDI_SYSTEM_EXCLUSIVE_BEGIN)
{ {
@ -373,6 +418,17 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign
m_pSynthesizer->notesOff (pMessage[2], nTG); m_pSynthesizer->notesOff (pMessage[2], nTG);
} }
break; break;
default:
// Check for system-level, cross-TG MIDI Controls, but only do it once.
// Also, if successfully handled, then no need to process other TGs,
// so it is possible to break out of the main TG loop too.
// Note: We handle this here so we get the TG MIDI channel checking.
if (!bSystemCCChecked) {
bSystemCCHandled = HandleMIDISystemCC(pMessage[1], pMessage[2]);
bSystemCCChecked = true;
}
break;
} }
break; break;
@ -418,6 +474,52 @@ void CMIDIDevice::AddDevice (const char *pDeviceName)
s_DeviceMap.insert (std::pair<std::string, CMIDIDevice *> (pDeviceName, this)); s_DeviceMap.insert (std::pair<std::string, CMIDIDevice *> (pDeviceName, this));
} }
bool CMIDIDevice::HandleMIDISystemCC(const u8 ucCC, const u8 ucCCval)
{
// This only makes sense when there are at least 8 TGs.
// Note: If more than 8 TGs then only 8 TGs are controllable this way.
if (m_pConfig->GetToneGenerators() < 8) {
return false;
}
// Quickly reject any CCs not in the configured maps
if ((m_MIDISystemCCBitmap[ucCC>>5] & (1<<(ucCC%32))) == 0) {
// Not in the map
return false;
}
// Not looking for duplicate CCs so return once handled
for (unsigned tg=0; tg<8; tg++) {
if (m_nMIDISystemCCVol != 0) {
if (ucCC == MIDISystemCCMap[m_nMIDISystemCCVol][tg]) {
m_pSynthesizer->SetVolume (ucCCval, tg);
return true;
}
}
if (m_nMIDISystemCCPan != 0) {
if (ucCC == MIDISystemCCMap[m_nMIDISystemCCPan][tg]) {
m_pSynthesizer->SetPan (ucCCval, tg);
return true;
}
}
if (m_nMIDISystemCCDetune != 0) {
if (ucCC == MIDISystemCCMap[m_nMIDISystemCCDetune][tg]) {
if (ucCCval == 0)
{
m_pSynthesizer->SetMasterTune (0, tg);
}
else
{
m_pSynthesizer->SetMasterTune (maplong (ucCCval, 1, 127, -99, 99), tg);
}
return true;
}
}
}
return false;
}
void CMIDIDevice::HandleSystemExclusive(const uint8_t* pMessage, const size_t nLength, const unsigned nCable, 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; int16_t sysex_return;

@ -60,6 +60,10 @@ protected:
void MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsigned nCable = 0); void MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsigned nCable = 0);
void AddDevice (const char *pDeviceName); void AddDevice (const char *pDeviceName);
void HandleSystemExclusive(const uint8_t* pMessage, const size_t nLength, const unsigned nCable, const uint8_t nTG); void HandleSystemExclusive(const uint8_t* pMessage, const size_t nLength, const unsigned nCable, const uint8_t nTG);
private:
bool HandleMIDISystemCC(const u8 ucCC, const u8 ucCCval);
private: private:
CMiniDexed *m_pSynthesizer; CMiniDexed *m_pSynthesizer;
CConfig *m_pConfig; CConfig *m_pConfig;
@ -67,6 +71,11 @@ private:
u8 m_ChannelMap[CConfig::AllToneGenerators]; u8 m_ChannelMap[CConfig::AllToneGenerators];
unsigned m_nMIDISystemCCVol;
unsigned m_nMIDISystemCCPan;
unsigned m_nMIDISystemCCDetune;
u32 m_MIDISystemCCBitmap[4]; // to allow for 128 bit entries
std::string m_DeviceName; std::string m_DeviceName;
typedef std::unordered_map<std::string, CMIDIDevice *> TDeviceMap; typedef std::unordered_map<std::string, CMIDIDevice *> TDeviceMap;

Loading…
Cancel
Save