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"
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 ;
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
int VERSION_HINT = 1 ;
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 > (
[ this ] ( int index , Vector2 input , const std : : vector < double > & values , double sampleRate ) {
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 > (
[ this ] ( int index , Vector2 input , const std : : vector < double > & values , double sampleRate ) {
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 > (
[ this ] ( int index , Vector2 input , const std : : vector < double > & values , double sampleRate ) {
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-07-14 14:34:24 +00:00
std : : shared_ptr < Effect > focalLength = std : : make_shared < Effect > (
[ this ] ( int index , Vector2 input , const std : : vector < double > & values , double sampleRate ) {
2023-07-05 11:02:28 +00:00
if ( getCurrentFileIndex ( ) ! = - 1 ) {
auto camera = getCurrentFileParser ( ) - > getCamera ( ) ;
if ( camera = = nullptr ) return input ;
2023-07-14 14:34:24 +00:00
camera - > setFocalLength ( values [ 0 ] ) ;
2023-07-05 11:02:28 +00:00
}
return input ;
2023-12-17 21:32:56 +00:00
} , new EffectParameter (
" Focal length " ,
" Controls the focal length of the camera being used to render the 3D object. A lower focal length results in a wider field of view, distorting the image, and making the image smaller. " ,
" objFocalLength " ,
VERSION_HINT , 1.0 , 0.0 , 2.0
)
2023-07-14 14:34:24 +00:00
) ;
2023-07-19 20:40:31 +00:00
2023-09-01 18:52:36 +00:00
BooleanParameter * fixedRotateX = new BooleanParameter ( " Object Fixed Rotate X " , " objFixedRotateX " , VERSION_HINT , false ) ;
BooleanParameter * fixedRotateY = new BooleanParameter ( " Object Fixed Rotate Y " , " objFixedRotateY " , VERSION_HINT , false ) ;
BooleanParameter * fixedRotateZ = new BooleanParameter ( " Object Fixed Rotate Z " , " objFixedRotateZ " , VERSION_HINT , false ) ;
2023-07-14 14:34:24 +00:00
std : : shared_ptr < Effect > rotateX = std : : make_shared < Effect > (
[ this ] ( int index , Vector2 input , const std : : vector < double > & values , double sampleRate ) {
2023-07-05 16:57:41 +00:00
if ( getCurrentFileIndex ( ) ! = - 1 ) {
auto obj = getCurrentFileParser ( ) - > getObject ( ) ;
if ( obj = = nullptr ) return input ;
2023-07-19 20:40:31 +00:00
auto rotation = values [ 0 ] * std : : numbers : : pi ;
2023-07-22 14:07:11 +00:00
if ( fixedRotateX - > getBoolValue ( ) ) {
2023-07-19 20:40:31 +00:00
obj - > setCurrentRotationX ( rotation ) ;
} else {
obj - > setBaseRotationX ( rotation ) ;
}
2023-07-05 16:57:41 +00:00
}
return input ;
2023-12-17 21:32:56 +00:00
} , new EffectParameter (
" Object Rotate X " ,
" Controls the rotation of the 3D object around the X axis. When Object Fixed Rotate X is enabled, the object is unaffected by the rotation speed, and remains in a fixed position. " ,
" objRotateX " ,
VERSION_HINT , 1.0 , - 1.0 , 1.0
)
2023-07-14 14:34:24 +00:00
) ;
std : : shared_ptr < Effect > rotateY = std : : make_shared < Effect > (
[ this ] ( int index , Vector2 input , const std : : vector < double > & values , double sampleRate ) {
2023-07-05 16:57:41 +00:00
if ( getCurrentFileIndex ( ) ! = - 1 ) {
auto obj = getCurrentFileParser ( ) - > getObject ( ) ;
if ( obj = = nullptr ) return input ;
2023-07-19 20:40:31 +00:00
auto rotation = values [ 0 ] * std : : numbers : : pi ;
2023-07-22 14:07:11 +00:00
if ( fixedRotateY - > getBoolValue ( ) ) {
2023-07-19 20:40:31 +00:00
obj - > setCurrentRotationY ( rotation ) ;
} else {
obj - > setBaseRotationY ( rotation ) ;
}
2023-07-05 16:57:41 +00:00
}
return input ;
2023-12-17 21:32:56 +00:00
} , new EffectParameter (
" Object Rotate Y " ,
" Controls the rotation of the 3D object around the Y axis. When Object Fixed Rotate Y is enabled, the object is unaffected by the rotation speed, and remains in a fixed position. " ,
" objRotateY " ,
VERSION_HINT , 1.0 , - 1.0 , 1.0
)
2023-07-14 14:34:24 +00:00
) ;
std : : shared_ptr < Effect > rotateZ = std : : make_shared < Effect > (
[ this ] ( int index , Vector2 input , const std : : vector < double > & values , double sampleRate ) {
2023-07-05 16:57:41 +00:00
if ( getCurrentFileIndex ( ) ! = - 1 ) {
auto obj = getCurrentFileParser ( ) - > getObject ( ) ;
if ( obj = = nullptr ) return input ;
2023-07-19 20:40:31 +00:00
auto rotation = values [ 0 ] * std : : numbers : : pi ;
2023-07-22 14:07:11 +00:00
if ( fixedRotateZ - > getBoolValue ( ) ) {
2023-07-19 20:40:31 +00:00
obj - > setCurrentRotationZ ( rotation ) ;
} else {
obj - > setBaseRotationZ ( rotation ) ;
}
2023-07-05 16:57:41 +00:00
}
return input ;
2023-12-17 21:32:56 +00:00
} , new EffectParameter (
" Object Rotate Z " ,
" Controls the rotation of the 3D object around the Z axis. When Object Fixed Rotate Z is enabled, the object is unaffected by the rotation speed, and remains in a fixed position. " ,
" objRotateZ " ,
VERSION_HINT , 0.0 , - 1.0 , 1.0
)
2023-07-14 14:34:24 +00:00
) ;
std : : shared_ptr < Effect > rotateSpeed = std : : make_shared < Effect > (
[ this ] ( int index , Vector2 input , const std : : vector < double > & values , double sampleRate ) {
if ( getCurrentFileIndex ( ) ! = - 1 ) {
auto obj = getCurrentFileParser ( ) - > getObject ( ) ;
if ( obj = = nullptr ) return input ;
obj - > setRotationSpeed ( values [ 0 ] ) ;
}
return input ;
2023-12-17 21:32:56 +00:00
} , new EffectParameter (
" Rotate Speed " ,
" Controls the speed at which the 3D object rotates. A negative value results in the object rotating in the opposite direction. The rotate speed is scaled by the different Object Rotate Axis values to rotate the object. " ,
" objRotateSpeed " ,
VERSION_HINT , 0.0 , - 1.0 , 1.0
)
2023-07-14 14:34:24 +00:00
) ;
2023-07-11 12:32:52 +00:00
2023-08-28 21:06:21 +00:00
std : : shared_ptr < Effect > traceMax = std : : make_shared < Effect > (
[ this ] ( int index , Vector2 input , const std : : vector < double > & values , double sampleRate ) {
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 > (
[ this ] ( int index , Vector2 input , const std : : vector < double > & values , double sampleRate ) {
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 > ( ) ;
2023-09-01 18:52:36 +00:00
std : : shared_ptr < PerspectiveEffect > perspectiveEffect = std : : make_shared < PerspectiveEffect > ( VERSION_HINT ) ;
2023-07-04 19:47:54 +00:00
2023-09-10 17:52:21 +00:00
BooleanParameter * midiEnabled = new BooleanParameter ( " MIDI Enabled " , " midiEnabled " , VERSION_HINT , ! juce : : JUCEApplicationBase : : isStandaloneApp ( ) ) ;
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-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-11-25 16:38:09 +00:00
FloatParameter * attackTime = new FloatParameter ( " Attack Time " , " attackTime " , VERSION_HINT , 0.05 , 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-11-25 16:38:09 +00:00
FloatParameter * decayTime = new FloatParameter ( " Decay Time " , " decayTime " , VERSION_HINT , 0.05 , 0.0 , 1.0 ) ;
FloatParameter * sustainLevel = new FloatParameter ( " Sustain Level " , " sustainLevel " , VERSION_HINT , 0.8 , 0.0 , 1.0 ) ;
FloatParameter * releaseTime = new FloatParameter ( " Release Time " , " releaseTime " , VERSION_HINT , 0.2 , 0.0 , 1.0 ) ;
FloatParameter * attackShape = new FloatParameter ( " Attack Shape " , " attackShape " , VERSION_HINT , 5 , - 50 , 50 ) ;
FloatParameter * decayShape = new FloatParameter ( " Decay Shape " , " decayShape " , VERSION_HINT , - 20 , - 50 , 50 ) ;
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-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-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-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
2023-07-25 13:09:21 +00:00
std : : vector < BooleanParameter * > booleanParameters ;
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-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-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
2023-07-05 11:02:28 +00:00
void updateObjValues ( ) ;
2023-07-25 13:09:21 +00:00
std : : shared_ptr < Effect > getEffect ( juce : : String id ) ;
BooleanParameter * getBooleanParameter ( 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 )
} ;