Skip to content

Commit 1652247

Browse files
committed
Update: Added 4 FX Channels for Vocal and Music Tracks; Fixed issue where Input changes automatically when switching audio devices; Added progress display for Plugin Scan
1 parent 39e1acd commit 1652247

28 files changed

+1261
-364
lines changed

Resources/Languages/lang_en.json

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@
3131
"activePlugins": "Active Plugins",
3232
"addPluginPlaceholder": "Add Plugin...",
3333
"add": "Add",
34-
"pleaseSelectDevice": "Please select an audio device"
34+
"pleaseSelectDevice": "Please select an audio device",
35+
"fxSends": "FX SENDS"
3536
},
3637
"pinnedPlugin": {
3738
"title": "PINNED PLUGIN",
@@ -127,5 +128,12 @@
127128
"title": "Application Error",
128129
"message": "idolLiveAudio has encountered a critical error and needs to close. Please copy the report below and submit it for support.",
129130
"copyButton": "Copy Report"
131+
},
132+
"scanProcess": {
133+
"title": "Scanning",
134+
"message": "Scanning for plugins, please wait...",
135+
"completeTitle": "Scan Complete",
136+
"completeMessage": "Plugin scanning has finished."
130137
}
138+
131139
}

Resources/Languages/lang_vi.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@
3131
"activePlugins": "Plugin đang hoạt động",
3232
"addPluginPlaceholder": "Thêm Plugin...",
3333
"add": "Thêm",
34-
"pleaseSelectDevice": "Vui lòng chọn thiết bị âm thanh"
34+
"pleaseSelectDevice": "Vui lòng chọn thiết bị âm thanh",
35+
"fxSends": "GỬI HIỆU ỨNG"
3536
},
3637
"pinnedPlugin": {
3738
"title": "PLUGIN ĐÃ GHIM",
@@ -127,5 +128,11 @@
127128
"title": "Lỗi Ứng Dụng",
128129
"message": "idolLiveAudio đã gặp một lỗi nghiêm trọng và cần phải đóng. Vui lòng sao chép báo cáo dưới đây và gửi đi để được hỗ trợ.",
129130
"copyButton": "Sao chép Báo cáo"
131+
},
132+
"scanProcess": {
133+
"title": "Đang quét",
134+
"message": "Đang quét plugin, vui lòng đợi...",
135+
"completeTitle": "Quét hoàn tất",
136+
"completeMessage": "Quá trình quét plugin đã kết thúc."
130137
}
131138
}

Source/Application/Application.cpp

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
#include "Application.h"
1+
#include "Application.h"
22
#include "../GUI/MainComponent/MainComponent.h"
33
#include "../GUI/Windows/PresetManagerWindow.h"
44
#include "../GUI/Windows/PluginManagerWindow.h"
55
#include "../GUI/Windows/SplashScreenComponent.h"
66
#include "../Data/AppState.h"
77
#include "../Data/LanguageManager/LanguageManager.h"
8-
// <<< NEW: Include the CrashHandler >>>
9-
#include "../System/CrashHandler/CrashHandler.h"
8+
// Dòng #include "CrashHandler.h" đã được xóa
109

1110

1211
PluginManager& getSharedPluginManager()
@@ -42,10 +41,10 @@ idolLiveAudioApplication::MainWindow::MainWindow(juce::String name)
4241
setFullScreen(true);
4342
#else
4443
setResizable(true, true);
45-
setResizeLimits(1024, 768, 10000, 10000);
46-
centreWithSize(1440, 810);
44+
setResizeLimits(1640, 1010, 10000, 10000);
45+
centreWithSize(1640, 1010);
4746
#endif
48-
setVisible(false); // Ban đầu ẩn, chỉ show khi splash tắt
47+
setVisible(false);
4948
}
5049

5150
void idolLiveAudioApplication::MainWindow::closeButtonPressed()
@@ -63,8 +62,7 @@ void idolLiveAudioApplication::MainWindow::closeButtonPressed()
6362
}
6463
}
6564

66-
// --- SplashWindow logic, Timer-based (fix race/destroy issues) ---
67-
65+
// ... (Class SplashWindow không thay đổi) ...
6866
class SplashWindow final : public juce::DocumentWindow
6967
{
7068
public:
@@ -101,12 +99,12 @@ class SplashWindow final : public juce::DocumentWindow
10199
void closeButtonPressed() override {}
102100
};
103101

