22 ==============================================================================
33
44 AudioEngine.cpp
5- (Fully Functional Send/Return FX Architecture )
5+ (Fixed: Implemented robust two-stage preset loading orchestration )
66
77 ==============================================================================
88*/
99
1010#include " AudioEngine.h"
11+ #include " ../Data/AppState.h"
1112#include " ../GUI/Layout/TrackComponent.h"
1213#include " ../GUI/Layout/MasterUtilityComponent.h"
1314#include " juce_audio_devices/juce_audio_devices.h"
@@ -20,18 +21,14 @@ AudioEngine::AudioEngine(juce::AudioDeviceManager& manager)
2021 musicFxChain(Identifiers::MusicFx1State, Identifiers::MusicFx2State, Identifiers::MusicFx3State, Identifiers::MusicFx4State)
2122{
2223 formatManager.registerBasicFormats ();
23-
2424 audioRecorder = std::make_unique<AudioRecorder>(formatManager, " " );
2525 vocalTrackRecorder = std::make_unique<AudioRecorder>(formatManager, " Vocal" );
2626 musicTrackRecorder = std::make_unique<AudioRecorder>(formatManager, " Music" );
2727 rawVocalRecorder = std::make_unique<AudioRecorder>(formatManager, " Projects" );
2828 rawMusicRecorder = std::make_unique<AudioRecorder>(formatManager, " Projects" );
29-
3029 soundPlayer = std::make_unique<IdolAZ::SoundPlayer>();
31-
3230 soundboardMixer.addInputSource (soundPlayer.get (), false );
3331 directOutputMixer.addInputSource (&playbackSource, false );
34-
3532}
3633
3734AudioEngine::~AudioEngine ()
@@ -42,42 +39,31 @@ void AudioEngine::prepareAllProcessors(double sampleRate, int samplesPerBlock)
4239{
4340 stableSampleRate = sampleRate;
4441 stableBlockSize = samplesPerBlock;
45-
4642 currentSampleRate = sampleRate;
4743 currentBlockSize = samplesPerBlock;
48-
49- DBG (" AudioEngine preparing all processors with settings: "
50- << sampleRate << " Hz, " << samplesPerBlock << " samples." );
51-
44+ DBG (" AudioEngine preparing all processors with settings: " << sampleRate << " Hz, " << samplesPerBlock << " samples." );
5245 juce::dsp::ProcessSpec stereoSpec{ sampleRate, static_cast <uint32_t >(samplesPerBlock), 2 };
53-
5446 vocalProcessor.prepare (stereoSpec);
5547 musicProcessor.prepare (stereoSpec);
5648 masterProcessor.prepare (stereoSpec);
57-
5849 for (auto & fxProc : vocalFxChain.processors ) fxProc.prepare (stereoSpec);
5950 for (auto & fxProc : musicFxChain.processors ) fxProc.prepare (stereoSpec);
60-
6151 soundboardMixer.prepareToPlay (samplesPerBlock, sampleRate);
6252 directOutputMixer.prepareToPlay (samplesPerBlock, sampleRate);
6353 playbackSource.prepareToPlay (samplesPerBlock, sampleRate);
6454 vocalTrackSource.prepareToPlay (samplesPerBlock, sampleRate);
6555 musicTrackSource.prepareToPlay (samplesPerBlock, sampleRate);
66-
6756 vocalBuffer.setSize (2 , samplesPerBlock);
6857 musicStereoBuffer.setSize (2 , samplesPerBlock);
6958 mixBuffer.setSize (2 , samplesPerBlock);
7059 soundboardBuffer.setSize (2 , samplesPerBlock);
7160 directOutputBuffer.setSize (2 , samplesPerBlock);
72-
7361 fxSendBuffer.setSize (2 , samplesPerBlock);
7462 for (auto & buffer : vocalFxReturnBuffers) buffer.setSize (2 , samplesPerBlock);
7563 for (auto & buffer : musicFxReturnBuffers) buffer.setSize (2 , samplesPerBlock);
76-
7764 vocalProcessor.reset ();
7865 musicProcessor.reset ();
7966 masterProcessor.reset ();
80-
8167 for (auto & fxProc : vocalFxChain.processors ) fxProc.reset ();
8268 for (auto & fxProc : musicFxChain.processors ) fxProc.reset ();
8369}
@@ -86,28 +72,22 @@ void AudioEngine::prepareAllProcessors(double sampleRate, int samplesPerBlock)
8672void AudioEngine::audioDeviceAboutToStart (juce::AudioIODevice* device)
8773{
8874 prepareAllProcessors (device->getCurrentSampleRate (), device->getCurrentBufferSizeSamples ());
89-
9075 if (onDeviceStarted)
91- {
9276 juce::MessageManager::callAsync (onDeviceStarted);
93- }
9477}
9578
9679void AudioEngine::audioDeviceStopped ()
9780{
9881 vocalProcessor.reset ();
9982 musicProcessor.reset ();
10083 masterProcessor.reset ();
101-
10284 for (auto & fxProc : vocalFxChain.processors ) fxProc.reset ();
10385 for (auto & fxProc : musicFxChain.processors ) fxProc.reset ();
104-
10586 soundboardMixer.releaseResources ();
10687 directOutputMixer.releaseResources ();
10788 playbackSource.releaseResources ();
10889 vocalTrackSource.releaseResources ();
10990 musicTrackSource.releaseResources ();
110-
11191 currentSampleRate = 0.0 ;
11292 currentBlockSize = 0 ;
11393 vocalInputChannel.store (-1 );
@@ -117,47 +97,30 @@ void AudioEngine::audioDeviceStopped()
11797 selectedOutputRightChannel.store (-1 );
11898}
11999
120- void AudioEngine::audioDeviceIOCallbackWithContext (const float * const * inputChannelData, int numInputChannels,
121- float * const * outputChannelData, int numOutputChannels,
122- int numSamples, const juce::AudioIODeviceCallbackContext& context)
100+ void AudioEngine::audioDeviceIOCallbackWithContext (const float * const * inputChannelData, int numInputChannels, float * const * outputChannelData, int numOutputChannels, int numSamples, const juce::AudioIODeviceCallbackContext& context)
123101{
124102 juce::ignoreUnused (context);
125-
126- // <<< FIX: Use deviceManager to get the current device safely >>>
127103 if (auto * currentDevice = deviceManager.getCurrentAudioDevice ())
128104 {
129105 if (numSamples != currentBlockSize || currentDevice->getCurrentSampleRate () != currentSampleRate)
130- {
131106 prepareAllProcessors (currentDevice->getCurrentSampleRate (), numSamples);
132- }
133107 }
134-
135108 juce::ScopedNoDenormals noDenormals;
136-
137- // --- 1. Xóa tất cả các buffer làm việc ---
138109 vocalBuffer.clear ();
139110 musicStereoBuffer.clear ();
140111 mixBuffer.clear ();
141112 soundboardBuffer.clear ();
142113 directOutputBuffer.clear ();
143114 for (auto & buffer : vocalFxReturnBuffers) buffer.clear ();
144115 for (auto & buffer : musicFxReturnBuffers) buffer.clear ();
145-
146116 vocalPlayerBuffer.setSize (2 , numSamples);
147117 musicPlayerBuffer.setSize (2 , numSamples);
148118 vocalPlayerBuffer.clear ();
149119 musicPlayerBuffer.clear ();
150-
151-
152- // --- 2. Lấy tín hiệu từ các Player của Track ---
153120 juce::AudioSourceChannelInfo vocalPlayerInfo (&vocalPlayerBuffer, 0 , numSamples);
154121 vocalTrackSource.getNextAudioBlock (vocalPlayerInfo);
155-
156122 juce::AudioSourceChannelInfo musicPlayerInfo (&musicPlayerBuffer, 0 , numSamples);
157123 musicTrackSource.getNextAudioBlock (musicPlayerInfo);
158-
159-
160- // --- 3. Xử lý Track Vocal ---
161124 const int currentVocalIn = vocalInputChannel.load ();
162125 if (juce::isPositiveAndBelow (currentVocalIn, numInputChannels))
163126 {
@@ -170,13 +133,9 @@ void AudioEngine::audioDeviceIOCallbackWithContext(const float* const* inputChan
170133 vocalBuffer.addFrom (1 , 0 , vocalPlayerBuffer, 1 , 0 , numSamples);
171134 vocalProcessor.process (vocalBuffer);
172135 vocalTrackRecorder->processBlock (vocalBuffer, currentSampleRate);
173-
174-
175- // --- 4. Xử lý Track Music ---
176136 const int currentMusicLeftIn = musicInputLeftChannel.load ();
177137 const int currentMusicRightIn = musicInputRightChannel.load ();
178- if (juce::isPositiveAndBelow (currentMusicLeftIn, numInputChannels) &&
179- juce::isPositiveAndBelow (currentMusicRightIn, numInputChannels))
138+ if (juce::isPositiveAndBelow (currentMusicLeftIn, numInputChannels) && juce::isPositiveAndBelow (currentMusicRightIn, numInputChannels))
180139 {
181140 juce::AudioBuffer<float > rawInput (const_cast <float **>(inputChannelData) + currentMusicLeftIn, 2 , numSamples);
182141 musicStereoBuffer.copyFrom (0 , 0 , rawInput, 0 , 0 , numSamples);
@@ -187,14 +146,8 @@ void AudioEngine::audioDeviceIOCallbackWithContext(const float* const* inputChan
187146 musicStereoBuffer.addFrom (1 , 0 , musicPlayerBuffer, 1 , 0 , numSamples);
188147 musicProcessor.process (musicStereoBuffer);
189148 musicTrackRecorder->processBlock (musicStereoBuffer, currentSampleRate);
190-
191-
192- // --- 5. Lấy tín hiệu từ Soundboard ---
193149 juce::AudioSourceChannelInfo soundboardChannelInfo (&soundboardBuffer, 0 , numSamples);
194150 soundboardMixer.getNextAudioBlock (soundboardChannelInfo);
195-
196-
197- // --- 6. Xử lý FX Sends/Returns ---
198151 for (int i = 0 ; i < 4 ; ++i)
199152 {
200153 fxSendBuffer.copyFrom (0 , 0 , vocalBuffer, 0 , 0 , numSamples);
@@ -215,20 +168,13 @@ void AudioEngine::audioDeviceIOCallbackWithContext(const float* const* inputChan
215168 musicFxReturnBuffers[i].copyFrom (1 , 0 , fxSendBuffer, 1 , 0 , numSamples);
216169 musicFxReturnBuffers[i].applyGain (musicFxChain.processors [i].getReturnLevel ());
217170 }
218-
219-
220- // --- 7. Tổng hợp tất cả vào Kênh Master ---
221171 mixBuffer.clear ();
222-
223172 mixBuffer.copyFrom (0 , 0 , vocalBuffer, 0 , 0 , numSamples);
224173 mixBuffer.copyFrom (1 , 0 , vocalBuffer, 1 , 0 , numSamples);
225-
226174 mixBuffer.addFrom (0 , 0 , musicStereoBuffer, 0 , 0 , numSamples);
227175 mixBuffer.addFrom (1 , 0 , musicStereoBuffer, 1 , 0 , numSamples);
228-
229176 mixBuffer.addFrom (0 , 0 , soundboardBuffer, 0 , 0 , numSamples);
230177 mixBuffer.addFrom (1 , 0 , soundboardBuffer, 1 , 0 , numSamples);
231-
232178 for (int i = 0 ; i < 4 ; ++i)
233179 {
234180 mixBuffer.addFrom (0 , 0 , vocalFxReturnBuffers[i], 0 , 0 , numSamples);
@@ -239,22 +185,14 @@ void AudioEngine::audioDeviceIOCallbackWithContext(const float* const* inputChan
239185 mixBuffer.addFrom (0 , 0 , musicFxReturnBuffers[i], 0 , 0 , numSamples);
240186 mixBuffer.addFrom (1 , 0 , musicFxReturnBuffers[i], 1 , 0 , numSamples);
241187 }
242-
243188 masterProcessor.process (mixBuffer);
244189 audioRecorder->processBlock (mixBuffer, currentSampleRate);
245-
246-
247- // --- 8. Lấy tín hiệu đi thẳng ra Output (Player của REC & PLAY) ---
248190 juce::AudioSourceChannelInfo directOutputChannelInfo (&directOutputBuffer, 0 , numSamples);
249191 directOutputMixer.getNextAudioBlock (directOutputChannelInfo);
250-
251-
252- // --- 9. Gửi tín hiệu cuối cùng ra loa ---
253192 const int currentOutputLeft = selectedOutputLeftChannel.load ();
254193 const int currentOutputRight = selectedOutputRightChannel.load ();
255194 for (int i = 0 ; i < numOutputChannels; ++i)
256195 juce::FloatVectorOperations::clear (outputChannelData[i], numSamples);
257-
258196 if (juce::isPositiveAndBelow (currentOutputLeft, numOutputChannels))
259197 {
260198 juce::FloatVectorOperations::copy (outputChannelData[currentOutputLeft], mixBuffer.getReadPointer (0 ), numSamples);
@@ -672,4 +610,75 @@ bool AudioEngine::isProjectPlaybackActive() const
672610juce::ValueTree& AudioEngine::getProjectState ()
673611{
674612 return projectState;
613+ }
614+
615+ void AudioEngine::setPlaybackGain (float newGain)
616+ {
617+ playbackSource.setGain (newGain);
618+ }
619+
620+ float AudioEngine::getPlaybackGain () const
621+ {
622+ return playbackSource.getGain ();
623+ }
624+
625+ juce::ValueTree AudioEngine::getFullState ()
626+ {
627+ juce::ValueTree state (" Preset" );
628+ state.addChild (vocalProcessor.getState (), -1 , nullptr );
629+ state.addChild (musicProcessor.getState (), -1 , nullptr );
630+ state.addChild (masterProcessor.getState (), -1 , nullptr );
631+ for (int i = 0 ; i < 4 ; ++i)
632+ {
633+ if (auto * p = getFxProcessorForVocal (i)) state.addChild (p->getState (), -1 , nullptr );
634+ if (auto * p = getFxProcessorForMusic (i)) state.addChild (p->getState (), -1 , nullptr );
635+ }
636+
637+ auto & appState = AppState::getInstance ();
638+ const bool isLocked = appState.isSystemLocked ();
639+ state.setProperty (Identifiers::lockState, isLocked, nullptr );
640+ if (isLocked)
641+ {
642+ state.setProperty (Identifiers::lockPasswordHash, appState.getPasswordHash (), nullptr );
643+ }
644+
645+ return state;
646+ }
647+
648+ bool AudioEngine::prepareToLoadState (const juce::ValueTree& newState)
649+ {
650+ if (!vocalProcessor.prepareToLoadState (newState)) return false ;
651+ if (!musicProcessor.prepareToLoadState (newState)) return false ;
652+ if (!masterProcessor.prepareToLoadState (newState)) return false ;
653+ for (int i = 0 ; i < 4 ; ++i)
654+ {
655+ if (auto * p = getFxProcessorForVocal (i)) { if (!p->prepareToLoadState (newState)) return false ; }
656+ if (auto * p = getFxProcessorForMusic (i)) { if (!p->prepareToLoadState (newState)) return false ; }
657+ }
658+ return true ;
659+ }
660+
661+ void AudioEngine::commitStateLoad ()
662+ {
663+ vocalProcessor.commitStateLoad ();
664+ musicProcessor.commitStateLoad ();
665+ masterProcessor.commitStateLoad ();
666+ for (int i = 0 ; i < 4 ; ++i)
667+ {
668+ if (auto * p = getFxProcessorForVocal (i)) p->commitStateLoad ();
669+ if (auto * p = getFxProcessorForMusic (i)) p->commitStateLoad ();
670+ }
671+ }
672+
673+ bool AudioEngine::tryHotSwapState (const juce::ValueTree& newState)
674+ {
675+ if (!vocalProcessor.tryHotSwapState (newState)) return false ;
676+ if (!musicProcessor.tryHotSwapState (newState)) return false ;
677+ if (!masterProcessor.tryHotSwapState (newState)) return false ;
678+ for (int i = 0 ; i < 4 ; ++i)
679+ {
680+ if (auto * p = getFxProcessorForVocal (i)) { if (!p->tryHotSwapState (newState)) return false ; }
681+ if (auto * p = getFxProcessorForMusic (i)) { if (!p->tryHotSwapState (newState)) return false ; }
682+ }
683+ return true ;
675684}
0 commit comments