Merge branch 'develop' into effect-twist

pull/308/head
James H Ball 2025-08-16 14:49:43 +01:00 zatwierdzone przez GitHub
commit 9fbd37206f
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
15 zmienionych plików z 88 dodań i 51 usunięć

Wyświetl plik

@ -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') {

Wyświetl plik

@ -16,6 +16,7 @@ CommonAudioProcessor::CommonAudioProcessor(const BusesProperties& busesPropertie
: AudioProcessor(busesProperties)
#endif
{
if (!applicationFolder.exists()) {
applicationFolder.createDirectory();
}

Wyświetl plik

@ -153,6 +153,12 @@ public:
#else
"ffmpeg";
#endif
void setAcceptsKeys(bool shouldAcceptKeys) {
setGlobalValue("acceptsAllKeys", shouldAcceptKeys);
}
bool getAcceptsKeys() {
return getGlobalBoolValue("acceptsAllKeys", juce::JUCEApplicationBase::isStandaloneApp());
}
protected:

Wyświetl plik

@ -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);

Wyświetl plik

@ -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.");

Wyświetl plik

@ -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);
DashedLineEffect(OscirenderAudioProcessor& p) : audioProcessor(p) {}
if (dashIndex >= dashLengthSamples) {
dashIndex = 0;
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]
};

Wyświetl plik

@ -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);

Wyświetl plik

@ -61,6 +61,10 @@ 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] {

Wyświetl plik

@ -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();

Wyświetl plik

@ -9,6 +9,7 @@ class SosciAudioProcessor;
class SosciMainMenuBarModel : public MainMenuBarModel {
public:
SosciMainMenuBarModel(SosciPluginEditor& editor, SosciAudioProcessor& processor);
void resetMenuItems();
SosciPluginEditor& editor;
SosciAudioProcessor& processor;

Wyświetl plik

@ -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() {

Wyświetl plik

@ -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:

Wyświetl plik

@ -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;
}

Wyświetl plik

@ -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;
}
};

Wyświetl plik

@ -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);