kopia lustrzana https://github.com/jameshball/osci-render
Hacky solution to get editing perspective function fully working
rodzic
26860a00e6
commit
d6436aa3fa
|
@ -2,7 +2,7 @@
|
|||
#include "audio/BitCrushEffect.h"
|
||||
#include "PluginEditor.h"
|
||||
|
||||
EffectsComponent::EffectsComponent(OscirenderAudioProcessor& p) : audioProcessor(p), itemData(p), listBoxModel(listBox, itemData) {
|
||||
EffectsComponent::EffectsComponent(OscirenderAudioProcessor& p, OscirenderAudioProcessorEditor& editor) : audioProcessor(p), itemData(p, editor), listBoxModel(listBox, itemData) {
|
||||
setText("Audio Effects");
|
||||
|
||||
addAndMakeVisible(frequency);
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
class OscirenderAudioProcessorEditor;
|
||||
class EffectsComponent : public juce::GroupComponent {
|
||||
public:
|
||||
EffectsComponent(OscirenderAudioProcessor&);
|
||||
EffectsComponent(OscirenderAudioProcessor&, OscirenderAudioProcessorEditor&);
|
||||
~EffectsComponent() override;
|
||||
|
||||
void resized() override;
|
||||
|
|
|
@ -15,14 +15,18 @@ MainComponent::MainComponent(OscirenderAudioProcessor& p, OscirenderAudioProcess
|
|||
|
||||
chooser->launchAsync(flags, [this](const juce::FileChooser& chooser) {
|
||||
juce::SpinLock::ScopedLockType lock(audioProcessor.parsersLock);
|
||||
bool fileAdded = false;
|
||||
for (auto& url : chooser.getURLResults()) {
|
||||
if (url.isLocalFile()) {
|
||||
auto file = url.getLocalFile();
|
||||
audioProcessor.addFile(file);
|
||||
fileAdded = true;
|
||||
}
|
||||
}
|
||||
pluginEditor.addCodeEditor(audioProcessor.getCurrentFileIndex());
|
||||
pluginEditor.fileUpdated(audioProcessor.getCurrentFileName());
|
||||
if (fileAdded) {
|
||||
pluginEditor.addCodeEditor(audioProcessor.getCurrentFileIndex());
|
||||
pluginEditor.fileUpdated(audioProcessor.getCurrentFileName());
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -13,19 +13,14 @@ OscirenderAudioProcessorEditor::OscirenderAudioProcessorEditor(OscirenderAudioPr
|
|||
addAndMakeVisible(collapseButton);
|
||||
collapseButton.onClick = [this] {
|
||||
juce::SpinLock::ScopedLockType lock(audioProcessor.parsersLock);
|
||||
int index = audioProcessor.getCurrentFileIndex();
|
||||
if (index != -1) {
|
||||
int originalIndex = audioProcessor.getCurrentFileIndex();
|
||||
int index = editingPerspective ? 0 : audioProcessor.getCurrentFileIndex() + 1;
|
||||
if (originalIndex != -1 || editingPerspective) {
|
||||
if (codeEditors[index]->isVisible()) {
|
||||
codeEditors[index]->setVisible(false);
|
||||
juce::Path path;
|
||||
path.addTriangle(0.0f, 0.5f, 1.0f, 1.0f, 1.0f, 0.0f);
|
||||
collapseButton.setShape(path, false, true, true);
|
||||
} else {
|
||||
codeEditors[index]->setVisible(true);
|
||||
updateCodeEditor();
|
||||
juce::Path path;
|
||||
path.addTriangle(0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.5f);
|
||||
collapseButton.setShape(path, false, true, true);
|
||||
}
|
||||
triggerAsyncUpdate();
|
||||
}
|
||||
|
@ -34,11 +29,14 @@ OscirenderAudioProcessorEditor::OscirenderAudioProcessorEditor(OscirenderAudioPr
|
|||
path.addTriangle(0.0f, 0.5f, 1.0f, 1.0f, 1.0f, 0.0f);
|
||||
collapseButton.setShape(path, false, true, true);
|
||||
|
||||
juce::SpinLock::ScopedLockType lock(audioProcessor.parsersLock);
|
||||
for (int i = 0; i < audioProcessor.numFiles(); i++) {
|
||||
addCodeEditor(i);
|
||||
{
|
||||
juce::SpinLock::ScopedLockType lock(audioProcessor.parsersLock);
|
||||
addCodeEditor(-1);
|
||||
for (int i = 0; i < audioProcessor.numFiles(); i++) {
|
||||
addCodeEditor(i);
|
||||
}
|
||||
fileUpdated(audioProcessor.getCurrentFileName());
|
||||
}
|
||||
fileUpdated(audioProcessor.getCurrentFileName());
|
||||
|
||||
setSize(1100, 750);
|
||||
setResizable(true, true);
|
||||
|
@ -62,18 +60,35 @@ void OscirenderAudioProcessorEditor::resized() {
|
|||
volume.setBounds(volumeArea.withSizeKeepingCentre(volumeArea.getWidth(), juce::jmin(volumeArea.getHeight(), 300)));
|
||||
area.removeFromLeft(3);
|
||||
auto sections = 2;
|
||||
int index = audioProcessor.getCurrentFileIndex();
|
||||
if (index != -1) {
|
||||
if (codeEditors[index]->isVisible()) {
|
||||
sections++;
|
||||
codeEditors[index]->setBounds(area.removeFromRight(getWidth() / sections));
|
||||
} else {
|
||||
codeEditors[index]->setBounds(0, 0, 0, 0);
|
||||
}
|
||||
collapseButton.setBounds(area.removeFromRight(20));
|
||||
bool editorVisible = false;
|
||||
{
|
||||
juce::SpinLock::ScopedLockType lock(audioProcessor.parsersLock);
|
||||
int originalIndex = audioProcessor.getCurrentFileIndex();
|
||||
int index = editingPerspective ? 0 : audioProcessor.getCurrentFileIndex() + 1;
|
||||
if (originalIndex != -1 || editingPerspective) {
|
||||
if (codeEditors[index]->isVisible()) {
|
||||
sections++;
|
||||
editorVisible = true;
|
||||
codeEditors[index]->setBounds(area.removeFromRight(getWidth() / sections));
|
||||
} else {
|
||||
codeEditors[index]->setBounds(0, 0, 0, 0);
|
||||
}
|
||||
collapseButton.setBounds(area.removeFromRight(20));
|
||||
} else {
|
||||
collapseButton.setBounds(0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (editorVisible) {
|
||||
juce::Path path;
|
||||
path.addTriangle(0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.5f);
|
||||
collapseButton.setShape(path, false, true, true);
|
||||
} else {
|
||||
collapseButton.setBounds(0, 0, 0, 0);
|
||||
}
|
||||
juce::Path path;
|
||||
path.addTriangle(0.0f, 0.5f, 1.0f, 1.0f, 1.0f, 0.0f);
|
||||
collapseButton.setShape(path, false, true, true);
|
||||
}
|
||||
|
||||
auto effectsSection = area.removeFromRight(1.2 * getWidth() / sections);
|
||||
main.setBounds(area);
|
||||
if (lua.isVisible() || obj.isVisible()) {
|
||||
|
@ -86,25 +101,37 @@ void OscirenderAudioProcessorEditor::resized() {
|
|||
}
|
||||
|
||||
void OscirenderAudioProcessorEditor::addCodeEditor(int index) {
|
||||
std::shared_ptr<juce::CodeDocument> codeDocument = std::make_shared<juce::CodeDocument>();
|
||||
int originalIndex = index;
|
||||
index++;
|
||||
std::shared_ptr<juce::CodeDocument> codeDocument;
|
||||
std::shared_ptr<juce::CodeEditorComponent> editor;
|
||||
|
||||
if (index == 0) {
|
||||
codeDocument = perspectiveCodeDocument;
|
||||
editor = perspectiveCodeEditor;
|
||||
} else {
|
||||
codeDocument = std::make_shared<juce::CodeDocument>();
|
||||
juce::String extension = audioProcessor.getFileName(originalIndex).fromLastOccurrenceOf(".", true, false);
|
||||
juce::CodeTokeniser* tokeniser = nullptr;
|
||||
if (extension == ".lua") {
|
||||
tokeniser = &luaTokeniser;
|
||||
} else if (extension == ".svg") {
|
||||
tokeniser = &xmlTokeniser;
|
||||
}
|
||||
editor = std::make_shared<juce::CodeEditorComponent>(*codeDocument, tokeniser);
|
||||
}
|
||||
|
||||
codeDocuments.insert(codeDocuments.begin() + index, codeDocument);
|
||||
juce::String extension = audioProcessor.getFileName(index).fromLastOccurrenceOf(".", true, false);
|
||||
juce::CodeTokeniser* tokeniser = nullptr;
|
||||
if (extension == ".lua") {
|
||||
tokeniser = &luaTokeniser;
|
||||
} else if (extension == ".svg") {
|
||||
tokeniser = &xmlTokeniser;
|
||||
}
|
||||
std::shared_ptr<juce::CodeEditorComponent> editor = std::make_shared<juce::CodeEditorComponent>(*codeDocument, tokeniser);
|
||||
codeEditors.insert(codeEditors.begin() + index, editor);
|
||||
addChildComponent(*editor);
|
||||
// I need to disable accessibility otherwise it doesn't work! Appears to be a JUCE issue, very annoying!
|
||||
editor->setAccessible(false);
|
||||
// listen for changes to the code editor
|
||||
codeDocument->addListener(this);
|
||||
codeEditors.insert(codeEditors.begin() + index, editor);
|
||||
addChildComponent(*editor);
|
||||
}
|
||||
|
||||
void OscirenderAudioProcessorEditor::removeCodeEditor(int index) {
|
||||
index++;
|
||||
codeEditors.erase(codeEditors.begin() + index);
|
||||
codeDocuments.erase(codeDocuments.begin() + index);
|
||||
}
|
||||
|
@ -116,17 +143,22 @@ void OscirenderAudioProcessorEditor::updateCodeEditor() {
|
|||
bool visible = false;
|
||||
for (int i = 0; i < codeEditors.size(); i++) {
|
||||
if (codeEditors[i]->isVisible()) {
|
||||
visible = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int index = audioProcessor.getCurrentFileIndex();
|
||||
if (index != -1 && visible) {
|
||||
visible = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int originalIndex = audioProcessor.getCurrentFileIndex();
|
||||
int index = editingPerspective ? 0 : audioProcessor.getCurrentFileIndex() + 1;
|
||||
if ((originalIndex != -1 || editingPerspective) && visible) {
|
||||
for (int i = 0; i < codeEditors.size(); i++) {
|
||||
codeEditors[i]->setVisible(false);
|
||||
}
|
||||
codeEditors[index]->setVisible(true);
|
||||
codeEditors[index]->loadContent(juce::MemoryInputStream(*audioProcessor.getFileBlock(index), false).readEntireStreamAsString());
|
||||
if (index == 0) {
|
||||
codeEditors[index]->loadContent(audioProcessor.perspectiveEffect->getCode());
|
||||
} else {
|
||||
codeEditors[index]->loadContent(juce::MemoryInputStream(*audioProcessor.getFileBlock(originalIndex), false).readEntireStreamAsString());
|
||||
}
|
||||
}
|
||||
triggerAsyncUpdate();
|
||||
}
|
||||
|
@ -151,6 +183,14 @@ void OscirenderAudioProcessorEditor::handleAsyncUpdate() {
|
|||
resized();
|
||||
}
|
||||
|
||||
void OscirenderAudioProcessorEditor::editPerspectiveFunction(bool enable) {
|
||||
editingPerspective = enable;
|
||||
juce::SpinLock::ScopedLockType lock1(audioProcessor.parsersLock);
|
||||
juce::SpinLock::ScopedLockType lock2(audioProcessor.effectsLock);
|
||||
codeEditors[0]->setVisible(enable);
|
||||
updateCodeEditor();
|
||||
}
|
||||
|
||||
// parsersLock AND effectsLock must be locked before calling this function
|
||||
void OscirenderAudioProcessorEditor::codeDocumentTextInserted(const juce::String& newText, int insertIndex) {
|
||||
updateCodeDocument();
|
||||
|
@ -161,10 +201,18 @@ void OscirenderAudioProcessorEditor::codeDocumentTextDeleted(int startIndex, int
|
|||
updateCodeDocument();
|
||||
}
|
||||
|
||||
// parsersLock AND effectsLock must be locked before calling this function
|
||||
void OscirenderAudioProcessorEditor::updateCodeDocument() {
|
||||
int index = audioProcessor.getCurrentFileIndex();
|
||||
juce::String file = codeDocuments[index]->getAllContent();
|
||||
audioProcessor.updateFileBlock(index, std::make_shared<juce::MemoryBlock>(file.toRawUTF8(), file.getNumBytesAsUTF8() + 1));
|
||||
if (editingPerspective) {
|
||||
juce::String file = codeDocuments[0]->getAllContent();
|
||||
audioProcessor.perspectiveEffect->updateCode(file);
|
||||
} else {
|
||||
int originalIndex = audioProcessor.getCurrentFileIndex();
|
||||
int index = audioProcessor.getCurrentFileIndex();
|
||||
index++;
|
||||
juce::String file = codeDocuments[index]->getAllContent();
|
||||
audioProcessor.updateFileBlock(originalIndex, std::make_shared<juce::MemoryBlock>(file.toRawUTF8(), file.getNumBytesAsUTF8() + 1));
|
||||
}
|
||||
}
|
||||
|
||||
bool OscirenderAudioProcessorEditor::keyPressed(const juce::KeyPress& key) {
|
||||
|
|
|
@ -21,19 +21,25 @@ public:
|
|||
void removeCodeEditor(int index);
|
||||
void fileUpdated(juce::String fileName);
|
||||
void handleAsyncUpdate() override;
|
||||
|
||||
void editPerspectiveFunction(bool enabled);
|
||||
|
||||
std::atomic<bool> editingPerspective = false;
|
||||
private:
|
||||
OscirenderAudioProcessor& audioProcessor;
|
||||
|
||||
MainComponent main{audioProcessor, *this};
|
||||
LuaComponent lua{audioProcessor, *this};
|
||||
ObjComponent obj{audioProcessor, *this};
|
||||
EffectsComponent effects{audioProcessor};
|
||||
EffectsComponent effects{audioProcessor, *this};
|
||||
VolumeComponent volume{audioProcessor};
|
||||
std::vector<std::shared_ptr<juce::CodeDocument>> codeDocuments;
|
||||
std::vector<std::shared_ptr<juce::CodeEditorComponent>> codeEditors;
|
||||
juce::LuaTokeniser luaTokeniser;
|
||||
juce::XmlTokeniser xmlTokeniser;
|
||||
juce::ShapeButton collapseButton;
|
||||
std::shared_ptr<juce::CodeDocument> perspectiveCodeDocument = std::make_shared<juce::CodeDocument>();
|
||||
std::shared_ptr<juce::CodeEditorComponent> perspectiveCodeEditor = std::make_shared<juce::CodeEditorComponent>(*perspectiveCodeDocument, &luaTokeniser);
|
||||
|
||||
void codeDocumentTextInserted(const juce::String& newText, int insertIndex) override;
|
||||
void codeDocumentTextDeleted(int startIndex, int endIndex) override;
|
||||
|
|
|
@ -45,16 +45,19 @@ Vector2 PerspectiveEffect::apply(int index, Vector2 input, const std::vector<dou
|
|||
auto y = input.y;
|
||||
auto z = 0.0;
|
||||
|
||||
if (!defaultScript) {
|
||||
parser.setVariable("x", x);
|
||||
parser.setVariable("y", y);
|
||||
parser.setVariable("z", z);
|
||||
{
|
||||
juce::SpinLock::ScopedLockType lock(codeLock);
|
||||
if (!defaultScript) {
|
||||
parser->setVariable("x", x);
|
||||
parser->setVariable("y", y);
|
||||
parser->setVariable("z", z);
|
||||
|
||||
auto result = parser.run();
|
||||
if (result.size() >= 3) {
|
||||
x = result[0];
|
||||
y = result[1];
|
||||
z = result[2];
|
||||
auto result = parser->run();
|
||||
if (result.size() >= 3) {
|
||||
x = result[0];
|
||||
y = result[1];
|
||||
z = result[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,3 +90,15 @@ Vector2 PerspectiveEffect::apply(int index, Vector2 input, const std::vector<dou
|
|||
(1 - effectScale) * input.y + effectScale * (y3 * focalLength / (z3 - depth))
|
||||
);
|
||||
}
|
||||
|
||||
void PerspectiveEffect::updateCode(const juce::String& newCode) {
|
||||
juce::SpinLock::ScopedLockType lock(codeLock);
|
||||
defaultScript = newCode == DEFAULT_SCRIPT;
|
||||
code = newCode;
|
||||
parser = std::make_unique<LuaParser>(code);
|
||||
}
|
||||
|
||||
juce::String PerspectiveEffect::getCode() {
|
||||
juce::SpinLock::ScopedLockType lock(codeLock);
|
||||
return code;
|
||||
}
|
||||
|
|
|
@ -9,14 +9,17 @@ public:
|
|||
PerspectiveEffect();
|
||||
|
||||
Vector2 apply(int index, Vector2 input, const std::vector<double>& values, double sampleRate) override;
|
||||
void updateCode(const juce::String& newCode);
|
||||
juce::String getCode();
|
||||
|
||||
BooleanParameter* fixedRotateX = new BooleanParameter("Perspective Fixed Rotate X", "perspectiveFixedRotateX", false);
|
||||
BooleanParameter* fixedRotateY = new BooleanParameter("Perspective Fixed Rotate Y", "perspectiveFixedRotateY", false);
|
||||
BooleanParameter* fixedRotateZ = new BooleanParameter("Perspective Fixed Rotate Z", "perspectiveFixedRotateZ", false);
|
||||
private:
|
||||
const juce::String DEFAULT_SCRIPT = "return { x, y, z }";
|
||||
juce::MemoryBlock code{DEFAULT_SCRIPT.toRawUTF8(), DEFAULT_SCRIPT.getNumBytesAsUTF8() + 1};
|
||||
LuaParser parser{DEFAULT_SCRIPT};
|
||||
juce::String code = DEFAULT_SCRIPT;
|
||||
juce::SpinLock codeLock;
|
||||
std::unique_ptr<LuaParser> parser = std::make_unique<LuaParser>(code);
|
||||
bool defaultScript = true;
|
||||
|
||||
float currentRotateX = 0;
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
#include "EffectsListComponent.h"
|
||||
#include "SvgButton.h"
|
||||
#include "../PluginEditor.h"
|
||||
|
||||
EffectsListComponent::EffectsListComponent(DraggableListBox& lb, AudioEffectListBoxItemData& data, int rn, Effect& effect) : DraggableListBoxItem(lb, data, rn), effect(effect), audioProcessor(data.audioProcessor) {
|
||||
EffectsListComponent::EffectsListComponent(DraggableListBox& lb, AudioEffectListBoxItemData& data, int rn, Effect& effect) : DraggableListBoxItem(lb, data, rn), effect(effect), audioProcessor(data.audioProcessor), editor(data.editor) {
|
||||
auto parameters = effect.parameters;
|
||||
for (int i = 0; i < parameters.size(); i++) {
|
||||
std::shared_ptr<EffectComponent> effectComponent = std::make_shared<EffectComponent>(audioProcessor, effect, i, i == 0);
|
||||
|
@ -88,10 +89,14 @@ std::shared_ptr<juce::Component> EffectsListComponent::createComponent(EffectPar
|
|||
};
|
||||
return button;
|
||||
} else if (parameter->paramID == "depthScale") {
|
||||
std::shared_ptr<SvgButton> button = std::make_shared<SvgButton>(parameter->name, BinaryData::pencil_svg, "white");
|
||||
std::shared_ptr<SvgButton> button = std::make_shared<SvgButton>(parameter->name, BinaryData::pencil_svg, "white", "red");
|
||||
std::weak_ptr<SvgButton> weakButton = button;
|
||||
button->setEdgeIndent(5);
|
||||
button->onClick = [this] {
|
||||
|
||||
button->setToggleState(editor.editingPerspective, juce::dontSendNotification);
|
||||
button->onClick = [this, weakButton] {
|
||||
if (auto button = weakButton.lock()) {
|
||||
editor.editPerspectiveFunction(button->getToggleState());
|
||||
}
|
||||
};
|
||||
return button;
|
||||
}
|
||||
|
|
|
@ -7,12 +7,14 @@
|
|||
#include "ComponentList.h"
|
||||
|
||||
// Application-specific data container
|
||||
class OscirenderAudioProcessorEditor;
|
||||
struct AudioEffectListBoxItemData : public DraggableListBoxItemData
|
||||
{
|
||||
std::vector<std::shared_ptr<Effect>> data;
|
||||
OscirenderAudioProcessor& audioProcessor;
|
||||
OscirenderAudioProcessorEditor& editor;
|
||||
|
||||
AudioEffectListBoxItemData(OscirenderAudioProcessor& p) : audioProcessor(p) {}
|
||||
AudioEffectListBoxItemData(OscirenderAudioProcessor& p, OscirenderAudioProcessorEditor& editor) : audioProcessor(p), editor(editor) {}
|
||||
|
||||
int getNumItems() override {
|
||||
return data.size();
|
||||
|
@ -102,6 +104,7 @@ protected:
|
|||
juce::ListBox list;
|
||||
private:
|
||||
OscirenderAudioProcessor& audioProcessor;
|
||||
OscirenderAudioProcessorEditor& editor;
|
||||
|
||||
std::shared_ptr<juce::Component> createComponent(EffectParameter* parameter);
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue