kopia lustrzana https://github.com/jameshball/osci-render
Merge develop
commit
8fa4034789
|
|
@ -1 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M16 16H8.9L11 13.9L7 10L9.8 7.2L13.9 11.1L16 8.9V16M5 21H19C20.1 21 21 20.1 21 19V5C21 3.9 20.1 3 19 3H5C3.9 3 3 3.9 3 5V19C3 20.1 3.9 21 5 21M5 5H19V19H5V5Z" /></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19.59,7L12,14.59L6.41,9H11V7H3V15H5V10.41L12,17.41L21,8.41" /></svg>
|
||||
|
Przed Szerokość: | Wysokość: | Rozmiar: 236 B Po Szerokość: | Wysokość: | Rozmiar: 138 B |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M13.41,19.31L16.59,22.5L18,21.07L14.83,17.9M15.54,11.53H15.53L12,15.07L8.47,11.53H8.46V11.53C7.56,10.63 7,9.38 7,8A5,5 0 0,1 12,3A5,5 0 0,1 17,8C17,9.38 16.44,10.63 15.54,11.53M16.9,13C18.2,11.73 19,9.96 19,8A7,7 0 0,0 12,1A7,7 0 0,0 5,8C5,9.96 5.81,11.73 7.1,13V13L10.59,16.5L6,21.07L7.41,22.5L16.9,13Z" /></svg>
|
||||
|
Po Szerokość: | Wysokość: | Rozmiar: 382 B |
|
|
@ -112,6 +112,9 @@ CommonPluginEditor::~CommonPluginEditor() {
|
|||
}
|
||||
|
||||
bool CommonPluginEditor::keyPressed(const juce::KeyPress& key) {
|
||||
// If we're not accepting special keys, end early
|
||||
if (!audioProcessor.getAcceptsKeys()) return false;
|
||||
|
||||
if (key.getModifiers().isCommandDown() && key.getModifiers().isShiftDown() && key.getKeyCode() == 'S') {
|
||||
saveProjectAs();
|
||||
} else if (key.getModifiers().isCommandDown() && key.getKeyCode() == 'S') {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ CommonAudioProcessor::CommonAudioProcessor(const BusesProperties& busesPropertie
|
|||
: AudioProcessor(busesProperties)
|
||||
#endif
|
||||
{
|
||||
|
||||
if (!applicationFolder.exists()) {
|
||||
applicationFolder.createDirectory();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -153,6 +153,12 @@ public:
|
|||
#else
|
||||
"ffmpeg";
|
||||
#endif
|
||||
void setAcceptsKeys(bool shouldAcceptKeys) {
|
||||
setGlobalValue("acceptsAllKeys", shouldAcceptKeys);
|
||||
}
|
||||
bool getAcceptsKeys() {
|
||||
return getGlobalBoolValue("acceptsAllKeys", juce::JUCEApplicationBase::isStandaloneApp());
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
|
|
|
|||
|
|
@ -11,10 +11,13 @@
|
|||
#include "PluginEditor.h"
|
||||
#include "audio/BitCrushEffect.h"
|
||||
#include "audio/BulgeEffect.h"
|
||||
#include "audio/TwistEffect.h"
|
||||
#include "audio/DistortEffect.h"
|
||||
#include "audio/KaleidoscopeEffect.h"
|
||||
#include "audio/MultiplexEffect.h"
|
||||
#include "audio/SmoothEffect.h"
|
||||
#include "audio/WobbleEffect.h"
|
||||
#include "audio/DashedLineEffect.h"
|
||||
#include "audio/VectorCancellingEffect.h"
|
||||
#include "audio/ScaleEffect.h"
|
||||
#include "audio/RotateEffect.h"
|
||||
|
|
@ -34,41 +37,28 @@ OscirenderAudioProcessor::OscirenderAudioProcessor() : CommonAudioProcessor(Buse
|
|||
// locking isn't necessary here because we are in the constructor
|
||||
|
||||
toggleableEffects.push_back(BitCrushEffect().build());
|
||||
|
||||
toggleableEffects.push_back(BulgeEffect().build());
|
||||
toggleableEffects.push_back(MultiplexEffect().build());
|
||||
toggleableEffects.push_back(KaleidoscopeEffect().build());
|
||||
toggleableEffects.push_back(BounceEffect().build());
|
||||
toggleableEffects.push_back(VectorCancellingEffect().build());
|
||||
{
|
||||
auto scaleEffect = ScaleEffectApp().build();
|
||||
booleanParameters.push_back(scaleEffect->linked);
|
||||
toggleableEffects.push_back(scaleEffect);
|
||||
}
|
||||
{
|
||||
auto distortEffect = DistortEffect().build();
|
||||
booleanParameters.push_back(distortEffect->linked);
|
||||
toggleableEffects.push_back(distortEffect);
|
||||
}
|
||||
toggleableEffects.push_back(RippleEffectApp().build());
|
||||
toggleableEffects.push_back(RotateEffectApp().build());
|
||||
toggleableEffects.push_back(TranslateEffectApp().build());
|
||||
toggleableEffects.push_back(SwirlEffectApp().build());
|
||||
|
||||
toggleableEffects.push_back(SmoothEffect().build());
|
||||
{
|
||||
auto wobble = std::make_shared<osci::Effect>(
|
||||
wobbleEffect,
|
||||
std::vector<osci::EffectParameter*>{
|
||||
new osci::EffectParameter("Wobble Amount", "Adds a sine wave of the prominent frequency in the audio currently playing. The sine wave's frequency is slightly offset to create a subtle 'wobble' in the image. Increasing the slider increases the strength of the wobble.", "wobble", VERSION_HINT, 0.3, 0.0, 1.0),
|
||||
new osci::EffectParameter("Wobble Phase", "Controls the phase of the wobble.", "wobblePhase", VERSION_HINT, 0.0, -1.0, 1.0, 0.0001f, osci::LfoType::Sawtooth, 1.0f),
|
||||
});
|
||||
wobble->setName("Wobble");
|
||||
wobble->setIcon(BinaryData::wobble_svg);
|
||||
toggleableEffects.push_back(wobble);
|
||||
}
|
||||
toggleableEffects.push_back(WobbleEffect(*this).build());
|
||||
toggleableEffects.push_back(DelayEffect().build());
|
||||
toggleableEffects.push_back(DashedLineEffect().build());
|
||||
toggleableEffects.push_back(DashedLineEffect(*this).build());
|
||||
toggleableEffects.push_back(TwistEffect().build());
|
||||
|
||||
auto scaleEffect = ScaleEffectApp().build();
|
||||
booleanParameters.push_back(scaleEffect->linked);
|
||||
toggleableEffects.push_back(scaleEffect);
|
||||
|
||||
auto distortEffect = DistortEffect().build();
|
||||
booleanParameters.push_back(distortEffect->linked);
|
||||
toggleableEffects.push_back(distortEffect);
|
||||
|
||||
custom->setIcon(BinaryData::lua_svg);
|
||||
toggleableEffects.push_back(custom);
|
||||
|
|
|
|||
|
|
@ -16,14 +16,12 @@
|
|||
#include "UGen/Env.h"
|
||||
#include "UGen/ugen_JuceEnvelopeComponent.h"
|
||||
#include "audio/CustomEffect.h"
|
||||
#include "audio/DashedLineEffect.h"
|
||||
#include "audio/DelayEffect.h"
|
||||
#include "audio/PerspectiveEffect.h"
|
||||
#include "audio/PublicSynthesiser.h"
|
||||
#include "audio/SampleRateManager.h"
|
||||
#include "audio/ShapeSound.h"
|
||||
#include "audio/ShapeVoice.h"
|
||||
#include "audio/WobbleEffect.h"
|
||||
#include "obj/ObjectServer.h"
|
||||
|
||||
#if (JUCE_MAC || JUCE_WINDOWS) && OSCI_PREMIUM
|
||||
|
|
@ -90,8 +88,6 @@ public:
|
|||
|
||||
std::shared_ptr<DelayEffect> delayEffect = std::make_shared<DelayEffect>();
|
||||
|
||||
std::shared_ptr<DashedLineEffect> dashedLineEffect = std::make_shared<DashedLineEffect>();
|
||||
|
||||
std::function<void(int, juce::String, juce::String)> errorCallback = [this](int lineNum, juce::String fileName, juce::String error) { notifyErrorListeners(lineNum, fileName, error); };
|
||||
std::shared_ptr<CustomEffect> customEffect = std::make_shared<CustomEffect>(errorCallback, luaValues);
|
||||
std::shared_ptr<osci::Effect> custom = std::make_shared<osci::Effect>(
|
||||
|
|
@ -103,7 +99,7 @@ public:
|
|||
perspectiveEffect,
|
||||
std::vector<osci::EffectParameter*>{
|
||||
new osci::EffectParameter("Perspective", "Controls the strength of the 3D perspective projection.", "perspectiveStrength", VERSION_HINT, 1.0, 0.0, 1.0),
|
||||
new osci::EffectParameter("Focal Length", "Controls the focal length of the 3D perspective effect. A higher focal length makes the image look more flat, and a lower focal length makes the image look more 3D.", "perspectiveFocalLength", VERSION_HINT, 2.0, 0.0, 10.0),
|
||||
new osci::EffectParameter("FOV", "Controls the camera's field of view in degrees. A lower field of view makes the image look more flat, and a higher field of view makes the image look more 3D.", "perspectiveFov", VERSION_HINT, 50.0, 5.0, 130.0),
|
||||
});
|
||||
|
||||
osci::BooleanParameter* midiEnabled = new osci::BooleanParameter("MIDI Enabled", "midiEnabled", VERSION_HINT, false, "Enable MIDI input for the synth. If disabled, the synth will play a constant tone, as controlled by the frequency slider.");
|
||||
|
|
@ -172,8 +168,6 @@ public:
|
|||
|
||||
std::atomic<double> animationFrame = 0.f;
|
||||
|
||||
std::shared_ptr<WobbleEffect> wobbleEffect = std::make_shared<WobbleEffect>(*this);
|
||||
|
||||
const double FONT_SIZE = 1.0f;
|
||||
juce::Font font = juce::Font(juce::Font::getDefaultSansSerifFontName(), FONT_SIZE, juce::Font::plain);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,118 +1,4 @@
|
|||
#include <JuceHeader.h>
|
||||
#include "obj/Camera.h"
|
||||
#include "mathter/Common/Approx.hpp"
|
||||
|
||||
class FrustumTest : public juce::UnitTest {
|
||||
public:
|
||||
FrustumTest() : juce::UnitTest("Frustum Culling") {}
|
||||
|
||||
void runTest() override {
|
||||
double focalLength = 1;
|
||||
|
||||
Camera camera;
|
||||
camera.setFocalLength(focalLength);
|
||||
Vec3 position = Vec3(0, 0, -focalLength);
|
||||
camera.setPosition(position);
|
||||
Frustum frustum = camera.getFrustum();
|
||||
|
||||
beginTest("Focal Plane Frustum In-Bounds");
|
||||
|
||||
// Focal plane is at z = 0
|
||||
Vec3 vecs[] = {
|
||||
Vec3(0, 0, 0), Vec3(0, 0, 0),
|
||||
Vec3(1, 1, 0), Vec3(1, 1, 0),
|
||||
Vec3(-1, -1, 0), Vec3(-1, -1, 0),
|
||||
Vec3(1, -1, 0), Vec3(1, -1, 0),
|
||||
Vec3(-1, 1, 0), Vec3(-1, 1, 0),
|
||||
Vec3(0.5, 0.5, 0), Vec3(0.5, 0.5, 0),
|
||||
};
|
||||
|
||||
testFrustumClippedEqualsExpected(vecs, camera, 6);
|
||||
|
||||
beginTest("Focal Plane Frustum Out-Of-Bounds");
|
||||
|
||||
// Focal plane is at z = 0
|
||||
Vec3 vecs2[] = {
|
||||
Vec3(1.1, 1.1, 0), Vec3(1, 1, 0),
|
||||
Vec3(-1.1, -1.1, 0), Vec3(-1, -1, 0),
|
||||
Vec3(1.1, -1.1, 0), Vec3(1, -1, 0),
|
||||
Vec3(-1.1, 1.1, 0), Vec3(-1, 1, 0),
|
||||
Vec3(1.1, 0.5, 0), Vec3(1, 0.5, 0),
|
||||
Vec3(-1.1, 0.5, 0), Vec3(-1, 0.5, 0),
|
||||
Vec3(0.5, -1.1, 0), Vec3(0.5, -1, 0),
|
||||
Vec3(0.5, 1.1, 0), Vec3(0.5, 1, 0),
|
||||
Vec3(10, 10, 0), Vec3(1, 1, 0),
|
||||
Vec3(-10, -10, 0), Vec3(-1, -1, 0),
|
||||
Vec3(10, -10, 0), Vec3(1, -1, 0),
|
||||
Vec3(-10, 10, 0), Vec3(-1, 1, 0),
|
||||
};
|
||||
|
||||
testFrustumClippedEqualsExpected(vecs2, camera, 12);
|
||||
|
||||
beginTest("Behind Camera Out-Of-Bounds");
|
||||
|
||||
double minZWorldCoords = -focalLength + camera.getFrustum().nearDistance;
|
||||
|
||||
Vec3 vecs3[] = {
|
||||
Vec3(0, 0, -focalLength), Vec3(0, 0, minZWorldCoords),
|
||||
Vec3(0, 0, -100), Vec3(0, 0, minZWorldCoords),
|
||||
Vec3(0.5, 0.5, -focalLength), Vec3(0.1, 0.1, minZWorldCoords),
|
||||
Vec3(10, -10, -focalLength), Vec3(0.1, -0.1, minZWorldCoords),
|
||||
Vec3(-0.5, 0.5, -100), Vec3(-0.1, 0.1, minZWorldCoords),
|
||||
Vec3(-10, 10, -100), Vec3(-0.1, 0.1, minZWorldCoords),
|
||||
};
|
||||
|
||||
testFrustumClippedEqualsExpected(vecs3, camera, 6);
|
||||
|
||||
beginTest("3D Point Out-Of-Bounds");
|
||||
|
||||
Vec3 vecs4[] = {
|
||||
Vec3(1, 1, -0.1),
|
||||
Vec3(-1, -1, -0.1),
|
||||
Vec3(1, -1, -0.1),
|
||||
Vec3(-1, 1, -0.1),
|
||||
Vec3(0.5, 0.5, minZWorldCoords),
|
||||
};
|
||||
|
||||
testFrustumClipOccurs(vecs4, camera, 5);
|
||||
}
|
||||
|
||||
Vec3 project(Vec3& p, double focalLength) {
|
||||
return Vec3(
|
||||
p.x * focalLength / p.z,
|
||||
p.y * focalLength / p.z,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
juce::String vec3ToString(Vec3& p) {
|
||||
return "(" + juce::String(p.x) + ", " + juce::String(p.y) + ", " + juce::String(p.z) + ")";
|
||||
}
|
||||
|
||||
juce::String errorMessage(Vec3& actual, Vec3& expected) {
|
||||
return "Expected: " + vec3ToString(expected) + ", Actual: " + vec3ToString(actual);
|
||||
}
|
||||
|
||||
void testFrustumClippedEqualsExpected(Vec3 vecs[], Camera& camera, int length) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
Vec3 p = vecs[2 * i];
|
||||
p = camera.toCameraSpace(p);
|
||||
camera.getFrustum().clipToFrustum(p);
|
||||
p = camera.toWorldSpace(p);
|
||||
expect(mathter::AlmostEqual(p, vecs[2 * i + 1]), errorMessage(p, vecs[2 * i + 1]));
|
||||
}
|
||||
}
|
||||
|
||||
void testFrustumClipOccurs(Vec3 vecs[], Camera& camera, int length) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
Vec3 p = vecs[i];
|
||||
p = camera.toCameraSpace(p);
|
||||
camera.getFrustum().clipToFrustum(p);
|
||||
p = camera.toWorldSpace(p);
|
||||
expect(!mathter::AlmostEqual(p, vecs[i]), errorMessage(p, vecs[i]));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class ProducerThread : public juce::Thread {
|
||||
public:
|
||||
|
|
@ -183,7 +69,6 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
static FrustumTest frustumTest;
|
||||
static BufferConsumerTest bufferConsumerTest;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ public:
|
|||
std::vector<osci::EffectParameter*>{
|
||||
new osci::EffectParameter("Bounce Size", "Size (scale) of the bouncing object.", "bounceSize", VERSION_HINT, 0.3, 0.05, 1.0),
|
||||
new osci::EffectParameter("Bounce Speed", "Speed of motion.", "bounceSpeed", VERSION_HINT, 5.0, 0.0, 10.0),
|
||||
new osci::EffectParameter("Bounce Angle", "Direction of travel (0..1 -> 0..360°).", "bounceAngle", VERSION_HINT, 0.16, 0.0, 1.0),
|
||||
new osci::EffectParameter("Bounce Angle", juce::String(juce::CharPointer_UTF8("Direction of travel (0..1 -> 0..360°).")), "bounceAngle", VERSION_HINT, 0.16, 0.0, 1.0),
|
||||
}
|
||||
);
|
||||
eff->setName("Bounce");
|
||||
|
|
|
|||
|
|
@ -1,36 +1,54 @@
|
|||
#pragma once
|
||||
#include <JuceHeader.h>
|
||||
#include "../PluginProcessor.h"
|
||||
|
||||
class DashedLineEffect : public osci::EffectApplication {
|
||||
public:
|
||||
osci::Point apply(int index, osci::Point vector, const std::vector<std::atomic<double>>& values, double sampleRate) override {
|
||||
// dash length in seconds
|
||||
double dashLength = values[0] / 400;
|
||||
int dashLengthSamples = (int)(dashLength * sampleRate);
|
||||
dashLengthSamples = juce::jmin(dashLengthSamples, MAX_BUFFER);
|
||||
|
||||
if (dashIndex >= dashLengthSamples) {
|
||||
dashIndex = 0;
|
||||
bufferIndex = 0;
|
||||
DashedLineEffect(OscirenderAudioProcessor& p) : audioProcessor(p) {}
|
||||
|
||||
osci::Point apply(int index, osci::Point input, const std::vector<std::atomic<double>>& values, double sampleRate) override {
|
||||
// if only 2 parameters are provided, this is being used as a 'trace effect'
|
||||
// where the dash count is 1.
|
||||
double dashCount = 1.0;
|
||||
int i = 0;
|
||||
|
||||
if (values.size() > 2) {
|
||||
dashCount = juce::jmax(1.0, values[i++].load()); // Dashes per cycle
|
||||
}
|
||||
|
||||
buffer[bufferIndex] = vector;
|
||||
double dashCoverage = juce::jlimit(0.0, 1.0, values[i++].load());
|
||||
double dashOffset = values[i++];
|
||||
|
||||
double dashLengthSamples = (sampleRate / audioProcessor.frequency) / dashCount;
|
||||
double dashPhase = framePhase * dashCount - dashOffset;
|
||||
dashPhase = dashPhase - std::floor(dashPhase); // Wrap
|
||||
buffer[bufferIndex] = input;
|
||||
|
||||
// Linear interpolation works much better than nearest for this
|
||||
double samplePos = bufferIndex - dashLengthSamples * dashPhase * (1 - dashCoverage);
|
||||
samplePos = samplePos - buffer.size() * std::floor(samplePos / buffer.size()); // Wrap to [0, size]
|
||||
int lowIndex = (int)std::floor(samplePos) % buffer.size();
|
||||
int highIndex = (lowIndex + 1) % buffer.size();
|
||||
double mixFactor = samplePos - std::floor(samplePos); // Fractional part
|
||||
osci::Point output = (1 - mixFactor) * buffer[lowIndex] + mixFactor * buffer[highIndex];
|
||||
|
||||
bufferIndex++;
|
||||
|
||||
vector = buffer[dashIndex];
|
||||
|
||||
if (index % 2 == 0) {
|
||||
dashIndex++;
|
||||
if (bufferIndex >= buffer.size()) {
|
||||
bufferIndex = 0;
|
||||
}
|
||||
|
||||
return vector;
|
||||
framePhase += audioProcessor.frequency / sampleRate;
|
||||
framePhase = framePhase - std::floor(framePhase);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
std::shared_ptr<osci::Effect> build() const override {
|
||||
auto eff = std::make_shared<osci::Effect>(
|
||||
std::make_shared<DashedLineEffect>(),
|
||||
std::make_shared<DashedLineEffect>(audioProcessor),
|
||||
std::vector<osci::EffectParameter*>{
|
||||
new osci::EffectParameter("Dash Length", "Controls the length of the dashed line.", "dashLength", VERSION_HINT, 0.3, 0.0, 1.0),
|
||||
new osci::EffectParameter("Dash Count", "Controls the number of dashed lines in the drawing.", "dashCount", VERSION_HINT, 16.0, 1.0, 32.0),
|
||||
new osci::EffectParameter("Dash Width", "Controls how much each dash unit is drawn.", "dashWidth", VERSION_HINT, 0.5, 0.0, 1.0),
|
||||
new osci::EffectParameter("Dash Offset", "Offsets the location of the dashed lines.", "dashOffset", VERSION_HINT, 0.0, 0.0, 1.0, 0.0001f, osci::LfoType::Sawtooth, 1.0f),
|
||||
}
|
||||
);
|
||||
eff->setName("Dash");
|
||||
|
|
@ -39,8 +57,9 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
OscirenderAudioProcessor &audioProcessor;
|
||||
const static int MAX_BUFFER = 192000;
|
||||
std::vector<osci::Point> buffer = std::vector<osci::Point>(MAX_BUFFER);
|
||||
int dashIndex = 0;
|
||||
int bufferIndex = 0;
|
||||
double framePhase = 0.0; // [0, 1]
|
||||
};
|
||||
|
|
|
|||
|
|
@ -6,11 +6,14 @@ class PerspectiveEffect : public osci::EffectApplication {
|
|||
public:
|
||||
osci::Point apply(int index, osci::Point input, const std::vector<std::atomic<double>>& values, double sampleRate) override {
|
||||
auto effectScale = values[0].load();
|
||||
auto focalLength = juce::jmax(values[1].load(), 0.001);
|
||||
// Far plane clipping happens at about 1.2 deg for 100 far plane dist
|
||||
double fovDegrees = juce::jlimit(1.5, 179.0, values[1].load());
|
||||
double fov = juce::degreesToRadians(fovDegrees);
|
||||
|
||||
Vec3 origin = Vec3(0, 0, -focalLength);
|
||||
// Place camera such that field of view is tangent to unit sphere
|
||||
Vec3 origin = Vec3(0, 0, -1.0f / std::sin(0.5f * (float)fov));
|
||||
camera.setPosition(origin);
|
||||
camera.setFocalLength(focalLength);
|
||||
camera.setFov(fov);
|
||||
Vec3 vec = Vec3(input.x, input.y, input.z);
|
||||
|
||||
Vec3 projected = camera.project(vec);
|
||||
|
|
@ -34,6 +37,6 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
|
||||
|
||||
Camera camera;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ public:
|
|||
weight *= 0.95;
|
||||
double strength = 10;
|
||||
weight = std::log(strength * weight + 1) / std::log(strength + 1);
|
||||
// TODO: This doesn't consider the sample rate!
|
||||
weight = std::pow(weight, 48000 / sampleRate);
|
||||
avg = weight * avg + (1 - weight) * input;
|
||||
|
||||
return avg;
|
||||
|
|
@ -29,5 +29,5 @@ public:
|
|||
private:
|
||||
osci::Point avg;
|
||||
juce::String idPrefix;
|
||||
float smoothingDefault = 0.75f;
|
||||
float smoothingDefault = 0.5f;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
#include <JuceHeader.h>
|
||||
#include <numbers>
|
||||
|
||||
class TwistEffect : public osci::EffectApplication {
|
||||
public:
|
||||
osci::Point apply(int index, osci::Point input, const std::vector<std::atomic<double>> &values, double sampleRate) override {
|
||||
double twistStrength = values[0] * 4 * std::numbers::pi;
|
||||
double twistTheta = twistStrength * input.y;
|
||||
input.rotate(0.0, twistTheta, 0.0);
|
||||
return input;
|
||||
}
|
||||
|
||||
std::shared_ptr<osci::Effect> build() const override {
|
||||
auto eff = std::make_shared<osci::Effect>(
|
||||
std::make_shared<TwistEffect>(),
|
||||
new osci::EffectParameter("Twist", "Twists the image in a corkscrew pattern.", "twist", VERSION_HINT, 0.5, 0.0, 1.0, 0.0001, osci::LfoType::Sine, 0.5)
|
||||
);
|
||||
eff->setIcon(BinaryData::twist_svg);
|
||||
return eff;
|
||||
}
|
||||
};
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
#include "WobbleEffect.h"
|
||||
#include "../PluginProcessor.h"
|
||||
|
||||
WobbleEffect::WobbleEffect(OscirenderAudioProcessor& p) : audioProcessor(p) {}
|
||||
|
||||
WobbleEffect::~WobbleEffect() {}
|
||||
|
||||
osci::Point WobbleEffect::apply(int index, osci::Point input, const std::vector<std::atomic<double>>& values, double sampleRate) {
|
||||
double wobblePhase = values[1] * std::numbers::pi;
|
||||
double theta = nextPhase(audioProcessor.frequency, sampleRate) + wobblePhase;
|
||||
double delta = 0.5 * values[0] * std::sin(theta);
|
||||
|
||||
return input + delta;
|
||||
}
|
||||
|
|
@ -1,18 +1,29 @@
|
|||
#pragma once
|
||||
#include <JuceHeader.h>
|
||||
#include "../PluginProcessor.h"
|
||||
|
||||
class OscirenderAudioProcessor;
|
||||
class WobbleEffect : public osci::EffectApplication {
|
||||
public:
|
||||
WobbleEffect(OscirenderAudioProcessor& p);
|
||||
~WobbleEffect();
|
||||
WobbleEffect(OscirenderAudioProcessor &p) : audioProcessor(p) {}
|
||||
|
||||
osci::Point apply(int index, osci::Point input, const std::vector<std::atomic<double>>& values, double sampleRate) override;
|
||||
osci::Point apply(int index, osci::Point input, const std::vector<std::atomic<double>>& values, double sampleRate) override {
|
||||
double wobblePhase = values[1] * std::numbers::pi;
|
||||
double theta = nextPhase(audioProcessor.frequency, sampleRate) + wobblePhase;
|
||||
double delta = 0.5 * values[0] * std::sin(theta);
|
||||
|
||||
return input + delta;
|
||||
}
|
||||
|
||||
std::shared_ptr<osci::Effect> build() const override {
|
||||
// Cannot build without processor reference; caller should construct explicitly and wrap in osci::Effect with parameters.
|
||||
jassertfalse;
|
||||
return nullptr;
|
||||
auto wobble = std::make_shared<osci::Effect>(
|
||||
std::make_shared<WobbleEffect>(audioProcessor),
|
||||
std::vector<osci::EffectParameter*>{
|
||||
new osci::EffectParameter("Wobble Amount", "Adds a sine wave of the prominent frequency in the audio currently playing. The sine wave's frequency is slightly offset to create a subtle 'wobble' in the image. Increasing the slider increases the strength of the wobble.", "wobble", VERSION_HINT, 0.3, 0.0, 1.0),
|
||||
new osci::EffectParameter("Wobble Phase", "Controls the phase of the wobble.", "wobblePhase", VERSION_HINT, 0.0, -1.0, 1.0, 0.0001f, osci::LfoType::Sawtooth, 1.0f),
|
||||
});
|
||||
wobble->setName("Wobble");
|
||||
wobble->setIcon(BinaryData::wobble_svg);
|
||||
return wobble;
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -102,7 +102,13 @@ void OsciMainMenuBarModel::resetMenuItems() {
|
|||
audioProcessor.clearPreviewEffect();
|
||||
}
|
||||
resetMenuItems(); // update tick state
|
||||
}, [this] { return audioProcessor.getGlobalBoolValue("previewEffectOnHover", true); });
|
||||
}, [this] { return audioProcessor.getGlobalBoolValue("previewEffectOnHover", true);
|
||||
});
|
||||
|
||||
addToggleMenuItem(interfaceMenuIndex, "Listen for Special Keys", [this] {
|
||||
audioProcessor.setAcceptsKeys(! audioProcessor.getAcceptsKeys());
|
||||
resetMenuItems();
|
||||
}, [this] { return audioProcessor.getAcceptsKeys(); });
|
||||
}
|
||||
|
||||
#if (JUCE_MAC || JUCE_WINDOWS) && OSCI_PREMIUM
|
||||
|
|
|
|||
|
|
@ -4,6 +4,10 @@
|
|||
#include "../SosciPluginProcessor.h"
|
||||
|
||||
SosciMainMenuBarModel::SosciMainMenuBarModel(SosciPluginEditor& e, SosciAudioProcessor& p) : editor(e), processor(p) {
|
||||
resetMenuItems();
|
||||
}
|
||||
|
||||
void SosciMainMenuBarModel::resetMenuItems() {
|
||||
addTopLevelMenu("File");
|
||||
addTopLevelMenu("About");
|
||||
addTopLevelMenu("Video");
|
||||
|
|
@ -105,4 +109,11 @@ SosciMainMenuBarModel::SosciMainMenuBarModel(SosciPluginEditor& e, SosciAudioPro
|
|||
if (editor.processor.wrapperType == juce::AudioProcessor::WrapperType::wrapperType_Standalone) {
|
||||
addMenuItem(3, "Settings...", [&]() { editor.openAudioSettings(); });
|
||||
}
|
||||
|
||||
// Interface menu index depends on whether Audio menu exists
|
||||
int interfaceMenuIndex = (editor.processor.wrapperType == juce::AudioProcessor::WrapperType::wrapperType_Standalone) ? 4 : 3;
|
||||
addToggleMenuItem(interfaceMenuIndex, "Listen for Special Keys", [this] {
|
||||
processor.setAcceptsKeys(! processor.getAcceptsKeys());
|
||||
resetMenuItems();
|
||||
}, [this] { return processor.getAcceptsKeys(); });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#include "Camera.h"
|
||||
|
||||
Camera::Camera() : frustum(1, 1, 0.1, 100) {
|
||||
Camera::Camera() : frustum(1, 1, 0.001, 100) {
|
||||
viewMatrix = mathter::Identity();
|
||||
}
|
||||
|
||||
|
|
@ -18,8 +18,8 @@ Vec3 Camera::toWorldSpace(Vec3& point) {
|
|||
return mathter::Inverse(viewMatrix) * point;
|
||||
}
|
||||
|
||||
void Camera::setFocalLength(double focalLength) {
|
||||
frustum.setCameraInternals(focalLength, frustum.ratio, frustum.nearDistance, frustum.farDistance);
|
||||
void Camera::setFov(double fov) {
|
||||
frustum.setCameraInternals(fov, frustum.ratio, frustum.nearDistance, frustum.farDistance);
|
||||
}
|
||||
|
||||
Vec3 Camera::project(Vec3& pWorld) {
|
||||
|
|
@ -27,10 +27,10 @@ Vec3 Camera::project(Vec3& pWorld) {
|
|||
|
||||
frustum.clipToFrustum(p);
|
||||
|
||||
double start = p.x * frustum.focalLength / p.z;
|
||||
double end = p.y * frustum.focalLength / p.z;
|
||||
float x = p.x * frustum.focalLength / p.z;
|
||||
float y = p.y * frustum.focalLength / p.z;
|
||||
|
||||
return Vec3(start, end, 0);
|
||||
return Vec3(x, y, 0);
|
||||
}
|
||||
|
||||
Frustum Camera::getFrustum() {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ public:
|
|||
void setPosition(Vec3& position);
|
||||
Vec3 toCameraSpace(Vec3& point);
|
||||
Vec3 toWorldSpace(Vec3& point);
|
||||
void setFocalLength(double focalLength);
|
||||
void setFov(double fov);
|
||||
Vec3 project(Vec3& p);
|
||||
Frustum getFrustum();
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -2,16 +2,16 @@
|
|||
|
||||
#include "Frustum.h"
|
||||
|
||||
void Frustum::setCameraInternals(float focalLength, float ratio, float nearDistance, float farDistance) {
|
||||
void Frustum::setCameraInternals(float fov, float ratio, float nearDistance, float farDistance) {
|
||||
// store the information
|
||||
this->focalLength = focalLength;
|
||||
this->fov = fov;
|
||||
this->ratio = ratio;
|
||||
this->nearDistance = nearDistance;
|
||||
this->farDistance = farDistance;
|
||||
|
||||
// compute width and height of the near section
|
||||
float fov = 2 * std::atan(1 / focalLength);
|
||||
tang = (float) std::tan(fov * 0.5);
|
||||
tang = std::tan(fov * 0.5f);
|
||||
focalLength = 1.0f / tang;
|
||||
height = nearDistance * tang;
|
||||
width = height * ratio;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,16 +9,13 @@ using Vec3 = mathter::Vector<float, 3, false>;
|
|||
|
||||
class Frustum {
|
||||
public:
|
||||
float ratio, nearDistance, farDistance, width, height, tang, focalLength;
|
||||
float ratio, nearDistance, farDistance, width, height, tang, fov, focalLength;
|
||||
|
||||
Frustum(float focalLength, float ratio, float nearDistance, float farDistance) {
|
||||
setCameraInternals(focalLength, ratio, nearDistance, farDistance);
|
||||
Frustum(float fov, float ratio, float nearDistance, float farDistance) {
|
||||
setCameraInternals(fov, ratio, nearDistance, farDistance);
|
||||
}
|
||||
~Frustum() {};
|
||||
|
||||
void setCameraInternals(float focalLength, float ratio, float nearD, float farD);
|
||||
void setCameraInternals(float fov, float ratio, float nearD, float farD);
|
||||
void clipToFrustum(Vec3 &p);
|
||||
float getFocalLength() {
|
||||
return focalLength;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -254,6 +254,9 @@ void VisualiserComponent::mouseDown(const juce::MouseEvent &event) {
|
|||
}
|
||||
|
||||
bool VisualiserComponent::keyPressed(const juce::KeyPress &key) {
|
||||
// If we're not accepting special keys, end early
|
||||
if (!audioProcessor.getAcceptsKeys()) return false;
|
||||
|
||||
if (key.isKeyCode(juce::KeyPress::escapeKey)) {
|
||||
if (fullScreenCallback) {
|
||||
fullScreenCallback(FullScreenMode::MAIN_COMPONENT);
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@
|
|||
<FILE id="rFYmV8" name="timer.svg" compile="0" resource="1" file="Resources/svg/timer.svg"/>
|
||||
<FILE id="ESR7bv" name="trace.svg" compile="0" resource="1" file="Resources/svg/trace.svg"/>
|
||||
<FILE id="ID1vTS" name="translate.svg" compile="0" resource="1" file="Resources/svg/translate.svg"/>
|
||||
<FILE id="Sw4WWb" name="twist.svg" compile="0" resource="1" file="Resources/svg/twist.svg"/>
|
||||
<FILE id="praXUY" name="vector-cancelling.svg" compile="0" resource="1"
|
||||
file="Resources/svg/vector-cancelling.svg"/>
|
||||
<FILE id="qC6QiP" name="volume.svg" compile="0" resource="1" file="Resources/svg/volume.svg"/>
|
||||
|
|
@ -134,10 +135,9 @@
|
|||
<FILE id="yiIupB" name="SwirlEffect.h" compile="0" resource="0" file="Source/audio/SwirlEffect.h"/>
|
||||
<FILE id="qZkeZC" name="TranslateEffect.h" compile="0" resource="0"
|
||||
file="Source/audio/TranslateEffect.h"/>
|
||||
<FILE id="RsHWPN" name="TwistEffect.h" compile="0" resource="0" file="Source/audio/TwistEffect.h"/>
|
||||
<FILE id="Be21D0" name="VectorCancellingEffect.h" compile="0" resource="0"
|
||||
file="Source/audio/VectorCancellingEffect.h"/>
|
||||
<FILE id="VHRytO" name="WobbleEffect.cpp" compile="1" resource="0"
|
||||
file="Source/audio/WobbleEffect.cpp"/>
|
||||
<FILE id="sgdTlo" name="WobbleEffect.h" compile="0" resource="0" file="Source/audio/WobbleEffect.h"/>
|
||||
</GROUP>
|
||||
<GROUP id="{2A41BAF3-5E83-B018-5668-39D89ABFA00C}" name="chinese_postman">
|
||||
|
|
@ -814,14 +814,13 @@
|
|||
microphonePermissionNeeded="1" frameworkSearchPaths="/Library/Frameworks"
|
||||
extraCustomFrameworks="/Library/Frameworks/Syphon.framework"
|
||||
hardenedRuntime="1" hardenedRuntimeOptions="com.apple.security.cs.disable-library-validation,com.apple.security.device.audio-input"
|
||||
iosDevelopmentTeamID="D86A3M3H2L">
|
||||
userNotes="D86A3M3H2L">
|
||||
<CONFIGURATIONS>
|
||||
<CONFIGURATION isDebug="1" name="Debug" targetName="osci-render" customXcodeFlags="LD_RUNPATH_SEARCH_PATHS = '/Library/Frameworks',OTHER_CODE_SIGN_FLAGS = --timestamp --force --deep"
|
||||
codeSigningIdentity="Developer ID Application: James Ball (D86A3M3H2L)"/>
|
||||
<CONFIGURATION name="Release" targetName="osci-render" customXcodeFlags="LD_RUNPATH_SEARCH_PATHS = '/Library/Frameworks',CODE_SIGN_INJECT_BASE_ENTITLEMENTS=NO,OTHER_CODE_SIGN_FLAGS = --timestamp --force --deep"
|
||||
codeSigningIdentity="Developer ID Application: James Ball (D86A3M3H2L)"/>
|
||||
<CONFIGURATION name="Release (Development)" targetName="osci-render" customXcodeFlags="LD_RUNPATH_SEARCH_PATHS = '/Library/Frameworks',OTHER_CODE_SIGN_FLAGS = --timestamp --force --deep"
|
||||
codeSigningIdentity="Developer ID Application: James Ball (D86A3M3H2L)"/>
|
||||
<CONFIGURATION name="Release (Development)" targetName="osci-render" customXcodeFlags="LD_RUNPATH_SEARCH_PATHS = '/Library/Frameworks',OTHER_CODE_SIGN_FLAGS = --timestamp --force --deep"/>
|
||||
</CONFIGURATIONS>
|
||||
<MODULEPATHS>
|
||||
<MODULEPATH id="juce_audio_basics" path="../../../JUCE/modules"/>
|
||||
|
|
|
|||
Ładowanie…
Reference in New Issue