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"
2023-09-01 22:42:17 +00:00
# include "concurrency/BufferConsumer.h"
2023-03-25 20:24:10 +00:00
# include "audio/Effect.h"
2023-08-28 21:06:21 +00:00
# include "audio/ShapeSound.h"
# include "audio/ShapeVoice.h"
2023-12-14 21:26:40 +00:00
# include "audio/PublicSynthesiser.h"
2023-07-05 11:02:28 +00:00
# include <numbers>
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-07-13 19:11:24 +00:00
# include "audio/PitchDetector.h"
# include "audio/WobbleEffect.h"
2023-07-21 16:42:29 +00:00
# include "audio/PerspectiveEffect.h"
2023-09-10 16:43:37 +00:00
# include "obj/ObjectServer.h"
2023-10-19 15:12:30 +00:00
# include "UGen/Env.h"
2023-11-25 15:37:33 +00:00
# include "UGen/ugen_JuceEnvelopeComponent.h"
2024-01-07 19:48:02 +00:00
# include "audio/CustomEffect.h"
2023-01-09 21:58:49 +00:00
//==============================================================================
/**
*/
2023-11-25 15:37:33 +00:00
class OscirenderAudioProcessor : public juce : : AudioProcessor , juce : : AudioProcessorParameter : : Listener , public EnvelopeComponentListener
2023-01-09 21:58:49 +00:00
# if JucePlugin_Enable_ARA
, public juce : : AudioProcessorARAExtension
# endif
{
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 ;
2024-01-28 19:58:28 +00:00
void setAudioThreadCallback ( std : : function < void ( const juce : : AudioBuffer < float > & ) > callback ) ;
2023-01-09 21:58:49 +00:00
bool acceptsMidi ( ) const override ;
bool producesMidi ( ) const override ;
bool isMidiEffect ( ) const override ;
double getTailLengthSeconds ( ) const override ;
int getNumPrograms ( ) override ;
int getCurrentProgram ( ) override ;
2023-07-28 12:55:44 +00:00
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-09-05 19:46:05 +00:00
std : : shared_ptr < BufferConsumer > consumerRegister ( std : : vector < float > & buffer ) ;
void consumerStop ( std : : shared_ptr < BufferConsumer > consumer ) ;
void consumerRead ( std : : shared_ptr < BufferConsumer > consumer ) ;
2023-09-16 12:59:52 +00:00
void parameterValueChanged ( int parameterIndex , float newValue ) override ;
void parameterGestureChanged ( int parameterIndex , bool gestureIsStarting ) override ;
2023-11-25 15:37:33 +00:00
void envelopeChanged ( EnvelopeComponent * changedEnvelope ) override ;
2023-09-01 18:52:36 +00:00
2024-01-07 19:48:02 +00:00
int VERSION_HINT = 2 ;
2023-01-09 21:58:49 +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-07-18 16:25:09 +00:00
std : : vector < std : : shared_ptr < Effect > > toggleableEffects ;
2023-07-04 13:58:36 +00:00
std : : vector < std : : shared_ptr < Effect > > luaEffects ;
2023-07-05 11:02:28 +00:00
2023-07-14 14:34:24 +00:00
std : : shared_ptr < Effect > frequencyEffect = std : : make_shared < Effect > (
2024-01-07 16:17:20 +00:00
[ this ] ( int index , Point input , const std : : vector < double > & values , double sampleRate ) {
2023-07-14 14:34:24 +00:00
frequency = values [ 0 ] ;
return input ;
2023-12-17 21:32:56 +00:00
} , new EffectParameter (
" Frequency " ,
" Controls how many times per second the image is drawn, thereby controlling the pitch of the sound. Lower frequencies result in more-accurately drawn images, but more flickering, and vice versa. " ,
" frequency " ,
VERSION_HINT , 440.0 , 0.0 , 12000.0 , 0.1
)
2023-07-14 14:34:24 +00:00
) ;
std : : shared_ptr < Effect > volumeEffect = std : : make_shared < Effect > (
2024-01-07 16:17:20 +00:00
[ this ] ( int index , Point input , const std : : vector < double > & values , double sampleRate ) {
2023-07-14 14:34:24 +00:00
volume = values [ 0 ] ;
return input ;
2023-12-17 21:32:56 +00:00
} , new EffectParameter (
" Volume " ,
" Controls the volume of the sound. Works by scaling the image and sound by a factor. " ,
" volume " ,
VERSION_HINT , 1.0 , 0.0 , 3.0
)
2023-07-14 14:34:24 +00:00
) ;
std : : shared_ptr < Effect > thresholdEffect = std : : make_shared < Effect > (
2024-01-07 16:17:20 +00:00
[ this ] ( int index , Point input , const std : : vector < double > & values , double sampleRate ) {
2023-07-14 14:34:24 +00:00
threshold = values [ 0 ] ;
return input ;
2023-12-17 21:32:56 +00:00
} , new EffectParameter (
" Threshold " ,
" Clips the sound and image to a maximum value. Applying a harsher threshold results in a more distorted sound. " ,
" threshold " ,
VERSION_HINT , 1.0 , 0.0 , 1.0
)
2023-07-14 14:34:24 +00:00
) ;
2023-03-30 20:09:53 +00:00
2023-08-28 21:06:21 +00:00
std : : shared_ptr < Effect > traceMax = std : : make_shared < Effect > (
2024-01-07 16:17:20 +00:00
[ this ] ( int index , Point input , const std : : vector < double > & values , double sampleRate ) {
2023-08-28 21:06:21 +00:00
return input ;
2023-12-17 21:32:56 +00:00
} , new EffectParameter (
" Trace max " ,
" Defines the maximum proportion of the image that is drawn before skipping to the next frame. This has the effect of 'tracing' out the image from a single dot when animated. By default, we draw until the end of the frame, so this value is 1.0. " ,
" traceMax " ,
VERSION_HINT , 1.0 , 0.0 , 1.0
)
2023-08-28 21:06:21 +00:00
) ;
std : : shared_ptr < Effect > traceMin = std : : make_shared < Effect > (
2024-01-07 16:17:20 +00:00
[ this ] ( int index , Point input , const std : : vector < double > & values , double sampleRate ) {
2023-08-28 21:06:21 +00:00
return input ;
2023-12-17 21:32:56 +00:00
} , new EffectParameter (
" Trace min " ,
" Defines the proportion of the image that drawing starts from. This has the effect of 'tracing' out the image from a single dot when animated. By default, we start drawing from the beginning of the frame, so this value is 0.0. " ,
" traceMin " ,
VERSION_HINT , 0.0 , 0.0 , 1.0
)
2023-08-28 21:06:21 +00:00
) ;
2023-07-11 12:32:52 +00:00
std : : shared_ptr < DelayEffect > delayEffect = std : : make_shared < DelayEffect > ( ) ;
2024-01-07 19:48:02 +00:00
2023-12-20 17:47:58 +00:00
std : : function < void ( int , juce : : String , juce : : String ) > errorCallback = [ this ] ( int lineNum , juce : : String fileName , juce : : String error ) { notifyErrorListeners ( lineNum , fileName , error ) ; } ;
2024-01-07 19:48:02 +00:00
std : : shared_ptr < CustomEffect > customEffect = std : : make_shared < CustomEffect > ( errorCallback ) ;
std : : shared_ptr < PerspectiveEffect > perspectiveEffect = std : : make_shared < PerspectiveEffect > ( VERSION_HINT ) ;
std : : shared_ptr < Effect > perspective = std : : make_shared < Effect > (
perspectiveEffect ,
std : : vector < EffectParameter * > {
new EffectParameter ( " 3D Perspective " , " Controls the strength of the 3D perspective projection. " , " perspectiveStrength " , VERSION_HINT , 1.0 , 0.0 , 1.0 ) ,
2024-01-17 01:26:07 +00:00
new 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 , 1.0 , 0.0 , 10.0 ) ,
2024-01-07 19:48:02 +00:00
new EffectParameter ( " Distance (z) " , " Controls how far away the 3D object is drawn away from the camera (the Z position). " , " perspectiveZPos " , VERSION_HINT , 0.1 , 0.0 , 1.0 ) ,
new EffectParameter ( " Rotate Speed " , " Controls how fast the 3D object rotates in the direction determined by the rotation sliders below. " , " perspectiveRotateSpeed " , VERSION_HINT , 0.0 , - 1.0 , 1.0 ) ,
new EffectParameter ( " Rotate X " , " Controls the rotation of the object in the X axis. " , " perspectiveRotateX " , VERSION_HINT , 1.0 , - 1.0 , 1.0 ) ,
new EffectParameter ( " Rotate Y " , " Controls the rotation of the object in the Y axis. " , " perspectiveRotateY " , VERSION_HINT , 1.0 , - 1.0 , 1.0 ) ,
new EffectParameter ( " Rotate Z " , " Controls the rotation of the object in the Z axis. " , " perspectiveRotateZ " , VERSION_HINT , 0.0 , - 1.0 , 1.0 ) ,
}
) ;
2023-07-04 19:47:54 +00:00
2023-12-18 13:41:56 +00:00
BooleanParameter * midiEnabled = new BooleanParameter ( " MIDI Enabled " , " midiEnabled " , VERSION_HINT , false ) ;
2023-12-14 21:26:40 +00:00
BooleanParameter * inputEnabled = new BooleanParameter ( " Audio Input Enabled " , " inputEnabled " , VERSION_HINT , false ) ;
2023-09-07 21:04:08 +00:00
std : : atomic < float > frequency = 440.0f ;
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 ;
2023-08-28 21:06:21 +00:00
std : : vector < ShapeSound : : Ptr > sounds ;
2023-03-30 16:28:47 +00:00
std : : vector < std : : shared_ptr < juce : : MemoryBlock > > fileBlocks ;
2023-07-05 21:45:51 +00:00
std : : vector < juce : : String > fileNames ;
2023-12-20 18:43:03 +00:00
int currentFileId = 0 ;
std : : vector < int > fileIds ;
2023-07-04 19:47:54 +00:00
std : : atomic < int > currentFile = - 1 ;
2023-07-25 13:09:21 +00:00
juce : : ChangeBroadcaster broadcaster ;
2023-09-10 16:43:37 +00:00
std : : atomic < bool > objectServerRendering = false ;
juce : : ChangeBroadcaster fileChangeBroadcaster ;
2023-01-15 17:01:27 +00:00
2023-12-18 13:41:56 +00:00
FloatParameter * attackTime = new FloatParameter ( " Attack Time " , " attackTime " , VERSION_HINT , 0.005 , 0.0 , 1.0 ) ;
2023-11-25 15:37:33 +00:00
FloatParameter * attackLevel = new FloatParameter ( " Attack Level " , " attackLevel " , VERSION_HINT , 1.0 , 0.0 , 1.0 ) ;
2023-12-18 13:41:56 +00:00
FloatParameter * decayTime = new FloatParameter ( " Decay Time " , " decayTime " , VERSION_HINT , 0.095 , 0.0 , 1.0 ) ;
FloatParameter * sustainLevel = new FloatParameter ( " Sustain Level " , " sustainLevel " , VERSION_HINT , 0.6 , 0.0 , 1.0 ) ;
FloatParameter * releaseTime = new FloatParameter ( " Release Time " , " releaseTime " , VERSION_HINT , 0.4 , 0.0 , 1.0 ) ;
2023-11-25 16:38:09 +00:00
FloatParameter * attackShape = new FloatParameter ( " Attack Shape " , " attackShape " , VERSION_HINT , 5 , - 50 , 50 ) ;
FloatParameter * decayShape = new FloatParameter ( " Decay Shape " , " decayShape " , VERSION_HINT , - 20 , - 50 , 50 ) ;
2023-12-18 13:41:56 +00:00
FloatParameter * releaseShape = new FloatParameter ( " Release Shape " , " releaseShape " , VERSION_HINT , - 5 , - 50 , 50 ) ;
2023-11-25 15:37:33 +00:00
Env adsrEnv = Env : : adsr (
2023-11-25 16:38:09 +00:00
attackTime - > getValueUnnormalised ( ) ,
decayTime - > getValueUnnormalised ( ) ,
sustainLevel - > getValueUnnormalised ( ) ,
releaseTime - > getValueUnnormalised ( ) ,
2023-11-25 15:37:33 +00:00
1.0 ,
std : : vector < EnvCurve > { attackShape - > getValueUnnormalised ( ) , decayShape - > getValueUnnormalised ( ) , releaseShape - > getValueUnnormalised ( ) }
) ;
2023-10-19 15:12:30 +00:00
2023-12-18 13:41:56 +00:00
juce : : MidiKeyboardState keyboardState ;
2023-12-21 14:14:33 +00:00
IntParameter * voices = new IntParameter ( " Voices " , " voices " , VERSION_HINT , 4 , 1 , 16 ) ;
2023-09-07 21:04:08 +00:00
private :
juce : : SpinLock consumerLock ;
std : : vector < std : : shared_ptr < BufferConsumer > > consumers ;
public :
2023-09-01 22:42:17 +00:00
PitchDetector pitchDetector { * this } ;
2023-07-13 19:11:24 +00:00
std : : shared_ptr < WobbleEffect > wobbleEffect = std : : make_shared < WobbleEffect > ( pitchDetector ) ;
2023-07-25 19:44:18 +00:00
// shouldn't be accessed by audio thread, but needs to persist when GUI is closed
// so should only be accessed by message thread
juce : : String currentProjectFile ;
2023-08-27 18:33:42 +00:00
juce : : SpinLock fontLock ;
juce : : Font font = juce : : Font ( juce : : Font : : getDefaultSansSerifFontName ( ) , 1.0f , juce : : Font : : plain ) ;
2023-09-10 16:43:37 +00:00
ShapeSound : : Ptr objectServerSound = new ShapeSound ( ) ;
2023-07-04 13:58:36 +00:00
void addLuaSlider ( ) ;
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-07-25 13:09:21 +00:00
void addFile ( juce : : String fileName , std : : shared_ptr < juce : : MemoryBlock > data ) ;
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 ) ;
2023-08-27 18:33:42 +00:00
void openFile ( int index ) ;
2023-03-30 20:09:53 +00:00
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-12-20 18:43:03 +00:00
juce : : String getFileId ( int index ) ;
2023-03-30 16:28:47 +00:00
std : : shared_ptr < juce : : MemoryBlock > getFileBlock ( int index ) ;
2023-09-10 16:43:37 +00:00
void setObjectServerRendering ( bool enabled ) ;
2023-10-19 11:20:24 +00:00
void updateLuaValues ( ) ;
2023-12-20 17:13:38 +00:00
void addErrorListener ( ErrorListener * listener ) ;
void removeErrorListener ( ErrorListener * listener ) ;
2023-12-20 17:47:58 +00:00
void notifyErrorListeners ( int lineNumber , juce : : String fileName , juce : : String error ) ;
2023-01-09 21:58:49 +00:00
private :
2023-07-14 14:34:24 +00:00
std : : atomic < double > volume = 1.0 ;
std : : atomic < double > threshold = 1.0 ;
2023-09-07 21:04:08 +00:00
bool prevMidiEnabled = ! midiEnabled - > getBoolValue ( ) ;
2023-01-15 17:01:27 +00:00
2024-01-28 19:58:28 +00:00
juce : : SpinLock audioThreadCallbackLock ;
std : : function < void ( const juce : : AudioBuffer < float > & ) > audioThreadCallback ;
2023-07-25 13:09:21 +00:00
std : : vector < BooleanParameter * > booleanParameters ;
2023-12-21 14:43:15 +00:00
std : : vector < FloatParameter * > floatParameters ;
std : : vector < IntParameter * > intParameters ;
2023-07-25 11:23:27 +00:00
std : : vector < std : : shared_ptr < Effect > > allEffects ;
2023-07-14 14:34:24 +00:00
std : : vector < std : : shared_ptr < Effect > > permanentEffects ;
2023-12-20 17:13:38 +00:00
juce : : SpinLock errorListenersLock ;
std : : vector < ErrorListener * > errorListeners ;
2023-09-05 21:57:29 +00:00
ShapeSound : : Ptr defaultSound = new ShapeSound ( std : : make_shared < FileParser > ( ) ) ;
2023-12-14 21:26:40 +00:00
PublicSynthesiser synth ;
2023-12-21 17:24:39 +00:00
bool retriggerMidi = true ;
2023-07-06 16:57:10 +00:00
2023-09-01 22:42:17 +00:00
AudioWebSocketServer softwareOscilloscopeServer { * this } ;
2023-09-10 16:43:37 +00:00
ObjectServer objectServer { * this } ;
2023-07-10 21:00:36 +00:00
2024-01-01 15:09:46 +00:00
const double VOLUME_BUFFER_SECONDS = 0.1 ;
std : : vector < double > volumeBuffer ;
int volumeBufferIndex = 0 ;
2024-01-01 16:21:10 +00:00
double squaredVolume = 0 ;
2024-01-01 15:09:46 +00:00
double currentVolume = 0 ;
2023-07-25 13:09:21 +00:00
std : : shared_ptr < Effect > getEffect ( juce : : String id ) ;
BooleanParameter * getBooleanParameter ( juce : : String id ) ;
2023-12-21 14:43:15 +00:00
FloatParameter * getFloatParameter ( juce : : String id ) ;
IntParameter * getIntParameter ( juce : : String id ) ;
2023-07-28 12:55:44 +00:00
void openLegacyProject ( const juce : : XmlElement * xml ) ;
std : : pair < std : : shared_ptr < Effect > , EffectParameter * > effectFromLegacyId ( const juce : : String & id , bool updatePrecedence = false ) ;
LfoType lfoTypeFromLegacyAnimationType ( const juce : : String & type ) ;
double valueFromLegacy ( double value , const juce : : String & id ) ;
2023-09-07 21:04:08 +00:00
void changeSound ( ShapeSound : : Ptr sound ) ;
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 )
} ;