Complete infinite lua slider support

pull/170/head
James Ball 2023-07-04 14:58:36 +01:00
rodzic 2ec4eaba52
commit b117aae5f5
14 zmienionych plików z 168 dodań i 28 usunięć

Wyświetl plik

@ -1,7 +1,7 @@
#include "LuaComponent.h"
#include "PluginEditor.h"
LuaComponent::LuaComponent(OscirenderAudioProcessor& p, OscirenderAudioProcessorEditor& editor) : audioProcessor(p), pluginEditor(editor), slidersModel(sliders) {
LuaComponent::LuaComponent(OscirenderAudioProcessor& p, OscirenderAudioProcessorEditor& editor) : audioProcessor(p), pluginEditor(editor), slidersModel(sliders, p) {
setText(".lua File Settings");
sliders.setModel(&slidersModel);

Wyświetl plik

@ -14,6 +14,9 @@
#include "audio/VectorCancellingEffect.h"
#include "audio/DistortEffect.h"
#include "audio/SmoothEffect.h"
#include "audio/BitCrushEffect.h"
#include "audio/BulgeEffect.h"
#include "audio/LuaEffect.h"
//==============================================================================
OscirenderAudioProcessor::OscirenderAudioProcessor()
@ -38,6 +41,10 @@ OscirenderAudioProcessor::OscirenderAudioProcessor()
allEffects.push_back(std::make_shared<Effect>(std::make_unique<DistortEffect>(true), "Vertical shift", "verticalDistort"));
allEffects.push_back(std::make_shared<Effect>(std::make_unique<DistortEffect>(false), "Horizontal shift", "horizontalDistort"));
allEffects.push_back(std::make_shared<Effect>(std::make_unique<SmoothEffect>(), "Smoothing", "smoothing"));
for (int i = 0; i < 5; i++) {
addLuaSlider();
}
}
OscirenderAudioProcessor::~OscirenderAudioProcessor()
@ -145,6 +152,26 @@ bool OscirenderAudioProcessor::isBusesLayoutSupported (const BusesLayout& layout
}
#endif
void OscirenderAudioProcessor::addLuaSlider() {
juce::String sliderName = "";
int sliderNum = luaEffects.size() + 1;
while (sliderNum > 0) {
int mod = (sliderNum - 1) % 26;
sliderName = (char)(mod + 'A') + sliderName;
sliderNum = (sliderNum - mod) / 26;
}
luaEffects.push_back(std::make_shared<Effect>(std::make_unique<LuaEffect>(sliderName, *this), "Lua " + sliderName, "lua" + sliderName));
}
void OscirenderAudioProcessor::updateLuaValues() {
Vector2 vector;
for (auto& effect : luaEffects) {
effect->apply(0, vector);
}
}
void OscirenderAudioProcessor::updateAngleDelta() {
auto cyclesPerSample = frequency / currentSampleRate;
thetaDelta = cyclesPerSample * 2.0 * juce::MathConstants<double>::pi;
@ -238,6 +265,7 @@ void OscirenderAudioProcessor::openFile(int index) {
producer->setSource(parsers[index], index);
currentFile = index;
invalidateFrameBuffer = true;
updateLuaValues();
}
void OscirenderAudioProcessor::changeCurrentFile(int index) {
@ -257,6 +285,10 @@ int OscirenderAudioProcessor::getCurrentFileIndex() {
return currentFile;
}
std::shared_ptr<FileParser> OscirenderAudioProcessor::getCurrentFileParser() {
return parsers[currentFile];
}
juce::File OscirenderAudioProcessor::getCurrentFile() {
return files[currentFile];
}

Wyświetl plik

@ -14,8 +14,6 @@
#include "parser/FrameProducer.h"
#include "parser/FrameConsumer.h"
#include "audio/Effect.h"
#include "audio/BitCrushEffect.h"
#include "audio/BulgeEffect.h"
//==============================================================================
/**
@ -72,8 +70,7 @@ public:
std::vector<std::shared_ptr<Effect>> allEffects;
std::shared_ptr<std::vector<std::shared_ptr<Effect>>> enabledEffects = std::make_shared<std::vector<std::shared_ptr<Effect>>>();
BitCrushEffect bitCrushEffect = BitCrushEffect();
BulgeEffect bulgeEffect = BulgeEffect();
std::vector<std::shared_ptr<Effect>> luaEffects;
std::vector<std::shared_ptr<FileParser>> parsers;
std::vector<std::shared_ptr<juce::MemoryBlock>> fileBlocks;
@ -82,6 +79,8 @@ public:
std::unique_ptr<FrameProducer> producer;
void addLuaSlider();
void updateLuaValues();
void updateAngleDelta();
void addFrame(std::vector<std::unique_ptr<Shape>> frame, int fileIndex) override;
void enableEffect(std::shared_ptr<Effect> effect);
@ -94,6 +93,7 @@ public:
void openFile(int index);
void changeCurrentFile(int index);
int getCurrentFileIndex();
std::shared_ptr<FileParser> getCurrentFileParser();
juce::File getCurrentFile();
juce::File getFile(int index);
std::shared_ptr<juce::MemoryBlock> getFileBlock(int index);
@ -116,6 +116,7 @@ private:
void updateFrame();
void updateLengthIncrement();
void syncLuaSliders();
const double MIN_LENGTH_INCREMENT = 0.000001;

Wyświetl plik

@ -0,0 +1,14 @@
#include "LuaEffect.h"
#include "../lua/LuaParser.h"
Vector2 LuaEffect::apply(int index, Vector2 input, double value, double frequency, double sampleRate) {
int fileIndex = audioProcessor.getCurrentFileIndex();
if (fileIndex == -1) {
return input;
}
std::shared_ptr<LuaParser> parser = audioProcessor.getCurrentFileParser()->getLua();
if (parser != nullptr) {
parser->setVariable("slider_" + name.toLowerCase(), value);
}
return input;
}

Wyświetl plik

@ -0,0 +1,15 @@
#pragma once
#include "EffectApplication.h"
#include "../shape/Vector2.h"
#include "../audio/Effect.h"
#include "../PluginProcessor.h"
class LuaEffect : public EffectApplication {
public:
LuaEffect(juce::String name, OscirenderAudioProcessor& p) : audioProcessor(p), name(name) {};
Vector2 apply(int index, Vector2 input, double value, double frequency, double sampleRate) override;
private:
OscirenderAudioProcessor& audioProcessor;
juce::String name;
};

Wyświetl plik

@ -1,17 +1,28 @@
#include "EffectComponent.h"
EffectComponent::EffectComponent(double min, double max, double step, double value, juce::String name, juce::String id) : name(name), id(id) {
componentSetup();
slider.setRange(min, max, step);
slider.setValue(value, juce::dontSendNotification);
}
EffectComponent::EffectComponent(double min, double max, double step, Effect& effect) : name(effect.getName()), id(effect.getId()) {
componentSetup();
slider.setRange(min, max, step);
slider.setValue(effect.getValue(), juce::dontSendNotification);
}
void EffectComponent::componentSetup() {
addAndMakeVisible(slider);
addAndMakeVisible(selected);
slider.setSliderStyle(juce::Slider::LinearHorizontal);
slider.setTextBoxStyle(juce::Slider::TextBoxRight, false, 90, slider.getTextBoxHeight());
slider.setRange(min, max, step);
slider.setValue(value, juce::dontSendNotification);
selected.setToggleState(false, juce::dontSendNotification);
selected.setToggleState(false, juce::dontSendNotification);
}
EffectComponent::~EffectComponent() {}
void EffectComponent::resized() {

Wyświetl plik

@ -7,6 +7,7 @@
class EffectComponent : public juce::Component {
public:
EffectComponent(double min, double max, double step, double value, juce::String name, juce::String id);
EffectComponent(double min, double max, double step, Effect& effect);
~EffectComponent();
void resized() override;
@ -20,6 +21,7 @@ public:
juce::ToggleButton selected;
private:
void componentSetup();
bool hideCheckbox = false;
juce::Rectangle<int> textBounds;

Wyświetl plik

@ -1,17 +1,14 @@
#include "LuaListComponent.h"
LuaListComponent::LuaListComponent(int sliderNum) {
juce::String sliderName = "";
sliderNum++;
while (sliderNum > 0) {
int mod = (sliderNum - 1) % 26;
sliderName = (char)(mod + 'A') + sliderName;
sliderNum = (sliderNum - mod) / 26;
}
effectComponent = std::make_shared<EffectComponent>(0.0, 1.0, 0.01, 0, "Lua " + sliderName, "lua" + sliderName);
LuaListComponent::LuaListComponent(OscirenderAudioProcessor& p, Effect& effect) {
effectComponent = std::make_shared<EffectComponent>(0.0, 1.0, 0.01, effect);
effectComponent->setHideCheckbox(true);
effectComponent->slider.onValueChange = [this, &effect, &p] {
effect.setValue(effectComponent->slider.getValue());
effect.apply(0, Vector2());
};
addAndMakeVisible(*effectComponent);
}
@ -24,23 +21,23 @@ void LuaListComponent::resized() {
void paintListBoxItem(int sliderNum, juce::Graphics& g, int width, int height, bool rowIsSelected) {}
int LuaListBoxModel::getNumRows() {
return numSliders + 1;
return audioProcessor.luaEffects.size() + 1;
}
void LuaListBoxModel::paintListBoxItem(int rowNumber, juce::Graphics& g, int width, int height, bool rowIsSelected) {}
juce::Component* LuaListBoxModel::refreshComponentForRow(int sliderNum, bool isRowSelected, juce::Component *existingComponentToUpdate) {
if (sliderNum < getNumRows() - 1) {
juce::Component* LuaListBoxModel::refreshComponentForRow(int rowNum, bool isRowSelected, juce::Component *existingComponentToUpdate) {
if (rowNum < getNumRows() - 1) {
std::unique_ptr<LuaListComponent> item(dynamic_cast<LuaListComponent*>(existingComponentToUpdate));
if (juce::isPositiveAndBelow(sliderNum, getNumRows())) {
item = std::make_unique<LuaListComponent>(sliderNum);
if (juce::isPositiveAndBelow(rowNum, getNumRows())) {
item = std::make_unique<LuaListComponent>(audioProcessor, *audioProcessor.luaEffects[rowNum]);
}
return item.release();
} else {
std::unique_ptr<juce::TextButton> item(dynamic_cast<juce::TextButton*>(existingComponentToUpdate));
item = std::make_unique<juce::TextButton>("Add");
item = std::make_unique<juce::TextButton>("+");
item->onClick = [this]() {
numSliders++;
audioProcessor.addLuaSlider();
listBox.updateContent();
};
return item.release();

Wyświetl plik

@ -7,7 +7,7 @@
class LuaListComponent : public juce::Component
{
public:
LuaListComponent(int sliderNum);
LuaListComponent(OscirenderAudioProcessor& p, Effect& effect);
~LuaListComponent();
void resized() override;
@ -21,7 +21,7 @@ private:
class LuaListBoxModel : public juce::ListBoxModel
{
public:
LuaListBoxModel(juce::ListBox& lb) : listBox(lb) {}
LuaListBoxModel(juce::ListBox& lb, OscirenderAudioProcessor& p) : listBox(lb), audioProcessor(p) {}
int getNumRows() override;
void paintListBoxItem(int rowNumber, juce::Graphics& g, int width, int height, bool rowIsSelected) override;
@ -30,4 +30,5 @@ public:
private:
int numSliders = 5;
juce::ListBox& listBox;
OscirenderAudioProcessor& audioProcessor;
};

Wyświetl plik

@ -27,6 +27,7 @@ void LuaParser::parse() {
}
}
// only the audio thread runs this fuction
Vector2 LuaParser::draw() {
Vector2 sample;
@ -36,6 +37,22 @@ Vector2 LuaParser::draw() {
lua_pushnumber(L, step);
lua_setglobal(L, "step");
// this CANNOT run at the same time as setVariable
if (updateVariables) {
bool expected = false;
if (accessingVariables.compare_exchange_strong(expected, true)) {
for (int i = 0; i < variableNames.size(); i++) {
lua_pushnumber(L, variables[i]);
lua_setglobal(L, variableNames[i].toUTF8());
DBG("set " + variableNames[i] + " to " + juce::String(variables[i]));
}
variableNames.clear();
variables.clear();
accessingVariables = false;
updateVariables = false;
}
}
lua_geti(L, LUA_REGISTRYINDEX, functionRef);
@ -66,3 +83,18 @@ Vector2 LuaParser::draw() {
return sample;
}
// this CANNOT run at the same time as draw()
// many threads can run this function
bool LuaParser::setVariable(juce::String variableName, double value) {
bool expected = false;
// this is very unlikely to fail, and if it does, it's not a big deal
if (accessingVariables.compare_exchange_strong(expected, true)) {
variableNames.push_back(variableName);
variables.push_back(value);
accessingVariables = false;
updateVariables = true;
return true;
}
return false;
}

Wyświetl plik

@ -10,10 +10,17 @@ public:
~LuaParser();
Vector2 draw();
bool setVariable(juce::String variableName, double value);
private:
void parse();
int functionRef = -1;
long step = 1;
lua_State* L;
juce::String script;
std::atomic<bool> updateVariables = false;
std::atomic<bool> accessingVariables = false;
std::vector<juce::String> variableNames;
std::vector<double> variables;
};

Wyświetl plik

@ -67,3 +67,23 @@ void FileParser::disable() {
void FileParser::enable() {
active = true;
}
std::shared_ptr<WorldObject> FileParser::getObject() {
return object;
}
std::shared_ptr<Camera> FileParser::getCamera() {
return camera;
}
std::shared_ptr<SvgParser> FileParser::getSvg() {
return svg;
}
std::shared_ptr<TextParser> FileParser::getText() {
return text;
}
std::shared_ptr<LuaParser> FileParser::getLua() {
return lua;
}

Wyświetl plik

@ -20,6 +20,12 @@ public:
void disable() override;
void enable() override;
std::shared_ptr<WorldObject> getObject();
std::shared_ptr<Camera> getCamera();
std::shared_ptr<SvgParser> getSvg();
std::shared_ptr<TextParser> getText();
std::shared_ptr<LuaParser> getLua();
private:
bool active = true;
bool sampleSource = false;

Wyświetl plik

@ -113,6 +113,8 @@
file="Source/audio/EffectApplication.cpp"/>
<FILE id="MIYJ9y" name="EffectApplication.h" compile="0" resource="0"
file="Source/audio/EffectApplication.h"/>
<FILE id="uhyh7T" name="LuaEffect.cpp" compile="1" resource="0" file="Source/audio/LuaEffect.cpp"/>
<FILE id="jqDcZq" name="LuaEffect.h" compile="0" resource="0" file="Source/audio/LuaEffect.h"/>
<FILE id="PbbNqz" name="RotateEffect.cpp" compile="1" resource="0"
file="Source/audio/RotateEffect.cpp"/>
<FILE id="tUwNZV" name="RotateEffect.h" compile="0" resource="0" file="Source/audio/RotateEffect.h"/>