From cfd2a24804cb56d4e2e31183216c94264252ca20 Mon Sep 17 00:00:00 2001 From: Kevin <68612569+diyelectromusic@users.noreply.github.com> Date: Sun, 2 Apr 2023 20:29:42 +0100 Subject: [PATCH] Support for headerless SysEx Voice Banks (#463) * Fix for Issue #457 - changed m_nNumLoadedBanks to be m_nNumHighestBank and updated functionality in menus accordingly. * Fix for Issue #460 implements MIDI Bank Select MSB/LSB based on PR #395 submitted by @abscisys * Fix for Issue #458 to not show blank banks in the menus. Also handles MIDI bank select messages and won't change banks if the final selected bank isn't loaded. * Firm up bank validity handling slightly. * Fix for Issue #459 Initial support for loading of headerless SysEx voice banks as a configuraton option * Fix for Issue #459 Added config option for headerless SysEx voice banks. --- src/config.cpp | 6 ++++++ src/config.h | 2 ++ src/minidexed.cpp | 2 +- src/minidexed.ini | 1 + src/sysexfileloader.cpp | 38 +++++++++++++++++++++++++++++++++++--- src/sysexfileloader.h | 4 +++- 6 files changed, 48 insertions(+), 5 deletions(-) diff --git a/src/config.cpp b/src/config.cpp index b5279a8..44ac32f 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -71,6 +71,7 @@ void CConfig::Load (void) m_bMIDIRXProgramChange = m_Properties.GetNumber ("MIDIRXProgramChange", 1) != 0; m_bIgnoreAllNotesOff = m_Properties.GetNumber ("IgnoreAllNotesOff", 0) != 0; m_bMIDIAutoVoiceDumpOnPC = m_Properties.GetNumber ("MIDIAutoVoiceDumpOnPC", 1) != 0; + m_bHeaderlessSysExVoices = m_Properties.GetNumber ("HeaderlessSysExVoices", 0) != 0; m_bLCDEnabled = m_Properties.GetNumber ("LCDEnabled", 0) != 0; m_nLCDPinEnable = m_Properties.GetNumber ("LCDPinEnable", 4); @@ -179,6 +180,11 @@ bool CConfig::GetMIDIAutoVoiceDumpOnPC (void) const return m_bMIDIAutoVoiceDumpOnPC; } +bool CConfig::GetHeaderlessSysExVoices (void) const +{ + return m_bHeaderlessSysExVoices; +} + bool CConfig::GetLCDEnabled (void) const { return m_bLCDEnabled; diff --git a/src/config.h b/src/config.h index 8a34239..bc5e7c6 100644 --- a/src/config.h +++ b/src/config.h @@ -77,6 +77,7 @@ public: bool GetMIDIRXProgramChange (void) const; // true if not specified bool GetIgnoreAllNotesOff (void) const; bool GetMIDIAutoVoiceDumpOnPC (void) const; // true if not specified + bool GetHeaderlessSysExVoices (void) const; // false if not specified // HD44780 LCD // GPIO pin numbers are chip numbers, not header positions @@ -157,6 +158,7 @@ private: bool m_bMIDIRXProgramChange; bool m_bIgnoreAllNotesOff; bool m_bMIDIAutoVoiceDumpOnPC; + bool m_bHeaderlessSysExVoices; bool m_bLCDEnabled; unsigned m_nLCDPinEnable; diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 66c6151..6acda43 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -170,7 +170,7 @@ bool CMiniDexed::Initialize (void) return false; } - m_SysExFileLoader.Load (); + m_SysExFileLoader.Load (m_pConfig->GetHeaderlessSysExVoices ()); if (m_SerialMIDI.Initialize ()) { diff --git a/src/minidexed.ini b/src/minidexed.ini index bb3edd7..2f5ce5b 100644 --- a/src/minidexed.ini +++ b/src/minidexed.ini @@ -17,6 +17,7 @@ MIDIBaudRate=31250 MIDIRXProgramChange=1 IgnoreAllNotesOff=0 MIDIAutoVoiceDumpOnPC=1 +HeaderlessSysExVoices=0 # HD44780 LCD LCDEnabled=1 diff --git a/src/sysexfileloader.cpp b/src/sysexfileloader.cpp index d5159eb..4eee065 100644 --- a/src/sysexfileloader.cpp +++ b/src/sysexfileloader.cpp @@ -81,7 +81,7 @@ CSysExFileLoader::~CSysExFileLoader (void) } } -void CSysExFileLoader::Load (void) +void CSysExFileLoader::Load (bool bHeaderlessSysExVoices) { m_nNumHighestBank = 0; @@ -124,6 +124,7 @@ void CSysExFileLoader::Load (void) m_pVoiceBank[nBank] = new TVoiceBank; assert (m_pVoiceBank[nBank]); + assert (sizeof(TVoiceBank) == VoiceSysExHdrSize + VoiceSysExSize); std::string Filename (m_DirName); Filename += "/"; @@ -132,7 +133,8 @@ void CSysExFileLoader::Load (void) FILE *pFile = fopen (Filename.c_str (), "rb"); if (pFile) { - if ( fread (m_pVoiceBank[nBank], sizeof (TVoiceBank), 1, pFile) == 1 + bool bBankLoaded = false; + if ( fread (m_pVoiceBank[nBank], VoiceSysExHdrSize+VoiceSysExSize, 1, pFile) == 1 && m_pVoiceBank[nBank]->StatusStart == 0xF0 && m_pVoiceBank[nBank]->CompanyID == 0x43 && m_pVoiceBank[nBank]->Format == 0x09 @@ -146,8 +148,38 @@ void CSysExFileLoader::Load (void) // This is the bank ID of the highest loaded bank m_nNumHighestBank = nBank; } + bBankLoaded = true; } - else + else if (bHeaderlessSysExVoices) + { + // Config says to accept headerless SysEx Voice Banks + // so reset file pointer and try again. + fseek (pFile, 0, SEEK_SET); + if (fread (m_pVoiceBank[nBank]->Voice, VoiceSysExSize, 1, pFile) == 1) + { + LOGDBG ("Bank #%u successfully loaded (headerless)", nBank); + + // Add in the missing header items. + // Naturally it isn't possible to validate these! + m_pVoiceBank[nBank]->StatusStart = 0xF0; + m_pVoiceBank[nBank]->CompanyID = 0x43; + m_pVoiceBank[nBank]->Format = 0x09; + m_pVoiceBank[nBank]->ByteCountMS = 0x20; + m_pVoiceBank[nBank]->ByteCountLS = 0x00; + m_pVoiceBank[nBank]->Checksum = 0x00; + m_pVoiceBank[nBank]->StatusEnd = 0xF7; + + m_BankFileName[nBank] = pEntry->d_name; + if (nBank > m_nNumHighestBank) + { + // This is the bank ID of the highest loaded bank + m_nNumHighestBank = nBank; + } + bBankLoaded = true; + } + } + + if (!bBankLoaded) { LOGWARN ("%s: Invalid size or format", Filename.c_str ()); diff --git a/src/sysexfileloader.h b/src/sysexfileloader.h index 3c20d0f..d3821da 100644 --- a/src/sysexfileloader.h +++ b/src/sysexfileloader.h @@ -33,6 +33,8 @@ public: static const unsigned VoicesPerBank = 32; static const size_t SizePackedVoice = 128; static const size_t SizeSingleVoice = 156; + static const unsigned VoiceSysExHdrSize = 8; // Additional (optional) Header/Footer bytes for bank of 32 voices + static const unsigned VoiceSysExSize = 4096; // Bank of 32 voices as per DX7 MIDI Spec struct TVoiceBank { @@ -54,7 +56,7 @@ public: CSysExFileLoader (const char *pDirName = "/sysex"); ~CSysExFileLoader (void); - void Load (void); + void Load (bool bHeaderlessSysExVoices = false); std::string GetBankName (unsigned nBankID); // 0 .. MaxVoiceBankID unsigned GetNumHighestBank (); // 0 .. MaxVoiceBankID