kopia lustrzana https://github.com/jameshball/osci-render
Support opening legacy osci-render projects and fix some bugs
rodzic
40c0086bf4
commit
b845d150ff
|
@ -0,0 +1,275 @@
|
|||
#include "PluginProcessor.h"
|
||||
|
||||
void OscirenderAudioProcessor::openLegacyProject(const juce::XmlElement* xml) {
|
||||
juce::SpinLock::ScopedLockType lock1(parsersLock);
|
||||
juce::SpinLock::ScopedLockType lock2(effectsLock);
|
||||
|
||||
if (xml != nullptr && xml->hasTagName("project")) {
|
||||
auto slidersXml = xml->getChildByName("sliders");
|
||||
if (slidersXml != nullptr) {
|
||||
for (auto sliderXml : slidersXml->getChildIterator()) {
|
||||
auto id = sliderXml->getTagName();
|
||||
auto valueXml = sliderXml->getChildByName("value");
|
||||
auto minXml = sliderXml->getChildByName("min");
|
||||
auto maxXml = sliderXml->getChildByName("max");
|
||||
|
||||
double value = valueXml != nullptr ? valueXml->getAllSubText().getDoubleValue() : 0.0;
|
||||
double min = minXml != nullptr ? minXml->getAllSubText().getDoubleValue() : 0.0;
|
||||
double max = maxXml != nullptr ? maxXml->getAllSubText().getDoubleValue() : 0.0;
|
||||
|
||||
value = valueFromLegacy(value, id);
|
||||
min = valueFromLegacy(min, id);
|
||||
max = valueFromLegacy(max, id);
|
||||
|
||||
auto pair = effectFromLegacyId(id, true);
|
||||
auto effect = pair.first;
|
||||
auto parameter = pair.second;
|
||||
|
||||
if (effect != nullptr && parameter != nullptr) {
|
||||
if (id != "volume" && id != "threshold") {
|
||||
parameter->min = min;
|
||||
parameter->max = max;
|
||||
}
|
||||
parameter->setUnnormalisedValueNotifyingHost(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto translationXml = xml->getChildByName("translation");
|
||||
if (translationXml != nullptr) {
|
||||
auto xXml = translationXml->getChildByName("x");
|
||||
auto yXml = translationXml->getChildByName("y");
|
||||
auto translateEffect = getEffect("translateX");
|
||||
if (translateEffect != nullptr) {
|
||||
auto x = translateEffect->getParameter("translateX");
|
||||
if (x != nullptr && xXml != nullptr) {
|
||||
x->setUnnormalisedValueNotifyingHost(xXml->getAllSubText().getDoubleValue());
|
||||
}
|
||||
auto y = translateEffect->getParameter("translateY");
|
||||
if (y != nullptr && yXml != nullptr) {
|
||||
y->setUnnormalisedValueNotifyingHost(yXml->getAllSubText().getDoubleValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto perspectiveFixedRotateXml = xml->getChildByName("perspectiveFixedRotate");
|
||||
if (perspectiveFixedRotateXml != nullptr) {
|
||||
auto xXml = perspectiveFixedRotateXml->getChildByName("x");
|
||||
auto yXml = perspectiveFixedRotateXml->getChildByName("y");
|
||||
auto zXml = perspectiveFixedRotateXml->getChildByName("z");
|
||||
auto x = getBooleanParameter("perspectiveFixedRotateX");
|
||||
auto y = getBooleanParameter("perspectiveFixedRotateY");
|
||||
auto z = getBooleanParameter("perspectiveFixedRotateZ");
|
||||
if (x != nullptr && xXml != nullptr) {
|
||||
x->setBoolValueNotifyingHost(xXml->getAllSubText() == "true");
|
||||
}
|
||||
if (y != nullptr && yXml != nullptr) {
|
||||
y->setBoolValueNotifyingHost(yXml->getAllSubText() == "true");
|
||||
}
|
||||
if (z != nullptr && zXml != nullptr) {
|
||||
z->setBoolValueNotifyingHost(zXml->getAllSubText() == "true");
|
||||
}
|
||||
}
|
||||
|
||||
auto objectFixedRotate = xml->getChildByName("objectFixedRotate");
|
||||
if (objectFixedRotate != nullptr) {
|
||||
auto xXml = objectFixedRotate->getChildByName("x");
|
||||
auto yXml = objectFixedRotate->getChildByName("y");
|
||||
auto zXml = objectFixedRotate->getChildByName("z");
|
||||
auto x = getBooleanParameter("objFixedRotateX");
|
||||
auto y = getBooleanParameter("objFixedRotateY");
|
||||
auto z = getBooleanParameter("objFixedRotateZ");
|
||||
if (x != nullptr && xXml != nullptr) {
|
||||
x->setBoolValueNotifyingHost(xXml->getAllSubText() == "true");
|
||||
}
|
||||
if (y != nullptr && yXml != nullptr) {
|
||||
y->setBoolValueNotifyingHost(yXml->getAllSubText() == "true");
|
||||
}
|
||||
if (z != nullptr && zXml != nullptr) {
|
||||
z->setBoolValueNotifyingHost(zXml->getAllSubText() == "true");
|
||||
}
|
||||
}
|
||||
|
||||
auto checkBoxesXml = xml->getChildByName("checkBoxes");
|
||||
if (checkBoxesXml != nullptr) {
|
||||
for (auto checkBoxXml : checkBoxesXml->getChildIterator()) {
|
||||
auto id = checkBoxXml->getTagName();
|
||||
auto selectedXml = checkBoxXml->getChildByName("selected");
|
||||
auto animationXml = checkBoxXml->getChildByName("animation");
|
||||
auto animationSpeedXml = checkBoxXml->getChildByName("animationSpeed");
|
||||
|
||||
bool selected = selectedXml != nullptr ? selectedXml->getAllSubText() == "true" : false;
|
||||
LfoType lfoType = animationXml != nullptr ? lfoTypeFromLegacyAnimationType(animationXml->getAllSubText()) : LfoType::Static;
|
||||
double lfoRate = animationSpeedXml != nullptr ? animationSpeedXml->getAllSubText().getDoubleValue() : 1.0;
|
||||
|
||||
auto pair = effectFromLegacyId(id, true);
|
||||
auto effect = pair.first;
|
||||
auto parameter = pair.second;
|
||||
|
||||
if (effect != nullptr && parameter != nullptr && parameter->lfo != nullptr && parameter->lfoRate != nullptr) {
|
||||
if (effect->enabled != nullptr && effect->getId() == parameter->paramID) {
|
||||
effect->enabled->setBoolValueNotifyingHost(selected);
|
||||
}
|
||||
parameter->lfo->setUnnormalisedValueNotifyingHost((int) lfoType);
|
||||
parameter->lfoRate->setUnnormalisedValueNotifyingHost(lfoRate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateEffectPrecedence();
|
||||
|
||||
auto perspectiveFunction = xml->getChildByName("depthFunction");
|
||||
if (perspectiveFunction != nullptr) {
|
||||
auto stream = juce::MemoryOutputStream();
|
||||
juce::Base64::convertFromBase64(stream, perspectiveFunction->getAllSubText());
|
||||
perspectiveEffect->updateCode(stream.toString());
|
||||
}
|
||||
// close all files
|
||||
auto numFiles = fileBlocks.size();
|
||||
for (int i = 0; i < numFiles; i++) {
|
||||
removeFile(0);
|
||||
}
|
||||
|
||||
auto filesXml = xml->getChildByName("files");
|
||||
if (filesXml != nullptr) {
|
||||
for (auto fileXml : filesXml->getChildIterator()) {
|
||||
auto nameXml = fileXml->getChildByName("name");
|
||||
auto dataXml = fileXml->getChildByName("data");
|
||||
auto fileName = nameXml != nullptr ? nameXml->getAllSubText() : "";
|
||||
auto data = dataXml != nullptr ? dataXml->getAllSubText() : "";
|
||||
|
||||
auto stream = juce::MemoryOutputStream();
|
||||
juce::Base64::convertFromBase64(stream, data);
|
||||
auto fileBlock = std::make_shared<juce::MemoryBlock>(stream.getData(), stream.getDataSize());
|
||||
addFile(fileName, fileBlock);
|
||||
}
|
||||
}
|
||||
|
||||
auto frameSourceXml = xml->getChildByName("frameSource");
|
||||
if (frameSourceXml != nullptr) {
|
||||
changeCurrentFile(frameSourceXml->getAllSubText().getIntValue());
|
||||
}
|
||||
broadcaster.sendChangeMessage();
|
||||
}
|
||||
}
|
||||
|
||||
// gets the effect from the legacy id and optionally updates the precedence
|
||||
std::pair<std::shared_ptr<Effect>, EffectParameter*> OscirenderAudioProcessor::effectFromLegacyId(const juce::String& id, bool updatePrecedence) {
|
||||
auto effectId = id;
|
||||
juce::String paramId = "";
|
||||
int precedence = -1;
|
||||
|
||||
if (id == "vectorCancelling") {
|
||||
precedence = 0;
|
||||
} else if (id == "bitCrush") {
|
||||
precedence = 1;
|
||||
} else if (id == "verticalDistort") {
|
||||
precedence = 2;
|
||||
effectId = "distortY";
|
||||
} else if (id == "horizontalDistort") {
|
||||
precedence = 3;
|
||||
effectId = "distortX";
|
||||
} else if (id == "wobble") {
|
||||
precedence = 4;
|
||||
} else if (id == "smoothing") {
|
||||
precedence = 100;
|
||||
} else if (id == "rotateSpeed3d") {
|
||||
precedence = 52;
|
||||
effectId = "perspectiveStrength";
|
||||
paramId = "perspectiveRotateSpeed";
|
||||
} else if (id == "zPos") {
|
||||
precedence = 52;
|
||||
effectId = "perspectiveStrength";
|
||||
paramId = "perspectiveZPos";
|
||||
} else if (id == "imageRotateX") {
|
||||
precedence = 52;
|
||||
effectId = "perspectiveStrength";
|
||||
paramId = "perspectiveRotateX";
|
||||
} else if (id == "imageRotateY") {
|
||||
precedence = 52;
|
||||
effectId = "perspectiveStrength";
|
||||
paramId = "perspectiveRotateY";
|
||||
} else if (id == "imageRotateZ") {
|
||||
precedence = 52;
|
||||
effectId = "perspectiveStrength";
|
||||
paramId = "perspectiveRotateZ";
|
||||
} else if (id == "depthScale") {
|
||||
precedence = 52;
|
||||
effectId = "perspectiveStrength";
|
||||
} else if (id == "translationScale") {
|
||||
// this doesn't exist in the new version
|
||||
} else if (id == "translationSpeed") {
|
||||
// this doesn't exist in the new version
|
||||
} else if (id == "rotateSpeed") {
|
||||
precedence = 50;
|
||||
effectId = "2DRotateSpeed";
|
||||
} else if (id == "visibility") {
|
||||
// this doesn't exist in the new version
|
||||
} else if (id == "delayDecay") {
|
||||
precedence = 101;
|
||||
} else if (id == "delayEchoLength") {
|
||||
precedence = 101;
|
||||
effectId = "delayDecay";
|
||||
paramId = "delayLength";
|
||||
} else if (id == "bulge") {
|
||||
precedence = 53;
|
||||
} else if (id == "focalLength") {
|
||||
effectId = "objFocalLength";
|
||||
} else if (id == "objectXRotate") {
|
||||
effectId = "objRotateX";
|
||||
} else if (id == "objectYRotate") {
|
||||
effectId = "objRotateY";
|
||||
} else if (id == "objectZRotate") {
|
||||
effectId = "objRotateZ";
|
||||
} else if (id == "objectRotateSpeed") {
|
||||
effectId = "objRotateSpeed";
|
||||
} else if (id == "octave") {
|
||||
// this doesn't exist in the new version
|
||||
} else if (id == "micVolume") {
|
||||
// this doesn't exist in the new version
|
||||
} else if (id == "brightness") {
|
||||
// this doesn't exist in the new version
|
||||
}
|
||||
|
||||
paramId = paramId == "" ? effectId : paramId;
|
||||
auto effect = getEffect(effectId);
|
||||
|
||||
if (effect == nullptr) {
|
||||
return std::make_pair(nullptr, nullptr);
|
||||
} else {
|
||||
if (updatePrecedence) {
|
||||
effect->setPrecedence(precedence);
|
||||
}
|
||||
auto parameter = effect->getParameter(paramId);
|
||||
return std::make_pair(effect, parameter);
|
||||
}
|
||||
}
|
||||
|
||||
LfoType OscirenderAudioProcessor::lfoTypeFromLegacyAnimationType(const juce::String& type) {
|
||||
if (type == "Static") {
|
||||
return LfoType::Static;
|
||||
} else if (type == "Sine") {
|
||||
return LfoType::Sine;
|
||||
} else if (type == "Square") {
|
||||
return LfoType::Square;
|
||||
} else if (type == "Seesaw") {
|
||||
return LfoType::Seesaw;
|
||||
} else if (type == "Linear") {
|
||||
return LfoType::Triangle;
|
||||
} else if (type == "Forward") {
|
||||
return LfoType::Sawtooth;
|
||||
} else if (type == "Reverse") {
|
||||
return LfoType::ReverseSawtooth;
|
||||
} else {
|
||||
return LfoType::Static;
|
||||
}
|
||||
}
|
||||
|
||||
double OscirenderAudioProcessor::valueFromLegacy(double value, const juce::String& id) {
|
||||
if (id == "volume") {
|
||||
return value / 3.0;
|
||||
} else if (id == "frequency") {
|
||||
return std::pow(12000.0, value);
|
||||
}
|
||||
return value;
|
||||
}
|
|
@ -34,11 +34,12 @@ OscirenderAudioProcessorEditor::OscirenderAudioProcessorEditor(OscirenderAudioPr
|
|||
|
||||
{
|
||||
juce::SpinLock::ScopedLockType lock(audioProcessor.parsersLock);
|
||||
addCodeEditor(-1);
|
||||
for (int i = 0; i < audioProcessor.numFiles(); i++) {
|
||||
addCodeEditor(i);
|
||||
}
|
||||
fileUpdated(audioProcessor.getCurrentFileName());
|
||||
initialiseCodeEditors();
|
||||
}
|
||||
|
||||
{
|
||||
juce::MessageManagerLock lock;
|
||||
audioProcessor.broadcaster.addChangeListener(this);
|
||||
}
|
||||
|
||||
setSize(1100, 750);
|
||||
|
@ -46,7 +47,22 @@ OscirenderAudioProcessorEditor::OscirenderAudioProcessorEditor(OscirenderAudioPr
|
|||
setResizeLimits(500, 400, 999999, 999999);
|
||||
}
|
||||
|
||||
OscirenderAudioProcessorEditor::~OscirenderAudioProcessorEditor() {}
|
||||
OscirenderAudioProcessorEditor::~OscirenderAudioProcessorEditor() {
|
||||
juce::MessageManagerLock lock;
|
||||
audioProcessor.broadcaster.removeChangeListener(this);
|
||||
}
|
||||
|
||||
// parsersLock must be held
|
||||
void OscirenderAudioProcessorEditor::initialiseCodeEditors() {
|
||||
codeDocuments.clear();
|
||||
codeEditors.clear();
|
||||
// -1 is the perspective function
|
||||
addCodeEditor(-1);
|
||||
for (int i = 0; i < audioProcessor.numFiles(); i++) {
|
||||
addCodeEditor(i);
|
||||
}
|
||||
fileUpdated(audioProcessor.getCurrentFileName());
|
||||
}
|
||||
|
||||
void OscirenderAudioProcessorEditor::paint(juce::Graphics& g) {
|
||||
g.fillAll(getLookAndFeel().findColour(juce::ResizableWindow::backgroundColourId));
|
||||
|
@ -101,7 +117,6 @@ void OscirenderAudioProcessorEditor::resized() {
|
|||
obj.setBounds(altEffectsSection);
|
||||
}
|
||||
effects.setBounds(effectsSection);
|
||||
|
||||
}
|
||||
|
||||
void OscirenderAudioProcessorEditor::addCodeEditor(int index) {
|
||||
|
@ -187,6 +202,11 @@ void OscirenderAudioProcessorEditor::handleAsyncUpdate() {
|
|||
resized();
|
||||
}
|
||||
|
||||
void OscirenderAudioProcessorEditor::changeListenerCallback(juce::ChangeBroadcaster* source) {
|
||||
juce::SpinLock::ScopedLockType lock(audioProcessor.parsersLock);
|
||||
initialiseCodeEditors();
|
||||
}
|
||||
|
||||
void OscirenderAudioProcessorEditor::editPerspectiveFunction(bool enable) {
|
||||
editingPerspective = enable;
|
||||
juce::SpinLock::ScopedLockType lock1(audioProcessor.parsersLock);
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "components/MainMenuBarModel.h"
|
||||
|
||||
|
||||
class OscirenderAudioProcessorEditor : public juce::AudioProcessorEditor, private juce::CodeDocument::Listener, public juce::AsyncUpdater {
|
||||
class OscirenderAudioProcessorEditor : public juce::AudioProcessorEditor, private juce::CodeDocument::Listener, public juce::AsyncUpdater, public juce::ChangeListener {
|
||||
public:
|
||||
OscirenderAudioProcessorEditor(OscirenderAudioProcessor&);
|
||||
~OscirenderAudioProcessorEditor() override;
|
||||
|
@ -18,10 +18,12 @@ public:
|
|||
void paint(juce::Graphics&) override;
|
||||
void resized() override;
|
||||
|
||||
void initialiseCodeEditors();
|
||||
void addCodeEditor(int index);
|
||||
void removeCodeEditor(int index);
|
||||
void fileUpdated(juce::String fileName);
|
||||
void handleAsyncUpdate() override;
|
||||
void changeListenerCallback(juce::ChangeBroadcaster* source) override;
|
||||
|
||||
void editPerspectiveFunction(bool enabled);
|
||||
|
||||
|
|
|
@ -93,10 +93,12 @@ OscirenderAudioProcessor::OscirenderAudioProcessor()
|
|||
toggleableEffects.push_back(traceMax);
|
||||
toggleableEffects.push_back(traceMin);
|
||||
|
||||
for (auto& effect : toggleableEffects) {
|
||||
for (int i = 0; i < toggleableEffects.size(); i++) {
|
||||
auto effect = toggleableEffects[i];
|
||||
effect->markEnableable(false);
|
||||
addParameter(effect->enabled);
|
||||
effect->enabled->setValueNotifyingHost(false);
|
||||
effect->setPrecedence(i);
|
||||
}
|
||||
|
||||
permanentEffects.push_back(frequencyEffect);
|
||||
|
@ -631,12 +633,27 @@ void OscirenderAudioProcessor::getStateInformation(juce::MemoryBlock& destData)
|
|||
}
|
||||
|
||||
void OscirenderAudioProcessor::setStateInformation(const void* data, int sizeInBytes) {
|
||||
juce::SpinLock::ScopedLockType lock1(parsersLock);
|
||||
juce::SpinLock::ScopedLockType lock2(effectsLock);
|
||||
std::unique_ptr<juce::XmlElement> xml;
|
||||
|
||||
std::unique_ptr<juce::XmlElement> xml(getXmlFromBinary(data, sizeInBytes));
|
||||
const uint32_t magicXmlNumber = 0x21324356;
|
||||
if (sizeInBytes > 8 && juce::ByteOrder::littleEndianInt(data) == magicXmlNumber) {
|
||||
// this is a binary xml format
|
||||
xml = getXmlFromBinary(data, sizeInBytes);
|
||||
} else {
|
||||
// this is a text xml format
|
||||
xml = juce::XmlDocument::parse(juce::String((const char*)data, sizeInBytes));
|
||||
}
|
||||
|
||||
if (xml.get() != nullptr && xml->hasTagName("project")) {
|
||||
auto versionXml = xml->getChildByName("version");
|
||||
if (versionXml != nullptr && versionXml->getAllSubText().startsWith("v1.")) {
|
||||
openLegacyProject(xml.get());
|
||||
return;
|
||||
}
|
||||
|
||||
juce::SpinLock::ScopedLockType lock1(parsersLock);
|
||||
juce::SpinLock::ScopedLockType lock2(effectsLock);
|
||||
|
||||
auto effectsXml = xml->getChildByName("effects");
|
||||
if (effectsXml != nullptr) {
|
||||
for (auto effectXml : effectsXml->getChildIterator()) {
|
||||
|
|
|
@ -32,11 +32,9 @@ class OscirenderAudioProcessor : public juce::AudioProcessor
|
|||
, public FrameConsumer
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
OscirenderAudioProcessor();
|
||||
~OscirenderAudioProcessor() override;
|
||||
|
||||
//==============================================================================
|
||||
void prepareToPlay (double sampleRate, int samplesPerBlock) override;
|
||||
void releaseResources() override;
|
||||
|
||||
|
@ -46,28 +44,22 @@ public:
|
|||
|
||||
void processBlock (juce::AudioBuffer<float>&, juce::MidiBuffer&) override;
|
||||
|
||||
//==============================================================================
|
||||
juce::AudioProcessorEditor* createEditor() override;
|
||||
bool hasEditor() const override;
|
||||
|
||||
//==============================================================================
|
||||
const juce::String getName() const override;
|
||||
|
||||
bool acceptsMidi() const override;
|
||||
bool producesMidi() const override;
|
||||
bool isMidiEffect() const override;
|
||||
double getTailLengthSeconds() const override;
|
||||
|
||||
//==============================================================================
|
||||
int getNumPrograms() override;
|
||||
int getCurrentProgram() override;
|
||||
void setCurrentProgram (int index) override;
|
||||
const juce::String getProgramName (int index) override;
|
||||
void changeProgramName (int index, const juce::String& newName) override;
|
||||
|
||||
//==============================================================================
|
||||
void getStateInformation (juce::MemoryBlock& destData) override;
|
||||
void setStateInformation (const void* data, int sizeInBytes) override;
|
||||
void setCurrentProgram(int index) override;
|
||||
const juce::String getProgramName(int index) override;
|
||||
void changeProgramName(int index, const juce::String& newName) override;
|
||||
void getStateInformation(juce::MemoryBlock& destData) override;
|
||||
void setStateInformation(const void* data, int sizeInBytes) override;
|
||||
|
||||
std::atomic<double> currentSampleRate = 0.0;
|
||||
|
||||
|
@ -257,6 +249,10 @@ private:
|
|||
void updateObjValues();
|
||||
std::shared_ptr<Effect> getEffect(juce::String id);
|
||||
BooleanParameter* getBooleanParameter(juce::String id);
|
||||
void openLegacyProject(const juce::XmlElement* xml);
|
||||
std::pair<std::shared_ptr<Effect>, EffectParameter*> effectFromLegacyId(const juce::String& id, bool updatePrecedence = false);
|
||||
LfoType lfoTypeFromLegacyAnimationType(const juce::String& type);
|
||||
double valueFromLegacy(double value, const juce::String& id);
|
||||
|
||||
const double MIN_LENGTH_INCREMENT = 0.000001;
|
||||
|
||||
|
|
|
@ -46,9 +46,6 @@ Vector2 PerspectiveEffect::apply(int index, Vector2 input, const std::vector<dou
|
|||
auto z = 0.0;
|
||||
|
||||
{
|
||||
// TODO: Instead of evaluating the script every time, we could evaluate it
|
||||
// once at the start for all values of x and y and then interpolate between
|
||||
// the results.
|
||||
juce::SpinLock::ScopedLockType lock(codeLock);
|
||||
if (!defaultScript) {
|
||||
parser->setVariable("x", x);
|
||||
|
|
|
@ -299,6 +299,8 @@
|
|||
<FILE id="eAqAle" name="IXWebSocketVersion.h" compile="0" resource="0"
|
||||
file="Source/ixwebsocket/IXWebSocketVersion.h"/>
|
||||
</GROUP>
|
||||
<FILE id="uyOdTl" name="LegacyProject.cpp" compile="1" resource="0"
|
||||
file="Source/LegacyProject.cpp"/>
|
||||
<GROUP id="{75F6236A-68A5-85DA-EDAE-23D1621601DB}" name="lua">
|
||||
<FILE id="X5i9iw" name="lapi.c" compile="1" resource="0" file="Source/lua/lapi.c"/>
|
||||
<FILE id="J62WSE" name="lapi.h" compile="0" resource="0" file="Source/lua/lapi.h"/>
|
||||
|
|
Ładowanie…
Reference in New Issue