Merge branch 'main' into getsysex.sh

pull/444/head
Luca 2 years ago committed by GitHub
commit f0e653fafe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 17
      .github/workflows/build.yml
  2. 2
      src/minidexed.h
  3. 201
      src/sysexfileloader.cpp
  4. 4
      src/sysexfileloader.h
  5. 33
      src/uimenu.cpp
  6. 13
      submod.sh

@ -16,22 +16,9 @@ jobs:
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Recursively pull git submodules - name: Get specific commits of git submodules
run: | run: |
set -ex sh -ex ./submod.sh
git submodule update --init --recursive
- name: Use Circle develop branch for SSD1306 display rotation support until it is merged upstream
run: |
set -ex
cd circle-stdlib/
git checkout e318f89 # Needed to support Circle develop?
cd -
cd circle-stdlib/libs/circle
git checkout ec09d7e # develop
cd -
cd circle-stdlib/libs/circle-newlib
git checkout 48bf91d # needed for circle ec09d7e
cd -
- name: Install toolchains - name: Install toolchains
run: | run: |
set -ex set -ex

@ -126,6 +126,7 @@ public:
bool GetPerformanceSelectToLoad(void); bool GetPerformanceSelectToLoad(void);
bool SavePerformance (bool bSaveAsDeault); bool SavePerformance (bool bSaveAsDeault);
// Must match the order in CUIMenu::TParameter
enum TParameter enum TParameter
{ {
ParameterCompressorEnable, ParameterCompressorEnable,
@ -148,6 +149,7 @@ public:
bool DeletePerformance(unsigned nID); bool DeletePerformance(unsigned nID);
bool DoDeletePerformance(void); bool DoDeletePerformance(void);
// Must match the order in CUIMenu::TGParameter
enum TTGParameter enum TTGParameter
{ {
TGParameterVoiceBank, TGParameterVoiceBank,

@ -84,6 +84,7 @@ CSysExFileLoader::~CSysExFileLoader (void)
void CSysExFileLoader::Load (bool bHeaderlessSysExVoices) void CSysExFileLoader::Load (bool bHeaderlessSysExVoices)
{ {
m_nNumHighestBank = 0; m_nNumHighestBank = 0;
m_nBanksLoaded = 0;
DIR *pDirectory = opendir (m_DirName.c_str ()); DIR *pDirectory = opendir (m_DirName.c_str ());
if (!pDirectory) if (!pDirectory)
@ -96,107 +97,155 @@ void CSysExFileLoader::Load (bool bHeaderlessSysExVoices)
dirent *pEntry; dirent *pEntry;
while ((pEntry = readdir (pDirectory)) != nullptr) while ((pEntry = readdir (pDirectory)) != nullptr)
{ {
unsigned nBank; LoadBank(m_DirName.c_str (), pEntry->d_name, bHeaderlessSysExVoices, 0);
size_t nLen = strlen (pEntry->d_name); }
LOGDBG ("%u Banks loaded. Highest Bank loaded: #%u", m_nBanksLoaded, m_nNumHighestBank);
if ( nLen < 5 // "[NNNN]N[_name].syx" closedir (pDirectory);
|| strcasecmp (&pEntry->d_name[nLen-4], ".syx") != 0 }
|| sscanf (pEntry->d_name, "%u", &nBank) != 1)
{
LOGWARN ("%s: Invalid filename format", pEntry->d_name);
continue; void CSysExFileLoader::LoadBank (const char * sDirName, const char * sBankName, bool bHeaderlessSysExVoices, unsigned nSubDirCount)
} {
unsigned nBank;
size_t nLen = strlen (sBankName);
if ( nLen < 5 // "[NNNN]N[_name].syx"
|| strcasecmp (&sBankName[nLen-4], ".syx") != 0
|| sscanf (sBankName, "%u", &nBank) != 1)
{
// See if this is a subdirectory...
std::string Dirname (sDirName);
Dirname += "/";
Dirname += sBankName;
if (nBank > MaxVoiceBankID) DIR *pDirectory = opendir (Dirname.c_str ());
if (pDirectory)
{ {
LOGWARN ("Bank #%u is not supported", nBank); if (nSubDirCount >= MaxSubDirs)
{
LOGWARN ("Too many nested subdirectories: %s", sBankName);
return;
}
LOGDBG ("Processing subdirectory %s", sBankName);
continue; dirent *pEntry;
while ((pEntry = readdir (pDirectory)) != nullptr)
{
LoadBank(Dirname.c_str (), pEntry->d_name, bHeaderlessSysExVoices, nSubDirCount+1);
}
closedir (pDirectory);
} }
else
if (m_pVoiceBank[nBank])
{ {
LOGWARN ("Bank #%u already loaded", nBank); LOGWARN ("%s: Invalid filename format", sBankName);
continue;
} }
m_pVoiceBank[nBank] = new TVoiceBank; return;
assert (m_pVoiceBank[nBank]); }
assert (sizeof(TVoiceBank) == VoiceSysExHdrSize + VoiceSysExSize);
// File and UI handling requires banks to be 1..indexed.
// Internally (and via MIDI) we need 0..indexed.
// Any mention of a BankID internally is assumed to be 0..indexed.
unsigned nBankIdx = nBank - 1;
// BankIdx goes from 0 to MaxVoiceBankID inclusive
if (nBankIdx > MaxVoiceBankID)
{
LOGWARN ("Bank #%u is not supported", nBank);
return;
}
std::string Filename (m_DirName); if (m_pVoiceBank[nBankIdx])
Filename += "/"; {
Filename += pEntry->d_name; LOGWARN ("Bank #%u already loaded", nBank);
return;
}
FILE *pFile = fopen (Filename.c_str (), "rb"); m_pVoiceBank[nBankIdx] = new TVoiceBank;
if (pFile) assert (m_pVoiceBank[nBankIdx]);
assert (sizeof(TVoiceBank) == VoiceSysExHdrSize + VoiceSysExSize);
std::string Filename (sDirName);
Filename += "/";
Filename += sBankName;
FILE *pFile = fopen (Filename.c_str (), "rb");
if (pFile)
{
bool bBankLoaded = false;
if ( fread (m_pVoiceBank[nBankIdx], VoiceSysExHdrSize+VoiceSysExSize, 1, pFile) == 1
&& m_pVoiceBank[nBankIdx]->StatusStart == 0xF0
&& m_pVoiceBank[nBankIdx]->CompanyID == 0x43
&& m_pVoiceBank[nBankIdx]->Format == 0x09
&& m_pVoiceBank[nBankIdx]->StatusEnd == 0xF7)
{ {
bool bBankLoaded = false; if (m_nBanksLoaded % 100 == 0)
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
&& m_pVoiceBank[nBank]->StatusEnd == 0xF7)
{ {
LOGDBG ("Bank #%u successfully loaded", nBank); LOGDBG ("Banks successfully loaded #%u", m_nBanksLoaded);
}
//LOGDBG ("Bank #%u successfully loaded", nBank);
m_BankFileName[nBank] = pEntry->d_name; m_BankFileName[nBankIdx] = sBankName;
if (nBank > m_nNumHighestBank)
{
// This is the bank ID of the highest loaded bank
m_nNumHighestBank = nBank;
}
m_nBanksLoaded++;
bBankLoaded = true;
}
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[nBankIdx]->Voice, VoiceSysExSize, 1, pFile) == 1)
{
if (m_nBanksLoaded % 100 == 0)
{
LOGDBG ("Banks successfully loaded #%u", m_nBanksLoaded);
}
//LOGDBG ("Bank #%u successfully loaded (headerless)", nBank);
// Add in the missing header items.
// Naturally it isn't possible to validate these!
m_pVoiceBank[nBankIdx]->StatusStart = 0xF0;
m_pVoiceBank[nBankIdx]->CompanyID = 0x43;
m_pVoiceBank[nBankIdx]->Format = 0x09;
m_pVoiceBank[nBankIdx]->ByteCountMS = 0x20;
m_pVoiceBank[nBankIdx]->ByteCountLS = 0x00;
m_pVoiceBank[nBankIdx]->Checksum = 0x00;
m_pVoiceBank[nBankIdx]->StatusEnd = 0xF7;
m_BankFileName[nBankIdx] = sBankName;
if (nBank > m_nNumHighestBank) if (nBank > m_nNumHighestBank)
{ {
// This is the bank ID of the highest loaded bank // This is the bank ID of the highest loaded bank
m_nNumHighestBank = nBank; m_nNumHighestBank = nBank;
} }
bBankLoaded = true; bBankLoaded = true;
m_nBanksLoaded++;
} }
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 ());
delete m_pVoiceBank[nBank];
m_pVoiceBank[nBank] = nullptr;
}
fclose (pFile);
} }
else
if (!bBankLoaded)
{ {
delete m_pVoiceBank[nBank]; LOGWARN ("%s: Invalid size or format", Filename.c_str ());
m_pVoiceBank[nBank] = nullptr;
delete m_pVoiceBank[nBankIdx];
m_pVoiceBank[nBankIdx] = nullptr;
} }
}
closedir (pDirectory); fclose (pFile);
}
else
{
delete m_pVoiceBank[nBankIdx];
m_pVoiceBank[nBankIdx] = nullptr;
}
} }
std::string CSysExFileLoader::GetBankName (unsigned nBankID) std::string CSysExFileLoader::GetBankName (unsigned nBankID)

