Add ability to save state of project to xml

pull/170/head
James Ball 2023-07-25 12:23:27 +01:00
rodzic e56ec999fe
commit c75a036048
6 zmienionych plików z 79 dodań i 30 usunięć

Wyświetl plik

@ -34,7 +34,7 @@ OscirenderAudioProcessor::OscirenderAudioProcessor()
{ {
producer.startThread(); producer.startThread();
juce::SpinLock::ScopedLockType lock(effectsLock); // locking isn't necessary here because we are in the constructor
toggleableEffects.push_back(std::make_shared<Effect>( toggleableEffects.push_back(std::make_shared<Effect>(
std::make_shared<BitCrushEffect>(), std::make_shared<BitCrushEffect>(),
@ -46,19 +46,19 @@ OscirenderAudioProcessor::OscirenderAudioProcessor()
)); ));
toggleableEffects.push_back(std::make_shared<Effect>( toggleableEffects.push_back(std::make_shared<Effect>(
std::make_shared<RotateEffect>(), std::make_shared<RotateEffect>(),
new EffectParameter("2D Rotate", "rotateSpeed", 0.0, 0.0, 1.0) new EffectParameter("2D Rotate", "2DRotateSpeed", 0.0, 0.0, 1.0)
)); ));
toggleableEffects.push_back(std::make_shared<Effect>( toggleableEffects.push_back(std::make_shared<Effect>(
std::make_shared<VectorCancellingEffect>(), std::make_shared<VectorCancellingEffect>(),
new EffectParameter("Vector Cancel", "vectorCancelling", 0.0, 0.0, 1.0) new EffectParameter("Vector Cancelling", "vectorCancelling", 0.0, 0.0, 1.0)
)); ));
toggleableEffects.push_back(std::make_shared<Effect>( toggleableEffects.push_back(std::make_shared<Effect>(
std::make_shared<DistortEffect>(false), std::make_shared<DistortEffect>(false),
new EffectParameter("X Distort", "horizontalDistort", 0.0, 0.0, 1.0) new EffectParameter("Distort X", "distortX", 0.0, 0.0, 1.0)
)); ));
toggleableEffects.push_back(std::make_shared<Effect>( toggleableEffects.push_back(std::make_shared<Effect>(
std::make_shared<DistortEffect>(true), std::make_shared<DistortEffect>(true),
new EffectParameter("Y Distort", "verticalDistort", 0.0, 0.0, 1.0) new EffectParameter("Distort Y", "distortY", 0.0, 0.0, 1.0)
)); ));
toggleableEffects.push_back(std::make_shared<Effect>( toggleableEffects.push_back(std::make_shared<Effect>(
[this](int index, Vector2 input, const std::vector<double>& values, double sampleRate) { [this](int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
@ -77,17 +77,17 @@ OscirenderAudioProcessor::OscirenderAudioProcessor()
)); ));
toggleableEffects.push_back(std::make_shared<Effect>( toggleableEffects.push_back(std::make_shared<Effect>(
delayEffect, delayEffect,
std::vector<EffectParameter*>{new EffectParameter("Delay Decay", "delayDecay", 0.0, 0.0, 1.0), new EffectParameter("Delay Length", "delayEchoLength", 0.5, 0.0, 1.0)} std::vector<EffectParameter*>{new EffectParameter("Delay Decay", "delayDecay", 0.0, 0.0, 1.0), new EffectParameter("Delay Length", "delayLength", 0.5, 0.0, 1.0)}
)); ));
toggleableEffects.push_back(std::make_shared<Effect>( toggleableEffects.push_back(std::make_shared<Effect>(
perspectiveEffect, perspectiveEffect,
std::vector<EffectParameter*>{ std::vector<EffectParameter*>{
new EffectParameter("3D Perspective", "depthScale", 0.0, 0.0, 1.0), new EffectParameter("3D Perspective", "perspectiveStrength", 0.0, 0.0, 1.0),
new EffectParameter("3D Depth (z)", "zPos", 0.1, 0.0, 1.0), new EffectParameter("Depth (z)", "perspectiveZPos", 0.1, 0.0, 1.0),
new EffectParameter("3D Rotate Speed", "rotateSpeed3D", 0.0, -1.0, 1.0), new EffectParameter("Rotate Speed", "perspectiveRotateSpeed", 0.0, -1.0, 1.0),
new EffectParameter("Rotate X", "rotateX", 1.0, -1.0, 1.0), new EffectParameter("Rotate X", "perspectiveRotateX", 1.0, -1.0, 1.0),
new EffectParameter("Rotate Y", "rotateY", 1.0, -1.0, 1.0), new EffectParameter("Rotate Y", "perspectiveRotateY", 1.0, -1.0, 1.0),
new EffectParameter("Rotate Z", "rotateZ", 0.0, -1.0, 1.0), new EffectParameter("Rotate Z", "perspectiveRotateZ", 0.0, -1.0, 1.0),
} }
)); ));
toggleableEffects.push_back(traceMax); toggleableEffects.push_back(traceMax);
@ -112,11 +112,11 @@ OscirenderAudioProcessor::OscirenderAudioProcessor()
addLuaSlider(); addLuaSlider();
} }
auto effects = toggleableEffects; allEffects = toggleableEffects;
effects.insert(effects.end(), permanentEffects.begin(), permanentEffects.end()); allEffects.insert(allEffects.end(), permanentEffects.begin(), permanentEffects.end());
effects.insert(effects.end(), luaEffects.begin(), luaEffects.end()); allEffects.insert(allEffects.end(), luaEffects.begin(), luaEffects.end());
for (auto effect : effects) { for (auto effect : allEffects) {
for (auto effectParameter : effect->parameters) { for (auto effectParameter : effect->parameters) {
auto parameters = effectParameter->getParameters(); auto parameters = effectParameter->getParameters();
for (auto parameter : parameters) { for (auto parameter : parameters) {
@ -553,26 +553,41 @@ void OscirenderAudioProcessor::incrementShapeDrawing() {
} }
//============================================================================== //==============================================================================
bool OscirenderAudioProcessor::hasEditor() const bool OscirenderAudioProcessor::hasEditor() const {
{
return true; // (change this to false if you choose to not supply an editor) return true; // (change this to false if you choose to not supply an editor)
} }
juce::AudioProcessorEditor* OscirenderAudioProcessor::createEditor() juce::AudioProcessorEditor* OscirenderAudioProcessor::createEditor() {
{
return new OscirenderAudioProcessorEditor (*this); return new OscirenderAudioProcessorEditor (*this);
} }
//============================================================================== //==============================================================================
void OscirenderAudioProcessor::getStateInformation (juce::MemoryBlock& destData) void OscirenderAudioProcessor::getStateInformation(juce::MemoryBlock& destData) {
{ juce::SpinLock::ScopedLockType lock1(parsersLock);
// You should use this method to store your parameters in the memory block. juce::SpinLock::ScopedLockType lock2(effectsLock);
// You could do that either as raw data, or use the XML or ValueTree classes
// as intermediaries to make it easy to save and load complex data. std::unique_ptr<juce::XmlElement> xml = std::make_unique<juce::XmlElement>("project");
xml->setAttribute("version", ProjectInfo::versionString);
auto effectsXml = xml->createNewChildElement("effects");
for (auto effect : allEffects) {
effect->save(effectsXml->createNewChildElement("effect"));
}
auto perspectiveFunction = xml->createNewChildElement("perspectiveFunction");
perspectiveFunction->addTextElement(juce::Base64::toBase64(perspectiveEffect->getCode()));
auto filesXml = xml->createNewChildElement("files");
for (int i = 0; i < fileBlocks.size(); i++) {
auto fileXml = filesXml->createNewChildElement("file");
fileXml->setAttribute("name", fileNames[i]);
auto fileString = juce::MemoryInputStream(*fileBlocks[i], false).readEntireStreamAsString();
fileXml->addTextElement(juce::Base64::toBase64(fileString));
}
xml->setAttribute("currentFile", currentFile);
DBG(xml->toString());
copyXmlToBinary(*xml, destData);
} }
void OscirenderAudioProcessor::setStateInformation (const void* data, int sizeInBytes) void OscirenderAudioProcessor::setStateInformation(const void* data, int sizeInBytes) {
{
// You should use this method to restore your parameters from this memory block, // You should use this method to restore your parameters from this memory block,
// whose contents will have been created by the getStateInformation() call. // whose contents will have been created by the getStateInformation() call.
} }

Wyświetl plik

@ -104,7 +104,7 @@ public:
camera->setFocalLength(values[0]); camera->setFocalLength(values[0]);
} }
return input; return input;
}, new EffectParameter("Focal length", "focalLength", 1.0, 0.0, 2.0) }, new EffectParameter("Focal length", "objFocalLength", 1.0, 0.0, 2.0)
); );
BooleanParameter* fixedRotateX = new BooleanParameter("Object Fixed Rotate X", "objFixedRotateX", false); BooleanParameter* fixedRotateX = new BooleanParameter("Object Fixed Rotate X", "objFixedRotateX", false);
@ -214,6 +214,7 @@ private:
double lengthIncrement = 0.0; double lengthIncrement = 0.0;
bool invalidateFrameBuffer = false; bool invalidateFrameBuffer = false;
std::vector<std::shared_ptr<Effect>> allEffects;
std::vector<std::shared_ptr<Effect>> permanentEffects; std::vector<std::shared_ptr<Effect>> permanentEffects;
std::shared_ptr<Effect> traceMax = std::make_shared<Effect>( std::shared_ptr<Effect> traceMax = std::make_shared<Effect>(

Wyświetl plik

@ -148,3 +148,12 @@ juce::String Effect::getId() {
juce::String Effect::getName() { juce::String Effect::getName() {
return parameters[0]->name; return parameters[0]->name;
} }
void Effect::save(juce::XmlElement* xml) {
if (enabled != nullptr) {
xml->setAttribute("enabled", enabled->getBoolValue());
}
for (auto parameter : parameters) {
parameter->save(xml->createNewChildElement("parameter"));
}
}

Wyświetl plik

@ -27,6 +27,7 @@ public:
void markEnableable(bool enabled); void markEnableable(bool enabled);
juce::String getId(); juce::String getId();
juce::String getName(); juce::String getName();
void save(juce::XmlElement* xml);
std::vector<EffectParameter*> parameters; std::vector<EffectParameter*> parameters;
BooleanParameter* enabled; BooleanParameter* enabled;

Wyświetl plik

@ -96,6 +96,14 @@ public:
return juce::AudioProcessorParameter::genericParameter; return juce::AudioProcessorParameter::genericParameter;
} }
void save(juce::XmlElement* xml) {
xml->setAttribute("id", paramID);
xml->setAttribute("value", value.load());
xml->setAttribute("min", min.load());
xml->setAttribute("max", max.load());
xml->setAttribute("step", step.load());
}
private: private:
// value is not necessarily in the range [min, max] so effect applications may need to clip to a valid range // value is not necessarily in the range [min, max] so effect applications may need to clip to a valid range
std::atomic<float> value = 0.0; std::atomic<float> value = 0.0;
@ -259,6 +267,10 @@ public:
return (int)LfoType::Static; return (int)LfoType::Static;
} }
} }
void save(juce::XmlElement* xml) {
xml->setAttribute("lfo", getText(getValue(), 100));
}
}; };
class EffectParameter : public FloatParameter { class EffectParameter : public FloatParameter {
@ -287,5 +299,15 @@ public:
lfoRate = nullptr; lfoRate = nullptr;
} }
void save(juce::XmlElement* xml) {
FloatParameter::save(xml);
if (lfo != nullptr && lfoRate != nullptr) {
auto lfoXml = xml->createNewChildElement("lfo");
lfo->save(lfoXml);
lfoRate->save(lfoXml);
}
}
EffectParameter(juce::String name, juce::String id, float value, float min, float max, float step = 0.001, bool smoothValueChange = true) : FloatParameter(name, id, value, min, max, step), smoothValueChange(smoothValueChange) {} EffectParameter(juce::String name, juce::String id, float value, float min, float max, float step = 0.001, bool smoothValueChange = true) : FloatParameter(name, id, value, min, max, step), smoothValueChange(smoothValueChange) {}
}; };

