diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp index 41f421f..c596a99 100644 --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -33,8 +33,8 @@ OscirenderAudioProcessor::OscirenderAudioProcessor() #endif { producer.startThread(); - - juce::SpinLock::ScopedLockType lock(effectsLock); + + // locking isn't necessary here because we are in the constructor toggleableEffects.push_back(std::make_shared( std::make_shared(), @@ -46,19 +46,19 @@ OscirenderAudioProcessor::OscirenderAudioProcessor() )); toggleableEffects.push_back(std::make_shared( std::make_shared(), - 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( std::make_shared(), - 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( std::make_shared(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( std::make_shared(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( [this](int index, Vector2 input, const std::vector& values, double sampleRate) { @@ -77,17 +77,17 @@ OscirenderAudioProcessor::OscirenderAudioProcessor() )); toggleableEffects.push_back(std::make_shared( delayEffect, - std::vector{new EffectParameter("Delay Decay", "delayDecay", 0.0, 0.0, 1.0), new EffectParameter("Delay Length", "delayEchoLength", 0.5, 0.0, 1.0)} + std::vector{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( perspectiveEffect, std::vector{ - new EffectParameter("3D Perspective", "depthScale", 0.0, 0.0, 1.0), - new EffectParameter("3D Depth (z)", "zPos", 0.1, 0.0, 1.0), - new EffectParameter("3D Rotate Speed", "rotateSpeed3D", 0.0, -1.0, 1.0), - new EffectParameter("Rotate X", "rotateX", 1.0, -1.0, 1.0), - new EffectParameter("Rotate Y", "rotateY", 1.0, -1.0, 1.0), - new EffectParameter("Rotate Z", "rotateZ", 0.0, -1.0, 1.0), + new EffectParameter("3D Perspective", "perspectiveStrength", 0.0, 0.0, 1.0), + new EffectParameter("Depth (z)", "perspectiveZPos", 0.1, 0.0, 1.0), + new EffectParameter("Rotate Speed", "perspectiveRotateSpeed", 0.0, -1.0, 1.0), + new EffectParameter("Rotate X", "perspectiveRotateX", 1.0, -1.0, 1.0), + new EffectParameter("Rotate Y", "perspectiveRotateY", 1.0, -1.0, 1.0), + new EffectParameter("Rotate Z", "perspectiveRotateZ", 0.0, -1.0, 1.0), } )); toggleableEffects.push_back(traceMax); @@ -112,11 +112,11 @@ OscirenderAudioProcessor::OscirenderAudioProcessor() addLuaSlider(); } - auto effects = toggleableEffects; - effects.insert(effects.end(), permanentEffects.begin(), permanentEffects.end()); - effects.insert(effects.end(), luaEffects.begin(), luaEffects.end()); + allEffects = toggleableEffects; + allEffects.insert(allEffects.end(), permanentEffects.begin(), permanentEffects.end()); + allEffects.insert(allEffects.end(), luaEffects.begin(), luaEffects.end()); - for (auto effect : effects) { + for (auto effect : allEffects) { for (auto effectParameter : effect->parameters) { auto parameters = effectParameter->getParameters(); 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) } -juce::AudioProcessorEditor* OscirenderAudioProcessor::createEditor() -{ +juce::AudioProcessorEditor* OscirenderAudioProcessor::createEditor() { return new OscirenderAudioProcessorEditor (*this); } //============================================================================== -void OscirenderAudioProcessor::getStateInformation (juce::MemoryBlock& destData) -{ - // You should use this method to store your parameters in the memory block. - // 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. +void OscirenderAudioProcessor::getStateInformation(juce::MemoryBlock& destData) { + juce::SpinLock::ScopedLockType lock1(parsersLock); + juce::SpinLock::ScopedLockType lock2(effectsLock); + + std::unique_ptr xml = std::make_unique("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, // whose contents will have been created by the getStateInformation() call. } diff --git a/Source/PluginProcessor.h b/Source/PluginProcessor.h index a4ed403..dff4c84 100644 --- a/Source/PluginProcessor.h +++ b/Source/PluginProcessor.h @@ -104,7 +104,7 @@ public: camera->setFocalLength(values[0]); } 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); @@ -214,6 +214,7 @@ private: double lengthIncrement = 0.0; bool invalidateFrameBuffer = false; + std::vector> allEffects; std::vector> permanentEffects; std::shared_ptr traceMax = std::make_shared( diff --git a/Source/audio/Effect.cpp b/Source/audio/Effect.cpp index 3a43295..f0fee50 100644 --- a/Source/audio/Effect.cpp +++ b/Source/audio/Effect.cpp @@ -148,3 +148,12 @@ juce::String Effect::getId() { juce::String Effect::getName() { 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")); + } +} diff --git a/Source/audio/Effect.h b/Source/audio/Effect.h index cad711d..6c8c0c7 100644 --- a/Source/audio/Effect.h +++ b/Source/audio/Effect.h @@ -27,6 +27,7 @@ public: void markEnableable(bool enabled); juce::String getId(); juce::String getName(); + void save(juce::XmlElement* xml); std::vector parameters; BooleanParameter* enabled; diff --git a/Source/audio/EffectParameter.h b/Source/audio/EffectParameter.h index 440e69c..36449bc 100644 --- a/Source/audio/EffectParameter.h +++ b/Source/audio/EffectParameter.h @@ -96,6 +96,14 @@ public: 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: // value is not necessarily in the range [min, max] so effect applications may need to clip to a valid range std::atomic value = 0.0; @@ -259,6 +267,10 @@ public: return (int)LfoType::Static; } } + + void save(juce::XmlElement* xml) { + xml->setAttribute("lfo", getText(getValue(), 100)); + } }; class EffectParameter : public FloatParameter { @@ -287,5 +299,15 @@ public: 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) {} }; \ No newline at end of file diff --git a/osci-render.jucer b/osci-render.jucer index 9560fa8..dc108f7 100644 --- a/osci-render.jucer +++ b/osci-render.jucer @@ -4,7 +4,8 @@ addUsingNamespaceToJuceHeader="0" displaySplashScreen="0" jucerFormatVersion="1" pluginCharacteristicsValue="pluginProducesMidiOut,pluginWantsMidiIn" pluginManufacturer="jameshball" aaxIdentifier="sh.ball.oscirender" - cppLanguageStandard="20" projectLineFeed=" " headerPath="./include"> + cppLanguageStandard="20" projectLineFeed=" " headerPath="./include" + version="2.0.0">