Add non-editable perspective effect

pull/170/head
James Ball 2023-07-21 17:42:29 +01:00
rodzic ee181b0276
commit e3c2010917
8 zmienionych plików z 125 dodań i 24 usunięć

Wyświetl plik

@ -79,6 +79,17 @@ OscirenderAudioProcessor::OscirenderAudioProcessor()
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)}
));
toggleableEffects.push_back(std::make_shared<Effect>(
perspectiveEffect,
std::vector<EffectParameter*>{
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),
}
));
toggleableEffects.push_back(traceMax);
toggleableEffects.push_back(traceMin);

Wyświetl plik

@ -20,6 +20,7 @@
#include "audio/DelayEffect.h"
#include "audio/PitchDetector.h"
#include "audio/WobbleEffect.h"
#include "audio/PerspectiveEffect.h"
//==============================================================================
/**
@ -122,7 +123,7 @@ public:
}
}
return input;
}, new EffectParameter("Rotate X", "rotateX", 1.0, -1.0, 1.0)
}, new EffectParameter("Rotate X", "objRotateX", 1.0, -1.0, 1.0)
);
std::shared_ptr<Effect> rotateY = std::make_shared<Effect>(
[this](int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
@ -137,7 +138,7 @@ public:
}
}
return input;
}, new EffectParameter("Rotate Y", "rotateY", 1.0, -1.0, 1.0)
}, new EffectParameter("Rotate Y", "objRotateY", 1.0, -1.0, 1.0)
);
std::shared_ptr<Effect> rotateZ = std::make_shared<Effect>(
[this](int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
@ -152,7 +153,7 @@ public:
}
}
return input;
}, new EffectParameter("Rotate Z", "rotateZ", 0.0, -1.0, 1.0)
}, new EffectParameter("Rotate Z", "objRotateZ", 0.0, -1.0, 1.0)
);
std::shared_ptr<Effect> rotateSpeed = std::make_shared<Effect>(
[this](int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
@ -162,10 +163,11 @@ public:
obj->setRotationSpeed(values[0]);
}
return input;
}, new EffectParameter("Rotate Speed", "rotateSpeed3D", 0.0, -1.0, 1.0)
}, new EffectParameter("Rotate Speed", "objRotateSpeed", 0.0, -1.0, 1.0)
);
std::shared_ptr<DelayEffect> delayEffect = std::make_shared<DelayEffect>();
std::shared_ptr<PerspectiveEffect> perspectiveEffect = std::make_shared<PerspectiveEffect>();
juce::SpinLock parsersLock;
std::vector<std::shared_ptr<FileParser>> parsers;

Wyświetl plik

@ -0,0 +1,61 @@
#include "PerspectiveEffect.h"
#include <numbers>
PerspectiveEffect::PerspectiveEffect() {}
Vector2 PerspectiveEffect::apply(int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
auto effectScale = values[0];
auto depth = 1.0 + (values[1] - 0.1) * 3;
auto rotateSpeed = linearSpeedToActualSpeed(values[2]);
auto baseRotateX = values[3] * std::numbers::pi;
auto baseRotateY = values[4] * std::numbers::pi;
auto baseRotateZ = values[5] * std::numbers::pi;
currentRotateX += baseRotateX * rotateSpeed;
currentRotateY += baseRotateY * rotateSpeed;
currentRotateZ += baseRotateZ * rotateSpeed;
auto x = input.x;
auto y = input.y;
auto z = 0.0;
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 rotateX = baseRotateX + currentRotateX;
auto rotateY = baseRotateY + currentRotateY;
auto rotateZ = baseRotateZ + currentRotateZ;
// rotate around x-axis
double cosValue = std::cos(rotateX);
double sinValue = std::sin(rotateX);
double y2 = cosValue * y - sinValue * z;
double z2 = sinValue * y + cosValue * z;
// rotate around y-axis
cosValue = std::cos(rotateY);
sinValue = std::sin(rotateY);
double x2 = cosValue * x + sinValue * z2;
double z3 = -sinValue * x + cosValue * z2;
// rotate around z-axis
cosValue = cos(rotateZ);
sinValue = sin(rotateZ);
double x3 = cosValue * x2 - sinValue * y2;
double y3 = sinValue * x2 + cosValue * y2;
// perspective projection
auto focalLength = 1.0;
return Vector2(
(1 - effectScale) * input.x + effectScale * (x3 * focalLength / (z3 - depth)),
(1 - effectScale) * input.y + effectScale * (y3 * focalLength / (z3 - depth))
);
}

Wyświetl plik

@ -0,0 +1,24 @@
#pragma once
#include "EffectApplication.h"
#include "../shape/Vector2.h"
#include "../audio/Effect.h"
#include "../lua/LuaParser.h"
class PerspectiveEffect : public EffectApplication {
public:
PerspectiveEffect();
Vector2 apply(int index, Vector2 input, const std::vector<double>& values, double sampleRate) override;
private:
const juce::String DEFAULT_SCRIPT = "return { x, y, z }";
juce::MemoryBlock code{DEFAULT_SCRIPT.toRawUTF8(), DEFAULT_SCRIPT.getNumBytesAsUTF8() + 1};
LuaParser parser{DEFAULT_SCRIPT};
float currentRotateX = 0;
float currentRotateY = 0;
float currentRotateZ = 0;
float linearSpeedToActualSpeed(float rotateSpeed) {
return (std::exp(3 * juce::jmin(10.0f, std::abs(rotateSpeed))) - 1) / 50000.0;
}
};

Wyświetl plik

@ -28,11 +28,11 @@ void LuaParser::parse() {
}
// only the audio thread runs this fuction
Vector2 LuaParser::draw() {
Vector2 sample;
std::vector<float> LuaParser::run() {
std::vector<float> values;
if (functionRef == -1) {
return sample;
return values;
}
lua_pushnumber(L, step);
@ -60,29 +60,25 @@ Vector2 LuaParser::draw() {
DBG(error);
functionRef = -1;
} else if (lua_istable(L, -1)) {
// get the first element of the table
lua_pushinteger(L, 1);
lua_gettable(L, -2);
float x = lua_tonumber(L, -1);
lua_pop(L, 1);
auto length = lua_rawlen(L, -1);
// get the second element of the table
lua_pushinteger(L, 2);
lua_gettable(L, -2);
float y = lua_tonumber(L, -1);
lua_pop(L, 1);
sample = Vector2(x, y);
for (int i = 1; i <= length; i++) {
lua_pushinteger(L, i);
lua_gettable(L, -2);
float value = lua_tonumber(L, -1);
lua_pop(L, 1);
values.push_back(value);
}
}
lua_pop(L, 1);
step++;
return sample;
return values;
}
// this CANNOT run at the same time as draw()
// this CANNOT run at the same time as run()
// many threads can run this function
void LuaParser::setVariable(juce::String variableName, double value) {
juce::SpinLock::ScopedLockType lock(variableLock);

Wyświetl plik

@ -1,5 +1,4 @@
#pragma once
#include "../shape/Vector2.h"
#include <JuceHeader.h>
#include "../shape/Shape.h"
@ -9,7 +8,7 @@ public:
LuaParser(juce::String script);
~LuaParser();
Vector2 draw();
std::vector<float> run();
void setVariable(juce::String variableName, double value);
private:

Wyświetl plik

@ -48,7 +48,11 @@ Vector2 FileParser::nextSample() {
juce::SpinLock::ScopedLockType scope(lock);
if (lua != nullptr) {
return lua->draw();
auto values = lua->run();
if (values.size() < 2) {
return Vector2();
}
return Vector2(values[0], values[1]);
}
}

Wyświetl plik

@ -54,6 +54,10 @@
file="Source/audio/EffectParameter.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="QBWW9w" name="PerspectiveEffect.cpp" compile="1" resource="0"
file="Source/audio/PerspectiveEffect.cpp"/>
<FILE id="h0dMim" name="PerspectiveEffect.h" compile="0" resource="0"
file="Source/audio/PerspectiveEffect.h"/>
<FILE id="t2bsR8" name="PitchDetector.cpp" compile="1" resource="0"
file="Source/audio/PitchDetector.cpp"/>
<FILE id="rQC2gX" name="PitchDetector.h" compile="0" resource="0" file="Source/audio/PitchDetector.h"/>