@ -35,6 +35,7 @@ public:
static const size_t SizeSingleVoice = 156; static const size_t SizeSingleVoice = 156;
static const unsigned VoiceSysExHdrSize = 8; // Additional (optional) Header/Footer bytes for bank of 32 voices 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 static const unsigned VoiceSysExSize = 4096; // Bank of 32 voices as per DX7 MIDI Spec
static const unsigned MaxSubDirs = 3; // Number of nested subdirectories supported.
struct TVoiceBank struct TVoiceBank
{ {
@ -75,11 +76,14 @@ private:
std::string m_DirName; std::string m_DirName;
unsigned m_nNumHighestBank; unsigned m_nNumHighestBank;
unsigned m_nBanksLoaded;
TVoiceBank *m_pVoiceBank[MaxVoiceBankID+1]; TVoiceBank *m_pVoiceBank[MaxVoiceBankID+1];
std::string m_BankFileName[MaxVoiceBankID+1]; std::string m_BankFileName[MaxVoiceBankID+1];
static uint8_t s_DefaultVoice[SizeSingleVoice]; static uint8_t s_DefaultVoice[SizeSingleVoice];
void LoadBank (const char * sDirName, const char * sBankName, bool bHeaderlessSysExVoices, unsigned nSubDirCount);
}; };
#endif #endif

