Merge branch 'dev_routing' of https://github.com/rerdavies/pipedal into dev_tone3000

This commit is contained in:
Robin E.R. Davies
2026-02-10 20:18:09 -05:00
48 changed files with 2959 additions and 595 deletions
+187 -49
View File
@@ -197,11 +197,11 @@ void Storage::SetDataRoot(const std::filesystem::path &path)
this->dataRoot__audio_uploads = dataRoot / "audio_uploads";
}
const std::filesystem::path &Storage::GetConfigRoot()
const std::filesystem::path &Storage::GetConfigRoot() const
{
return this->configRoot;
}
const std::filesystem::path &Storage::GetDataRoot()
const std::filesystem::path &Storage::GetDataRoot() const
{
return this->dataRoot;
}
@@ -250,7 +250,6 @@ static void removeFileNoThrow(const std::filesystem::path &path)
}
}
void Storage::UpgradeFactoryPresets()
{
auto presetsDirectory = this->GetPresetsDirectory();
@@ -378,7 +377,7 @@ void Storage::Initialize()
LoadCurrentBank();
try
{
LoadChannelSelection();
LoadJackChannelSelection();
}
catch (const std::exception &)
{
@@ -387,8 +386,10 @@ void Storage::Initialize()
LoadWifiConfigSettings();
LoadWifiDirectConfigSettings();
this->channelRouterSettings = LoadChannelRouterSettings();
LoadUserSettings();
UpgradeFactoryPresets();
UpgradeChannelRouterSettings();
}
void Storage::LoadBank(int64_t instanceId)
@@ -471,7 +472,7 @@ void Storage::LoadBankIndex()
if (bankIndex.entries().size() == 0)
{
currentBank.clear();
Pedalboard defaultPedalboard = Pedalboard::MakeDefault();
Pedalboard defaultPedalboard = Pedalboard::MakeDefault(Pedalboard::PedalboardType::MainPedalboard);
int64_t instanceId = currentBank.addPreset(defaultPedalboard);
currentBank.selectedPreset(instanceId);
@@ -683,40 +684,46 @@ int64_t Storage::SaveCurrentPresetAs(const Pedalboard &pedalboard, int64_t bankI
}
}
static std::string stripNumericSuffix(const std::string &name) {
static std::string stripNumericSuffix(const std::string &name)
{
// remove (digit*) from the end of the string.
// Find the last '(' character
size_t pos = name.find_last_of('(');
if (pos == std::string::npos) {
if (pos == std::string::npos)
{
return name;
}
// Check if everything between '(' and ')' is digits
size_t len = name.length()-1;
if (name[len] != ')')
size_t len = name.length() - 1;
if (name[len] != ')')
{
return name;
}
bool allDigits = true;
for (size_t i = pos + 1; i < len - 1; ++i) {
if (name[i] < '0' || name[i] > '9') {
for (size_t i = pos + 1; i < len - 1; ++i)
{
if (name[i] < '0' || name[i] > '9')
{
allDigits = false;
break;
}
}
if (!allDigits) {
if (!allDigits)
{
return name;
}
// Remove trailing spaces before the '('
while (pos > 0 && name[pos - 1] == ' ') {
while (pos > 0 && name[pos - 1] == ' ')
{
--pos;
}
return name.substr(0, pos);
}
static std::string makeUniqueName(const std::string &name, const std::set<std::string>&existingNames)
static std::string makeUniqueName(const std::string &name, const std::set<std::string> &existingNames)
{
if (!existingNames.contains(name))
{
@@ -725,9 +732,11 @@ static std::string makeUniqueName(const std::string &name, const std::set<std::s
std::string baseName = stripNumericSuffix(name);
size_t i = 2;
while (true) {
while (true)
{
std::string newName = SS(baseName << " (" << i << ")");
if (!existingNames.contains(newName)) {
if (!existingNames.contains(newName))
{
return newName;
}
++i;
@@ -735,23 +744,27 @@ static std::string makeUniqueName(const std::string &name, const std::set<std::s
}
int64_t Storage::ImportPresetsFromBank(int64_t bankInstanceId, const std::vector<int64_t> &presets)
{
if (bankIndex.selectedBank() == bankInstanceId) {
if (bankIndex.selectedBank() == bankInstanceId)
{
throw std::runtime_error("Can't import to self.");
}
std::set<int64_t> presetsSet { presets.begin(), presets.end()};
std::set<int64_t> presetsSet{presets.begin(), presets.end()};
auto indexEntry = this->bankIndex.getBankIndexEntry(bankInstanceId);
std::set<std::string> existingNames;
for (auto&preset: this->currentBank.presets()) {
for (auto &preset : this->currentBank.presets())
{
existingNames.insert(preset->preset().name());
}
BankFile bankFile;
LoadBankFile(indexEntry.name(),&bankFile);
LoadBankFile(indexEntry.name(), &bankFile);
int64_t lastPresetId = -1;
for (auto &presetEntry: bankFile.presets()) {
if (presetsSet.contains(presetEntry->instanceId())) {
std::string uniqueName = makeUniqueName(presetEntry->preset().name(),existingNames);
for (auto &presetEntry : bankFile.presets())
{
if (presetsSet.contains(presetEntry->instanceId()))
{
std::string uniqueName = makeUniqueName(presetEntry->preset().name(), existingNames);
existingNames.insert(uniqueName);
Pedalboard t = presetEntry->preset();
t.name(uniqueName);
@@ -763,31 +776,35 @@ int64_t Storage::ImportPresetsFromBank(int64_t bankInstanceId, const std::vector
}
int64_t Storage::CopyPresetsToBank(int64_t bankInstanceId, const std::vector<int64_t> &presets)
{
if (bankIndex.selectedBank() == bankInstanceId) {
if (bankIndex.selectedBank() == bankInstanceId)
{
throw std::runtime_error("Can't copy to self.");
}
auto indexEntry = this->bankIndex.getBankIndexEntry(bankInstanceId);
BankFile bankFile;
LoadBankFile(indexEntry.name(),&bankFile);
LoadBankFile(indexEntry.name(), &bankFile);
std::set<int64_t> presetsSet { presets.begin(), presets.end()};
std::set<int64_t> presetsSet{presets.begin(), presets.end()};
std::set<std::string> existingNames;
for (auto&preset: bankFile.presets()) {
for (auto &preset : bankFile.presets())
{
existingNames.insert(preset->preset().name());
}
for (auto &presetEntry: this->currentBank.presets()) {
if (presetsSet.contains(presetEntry->instanceId())) {
std::string uniqueName = makeUniqueName(presetEntry->preset().name(),existingNames);
for (auto &presetEntry : this->currentBank.presets())
{
if (presetsSet.contains(presetEntry->instanceId()))
{
std::string uniqueName = makeUniqueName(presetEntry->preset().name(), existingNames);
existingNames.insert(uniqueName);
Pedalboard t = presetEntry->preset();
t.name(uniqueName);
bankFile.addPreset(t);
}
}
SaveBankFile(indexEntry.name(),bankFile);
SaveBankFile(indexEntry.name(), bankFile);
return -1;
}
@@ -797,17 +814,15 @@ std::vector<PresetIndexEntry> Storage::RequestBankPresets(int64_t bankInstanceId
std::vector<PresetIndexEntry> result;
BankFile bankFile;
LoadBankFile(indexEntry.name(),&bankFile);
for (auto &preset: bankFile.presets()) {
LoadBankFile(indexEntry.name(), &bankFile);
for (auto &preset : bankFile.presets())
{
result.push_back(
PresetIndexEntry(preset->instanceId(),preset->preset().name())
);
PresetIndexEntry(preset->instanceId(), preset->preset().name()));
}
return result;
}
void Storage::SetPresetIndex(const PresetIndex &presets)
{
// painful because we must move unique_ptrs.
@@ -881,7 +896,8 @@ Pedalboard Storage::GetPreset(int64_t instanceId) const
int64_t Storage::DeletePresets(const std::vector<int64_t> &presetInstanceIds)
{
int64_t newSelection = currentBank.selectedPreset();
for (auto presetId: presetInstanceIds) {
for (auto presetId : presetInstanceIds)
{
newSelection = currentBank.deletePreset(presetId);
}
SaveCurrentBank();
@@ -973,7 +989,7 @@ int64_t Storage::CreateNewPreset()
}
}
newPedalboard.name(name);
auto t = this->currentBank.addPreset(newPedalboard, -1);
auto t = this->currentBank.addPreset(newPedalboard, -1);
SaveCurrentBank();
return t;
}
@@ -993,7 +1009,7 @@ int64_t Storage::CopyPreset(int64_t fromId, int64_t toId)
{
auto &toItem = this->currentBank.getItem(toId);
toItem.preset(fromItem.preset());
result = toId;
result = toId;
}
SaveCurrentBank();
return result;
@@ -1115,7 +1131,7 @@ AlsaSequencerConfiguration Storage::GetAlsaSequencerConfiguration() const
return this->alsaSequencerConfiguration;
}
void Storage::LoadChannelSelection()
void Storage::LoadJackChannelSelection()
{
auto fileName = this->GetChannelSelectionFileName();
if (std::filesystem::exists(fileName))
@@ -2071,21 +2087,21 @@ static bool ensureNoDotDot(const std::filesystem::path &path)
return true;
}
static bool isInfoFile(const std::string&fileName)
static bool isInfoFile(const std::string &fileName)
{
if (strcasecmp(fileName.c_str(),"license.txt") == 0)
if (strcasecmp(fileName.c_str(), "license.txt") == 0)
{
return true;
}
if (strcasecmp(fileName.c_str(),"license.md") == 0)
if (strcasecmp(fileName.c_str(), "license.md") == 0)
{
return true;
}
if (strcasecmp(fileName.c_str(),"readme.txt") == 0)
if (strcasecmp(fileName.c_str(), "readme.txt") == 0)
{
return true;
}
if (strcasecmp(fileName.c_str(),"readme.md") == 0)
if (strcasecmp(fileName.c_str(), "readme.md") == 0)
{
return true;
}
@@ -2983,11 +2999,13 @@ const PluginPresetIndex &Storage::GetPluginPresetIndex()
std::filesystem::path Storage::FromAbstractPathString(const std::string &stringPath)
{
if (stringPath.empty()) {
if (stringPath.empty())
{
return "";
}
fs::path path { stringPath};
if (path.is_absolute()) {
fs::path path{stringPath};
if (path.is_absolute())
{
return path;
}
return GetPluginUploadDirectory() / path;
@@ -3010,6 +3028,126 @@ std::string Storage::FromAbstractPathJson(const std::string &pathJson)
return v.to_string();
}
void Storage::SetChannelRouterSettings(ChannelRouterSettings::ptr settings)
{
this->channelRouterSettings = settings;
this->channelSelection = ChannelSelection(*settings);
SaveChannelRouterSettings(settings);
}
ChannelRouterSettings::ptr Storage::GetChannelRouterSettings()
{
return channelRouterSettings;
}
std::filesystem::path Storage::GetChannelRouterSettingsPath() const
{
return GetDataRoot() / "ChannelRouterSettings.json";
}
void Storage::SaveChannelRouterSettings(ChannelRouterSettings::ptr settings)
{
std::ofstream os(GetChannelRouterSettingsPath());
json_writer writer(os);
writer.write(settings);
}
ChannelRouterSettings::ptr Storage::LoadChannelRouterSettings()
{
auto path = GetChannelRouterSettingsPath();
if (!fs::exists(path))
{
// See UpgradeChannelRouterSettings(), which will upgrade from old settings
// or create a default instance.
return nullptr; // will be upgraded later.
}
try {
std::ifstream is(path);
json_reader reader(is);
ChannelRouterSettings::ptr result;
reader.read(&result);
this->channelSelection = ChannelSelection(*result);
return result;
} catch (const std::exception &e) {
Lv2Log::error("Failed to load Channel Router settings: %s", e.what());
return std::make_shared<ChannelRouterSettings>();
}
}
static int64_t GetUpgradedPortIndex(const std::string &portName)
{
auto nPos = portName.find_last_of('_');
if (nPos != std::string::npos)
{
std::string channelStr = portName.substr(nPos + 1);
try
{
int64_t channelIndex = std::stoll(channelStr);
return channelIndex;
} catch (const std::exception &) {
return -1;
}
}
return -1;
}
void Storage::UpgradeChannelRouterSettings()
{
if (channelRouterSettings == nullptr)
{
channelRouterSettings = std::make_shared<ChannelRouterSettings>();
if (jackChannelSelection.isValid())
{
channelRouterSettings->configured(true);
channelRouterSettings->mainInputChannels().resize(2);
const std::vector<std::string>& oldInputs = jackChannelSelection.GetInputAudioPorts();
std::vector<int64_t>& newInputs = channelRouterSettings->mainInputChannels();
if (oldInputs.size() ==1)
{
int64_t leftIndex = GetUpgradedPortIndex(oldInputs[0]);
newInputs.resize(2);
newInputs[0] = leftIndex;
newInputs[1] = leftIndex;
} else if (oldInputs.size() == 2) {
newInputs.resize(2);
for (size_t i = 0; i < std::min(oldInputs.size(), newInputs.size()); ++i)
{
int64_t portIndex = GetUpgradedPortIndex(oldInputs[i]);
newInputs[i] = portIndex;
}
}
const std::vector<std::string>& oldOutputs = jackChannelSelection.GetOutputAudioPorts();
auto &newMainOutputs = channelRouterSettings->mainOutputChannels();
if (oldOutputs.size() == 1) {
int64_t leftIndex = GetUpgradedPortIndex(oldOutputs[0]);
newMainOutputs.resize(2);
newMainOutputs[0] = leftIndex;
newMainOutputs[1] = leftIndex;
} else if (oldOutputs.size() == 2) {
newMainOutputs.resize(2);
for (size_t i = 0; i < std::min(oldOutputs.size(), newMainOutputs.size()); ++i)
{
int64_t portIndex = GetUpgradedPortIndex(oldOutputs[i]);
newMainOutputs[i] = portIndex;
}
}
auto &newAuxInputs = channelRouterSettings->auxInputChannels();
newAuxInputs.resize(2);
newAuxInputs[0] = -1;
newAuxInputs[1] = -1;
auto &newAuxOutputs = channelRouterSettings->auxOutputChannels();
newAuxOutputs.resize(2);
newAuxOutputs[0] = -1;
newAuxOutputs[1] = -1;
SaveChannelRouterSettings(channelRouterSettings);
}
channelSelection = ChannelSelection(*channelRouterSettings);
}
}
const ChannelSelection& Storage::GetChannelSelection() const {
return channelSelection;
}
JSON_MAP_BEGIN(UserSettings)
JSON_MAP_REFERENCE(UserSettings, governor)