diff --git a/CMakeLists.txt b/CMakeLists.txt index 89d7503..4f01d76 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,10 @@ cmake_minimum_required(VERSION 3.16.0) project(pipedal - VERSION 1.3.59 + VERSION 1.3.60 DESCRIPTION "PiPedal Guitar Effect Pedal For Raspberry Pi" HOMEPAGE_URL "https://rerdavies.github.io/pipedal" ) -set (DISPLAY_VERSION "PiPedal v1.3.59-Release") +set (DISPLAY_VERSION "PiPedal v1.3.60-Release") set (PACKAGE_ARCHITECTURE "arm64") set (CMAKE_INSTALL_PREFIX "/usr/") diff --git a/README.md b/README.md index 16fe6df..a3fc0f5 100644 --- a/README.md +++ b/README.md @@ -6,13 +6,13 @@ -Download: v1.3.59 +Download: v1.3.60 Website: [https://rerdavies.github.io/pipedal](https://rerdavies.github.io/pipedal). Documentation: [https://rerdavies.github.io/pipedal/Documentation.html](https://rerdavies.github.io/pipedal/Documentation.html).   -#### NEW version 1.3.59 Release, providing [snapshots](https://rerdavies.github.io/pipedal/Snaphots.html), and a new Performance View. See the [release notes](https://rerdavies.github.io/pipedal/ReleaseNotes) for details. +#### NEW version 1.3.60 Release, providing [snapshots](https://rerdavies.github.io/pipedal/Snaphots.html), and a new Performance View. See the [release notes](https://rerdavies.github.io/pipedal/ReleaseNotes) for details.   diff --git a/docs/Installing.md b/docs/Installing.md index 4855311..4af51c5 100644 --- a/docs/Installing.md +++ b/docs/Installing.md @@ -13,17 +13,17 @@ page_icon: img/Install4.jpg Download the most recent Debian (.deb) package for your platform: -- [Raspberry Pi OS bookworm (64-bit) v1.3.59](https://github.com/rerdavies/pipedal/releases/download/) +- [Raspberry Pi OS bookworm (64-bit) v1.3.60](https://github.com/rerdavies/pipedal/releases/download/) - [Ubuntu/Raspberry Pi OS bullseyeye (64-bit) v1.2.31](https://github.com/rerdavies/pipedal/releases/download/v1.1.31/pipedal_1.1.31_arm64.deb) -Version 1.3.59 has not yet been tested on Ubuntu or Raspberry Pi OS bullseye. On these platforms, we recommend that you use version 1.1.31. +Version 1.3.60 has not yet been tested on Ubuntu or Raspberry Pi OS bullseye. On these platforms, we recommend that you use version 1.1.31. Install the package by running ``` sudo apt update cd ~/Downloads - sudo apt-get install pipedal_1.3.59_arm64.deb + sudo apt-get install pipedal_1.3.60_arm64.deb ``` Adjust accordingly if you have downloaded v1.1.31. diff --git a/docs/ReleaseNotes.md b/docs/ReleaseNotes.md index 8ab10d2..0d7e5be 100644 --- a/docs/ReleaseNotes.md +++ b/docs/ReleaseNotes.md @@ -1,5 +1,11 @@ # Release Notes +## PiPedal 1.3.60 Release + +Bug fixes: +- Uploading of preset and bank files now work properly. +- Uploaded plugin presets are merged with existing presets, instead of overwriting existing presets. + ## PiPedal 1.3.59 Release 20% performance improvement when using Toob Neural Amp Modeller with large Wavenet models. diff --git a/docs/download.md b/docs/download.md index f858180..ab98513 100644 --- a/docs/download.md +++ b/docs/download.md @@ -4,7 +4,7 @@ Download the most recent Debian (.deb) package for your platform: -- Raspberry Pi OS Bookworm (64-bit) v1.3.59 +- Raspberry Pi OS Bookworm (64-bit) v1.3.60 Install the package by running @@ -12,7 +12,7 @@ Install the package by running ``` sudo apt update cd ~/Downloads - sudo apt-get install ./pipedal_1.3.59_arm64.deb + sudo apt-get install ./pipedal_1.3.60_arm64.deb ``` Follow the instructions in [_Configuring PiPedal After Installation_](https://rerdavies.github.io/pipedal/Configuring.html) to complete the installation. diff --git a/docs/index.md b/docs/index.md index dcb02f7..76bb850 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,7 +1,7 @@ -v1.3.59 +v1.3.60   @@ -9,7 +9,7 @@ To download PiPedal, click [here](download.md). To view PiPedal documentation, click [here](Documentation.md). -#### NEW version 1.3.59 Release. See the [release notes](https://rerdavies.github.io/pipedal/ReleaseNotes) for details. +#### NEW version 1.3.60 Release. See the [release notes](https://rerdavies.github.io/pipedal/ReleaseNotes) for details.   diff --git a/react/src/PluginPresetsDialog.tsx b/react/src/PluginPresetsDialog.tsx index 9e012c9..0ab5dac 100644 --- a/react/src/PluginPresetsDialog.tsx +++ b/react/src/PluginPresetsDialog.tsx @@ -354,7 +354,7 @@ const PluginPresetsDialog = withStyles(styles, { withTheme: true })( let pluginUri = this.getPluginUri(); let plugin = this.model.getUiPlugin(pluginUri); if (plugin) { - title = "Presets - " + plugin.name; + title = "Plugin Presets - " + plugin.name; } @@ -440,7 +440,7 @@ const PluginPresetsDialog = withStyles(styles, { withTheme: true })( - Download presets + Download plugin presets @@ -449,7 +449,7 @@ const PluginPresetsDialog = withStyles(styles, { withTheme: true })( - Upload presets + Upload plugin presets diff --git a/react/src/SnapshotDialog.tsx b/react/src/SnapshotDialog.tsx index 8c1b973..9207334 100644 --- a/react/src/SnapshotDialog.tsx +++ b/react/src/SnapshotDialog.tsx @@ -35,6 +35,7 @@ import ResizeResponsiveComponent from './ResizeResponsiveComponent'; import { TransitionProps } from '@mui/material/transitions'; import Fade from '@mui/material/Fade'; +import Slide from '@mui/material/Slide'; import SnapshotPanel from './SnapshotPanel'; const styles = { @@ -45,7 +46,7 @@ const styles = { }; -const Transition = React.forwardRef(function Transition( +const FadeTransition = React.forwardRef(function Transition( props: TransitionProps & { children: React.ReactElement; }, @@ -55,6 +56,17 @@ const Transition = React.forwardRef(function Transition( }); +const SlideTransition = React.forwardRef(function Transition( + props: TransitionProps & { + children: React.ReactElement; + }, + ref: React.Ref, + ) { + return ; + }); + + + export interface SnapshotDialogProps { open: boolean, @@ -100,11 +112,10 @@ export default class SnapshotDialog extends ResizeResponsiveComponent this.props.onOk()} fullScreen={this.state.fullScreen} - TransitionComponent={Transition} keepMounted + TransitionComponent={this.state.fullScreen? SlideTransition: FadeTransition} keepMounted style={{ userSelect: "none", }} PaperProps={{ style: { - maxWidth: '1000px' }, }} diff --git a/src/PiPedalModel.cpp b/src/PiPedalModel.cpp index 8f7f1a3..6cbe83f 100644 --- a/src/PiPedalModel.cpp +++ b/src/PiPedalModel.cpp @@ -844,7 +844,7 @@ void PiPedalModel::UploadPluginPresets(const PluginPresets &pluginPresets) throw PiPedalException("Invalid plugin presets."); } std::lock_guard guard{mutex}; - storage.SavePluginPresets(pluginPresets.pluginUri_, pluginPresets); + storage.MergePluginPresets(pluginPresets.pluginUri_, pluginPresets); FirePluginPresetsChanged(pluginPresets.pluginUri_); } int64_t PiPedalModel::UploadPreset(const BankFile &bankFile, int64_t uploadAfter) diff --git a/src/PluginPreset.cpp b/src/PluginPreset.cpp index e41166b..2d34e47 100644 --- a/src/PluginPreset.cpp +++ b/src/PluginPreset.cpp @@ -2,6 +2,77 @@ using namespace pipedal; + +static std::string GetUnversionedLabel(const std::string label) +{ + size_t pos = label.length(); + if (pos != 0 && label.at(pos-1) == ')') + { + --pos; + while (true) + { + if (pos == 0) + { + return label; // not versioned. return the original. + } + --pos; + char c = label[pos]; + if (c >= '0' && c <= '9') + { + continue; // eat the number. + } + else if (c == '(') + { + return label.substr(0,pos); + + } else { + return label; // failure. return the unmodified original + } + } + } + return label; +} + +bool PluginPreset::equals(const PluginPreset&other) const +{ + // everything EXCEPT instanceId (since preset may be from another PluginPresets collection) + return label_ == other.label_ && + lilvPresetUri_ == other.lilvPresetUri_ && + controlValues_ == other.controlValues_ && + state_ == other.state_; +} + +void PluginPresets::MergePreset(const PluginPreset&preset) +{ + int existingPresetIndex = Find(preset.label_); + if (existingPresetIndex != -1) + { + if (this->presets_[existingPresetIndex].equals(preset)) + { + // an exact duplicate. discard the new preset. + return; + } + std::string baseLabel = GetUnversionedLabel(preset.label_); + + for (int i = 1; i < 1000; ++i) + { + std::string newLabel = SS(baseLabel << "(" << i << ")"); + if (Find(newLabel) == -1) + { + PluginPreset versionedPreset = preset; + versionedPreset.label_ = newLabel; + MergePreset(versionedPreset); + return; + } + } + // A thousand duplicates?! Heck. just add a duplicate label. :-/ + } + this->presets_.push_back(preset); + this->presets_.back().instanceId_ = this->nextInstanceId_++; + +} + + JSON_MAP_BEGIN(PluginUiPreset) JSON_MAP_REFERENCE(PluginUiPreset,label) JSON_MAP_REFERENCE(PluginUiPreset,instanceId) diff --git a/src/PluginPreset.hpp b/src/PluginPreset.hpp index e27dec1..d53906e 100644 --- a/src/PluginPreset.hpp +++ b/src/PluginPreset.hpp @@ -111,6 +111,8 @@ public: return preset; } + bool equals(const PluginPreset&other) const; + uint64_t instanceId_; std::string label_; std::string lilvPresetUri_; @@ -158,6 +160,9 @@ public: return -1; } + void MergePreset(const PluginPreset&preset); + + DECLARE_JSON_MAP(PluginPresets); }; diff --git a/src/PresetBundle.cpp b/src/PresetBundle.cpp index f7e6904..27ae4da 100644 --- a/src/PresetBundle.cpp +++ b/src/PresetBundle.cpp @@ -214,17 +214,17 @@ public: { this->pluginUploadDirectory = model.GetPluginUploadDirectory(); zipFile = ZipFileReader::Create(path); - auto s = zipFile->GetFileInputStream("pluginPresets.json"); + auto s = zipFile->GetFileInputStream("bankFile.json"); json_reader reader(s); - reader.read(&pluginPresets); + reader.read(&bankFile); } void LoadPluginPresetFile(PiPedalModel &model, const std::filesystem::path &path) { this->pluginUploadDirectory = model.GetPluginUploadDirectory(); zipFile = ZipFileReader::Create(path); - auto s = zipFile->GetFileInputStream("bankFile.json"); + auto s = zipFile->GetFileInputStream("pluginPresets.json"); json_reader reader(s); - reader.read(&bankFile); + reader.read(&pluginPresets); } virtual ~PresetBundleReaderImpl() noexcept; @@ -296,7 +296,7 @@ PresetBundleReader::ptr PresetBundleReader::LoadPresetsFile(PiPedalModel &model, PresetBundleReader::ptr PresetBundleReader::LoadPluginPresetsFile(PiPedalModel &model, const std::filesystem::path &filePath) { std::unique_ptr result = std::make_unique(); - result->LoadPluginPresetsFile(model, filePath); + result->LoadPluginPresetFile(model, filePath); return result; } diff --git a/src/Storage.cpp b/src/Storage.cpp index 92f49cc..fbea14f 100644 --- a/src/Storage.cpp +++ b/src/Storage.cpp @@ -1107,6 +1107,67 @@ std::filesystem::path Storage::GetPluginPresetPath(const std::string &pluginUri) } throw PiPedalArgumentException("Plugin preset file not found."); } + +void Storage::MergePluginPresets(const std::string &pluginUri, const PluginPresets &presets) +{ + std::string name; + std::filesystem::path path; + bool presetAdded = false; + PluginPresets existingPresets; + if (!HasPluginPresets(pluginUri)) + { + name = SS(pluginPresetIndex.nextInstanceId_ << ".json"); + path = GetPluginPresetsDirectory() / name; + presetAdded = true; + } + else + { + path = GetPluginPresetPath(pluginUri); + try { + std::ifstream f(path); + if (f.is_open()) + { + json_reader reader(f); + reader.read(&existingPresets); + } + } catch (const std::exception &e) + { + Lv2Log::error(SS("Storage::MergePluginPresets: Can't reading existing plugin presets." << e.what())); + } + } + for (const PluginPreset &preset: presets.presets_) + { + + existingPresets.MergePreset(preset); + } + auto tempPath = path.string() + ".$$$"; + { + pipedal::ofstream_synced os; + os.open(tempPath, std::ios_base::trunc); + if (os.fail()) + { + throw PiPedalException(SS("Can't write to " << path)); + } + json_writer writer(os, true); + writer.write(existingPresets); + } + if (std::filesystem::exists(path)) + { + std::filesystem::remove(path); + } + std::filesystem::rename(tempPath, path); + + if (presetAdded) + { + pluginPresetIndex.entries_.push_back( + PluginPresetIndexEntry( + pluginUri, name)); + pluginPresetIndex.nextInstanceId_++; + this->pluginPresetIndexChanged = true; + SavePluginPresetIndex(); + } +} + void Storage::SavePluginPresets(const std::string &pluginUri, const PluginPresets &presets) { std::string name; diff --git a/src/Storage.hpp b/src/Storage.hpp index b129852..e00da98 100644 --- a/src/Storage.hpp +++ b/src/Storage.hpp @@ -187,6 +187,7 @@ private: public: bool HasPluginPresets(const std::string&pluginUri) const; void SavePluginPresets(const std::string&pluginUri, const PluginPresets&presets); + void MergePluginPresets(const std::string&pluginUri, const PluginPresets&presets); PluginPresets GetPluginPresets(const std::string&pluginUri) const; const PluginPresetIndex& GetPluginPresetIndex(); diff --git a/src/WebServerConfig.cpp b/src/WebServerConfig.cpp index e453a5e..e516139 100644 --- a/src/WebServerConfig.cpp +++ b/src/WebServerConfig.cpp @@ -37,7 +37,7 @@ #define OLD_PRESET_EXTENSION ".piPreset" #define PRESET_EXTENSION ".piPreset" #define OLD_BANK_EXTENSION ".piBank" -#define BANK_EXTENSION ".piBankBundle" +#define BANK_EXTENSION ".piBank" #define PLUGIN_PRESETS_EXTENSION ".piPluginPresets" static const std::filesystem::path WEB_TEMP_DIR{"/var/pipedal/web_temp"}; @@ -598,6 +598,7 @@ public: } catch (const std::exception &e) { + Lv2Log::error(SS("Error uploading file: " << e.what()) ); if (strcmp(e.what(), "Not found") == 0) { ec = boost::system::errc::make_error_code(boost::system::errc::no_such_file_or_directory);