2026-08-15 15:36:28 +02:00
|
|
|
#include "PresetManager.h"
|
|
|
|
|
#include "PluginProcessor.h"
|
2026-08-15 18:31:51 +02:00
|
|
|
#include "FactoryPresets.h"
|
2026-08-15 15:36:28 +02:00
|
|
|
|
|
|
|
|
PresetManager::PresetManager(FDNReverbAudioProcessor& p)
|
|
|
|
|
: processor(p)
|
|
|
|
|
{
|
2026-08-15 18:31:51 +02:00
|
|
|
seedFactoryPresets();
|
2026-08-15 15:36:28 +02:00
|
|
|
refreshPresetList();
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-15 18:31:51 +02:00
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
// 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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-15 15:36:28 +02:00
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
// 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<int>(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]);
|
|
|
|
|
}
|