1+ #include " PluginProcessor.h"
2+ #include " PluginEditor.h"
3+ #include < iostream>
4+ #include < jonssonic/utils/buffer_utils.h>
5+
6+ ChorusAudioProcessor::ChorusAudioProcessor () : parameterManager(ChorusParams().createParams(), *this) {
7+ // ============================================================================
8+ // [DEBUG]: Prints all APVTS parameter IDs at startup
9+ // This helps verify that your parameters are registered correctly.
10+ // You can remove or comment out this block when you no longer need it.
11+ auto & apvts = parameterManager.getAPVTS ();
12+ DBG (" [DEBUG] APVTS parameter IDs at startup:" );
13+ for (auto * param : apvts.processor .getParameters ()) {
14+ if (auto * paramWithID = dynamic_cast <juce::AudioProcessorParameterWithID*>(param)) {
15+ DBG (" " + paramWithID->paramID );
16+ }
17+ }
18+ // ============================================================================
19+
20+ // Register callbacks for parameter changes
21+ using ID = ChorusParams::ID;
22+
23+ parameterManager.on (ID::Mix, [this ](float value, bool skipSmoothing) {
24+ DBG (" [DEBUG] Mix changed: " + juce::String (value) + " , skipSmoothing: " + (skipSmoothing ? " true" : " false" ));
25+ // Call your DSP mix setter here
26+ dryWetMixer.setMix (value * 0 .01f ); // We are converting from [0,100] to [0,1]
27+ });
28+ parameterManager.on (ID::Enable, [this ](bool value, bool skipSmoothing) {
29+ DBG (" [DEBUG] Enable changed: " + juce::String (value ? " true" : " false" ) +
30+ " , skipSmoothing: " + (skipSmoothing ? " true" : " false" ));
31+ // Call your DSP enable setter here
32+ });
33+ parameterManager.on (ID::Mode, [this ](int value, bool skipSmoothing) {
34+ DBG (" [DEBUG] Mode changed: " + juce::String (value) + " , skipSmoothing: " + (skipSmoothing ? " true" : " false" ));
35+ // Call your DSP mode setter here
36+ });
37+ }
38+
39+ ChorusAudioProcessor::~ChorusAudioProcessor () {}
40+
41+ void ChorusAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock) {
42+ auto numChannels = static_cast <size_t >(getTotalNumOutputChannels ());
43+ // Prepare all DSP objects and buffers here
44+ dryWetMixer.prepare (numChannels, static_cast <float >(sampleRate));
45+ fxBuffer.resize (numChannels, static_cast <size_t >(samplesPerBlock));
46+
47+ // Initialize DSP with parameter defaults (defined in Params.h) (skip smoothing for instant setup)
48+ parameterManager.syncAll (true );
49+ }
50+
51+ void ChorusAudioProcessor::releaseResources () {
52+ // Release DSP resources here
53+ dryWetMixer.reset ();
54+ fxBuffer.resize (0 , 0 );
55+ }
56+
57+ void ChorusAudioProcessor::processBlock (juce::AudioBuffer<float >& buffer, juce::MidiBuffer& midiMessages) {
58+ // Get audio buffer info
59+ const int numInputChannels = getTotalNumInputChannels ();
60+ const int numOutputChannels = getTotalNumOutputChannels ();
61+ const int numSamples = buffer.getNumSamples ();
62+
63+ // Early return if no audio to process
64+ if (numInputChannels == 0 || numOutputChannels == 0 || numSamples == 0 )
65+ return ;
66+ // Update all parameters from FIFO (GUI thread → Audio thread)
67+ parameterManager.update ();
68+
69+ // Handle denormals
70+ juce::ScopedNoDenormals noDenormals;
71+
72+ // Note: Jonssonic DSP expects numInputChannels == numOutputChannels
73+ // So we map the input channels to output channels accordingly
74+ jnsc::utils::mapChannels<float >(
75+ buffer.getArrayOfReadPointers (), // juce::AudioBuffer<float> uses getArrayOfReadPointers() for const access
76+ fxBuffer.writePtrs (), // Jonssonic::AudioBuffer<float> uses writePtrs() for non-const access
77+ numInputChannels,
78+ numOutputChannels,
79+ numSamples);
80+
81+ // DSP processing here (this template includes only a dry/wet mixer as an example)
82+ dryWetMixer.processBlock (buffer.getArrayOfReadPointers (), // dry buffer
83+ fxBuffer.readPtrs (), // wet buffer
84+ buffer.getArrayOfWritePointers (), // final output
85+ static_cast <size_t >(numSamples)); // number of samples
86+ }
87+
88+ void ChorusAudioProcessor::getStateInformation (juce::MemoryBlock& destData) {
89+ // This is taken care of by the parameter manager automatically
90+ parameterManager.saveState (destData);
91+ }
92+
93+ void ChorusAudioProcessor::setStateInformation (const void * data, int sizeInBytes) {
94+ // This is taken care of by the parameter manager automatically
95+ parameterManager.loadState (data, sizeInBytes);
96+ }
97+
98+ bool ChorusAudioProcessor::acceptsMidi () const {
99+ return true ;
100+ }
101+
102+ // ==============================================================================
103+ const juce::String ChorusAudioProcessor::getName () const {
104+ return JucePlugin_Name;
105+ }
106+ bool ChorusAudioProcessor::producesMidi () const {
107+ return false ;
108+ }
109+ bool ChorusAudioProcessor::isMidiEffect () const {
110+ return false ;
111+ }
112+ double ChorusAudioProcessor::getTailLengthSeconds () const {
113+ return 0.0 ;
114+ }
115+ int ChorusAudioProcessor::getNumPrograms () {
116+ return 1 ;
117+ }
118+ int ChorusAudioProcessor::getCurrentProgram () {
119+ return 0 ;
120+ }
121+ void ChorusAudioProcessor::setCurrentProgram (int ) {}
122+ const juce::String ChorusAudioProcessor::getProgramName (int ) {
123+ return {};
124+ }
125+ void ChorusAudioProcessor::changeProgramName (int , const juce::String&) {}
126+ bool ChorusAudioProcessor::hasEditor () const {
127+ return true ;
128+ }
129+ juce::AudioProcessorEditor* ChorusAudioProcessor::createEditor () {
130+ return new ChorusAudioProcessorEditor (*this );
131+ }
132+ // ==============================================================================
133+
134+ // ==============================================================================
135+ // This creates new instances of the plugin..
136+ juce::AudioProcessor* JUCE_CALLTYPE createPluginFilter () {
137+ return new ChorusAudioProcessor ();
138+ }
0 commit comments