1
- /*
1
+ /*
2
2
==============================================================================
3
3
4
4
AudioEngine.cpp
5
- (Final fix using std::function callback )
5
+ (Fully Functional Send/Return FX Architecture )
6
6
7
7
==============================================================================
8
8
*/
14
14
#include " SoundPlayer.h"
15
15
16
16
AudioEngine::AudioEngine (juce::AudioDeviceManager& manager)
17
- : deviceManager(manager)
17
+ : deviceManager(manager),
18
+ vocalFxChain(Identifiers::VocalFx1State, Identifiers::VocalFx2State, Identifiers::VocalFx3State, Identifiers::VocalFx4State),
19
+ musicFxChain(Identifiers::MusicFx1State, Identifiers::MusicFx2State, Identifiers::MusicFx3State, Identifiers::MusicFx4State)
18
20
{
19
21
soundPlayer = std::make_unique<IdolAZ::SoundPlayer>();
20
22
}
@@ -36,23 +38,30 @@ void AudioEngine::audioDeviceAboutToStart(juce::AudioIODevice* device)
36
38
vocalProcessor.prepare (stereoSpec);
37
39
musicProcessor.prepare (stereoSpec);
38
40
masterProcessor.prepare (stereoSpec);
41
+
42
+ for (auto & fxProc : vocalFxChain.processors ) fxProc.prepare (stereoSpec);
43
+ for (auto & fxProc : musicFxChain.processors ) fxProc.prepare (stereoSpec);
39
44
40
45
soundPlayer->prepareToPlay (currentBlockSize, currentSampleRate);
41
46
42
47
vocalBuffer.setSize (2 , currentBlockSize);
43
48
musicStereoBuffer.setSize (2 , currentBlockSize);
44
49
mixBuffer.setSize (2 , currentBlockSize);
45
50
soundboardBuffer.setSize (2 , currentBlockSize);
51
+
52
+ fxSendBuffer.setSize (2 , currentBlockSize);
53
+ for (auto & buffer : vocalFxReturnBuffers) buffer.setSize (2 , currentBlockSize);
54
+ for (auto & buffer : musicFxReturnBuffers) buffer.setSize (2 , currentBlockSize);
46
55
47
56
vocalProcessor.reset ();
48
57
musicProcessor.reset ();
49
58
masterProcessor.reset ();
50
59
51
- // --- NEW LOGIC: Trigger the callback ---
60
+ for (auto & fxProc : vocalFxChain.processors ) fxProc.reset ();
61
+ for (auto & fxProc : musicFxChain.processors ) fxProc.reset ();
62
+
52
63
if (onDeviceStarted)
53
64
{
54
- // Use callAsync to run the callback on the main message thread,
55
- // which is safe for UI operations and completing the session restore.
56
65
juce::MessageManager::callAsync (onDeviceStarted);
57
66
}
58
67
}
@@ -63,6 +72,10 @@ void AudioEngine::audioDeviceStopped()
63
72
vocalProcessor.reset ();
64
73
musicProcessor.reset ();
65
74
masterProcessor.reset ();
75
+
76
+ for (auto & fxProc : vocalFxChain.processors ) fxProc.reset ();
77
+ for (auto & fxProc : musicFxChain.processors ) fxProc.reset ();
78
+
66
79
soundPlayer->releaseResources ();
67
80
68
81
currentSampleRate = 0.0 ;
@@ -79,29 +92,33 @@ void AudioEngine::audioDeviceStopped()
79
92
musicTrackComponent->populateInputChannels ({}, {});
80
93
}
81
94
95
+
96
+ // <<< MODIFIED: Full audio callback logic with send/return levels >>>
82
97
void AudioEngine::audioDeviceIOCallbackWithContext (const float * const * inputChannelData, int numInputChannels,
83
98
float * const * outputChannelData, int numOutputChannels,
84
99
int numSamples, const juce::AudioIODeviceCallbackContext& context)
85
100
{
86
101
juce::ignoreUnused (context);
87
102
juce::ScopedNoDenormals noDenormals;
88
103
104
+ vocalBuffer.clear ();
105
+ musicStereoBuffer.clear ();
106
+ mixBuffer.clear ();
107
+ soundboardBuffer.clear ();
108
+ for (auto & buffer : vocalFxReturnBuffers) buffer.clear ();
109
+ for (auto & buffer : musicFxReturnBuffers) buffer.clear ();
110
+
89
111
const int currentVocalIn = vocalInputChannel.load ();
90
112
const int currentMusicLeftIn = musicInputLeftChannel.load ();
91
113
const int currentMusicRightIn = musicInputRightChannel.load ();
92
114
const int currentOutputLeft = selectedOutputLeftChannel.load ();
93
115
const int currentOutputRight = selectedOutputRightChannel.load ();
94
116
95
- vocalBuffer.clear ();
96
- musicStereoBuffer.clear ();
97
- mixBuffer.clear ();
98
- soundboardBuffer.clear ();
99
-
117
+ // --- Process main "dry" signal paths ---
100
118
if (juce::isPositiveAndBelow (currentVocalIn, numInputChannels))
101
119
{
102
- const float * monoInputSignal = inputChannelData[currentVocalIn];
103
- vocalBuffer.copyFrom (0 , 0 , monoInputSignal, numSamples);
104
- vocalBuffer.copyFrom (1 , 0 , monoInputSignal, numSamples);
120
+ vocalBuffer.copyFrom (0 , 0 , inputChannelData[currentVocalIn], numSamples);
121
+ vocalBuffer.copyFrom (1 , 0 , inputChannelData[currentVocalIn], numSamples);
105
122
vocalProcessor.process (vocalBuffer);
106
123
}
107
124
@@ -116,15 +133,55 @@ void AudioEngine::audioDeviceIOCallbackWithContext(const float* const* inputChan
116
133
juce::AudioSourceChannelInfo soundboardChannelInfo (&soundboardBuffer, 0 , numSamples);
117
134
soundPlayer->getNextAudioBlock (soundboardChannelInfo);
118
135
136
+ // --- Process FX Send/Return paths ---
137
+ // Vocal FX
138
+ for (int i = 0 ; i < 4 ; ++i)
139
+ {
140
+ fxSendBuffer.copyFrom (0 , 0 , vocalBuffer, 0 , 0 , numSamples);
141
+ fxSendBuffer.copyFrom (1 , 0 , vocalBuffer, 1 , 0 , numSamples);
142
+ fxSendBuffer.applyGain (vocalFxChain.processors [i].getSendLevel ());
143
+
144
+ vocalFxChain.processors [i].process (fxSendBuffer);
145
+
146
+ vocalFxReturnBuffers[i].copyFrom (0 , 0 , fxSendBuffer, 0 , 0 , numSamples);
147
+ vocalFxReturnBuffers[i].copyFrom (1 , 0 , fxSendBuffer, 1 , 0 , numSamples);
148
+ vocalFxReturnBuffers[i].applyGain (vocalFxChain.processors [i].getReturnLevel ());
149
+ }
150
+
151
+ // Music FX
152
+ for (int i = 0 ; i < 4 ; ++i)
153
+ {
154
+ fxSendBuffer.copyFrom (0 , 0 , musicStereoBuffer, 0 , 0 , numSamples);
155
+ fxSendBuffer.copyFrom (1 , 0 , musicStereoBuffer, 1 , 0 , numSamples);
156
+ fxSendBuffer.applyGain (musicFxChain.processors [i].getSendLevel ());
157
+
158
+ musicFxChain.processors [i].process (fxSendBuffer);
159
+
160
+ musicFxReturnBuffers[i].copyFrom (0 , 0 , fxSendBuffer, 0 , 0 , numSamples);
161
+ musicFxReturnBuffers[i].copyFrom (1 , 0 , fxSendBuffer, 1 , 0 , numSamples);
162
+ musicFxReturnBuffers[i].applyGain (musicFxChain.processors [i].getReturnLevel ());
163
+ }
164
+
165
+ // --- Sum all signals into the main mix buffer ---
119
166
mixBuffer.addFrom (0 , 0 , vocalBuffer, 0 , 0 , numSamples);
120
167
mixBuffer.addFrom (1 , 0 , vocalBuffer, 1 , 0 , numSamples);
121
168
mixBuffer.addFrom (0 , 0 , musicStereoBuffer, 0 , 0 , numSamples);
122
169
mixBuffer.addFrom (1 , 0 , musicStereoBuffer, 1 , 0 , numSamples);
123
170
mixBuffer.addFrom (0 , 0 , soundboardBuffer, 0 , 0 , numSamples);
124
171
mixBuffer.addFrom (1 , 0 , soundboardBuffer, 1 , 0 , numSamples);
172
+
173
+ for (int i = 0 ; i < 4 ; ++i)
174
+ {
175
+ mixBuffer.addFrom (0 , 0 , vocalFxReturnBuffers[i], 0 , 0 , numSamples);
176
+ mixBuffer.addFrom (1 , 0 , vocalFxReturnBuffers[i], 1 , 0 , numSamples);
177
+ mixBuffer.addFrom (0 , 0 , musicFxReturnBuffers[i], 0 , 0 , numSamples);
178
+ mixBuffer.addFrom (1 , 0 , musicFxReturnBuffers[i], 1 , 0 , numSamples);
179
+ }
125
180
181
+ // --- Process the final Master Processor Chain ---
126
182
masterProcessor.process (mixBuffer);
127
183
184
+ // --- Final Output ---
128
185
for (int i = 0 ; i < numOutputChannels; ++i)
129
186
juce::FloatVectorOperations::clear (outputChannelData[i], numSamples);
130
187
@@ -135,6 +192,21 @@ void AudioEngine::audioDeviceIOCallbackWithContext(const float* const* inputChan
135
192
juce::FloatVectorOperations::copy (outputChannelData[currentOutputRight], mixBuffer.getReadPointer (1 ), numSamples);
136
193
}
137
194
195
+
196
+ TrackProcessor* AudioEngine::getFxProcessorForVocal (int index)
197
+ {
198
+ if (juce::isPositiveAndBelow (index, 4 ))
199
+ return &vocalFxChain.processors [index];
200
+ return nullptr ;
201
+ }
202
+
203
+ TrackProcessor* AudioEngine::getFxProcessorForMusic (int index)
204
+ {
205
+ if (juce::isPositiveAndBelow (index, 4 ))
206
+ return &musicFxChain.processors [index];
207
+ return nullptr ;
208
+ }
209
+
138
210
void AudioEngine::setVocalInputChannel (int channelIndex)
139
211
{
140
212
vocalInputChannel.store (channelIndex);
0 commit comments