diff --git a/.vscode/settings.json b/.vscode/settings.json index af215ac..e6e4f3a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -170,7 +170,7 @@ "cSpell.ignoreWords": [ "nammodel" ], - "cSpell.enabled": true, + "cSpell.enabled": false, // Disable all automatic completion suggestions - only show when Ctrl+Space is pressed "editor.quickSuggestions": { diff --git a/src/FileBrowserFilesFeature.cpp b/src/FileBrowserFilesFeature.cpp index 92d8709..d3a5cc5 100644 --- a/src/FileBrowserFilesFeature.cpp +++ b/src/FileBrowserFilesFeature.cpp @@ -37,24 +37,6 @@ using namespace pipedal::implementation; namespace fs = std::filesystem; -namespace pipedal::implementation { - class BrowserFilesVersionInfo - { - public: - bool Load(std::filesystem::path &path); - void Save(std::filesystem::path &path); - const std::vector &InstalledFiles() const; - bool IsInstalled(const std::string &file) const; - void AddFile(const std::string &file); - uint32_t Version() const; - void Version(uint32_t value); - - private: - uint32_t version = 0; - std::vector installedFiles; - std::unordered_set installedFileMap; - }; -}; inline uint32_t BrowserFilesVersionInfo::Version() const { return version; } inline void BrowserFilesVersionInfo::Version(uint32_t value) { version = value; } @@ -75,7 +57,7 @@ void BrowserFilesVersionInfo::AddFile(const std::string &file) } } -bool BrowserFilesVersionInfo::Load(std::filesystem::path &path) +bool BrowserFilesVersionInfo::Load(const std::filesystem::path &path) { std::ifstream f{path}; if (!f.is_open()) @@ -102,7 +84,7 @@ FileBrowserFilesFeature::FileBrowserFilesFeature() feature.URI = LV2_FILEBROWSER__files; feature.data = &(this->featureData); } -void BrowserFilesVersionInfo::Save(std::filesystem::path &path) +void BrowserFilesVersionInfo::Save(const std::filesystem::path &path) { pipedal::ofstream_synced f{path}; if (!f.is_open()) diff --git a/src/FileBrowserFilesFeature.hpp b/src/FileBrowserFilesFeature.hpp index 6d9cb05..9efcdbd 100644 --- a/src/FileBrowserFilesFeature.hpp +++ b/src/FileBrowserFilesFeature.hpp @@ -1,18 +1,18 @@ /* * MIT License - * + * * Copyright (c) 2023 Robin E. R. Davies - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is furnished to do * so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -30,62 +30,79 @@ #include #include #include +#include +#include +#include - - -namespace pipedal { +namespace pipedal +{ // Private forward declaration - namespace implementation { - class BrowserFilesVersionInfo; + namespace implementation + { + class BrowserFilesVersionInfo + { + public: + bool Load(const std::filesystem::path &path); + void Save(const std::filesystem::path &path); + const std::vector &InstalledFiles() const; + bool IsInstalled(const std::string &file) const; + void AddFile(const std::string &file); + uint32_t Version() const; + void Version(uint32_t value); + + private: + uint32_t version = 0; + std::vector installedFiles; + std::unordered_set installedFileMap; + }; }; - class FileBrowserFilesFeature { + class FileBrowserFilesFeature + { public: FileBrowserFilesFeature(); void Initialize( const LV2_URID_Map *lv2Map, const LV2_Log_Log *lv2Log, - const std::string&bundleDirectory, - const std::string&browserDirectory); - const LV2_Feature*GetFeature() { return &feature; } - private: - static void MakeDirectoryMap(const std::filesystem::path&rootBrowserDirectory); + const std::string &bundleDirectory, + const std::string &browserDirectory); + const LV2_Feature *GetFeature() { return &feature; } - using WellKnownDirectoryMap = std::map; + private: + static void MakeDirectoryMap(const std::filesystem::path &rootBrowserDirectory); + + using WellKnownDirectoryMap = std::map; static std::mutex g_DirectoryMap_mutex; static std::unique_ptr g_wellKnownDirectoryMap; - LV2_Feature feature; const LV2_URID_Map *lv2Map = nullptr; - LV2_Log_Logger lv2Logger = {nullptr,0,0,0,0}; + LV2_Log_Logger lv2Logger = {nullptr, 0, 0, 0, 0}; std::filesystem::path bundleDirectory; std::filesystem::path browserRootDirectory; std::filesystem::path privateDirectory; LV2_FileBrowser_Files featureData; - std::map wellKnownPaths; + std::map wellKnownPaths; + static char *FN_get_upload_path(LV2_FileBrowser_Files_Handle handle, const char *fileBrowserDirectory); + static char *FN_map_path(LV2_FileBrowser_Files_Handle handle, const char *path, const char *resourcePathBase, const char *fileBrowserDirectory); + static void FN_free_path(LV2_FileBrowser_Files_Handle handle, char *path); + static LV2_FileBrowser_Status FN_publish_resource_files(LV2_FileBrowser_Files_Handle handle, uint32_t version, const char *resourcePath, const char *uploadDirectory); - static char* FN_get_upload_path(LV2_FileBrowser_Files_Handle handle, const char* fileBrowserDirectory); - static char* FN_map_path(LV2_FileBrowser_Files_Handle handle, const char* path, const char *resourcePathBase,const char*fileBrowserDirectory); - static void FN_free_path(LV2_FileBrowser_Files_Handle handle, char* path); - static LV2_FileBrowser_Status FN_publish_resource_files(LV2_FileBrowser_Files_Handle handle,uint32_t version,const char*resourcePath, const char*uploadDirectory); + const char *GetWellKnownDirectory(const std::string &directory); - const char*GetWellKnownDirectory(const std::string&directory); - - void LogError(const char*message); - char* GetUploadPath(const char* fileBrowserDirectory); - char* MapPath(const char* path,const char*resourcePathBase,const char* fileBrowserDirectory); - void FreePath(char* path); - LV2_FileBrowser_Status PublishResourceFiles(uint32_t version,const char*resourcePath, const char*uploadDirectory); + void LogError(const char *message); + char *GetUploadPath(const char *fileBrowserDirectory); + char *MapPath(const char *path, const char *resourcePathBase, const char *fileBrowserDirectory); + void FreePath(char *path); + LV2_FileBrowser_Status PublishResourceFiles(uint32_t version, const char *resourcePath, const char *uploadDirectory); void PublishRecursive( - implementation::BrowserFilesVersionInfo& versionInfo, - const std::filesystem::path& rootResourcePath, - const std::filesystem::path& resourcePath, - const std::filesystem::path& browserPath - ); + implementation::BrowserFilesVersionInfo &versionInfo, + const std::filesystem::path &rootResourcePath, + const std::filesystem::path &resourcePath, + const std::filesystem::path &browserPath); }; } \ No newline at end of file diff --git a/src/Storage.cpp b/src/Storage.cpp index 8e81a04..a55c985 100644 --- a/src/Storage.cpp +++ b/src/Storage.cpp @@ -41,6 +41,7 @@ #include "AudioFiles.hpp" #include "Utf8Utils.hpp" #include "AtomConverter.hpp" +#include "FileBrowserFilesFeature.hpp" using namespace pipedal; namespace fs = std::filesystem; @@ -222,23 +223,122 @@ static void CopyDirectory(const std::filesystem::path &source, const std::filesy } } } + + void Storage::MaybeCopyDefaultPresets() { auto presetsDirectory = this->GetPresetsDirectory(); + auto presetsDirectory = this->GetPresetsDirectory(); + auto presetsConfigDirectory = this->configRoot / "default_presets" / "presets"; if (!std::filesystem::exists(presetsDirectory / "index.banks")) { - CopyDirectory(this->configRoot / "default_presets" / "presets", - presetsDirectory); + fs::copy(presetsConfigDirectory / "index.banks", presetsDirectory / "index.banks"); + fs::copy(presetsConfigDirectory / "Default+Bank.bank", presetsDirectory / "Default+Bank.bank"); } +} +void Storage::UpgradeFactoryPresets() +{ + auto presetsDirectory = this->GetPresetsDirectory(); + auto presetsConfigDirectory = this->configRoot / "default_presets" / "presets"; - // Obsolete: TooB effects now have correct preset declarations. - // auto pluginDirectory = this->GetPluginPresetsDirectory(); - // if (!std::filesystem::exists(pluginDirectory / "index.json")) - // { - // CopyDirectory(this->configRoot / "default_presets" / "plugin_presets", - // pluginDirectory); - // } + using namespace ::pipedal::implementation; + + BrowserFilesVersionInfo defaultConfigPresetsVersion; + fs::path defaultConfigPresetsVersionFile = presetsConfigDirectory / "banks.versionInfo"; + defaultConfigPresetsVersion.Load(defaultConfigPresetsVersionFile); + + BrowserFilesVersionInfo presetsVersion; + fs::path defaultPresetsVersionFile = presetsDirectory / "banks.versionInfo"; + presetsVersion.Load(defaultPresetsVersionFile); + + // Maybe install or upgrade factory presets. + if (defaultConfigPresetsVersion.Version() > presetsVersion.Version() || defaultConfigPresetsVersion.Version() == 0) + { + + std::string name = "Factory Presets"; + BankFile newFactoryPresets; + { + fs::path defaultBankPath = presetsConfigDirectory / "Default+Bank.bank"; + try + { + std::ifstream is(defaultBankPath); + json_reader reader(is); + reader.read(&newFactoryPresets); + } + catch (const std::exception &e) + { + Lv2Log::error(SS("Failed to isntall factory presets. Can't read " << defaultBankPath << ".")); + } + } + newFactoryPresets.name("Factory Presets"); + + BankIndexEntry *existingEntry = bankIndex.getEntryByName(name); + if (existingEntry == nullptr) + { + BankFile bankFile; + bankFile.name(name); + + for (auto &presetEntry : newFactoryPresets.presets()) + { + bankFile.addPreset(presetEntry->preset(), -1); + } + + int64_t instanceId = bankFile.presets()[0]->instanceId(); + bankFile.selectedPreset(instanceId); + SaveBankFile(name, bankFile); + this->bankIndex.addBank(-1, name); + this->SaveBankIndex(); + } + else + { + + // either use the current bank (if the factory bank is selected), or create a new one. + BankFile bankFile; + bankFile.name(name); + BankFile *pFactoryPresetsBank = nullptr; + bool usingCurrentBank = false; + if (bankIndex.selectedBank() == existingEntry->instanceId()) + { + usingCurrentBank = true; + pFactoryPresetsBank = &(this->currentBank); + } + else + { + LoadBankFile(name, &bankFile); + pFactoryPresetsBank = &bankFile; + } + // index existing presets. + std::unordered_map nameToPositionIndex; + for (size_t i = 0; i < pFactoryPresetsBank->presets().size(); ++i) + { + auto &preset = pFactoryPresetsBank->presets()[i]; + nameToPositionIndex[preset->preset().name()] = i; + } + + // merge new presets into the existing ones (overwriting as neccessary) + for (auto &newPresetEntry : newFactoryPresets.presets()) + { + const std::string name = newPresetEntry->preset().name(); + + auto f = nameToPositionIndex.find(name); + if (f != nameToPositionIndex.end()) + { + size_t postition = f->second; + // overwrite the existing entry. + pFactoryPresetsBank->presets()[postition]->preset(newPresetEntry->preset()); + } + else + { + pFactoryPresetsBank->addPreset(newPresetEntry->preset()); + } + } + SaveBankFile(name, *pFactoryPresetsBank); + + presetsVersion.Version(defaultConfigPresetsVersion.Version()); + presetsVersion.Save(defaultPresetsVersionFile); + } + } } void Storage::Initialize() { @@ -269,6 +369,7 @@ void Storage::Initialize() LoadWifiConfigSettings(); LoadWifiDirectConfigSettings(); LoadUserSettings(); + UpgradeFactoryPresets(); } void Storage::LoadBank(int64_t instanceId) @@ -1248,7 +1349,6 @@ void Storage::SetPluginPresetIndexVersion(uint64_t version) this->pluginPresetIndex.version_ = version; SavePluginPresetIndex(); } - } bool Storage::HasPluginPresets(const std::string &pluginUri) const @@ -1428,7 +1528,7 @@ PluginPresetValues Storage::GetPluginPresetValues(const std::string &pluginUri, { result.controls.push_back(ControlValue(valuePair.first.c_str(), valuePair.second)); } - for (const auto&pair: preset.pathProperties_) + for (const auto &pair : preset.pathProperties_) { result.pathProperties[pair.first] = pair.second; } @@ -1503,8 +1603,7 @@ uint64_t Storage::SavePluginPreset( uint64_t Storage::SavePluginPreset( const std::string &pluginUri, - PluginPreset &pluginPreset -) + PluginPreset &pluginPreset) { auto presets = GetPluginPresets(pluginUri); uint64_t result = -1; @@ -1797,6 +1896,17 @@ static bool ensureNoDotDot(const std::filesystem::path &path) return true; } +static bool isInfoFile(const FileEntry &l) +{ + if (l.displayName_.starts_with("LICENSE")) + return true; + if (l.displayName_.starts_with("README")) + return true; + if (l.displayName_.find(".md") == l.displayName_.length() - 3) + return true; + return false; +} + static void AddFilesToResult( FileRequestResult &result, const ModFileTypes::ModDirectory *modDirectoryInfo, // yyx @@ -1862,6 +1972,12 @@ static void AddFilesToResult( { return l.isDirectory_ > r.isDirectory_; } + bool lIsInfoFile = isInfoFile(l); + bool rIsInfoFile = isInfoFile(r); + if (lIsInfoFile != rIsInfoFile) + { + return lIsInfoFile > rIsInfoFile; + } return collator->Compare(l.displayName_,r.displayName_) < 0; }); } @@ -1931,6 +2047,13 @@ static void AddTracksToResult( { return l.isDirectory_ > r.isDirectory_; } + bool lIsInfoFile = isInfoFile(l); + bool rIsInfoFile = isInfoFile(r); + if (lIsInfoFile != rIsInfoFile) + { + return lIsInfoFile < rIsInfoFile; + } + return collator->Compare(l.displayName_, r.displayName_) < 0; }); // Add audio files. @@ -2702,7 +2825,7 @@ std::string Storage::ToAbstractPathJson(const std::string &pathJson) { json_variant v = json_variant::parse(pathJson); - v = AtomConverter::AbstractPath(v,GetPluginUploadDirectory().string()); + v = AtomConverter::AbstractPath(v, GetPluginUploadDirectory().string()); return v.to_string(); } @@ -2710,7 +2833,7 @@ std::string Storage::FromAbstractPathJson(const std::string &pathJson) { json_variant v = json_variant::parse(pathJson); - v = AtomConverter::MapPath(v,GetPluginUploadDirectory().string()); + v = AtomConverter::MapPath(v, GetPluginUploadDirectory().string()); return v.to_string(); } diff --git a/src/Storage.hpp b/src/Storage.hpp index 796a23a..e31212c 100644 --- a/src/Storage.hpp +++ b/src/Storage.hpp @@ -66,8 +66,6 @@ struct PluginPresetValues { }; -// controls user-defined storage. Implmentation hidden to allow to later migration to a database (perhaps) - class Storage { private: std::filesystem::path dataRoot; @@ -81,7 +79,7 @@ private: private: void FillSampleDirectoryTree(FilePropertyDirectoryTree*node, const std::filesystem::path&directory) const; - + void UpgradeFactoryPresets(); void MaybeCopyDefaultPresets(); static std::string SafeEncodeName(const std::string& name); static std::string SafeDecodeName(const std::string& name);