102+
104103
//==============================================================================
105104

106105
void idolLiveAudioApplication::initialise(const juce::String& commandLine)
107106
{
108-
// <<< NEW: Install the crash handler as the very first thing >>>
109-
CrashHandler::install();
107+
// Lời gọi CrashHandler::install(); đã được xóa
110108

111109
juce::ignoreUnused(commandLine);
112110

@@ -169,9 +167,15 @@ void idolLiveAudioApplication::shutdown()
169167
if (auto* mainComp = dynamic_cast<MainComponent*>(mainWindow->getContentComponent()))
170168
AppState::getInstance().saveState(*mainComp);
171169
}
170+
171+
if (auto* mainComp = dynamic_cast<MainComponent*>(mainWindow->getContentComponent()))
172+
{
173+
mainComp->getAudioDeviceManager().closeAudioDevice();
174+
}
175+
172176
mainWindow = nullptr;
173177
presetManagerWindow = nullptr;
174-
pluginManagerWindow = nullptr; // Đảm bảo có dòng này
178+
pluginManagerWindow = nullptr;
175179
presetManager = nullptr;
176180
pluginManager = nullptr;
177181
splashWindow = nullptr;

Source/Application/Application.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
#pragma once
1+
#pragma once
22

33
#include "JuceHeader.h"
44
#include "Data/PluginManager/PluginManager.h"
55
#include "Data/PresetManager.h"
66

77
// Forward declarations
88
class PresetManagerWindow;
9-
class PluginManagerWindow; // Đảm bảo có dòng này
9+
class PluginManagerWindow;
1010
class MainComponent;
1111
class SplashWindow;
1212

@@ -33,7 +33,7 @@ class idolLiveAudioApplication : public juce::JUCEApplication
3333
PresetManager* getPresetManager() { return presetManager.get(); }
3434

3535
void showPresetManagerWindow();
36-
void showPluginManagerWindow(); // Đảm bảo có dòng này
36+
void showPluginManagerWindow();
3737

3838
private:
3939
class MainWindow : public juce::DocumentWindow
@@ -46,11 +46,11 @@ class idolLiveAudioApplication : public juce::JUCEApplication
4646
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MainWindow)
4747
};
4848

49-
std::unique_ptr<SplashWindow> splashWindow;
50-
std::unique_ptr<MainWindow> mainWindow;
5149
std::unique_ptr<PluginManager> pluginManager;
5250
std::unique_ptr<PresetManager> presetManager;
5351

52+
std::unique_ptr<SplashWindow> splashWindow;
53+
std::unique_ptr<MainWindow> mainWindow;
5454
std::unique_ptr<PresetManagerWindow> presetManagerWindow;
55-
std::unique_ptr<PluginManagerWindow> pluginManagerWindow; // Đảm bảo có dòng này
55+
std::unique_ptr<PluginManagerWindow> pluginManagerWindow;
5656
};

Source/AudioEngine/AudioEngine.cpp

Lines changed: 86 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
/*
1+
/*
22
==============================================================================
33
44
AudioEngine.cpp
5-
(Final fix using std::function callback)
5+
(Fully Functional Send/Return FX Architecture)
66
77
==============================================================================
88
*/
@@ -14,7 +14,9 @@
1414
#include "SoundPlayer.h"
1515

1616
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)
1820
{
1921
soundPlayer = std::make_unique<IdolAZ::SoundPlayer>();
2022
}
@@ -36,23 +38,30 @@ void AudioEngine::audioDeviceAboutToStart(juce::AudioIODevice* device)
3638
vocalProcessor.prepare(stereoSpec);
3739
musicProcessor.prepare(stereoSpec);
3840
masterProcessor.prepare(stereoSpec);
41+
42+
for (auto& fxProc : vocalFxChain.processors) fxProc.prepare(stereoSpec);
43+
for (auto& fxProc : musicFxChain.processors) fxProc.prepare(stereoSpec);
3944

4045
soundPlayer->prepareToPlay(currentBlockSize, currentSampleRate);
4146

4247
vocalBuffer.setSize(2, currentBlockSize);
4348
musicStereoBuffer.setSize(2, currentBlockSize);
4449
mixBuffer.setSize(2, currentBlockSize);
4550
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);
4655

