kopia lustrzana https://github.com/jameshball/osci-render
Add non-editable perspective effect
rodzic
ee181b0276
commit
e3c2010917
|
@ -79,6 +79,17 @@ OscirenderAudioProcessor::OscirenderAudioProcessor()
|
||||||
delayEffect,
|
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)}
|
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(traceMax);
|
||||||
toggleableEffects.push_back(traceMin);
|
toggleableEffects.push_back(traceMin);
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "audio/DelayEffect.h"
|
#include "audio/DelayEffect.h"
|
||||||
#include "audio/PitchDetector.h"
|
#include "audio/PitchDetector.h"
|
||||||
#include "audio/WobbleEffect.h"
|
#include "audio/WobbleEffect.h"
|
||||||
|
#include "audio/PerspectiveEffect.h"
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
/**
|
/**
|
||||||
|
@ -122,7 +123,7 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return input;
|
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>(
|
std::shared_ptr<Effect> rotateY = std::make_shared<Effect>(
|
||||||
[this](int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
|
[this](int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
|
||||||
|
@ -137,7 +138,7 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return input;
|
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>(
|
std::shared_ptr<Effect> rotateZ = std::make_shared<Effect>(
|
||||||
[this](int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
|
[this](int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
|
||||||
|
@ -152,7 +153,7 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return input;
|
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>(
|
std::shared_ptr<Effect> rotateSpeed = std::make_shared<Effect>(
|
||||||
[this](int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
|
[this](int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
|
||||||
|
@ -162,10 +163,11 @@ public:
|
||||||
obj->setRotationSpeed(values[0]);
|
obj->setRotationSpeed(values[0]);
|
||||||
}
|
}
|
||||||
return input;
|
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<DelayEffect> delayEffect = std::make_shared<DelayEffect>();
|
||||||
|
std::shared_ptr<PerspectiveEffect> perspectiveEffect = std::make_shared<PerspectiveEffect>();
|
||||||
|
|
||||||
juce::SpinLock parsersLock;
|
juce::SpinLock parsersLock;
|
||||||
std::vector<std::shared_ptr<FileParser>> parsers;
|
std::vector<std::shared_ptr<FileParser>> parsers;
|
||||||
|
|
|
@ -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))
|
||||||
|
);
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
};
|
|
@ -28,11 +28,11 @@ void LuaParser::parse() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// only the audio thread runs this fuction
|
// only the audio thread runs this fuction
|
||||||
Vector2 LuaParser::draw() {
|
std::vector<float> LuaParser::run() {
|
||||||
Vector2 sample;
|
std::vector<float> values;
|
||||||
|
|
||||||
if (functionRef == -1) {
|
if (functionRef == -1) {
|
||||||
return sample;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
lua_pushnumber(L, step);
|
lua_pushnumber(L, step);
|
||||||
|
@ -60,29 +60,25 @@ Vector2 LuaParser::draw() {
|
||||||
DBG(error);
|
DBG(error);
|
||||||
functionRef = -1;
|
functionRef = -1;
|
||||||
} else if (lua_istable(L, -1)) {
|
} else if (lua_istable(L, -1)) {
|
||||||
// get the first element of the table
|
auto length = lua_rawlen(L, -1);
|
||||||
lua_pushinteger(L, 1);
|
|
||||||
lua_gettable(L, -2);
|
|
||||||
float x = lua_tonumber(L, -1);
|
|
||||||
lua_pop(L, 1);
|
|
||||||
|
|
||||||
// get the second element of the table
|
for (int i = 1; i <= length; i++) {
|
||||||
lua_pushinteger(L, 2);
|
lua_pushinteger(L, i);
|
||||||
lua_gettable(L, -2);
|
lua_gettable(L, -2);
|
||||||
float y = lua_tonumber(L, -1);
|
float value = lua_tonumber(L, -1);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
|
values.push_back(value);
|
||||||
sample = Vector2(x, y);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
|
|
||||||
step++;
|
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
|
// many threads can run this function
|
||||||
void LuaParser::setVariable(juce::String variableName, double value) {
|
void LuaParser::setVariable(juce::String variableName, double value) {
|
||||||
juce::SpinLock::ScopedLockType lock(variableLock);
|
juce::SpinLock::ScopedLockType lock(variableLock);
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "../shape/Vector2.h"
|
|
||||||
#include <JuceHeader.h>
|
#include <JuceHeader.h>
|
||||||
#include "../shape/Shape.h"
|
#include "../shape/Shape.h"
|
||||||
|
|
||||||
|
@ -9,7 +8,7 @@ public:
|
||||||
LuaParser(juce::String script);
|
LuaParser(juce::String script);
|
||||||
~LuaParser();
|
~LuaParser();
|
||||||
|
|
||||||
Vector2 draw();
|
std::vector<float> run();
|
||||||
void setVariable(juce::String variableName, double value);
|
void setVariable(juce::String variableName, double value);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -48,7 +48,11 @@ Vector2 FileParser::nextSample() {
|
||||||
juce::SpinLock::ScopedLockType scope(lock);
|
juce::SpinLock::ScopedLockType scope(lock);
|
||||||
|
|
||||||
if (lua != nullptr) {
|
if (lua != nullptr) {
|
||||||
return lua->draw();
|
auto values = lua->run();
|
||||||
|
if (values.size() < 2) {
|
||||||
|
return Vector2();
|
||||||
|
}
|
||||||
|
return Vector2(values[0], values[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,10 @@
|
||||||
file="Source/audio/EffectParameter.h"/>
|
file="Source/audio/EffectParameter.h"/>
|
||||||
<FILE id="uhyh7T" name="LuaEffect.cpp" compile="1" resource="0" file="Source/audio/LuaEffect.cpp"/>
|
<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="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 id="t2bsR8" name="PitchDetector.cpp" compile="1" resource="0"
|
||||||
file="Source/audio/PitchDetector.cpp"/>
|
file="Source/audio/PitchDetector.cpp"/>
|
||||||
<FILE id="rQC2gX" name="PitchDetector.h" compile="0" resource="0" file="Source/audio/PitchDetector.h"/>
|
<FILE id="rQC2gX" name="PitchDetector.h" compile="0" resource="0" file="Source/audio/PitchDetector.h"/>
|
||||||
|
|
Ładowanie…
Reference in New Issue