Wyświetl plik

@ -4,7 +4,8 @@
addUsingNamespaceToJuceHeader="0" displaySplashScreen="0" jucerFormatVersion="1" addUsingNamespaceToJuceHeader="0" displaySplashScreen="0" jucerFormatVersion="1"
pluginCharacteristicsValue="pluginProducesMidiOut,pluginWantsMidiIn" pluginCharacteristicsValue="pluginProducesMidiOut,pluginWantsMidiIn"
pluginManufacturer="jameshball" aaxIdentifier="sh.ball.oscirender" pluginManufacturer="jameshball" aaxIdentifier="sh.ball.oscirender"
cppLanguageStandard="20" projectLineFeed="&#10;" headerPath="./include"> cppLanguageStandard="20" projectLineFeed="&#10;" headerPath="./include"
version="2.0.0">
<MAINGROUP id="j5Ge2T" name="osci-render"> <MAINGROUP id="j5Ge2T" name="osci-render">
<GROUP id="{5ABCED88-0059-A7AF-9596-DBF91DDB0292}" name="Resources"> <GROUP id="{5ABCED88-0059-A7AF-9596-DBF91DDB0292}" name="Resources">
<GROUP id="{C2609827-4F4A-1ADA-8BA1-A40C1D92649C}" name="lua"> <GROUP id="{C2609827-4F4A-1ADA-8BA1-A40C1D92649C}" name="lua">