4756
vocalProcessor.reset();
4857
musicProcessor.reset();
4958
masterProcessor.reset();
5059

51-
// --- NEW LOGIC: Trigger the callback ---
60+
for (auto& fxProc : vocalFxChain.processors) fxProc.reset();
61+
for (auto& fxProc : musicFxChain.processors) fxProc.reset();
62+
5263
if (onDeviceStarted)
5364
{
54-
// Use callAsync to run the callback on the main message thread,
55-
// which is safe for UI operations and completing the session restore.
5665
juce::MessageManager::callAsync(onDeviceStarted);
5766
}
5867
}
@@ -63,6 +72,10 @@ void AudioEngine::audioDeviceStopped()
6372
vocalProcessor.reset();
6473
musicProcessor.reset();
6574
masterProcessor.reset();
75+
76+
for (auto& fxProc : vocalFxChain.processors) fxProc.reset();
77+
for (auto& fxProc : musicFxChain.processors) fxProc.reset();
78+
6679
soundPlayer->releaseResources();
6780

6881
currentSampleRate = 0.0;
@@ -79,29 +92,33 @@ void AudioEngine::audioDeviceStopped()
7992
musicTrackComponent->populateInputChannels({}, {});
8093
}
8194

95+
96+
// <<< MODIFIED: Full audio callback logic with send/return levels >>>
8297
void AudioEngine::audioDeviceIOCallbackWithContext(const float* const* inputChannelData, int numInputChannels,
8398
float* const* outputChannelData, int numOutputChannels,
8499
int numSamples, const juce::AudioIODeviceCallbackContext& context)
85100
{
86101
juce::ignoreUnused(context);
87102
juce::ScopedNoDenormals noDenormals;
88103

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+
89111
const int currentVocalIn = vocalInputChannel.load();
90112
const int currentMusicLeftIn = musicInputLeftChannel.load();
91113
const int currentMusicRightIn = musicInputRightChannel.load();
92114
const int currentOutputLeft = selectedOutputLeftChannel.load();
93115
const int currentOutputRight = selectedOutputRightChannel.load();
94116

95-
vocalBuffer.clear();
96-
musicStereoBuffer.clear();
97-
mixBuffer.clear();
98-
soundboardBuffer.clear();
99-
117+
// --- Process main "dry" signal paths ---
100118
if (juce::isPositiveAndBelow(currentVocalIn, numInputChannels))
101119
{
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);
105122
vocalProcessor.process(vocalBuffer);
106123
}
107124

@@ -116,15 +133,55 @@ void AudioEngine::audioDeviceIOCallbackWithContext(const float* const* inputChan
116133
juce::AudioSourceChannelInfo soundboardChannelInfo(&soundboardBuffer, 0, numSamples);
117134
soundPlayer->getNextAudioBlock(soundboardChannelInfo);
118135

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 ---
119166
mixBuffer.addFrom(0, 0, vocalBuffer, 0, 0, numSamples);
120167
mixBuffer.addFrom(1, 0, vocalBuffer, 1, 0, numSamples);
121168
mixBuffer.addFrom(0, 0, musicStereoBuffer, 0, 0, numSamples);
122169
mixBuffer.addFrom(1, 0, musicStereoBuffer, 1, 0, numSamples);
123170
mixBuffer.addFrom(0, 0, soundboardBuffer, 0, 0, numSamples);
124171
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+
}
125180

181+
// --- Process the final Master Processor Chain ---
126182
masterProcessor.process(mixBuffer);
127183

184+
// --- Final Output ---
128185
for (int i = 0; i < numOutputChannels; ++i)
129186
juce::FloatVectorOperations::clear(outputChannelData[i], numSamples);
130187

@@ -135,6 +192,21 @@ void AudioEngine::audioDeviceIOCallbackWithContext(const float* const* inputChan
135192
juce::FloatVectorOperations::copy(outputChannelData[currentOutputRight], mixBuffer.getReadPointer(1), numSamples);
136193
}
137194

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+
138210
void AudioEngine::setVocalInputChannel(int channelIndex)
139211
{
140212
vocalInputChannel.store(channelIndex);

0 commit comments

Comments
 (0)