@ -219,6 +219,8 @@ const CUIMenu::TParameter CUIMenu::s_GlobalParameter[CMiniDexed::ParameterUnknow
const CUIMenu::TParameter CUIMenu::s_TGParameter[CMiniDexed::TGParameterUnknown] = const CUIMenu::TParameter CUIMenu::s_TGParameter[CMiniDexed::TGParameterUnknown] =
{ {
{0, CSysExFileLoader::MaxVoiceBankID, 1}, // TGParameterVoiceBank {0, CSysExFileLoader::MaxVoiceBankID, 1}, // TGParameterVoiceBank
{0, 0, 0}, // TGParameterVoiceBankMSB (not used in menus)
{0, 0, 0}, // TGParameterVoiceBankLSB (not used in menus)
{0, CSysExFileLoader::VoicesPerBank-1, 1}, // TGParameterProgram {0, CSysExFileLoader::VoicesPerBank-1, 1}, // TGParameterProgram
{0, 127, 8, ToVolume}, // TGParameterVolume {0, 127, 8, ToVolume}, // TGParameterVolume
{0, 127, 8, ToPan}, // TGParameterPan {0, 127, 8, ToPan}, // TGParameterPan
@ -249,7 +251,6 @@ const CUIMenu::TParameter CUIMenu::s_TGParameter[CMiniDexed::TGParameterUnknown]
{0, 1, 1, ToOnOff}, //AT Pitch {0, 1, 1, ToOnOff}, //AT Pitch
{0, 1, 1, ToOnOff}, //AT Amp {0, 1, 1, ToOnOff}, //AT Amp
{0, 1, 1, ToOnOff} //AT EGBias {0, 1, 1, ToOnOff} //AT EGBias
}; };
// must match DexedVoiceParameters in Synth_Dexed // must match DexedVoiceParameters in Synth_Dexed
@ -580,15 +581,29 @@ void CUIMenu::EditProgramNumber (CUIMenu *pUIMenu, TMenuEvent Event)
return; return;
} }
string TG ("TG"); string voiceName = pUIMenu->m_pMiniDexed->GetVoiceName (nTG); // Skip empty voices
TG += to_string (nTG+1); if (voiceName == "EMPTY "
|| voiceName == " "
|| voiceName == "----------"
|| voiceName == "~~~~~~~~~~" )
{
if (Event == MenuEventStepUp) {
CUIMenu::EditProgramNumber (pUIMenu, MenuEventStepUp);
}
if (Event == MenuEventStepDown) {
CUIMenu::EditProgramNumber (pUIMenu, MenuEventStepDown);
}
} else {
string TG ("TG");
TG += to_string (nTG+1);
string Value = to_string (nValue+1) + "=" + pUIMenu->m_pMiniDexed->GetVoiceName (nTG); string Value = to_string (nValue+1) + "=" + pUIMenu->m_pMiniDexed->GetVoiceName (nTG);
pUIMenu->m_pUI->DisplayWrite (TG.c_str (), pUIMenu->m_pUI->DisplayWrite (TG.c_str (),
pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name,
Value.c_str (), Value.c_str (),
nValue > 0, nValue < (int) CSysExFileLoader::VoicesPerBank-1); nValue > 0, nValue < (int) CSysExFileLoader::VoicesPerBank-1);
}
} }
void CUIMenu::EditTGParameter (CUIMenu *pUIMenu, TMenuEvent Event) void CUIMenu::EditTGParameter (CUIMenu *pUIMenu, TMenuEvent Event)
@ -1467,8 +1482,6 @@ void CUIMenu::EditTGParameterModulation (CUIMenu *pUIMenu, TMenuEvent Event)
unsigned nController = pUIMenu->m_nMenuStackParameter[pUIMenu->m_nCurrentMenuDepth-1]; unsigned nController = pUIMenu->m_nMenuStackParameter[pUIMenu->m_nCurrentMenuDepth-1];
unsigned nParameter = pUIMenu->m_nCurrentParameter + nController; unsigned nParameter = pUIMenu->m_nCurrentParameter + nController;
CMiniDexed::TTGParameter Param = (CMiniDexed::TTGParameter) nParameter; CMiniDexed::TTGParameter Param = (CMiniDexed::TTGParameter) nParameter;
const TParameter &rParam = s_TGParameter[Param]; const TParameter &rParam = s_TGParameter[Param];

@ -0,0 +1,13 @@
#!/bin/bash
set -ex
git submodule update --init --recursive
cd circle-stdlib/
git checkout e318f89 # Needed to support Circle develop?
cd -
cd circle-stdlib/libs/circle
git checkout ec09d7e # develop
cd -
cd circle-stdlib/libs/circle-newlib
git checkout 48bf91d # needed for circle ec09d7e
cd -
Loading…
Cancel
Save