2023-01-09 21:58:49 +00:00
|
|
|
/*
|
|
|
|
==============================================================================
|
|
|
|
|
|
|
|
This file contains the basic framework code for a JUCE plugin processor.
|
|
|
|
|
|
|
|
==============================================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <JuceHeader.h>
|
2023-01-15 17:01:27 +00:00
|
|
|
#include "shape/Shape.h"
|
|
|
|
#include "parser/FileParser.h"
|
|
|
|
#include "parser/FrameProducer.h"
|
|
|
|
#include "parser/FrameConsumer.h"
|
2023-03-25 20:24:10 +00:00
|
|
|
#include "audio/Effect.h"
|
2023-07-05 11:02:28 +00:00
|
|
|
#include <numbers>
|
2023-07-08 12:25:35 +00:00
|
|
|
#include "concurrency/BufferProducer.h"
|
2023-07-10 21:00:36 +00:00
|
|
|
#include "audio/AudioWebSocketServer.h"
|
2023-07-11 12:32:52 +00:00
|
|
|
#include "audio/DelayEffect.h"
|
2023-01-09 21:58:49 +00:00
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
/**
|
|
|
|
*/
|
|
|
|
class OscirenderAudioProcessor : public juce::AudioProcessor
|
|
|
|
#if JucePlugin_Enable_ARA
|
|
|
|
, public juce::AudioProcessorARAExtension
|
|
|
|
#endif
|
2023-01-15 17:01:27 +00:00
|
|
|
, public FrameConsumer
|
2023-01-09 21:58:49 +00:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
//==============================================================================
|
|
|
|
OscirenderAudioProcessor();
|
|
|
|
~OscirenderAudioProcessor() override;
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
void prepareToPlay (double sampleRate, int samplesPerBlock) override;
|
|
|
|
void releaseResources() override;
|
|
|
|
|
|
|
|
#ifndef JucePlugin_PreferredChannelConfigurations
|
|
|
|
bool isBusesLayoutSupported (const BusesLayout& layouts) const override;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void processBlock (juce::AudioBuffer<float>&, juce::MidiBuffer&) override;
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
juce::AudioProcessorEditor* createEditor() override;
|
|
|
|
bool hasEditor() const override;
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
const juce::String getName() const override;
|
|
|
|
|
|
|
|
bool acceptsMidi() const override;
|
|
|
|
bool producesMidi() const override;
|
|
|
|
bool isMidiEffect() const override;
|
|
|
|
double getTailLengthSeconds() const override;
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
int getNumPrograms() override;
|
|
|
|
int getCurrentProgram() override;
|
|
|
|
void setCurrentProgram (int index) override;
|
|
|
|
const juce::String getProgramName (int index) override;
|
|
|
|
void changeProgramName (int index, const juce::String& newName) override;
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
void getStateInformation (juce::MemoryBlock& destData) override;
|
|
|
|
void setStateInformation (const void* data, int sizeInBytes) override;
|
|
|
|
|
2023-07-10 16:42:22 +00:00
|
|
|
std::atomic<float> frequency = 440.0f;
|
|
|
|
std::atomic<double> volume = 1.0;
|
|
|
|
std::atomic<double> threshold = 1.0;
|
2023-01-15 17:01:27 +00:00
|
|
|
|
2023-07-10 16:42:22 +00:00
|
|
|
std::atomic<double> currentSampleRate = 0.0;
|
2023-01-15 17:01:27 +00:00
|
|
|
|
2023-07-05 14:17:17 +00:00
|
|
|
juce::SpinLock effectsLock;
|
2023-03-26 12:58:31 +00:00
|
|
|
std::vector<std::shared_ptr<Effect>> allEffects;
|
2023-07-05 16:57:41 +00:00
|
|
|
std::vector<std::shared_ptr<Effect>> enabledEffects;
|
2023-07-04 13:58:36 +00:00
|
|
|
std::vector<std::shared_ptr<Effect>> luaEffects;
|
2023-07-05 11:02:28 +00:00
|
|
|
|
|
|
|
// TODO see if there is a way to move this code to .cpp
|
2023-07-11 12:32:52 +00:00
|
|
|
std::function<Vector2(int, Vector2, std::vector<EffectDetails>, double, int)> onRotationChange = [this](int index, Vector2 input, std::vector<EffectDetails> details, double frequency, double sampleRate) {
|
2023-07-05 11:02:28 +00:00
|
|
|
if (getCurrentFileIndex() != -1) {
|
|
|
|
auto obj = getCurrentFileParser()->getObject();
|
|
|
|
if (obj == nullptr) return input;
|
|
|
|
obj->setBaseRotation(
|
|
|
|
rotateX.getValue() * std::numbers::pi,
|
|
|
|
rotateY.getValue() * std::numbers::pi,
|
|
|
|
rotateZ.getValue() * std::numbers::pi
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return input;
|
|
|
|
};
|
2023-03-30 20:09:53 +00:00
|
|
|
|
2023-07-05 11:02:28 +00:00
|
|
|
Effect focalLength{
|
2023-07-11 12:32:52 +00:00
|
|
|
[this](int index, Vector2 input, std::vector<EffectDetails> details, double frequency, double sampleRate) {
|
2023-07-05 11:02:28 +00:00
|
|
|
if (getCurrentFileIndex() != -1) {
|
|
|
|
auto camera = getCurrentFileParser()->getCamera();
|
|
|
|
if (camera == nullptr) return input;
|
2023-07-11 12:32:52 +00:00
|
|
|
camera->setFocalLength(details[0].value);
|
2023-07-05 11:02:28 +00:00
|
|
|
}
|
|
|
|
return input;
|
|
|
|
},
|
|
|
|
"Focal length",
|
|
|
|
"focalLength",
|
|
|
|
1
|
|
|
|
};
|
|
|
|
Effect rotateX{onRotationChange, "Rotate x", "rotateX", 1};
|
|
|
|
Effect rotateY{onRotationChange, "Rotate y", "rotateY", 1};
|
|
|
|
Effect rotateZ{onRotationChange, "Rotate z", "rotateZ", 0};
|
2023-07-05 16:57:41 +00:00
|
|
|
Effect currentRotateX{
|
2023-07-11 12:32:52 +00:00
|
|
|
[this](int index, Vector2 input, std::vector<EffectDetails> details, double frequency, double sampleRate) {
|
2023-07-05 16:57:41 +00:00
|
|
|
if (getCurrentFileIndex() != -1) {
|
|
|
|
auto obj = getCurrentFileParser()->getObject();
|
|
|
|
if (obj == nullptr) return input;
|
2023-07-11 12:32:52 +00:00
|
|
|
obj->setCurrentRotationX(details[0].value * std::numbers::pi);
|
2023-07-05 16:57:41 +00:00
|
|
|
}
|
|
|
|
return input;
|
|
|
|
},
|
|
|
|
"Current Rotate x",
|
|
|
|
"currentRotateX",
|
|
|
|
0
|
|
|
|
};
|
|
|
|
Effect currentRotateY{
|
2023-07-11 12:32:52 +00:00
|
|
|
[this](int index, Vector2 input, std::vector<EffectDetails> details, double frequency, double sampleRate) {
|
2023-07-05 16:57:41 +00:00
|
|
|
if (getCurrentFileIndex() != -1) {
|
|
|
|
auto obj = getCurrentFileParser()->getObject();
|
|
|
|
if (obj == nullptr) return input;
|
2023-07-11 12:32:52 +00:00
|
|
|
obj->setCurrentRotationY(details[0].value * std::numbers::pi);
|
2023-07-05 16:57:41 +00:00
|
|
|
}
|
|
|
|
return input;
|
|
|
|
},
|
|
|
|
"Current Rotate y",
|
|
|
|
"currentRotateY",
|
|
|
|
0
|
|
|
|
};
|
|
|
|
Effect currentRotateZ{
|
2023-07-11 12:32:52 +00:00
|
|
|
[this](int index, Vector2 input, std::vector<EffectDetails> details, double frequency, double sampleRate) {
|
2023-07-05 16:57:41 +00:00
|
|
|
if (getCurrentFileIndex() != -1) {
|
|
|
|
auto obj = getCurrentFileParser()->getObject();
|
|
|
|
if (obj == nullptr) return input;
|
2023-07-11 12:32:52 +00:00
|
|
|
obj->setCurrentRotationZ(details[0].value * std::numbers::pi);
|
2023-07-05 16:57:41 +00:00
|
|
|
}
|
|
|
|
return input;
|
2023-07-11 12:32:52 +00:00
|
|
|
},
|
2023-07-05 16:57:41 +00:00
|
|
|
"Current Rotate z",
|
|
|
|
"currentRotateZ",
|
|
|
|
0
|
|
|
|
};
|
2023-07-05 11:02:28 +00:00
|
|
|
Effect rotateSpeed{
|
2023-07-11 12:32:52 +00:00
|
|
|
[this](int index, Vector2 input, std::vector<EffectDetails> details, double frequency, double sampleRate) {
|
2023-07-05 11:02:28 +00:00
|
|
|
if (getCurrentFileIndex() != -1) {
|
|
|
|
auto obj = getCurrentFileParser()->getObject();
|
|
|
|
if (obj == nullptr) return input;
|
2023-07-11 12:32:52 +00:00
|
|
|
obj->setRotationSpeed(details[0].value);
|
2023-07-05 11:02:28 +00:00
|
|
|
}
|
|
|
|
return input;
|
|
|
|
},
|
|
|
|
"Rotate speed",
|
|
|
|
"rotateSpeed",
|
|
|
|
0
|
|
|
|
};
|
2023-07-05 16:57:41 +00:00
|
|
|
std::atomic<bool> fixedRotateX = false;
|
|
|
|
std::atomic<bool> fixedRotateY = false;
|
|
|
|
std::atomic<bool> fixedRotateZ = false;
|
2023-07-11 12:32:52 +00:00
|
|
|
|
|
|
|
std::shared_ptr<DelayEffect> delayEffect = std::make_shared<DelayEffect>();
|
2023-07-04 19:47:54 +00:00
|
|
|
|
|
|
|
juce::SpinLock parsersLock;
|
2023-03-30 16:28:47 +00:00
|
|
|
std::vector<std::shared_ptr<FileParser>> parsers;
|
|
|
|
std::vector<std::shared_ptr<juce::MemoryBlock>> fileBlocks;
|
2023-07-05 21:45:51 +00:00
|
|
|
std::vector<juce::String> fileNames;
|
2023-07-04 19:47:54 +00:00
|
|
|
std::atomic<int> currentFile = -1;
|
2023-03-30 16:28:47 +00:00
|
|
|
|
2023-07-11 21:28:54 +00:00
|
|
|
FrameProducer producer = FrameProducer(*this, std::make_shared<FileParser>());
|
2023-01-15 17:01:27 +00:00
|
|
|
|
2023-07-08 12:25:35 +00:00
|
|
|
BufferProducer audioProducer;
|
|
|
|
|
2023-07-04 13:58:36 +00:00
|
|
|
void addLuaSlider();
|
2023-01-15 17:01:27 +00:00
|
|
|
void updateAngleDelta();
|
2023-03-30 20:09:53 +00:00
|
|
|
void addFrame(std::vector<std::unique_ptr<Shape>> frame, int fileIndex) override;
|
2023-03-26 12:58:31 +00:00
|
|
|
void enableEffect(std::shared_ptr<Effect> effect);
|
2023-03-29 09:55:11 +00:00
|
|
|
void disableEffect(std::shared_ptr<Effect> effect);
|
2023-03-28 15:21:18 +00:00
|
|
|
void updateEffectPrecedence();
|
2023-03-30 16:28:47 +00:00
|
|
|
void updateFileBlock(int index, std::shared_ptr<juce::MemoryBlock> block);
|
|
|
|
void addFile(juce::File file);
|
2023-07-05 21:45:51 +00:00
|
|
|
void addFile(juce::String fileName, const char* data, const int size);
|
2023-03-30 16:28:47 +00:00
|
|
|
void removeFile(int index);
|
|
|
|
int numFiles();
|
2023-03-30 20:09:53 +00:00
|
|
|
void changeCurrentFile(int index);
|
|
|
|
int getCurrentFileIndex();
|
2023-07-04 13:58:36 +00:00
|
|
|
std::shared_ptr<FileParser> getCurrentFileParser();
|
2023-07-05 21:45:51 +00:00
|
|
|
juce::String getCurrentFileName();
|
|
|
|
juce::String getFileName(int index);
|
2023-03-30 16:28:47 +00:00
|
|
|
std::shared_ptr<juce::MemoryBlock> getFileBlock(int index);
|
2023-01-09 21:58:49 +00:00
|
|
|
private:
|
2023-01-15 17:01:27 +00:00
|
|
|
double theta = 0.0;
|
|
|
|
double thetaDelta = 0.0;
|
|
|
|
|
|
|
|
juce::AbstractFifo frameFifo{ 10 };
|
|
|
|
std::vector<std::unique_ptr<Shape>> frameBuffer[10];
|
2023-03-30 20:09:53 +00:00
|
|
|
int frameBufferIndices[10];
|
2023-01-15 17:01:27 +00:00
|
|
|
|
|
|
|
int currentShape = 0;
|
2023-01-15 22:34:02 +00:00
|
|
|
std::vector<std::unique_ptr<Shape>> frame;
|
2023-03-30 20:09:53 +00:00
|
|
|
int currentBufferIndex = -1;
|
2023-01-15 17:01:27 +00:00
|
|
|
double frameLength;
|
|
|
|
double shapeDrawn = 0.0;
|
|
|
|
double frameDrawn = 0.0;
|
|
|
|
double lengthIncrement = 0.0;
|
2023-03-30 20:09:53 +00:00
|
|
|
bool invalidateFrameBuffer = false;
|
2023-01-15 17:01:27 +00:00
|
|
|
|
2023-07-06 16:57:10 +00:00
|
|
|
std::shared_ptr<Effect> traceMax = std::make_shared<Effect>(
|
2023-07-11 12:32:52 +00:00
|
|
|
[this](int index, Vector2 input, std::vector<EffectDetails> details, double frequency, double sampleRate) {
|
2023-07-06 16:57:10 +00:00
|
|
|
traceMaxEnabled = true;
|
|
|
|
return input;
|
|
|
|
},
|
|
|
|
"Trace max",
|
|
|
|
"traceMax",
|
|
|
|
1
|
|
|
|
);
|
|
|
|
std::shared_ptr<Effect> traceMin = std::make_shared<Effect>(
|
2023-07-11 12:32:52 +00:00
|
|
|
[this](int index, Vector2 input, std::vector<EffectDetails> details, double frequency, double sampleRate) {
|
2023-07-06 16:57:10 +00:00
|
|
|
traceMinEnabled = true;
|
|
|
|
return input;
|
|
|
|
},
|
|
|
|
"Trace min",
|
|
|
|
"traceMin",
|
|
|
|
0
|
|
|
|
);
|
|
|
|
const double MIN_TRACE = 0.005;
|
|
|
|
double actualTraceMax = traceMax->getValue();
|
|
|
|
double actualTraceMin = traceMin->getValue();
|
|
|
|
bool traceMaxEnabled = false;
|
|
|
|
bool traceMinEnabled = false;
|
|
|
|
|
2023-07-10 21:00:36 +00:00
|
|
|
AudioWebSocketServer softwareOscilloscopeServer{audioProducer};
|
|
|
|
|
2023-01-15 17:01:27 +00:00
|
|
|
void updateFrame();
|
|
|
|
void updateLengthIncrement();
|
2023-07-06 16:57:10 +00:00
|
|
|
void incrementShapeDrawing();
|
2023-07-04 19:47:54 +00:00
|
|
|
void openFile(int index);
|
2023-07-05 11:02:28 +00:00
|
|
|
void updateLuaValues();
|
|
|
|
void updateObjValues();
|
2023-01-15 17:01:27 +00:00
|
|
|
|
|
|
|
const double MIN_LENGTH_INCREMENT = 0.000001;
|
|
|
|
|
2023-01-09 21:58:49 +00:00
|
|
|
//==============================================================================
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OscirenderAudioProcessor)
|
|
|
|
};
|