kopia lustrzana https://github.com/jameshball/osci-render
Merge branch 'develop' into effect-twist
commit
9fbd37206f
|
@ -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:
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "audio/MultiplexEffect.h"
|
||||
#include "audio/SmoothEffect.h"
|
||||
#include "audio/WobbleEffect.h"
|
||||
#include "audio/DashedLineEffect.h"
|
||||
#include "audio/VectorCancellingEffect.h"
|
||||
#include "parser/FileParser.h"
|
||||
#include "parser/FrameProducer.h"
|
||||
|
@ -144,11 +145,16 @@ OscirenderAudioProcessor::OscirenderAudioProcessor() : CommonAudioProcessor(Buse
|
|||
std::vector<osci::EffectParameter*>{
|
||||
new osci::EffectParameter("Delay Decay", "Adds repetitions, delays, or echos to the audio. This slider controls the volume of the echo.", "delayDecay", VERSION_HINT, 0.4, 0.0, 1.0),
|
||||
new osci::EffectParameter("Delay Length", "Controls the time in seconds between echos.", "delayLength", VERSION_HINT, 0.5, 0.0, 1.0)}));
|
||||
toggleableEffects.push_back(std::make_shared<osci::Effect>(
|
||||
dashedLineEffect,
|
||||
auto dashedLineEffect = std::make_shared<osci::Effect>(
|
||||
std::make_shared<DashedLineEffect>(*this),
|
||||
std::vector<osci::EffectParameter*>{
|
||||
new osci::EffectParameter("Dash Length", "Controls the length of the dashed line.", "dashLength", VERSION_HINT, 0.2, 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 Coverage", "Controls the fraction of each dash unit that is drawn.", "dashCoverage", 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),
|
||||
});
|
||||
dashedLineEffect->getParameter("dashOffset")->lfo->setUnnormalisedValueNotifyingHost((int)osci::LfoType::Sawtooth);
|
||||
dashedLineEffect->getParameter("dashOffset")->lfoRate->setUnnormalisedValueNotifyingHost(1.0);
|
||||
toggleableEffects.push_back(dashedLineEffect);
|
||||
toggleableEffects.push_back(custom);
|
||||
toggleableEffects.push_back(trace);
|
||||
trace->getParameter("traceLength")->lfo->setUnnormalisedValueNotifyingHost((int)osci::LfoType::Sawtooth);
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#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"
|
||||
|
@ -89,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>(
|
||||
|
@ -102,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.");
|
||||
|
|
|
@ -1,34 +1,42 @@
|
|||
#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;
|
||||
DashedLineEffect(OscirenderAudioProcessor& p) : audioProcessor(p) {}
|
||||
|
||||
osci::Point apply(int index, osci::Point input, const std::vector<std::atomic<double>>& values, double sampleRate) override {
|
||||
double dashCount = juce::jmax(1.0, values[0].load()); // Dashes per cycle
|
||||
double dashCoverage = juce::jlimit(0.0, 1.0, values[1].load());
|
||||
double dashOffset = values[2];
|
||||
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++;
|
||||
if (bufferIndex >= buffer.size()) {
|
||||
bufferIndex = 0;
|
||||
}
|
||||
framePhase += audioProcessor.frequency / sampleRate;
|
||||
framePhase = framePhase - std::floor(framePhase);
|
||||
|
||||
buffer[bufferIndex] = vector;
|
||||
bufferIndex++;
|
||||
|
||||
vector = buffer[dashIndex];
|
||||
|
||||
if (index % 2 == 0) {
|
||||
dashIndex++;
|
||||
}
|
||||
|
||||
return vector;
|
||||
return output;
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -23,6 +26,6 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
|
||||
|
||||
Camera camera;
|
||||
};
|
||||
|
|
|
@ -60,7 +60,11 @@ void OsciMainMenuBarModel::resetMenuItems() {
|
|||
});
|
||||
addMenuItem(1, "Randomize Blender Port", [this] {
|
||||
audioProcessor.setObjectServerPort(juce::Random::getSystemRandom().nextInt(juce::Range<int>(51600, 51700)));
|
||||
});
|
||||
});
|
||||
addMenuItem(1, audioProcessor.getAcceptsKeys() ? "Disable Special Keys" : "Enable Special Keys", [this] {
|
||||
audioProcessor.setAcceptsKeys(!audioProcessor.getAcceptsKeys());
|
||||
resetMenuItems();
|
||||
});
|
||||
|
||||
#if !OSCI_PREMIUM
|
||||
addMenuItem(1, "Purchase osci-render premium!", [this] {
|
||||
|
|
|
@ -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");
|
||||
|
@ -92,6 +96,10 @@ SosciMainMenuBarModel::SosciMainMenuBarModel(SosciPluginEditor& e, SosciAudioPro
|
|||
|
||||
juce::DialogWindow* dw = options.launchAsync();
|
||||
});
|
||||
addMenuItem(1, processor.getAcceptsKeys() ? "Disable Special Keys" : "Enable Special Keys", [this] {
|
||||
processor.setAcceptsKeys(!processor.getAcceptsKeys());
|
||||
resetMenuItems();
|
||||
});
|
||||
|
||||
addMenuItem(2, "Settings...", [this] {
|
||||
editor.openRecordingSettings();
|
||||
|
|
|
@ -9,6 +9,7 @@ class SosciAudioProcessor;
|
|||
class SosciMainMenuBarModel : public MainMenuBarModel {
|
||||
public:
|
||||
SosciMainMenuBarModel(SosciPluginEditor& editor, SosciAudioProcessor& processor);
|
||||
void resetMenuItems();
|
||||
|
||||
SosciPluginEditor& editor;
|
||||
SosciAudioProcessor& processor;
|
||||
|
|
|
@ -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);
|
||||
|
|
Ładowanie…
Reference in New Issue