#include "PresetManager.h" #include "PluginProcessor.h" #include "FactoryPresets.h" PresetManager::PresetManager(FDNReverbAudioProcessor& p) : processor(p) { seedFactoryPresets(); refreshPresetList(); } // ----------------------------------------------------------------------------- // factory presets // ----------------------------------------------------------------------------- // embeds Presets/*.ambpreset into the binary, then copies any that are // missing into the user folder, so the factory set survives fresh installs. // ----------------------------------------------------------------------------- void PresetManager::seedFactoryPresets() { auto folder = getPresetsFolder(); for (int i = 0; i < FactoryPresets::namedResourceListSize; ++i) { const auto filename = juce::String::fromUTF8(FactoryPresets::originalFilenames[i]); auto dest = folder.getChildFile(filename); if (dest.exists()) continue; int size = 0; if (auto* data = FactoryPresets::getNamedResource(FactoryPresets::namedResourceList[i], size)) dest.replaceWithData(data, size); } } // ----------------------------------------------------------------------------- // filesystem // ----------------------------------------------------------------------------- juce::File PresetManager::getPresetsFolder() const { auto folder = juce::File::getSpecialLocation( juce::File::userDocumentsDirectory) .getChildFile(kSubFolder); if (!folder.exists()) folder.createDirectory(); return folder; } juce::File PresetManager::getPresetFile(const juce::String& name) const { return getPresetsFolder().getChildFile(name + kExtension); } void PresetManager::refreshPresetList() { presetNames.clear(); auto files = getPresetsFolder().findChildFiles( juce::File::findFiles, false, juce::String("*") + kExtension); files.sort(); for (const auto& f : files) presetNames.add(f.getFileNameWithoutExtension()); } // ----------------------------------------------------------------------------- // save // ----------------------------------------------------------------------------- // reuses PluginProcessor::getStateInformation() directly, // so no PluginProcessor changes are needed. // ----------------------------------------------------------------------------- // --- after changes --- bool PresetManager::savePreset(const juce::String& name) { if (name.isEmpty()) return false; // * fix: notify the Processor of the name before getStateInformation() // so getStateInformation() writes the correct name into the ValueTree processor.setLastSavedPresetName(name); juce::MemoryBlock data; processor.getStateInformation(data); auto file = getPresetFile(name); if (!file.replaceWithData(data.getData(), data.getSize())) return false; currentPresetName = name; refreshPresetList(); if (onPresetListChanged) onPresetListChanged(); if (onPresetLoaded) onPresetLoaded(name); return true; } // ----------------------------------------------------------------------------- // load // ----------------------------------------------------------------------------- // reuses PluginProcessor::setStateInformation() directly. // setStateInformation() sets paramsNeedUpdate=true, so // the next processBlock() sends the new parameters to the engine. // ----------------------------------------------------------------------------- bool PresetManager::loadPreset(const juce::String& name) { auto file = getPresetFile(name); if (!file.exists()) return false; juce::MemoryBlock data; if (!file.loadFileAsData(data)) return false; processor.setStateInformation(data.getData(), static_cast(data.getSize())); // * after loading a preset always normal view (Normal Mode) if (auto* param = processor.apvts.getParameter("promode")) param->setValueNotifyingHost(0.0f); currentPresetName = name; if (onPresetLoaded) onPresetLoaded(name); return true; } // ----------------------------------------------------------------------------- // delete // ----------------------------------------------------------------------------- bool PresetManager::deletePreset(const juce::String& name) { auto file = getPresetFile(name); if (!file.exists()) return false; if (!file.deleteFile()) return false; if (currentPresetName == name) currentPresetName.clear(); refreshPresetList(); if (onPresetListChanged) onPresetListChanged(); return true; } // ----------------------------------------------------------------------------- // navigation // ----------------------------------------------------------------------------- int PresetManager::getCurrentPresetIndex() const noexcept { return presetNames.indexOf(currentPresetName); } void PresetManager::loadPrevPreset() { if (presetNames.isEmpty()) return; int idx = getCurrentPresetIndex(); if (idx <= 0) idx = presetNames.size(); loadPreset(presetNames[idx - 1]); } void PresetManager::loadNextPreset() { if (presetNames.isEmpty()) return; int idx = getCurrentPresetIndex(); if (idx < 0 || idx >= presetNames.size() - 1) idx = -1; loadPreset(presetNames[idx + 1]); }