Skip to content

Commit 3cfe562

Browse files
committed
Resolved UI issues, ensured support for Waves plugins requiring advanced I/O, and completed Status Bar implementation
1 parent b14f6cd commit 3cfe562

14 files changed

+199
-127
lines changed

Source/AudioEngine/ProcessorBase.cpp

Lines changed: 5 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,6 @@ void ProcessorBase::setState(const juce::ValueTree& newState)
9393
return;
9494
}
9595

96-
// Load send/return levels
9796
setSendLevel(newState.getProperty(IDs::sendLevel, 1.0f));
9897
setReturnLevel(newState.getProperty(IDs::returnLevel, 1.0f));
9998

@@ -128,55 +127,16 @@ void ProcessorBase::setState(const juce::ValueTree& newState)
128127

129128
if (auto instance = pluginManager.createPluginInstance(desc, processSpec))
130129
{
131-
instance->suspendProcessing(true);
132-
133-
const auto pluginName = instance->getName().toLowerCase();
134-
const bool isPickyPlugin = pluginName.contains("auto-tune") || pluginName.contains("antares");
135-
bool layoutSet = false;
136-
137-
if (isPickyPlugin)
138-
{
139-
DBG("Picky plugin detected on preset load: " << instance->getName() << ". Skipping explicit layout negotiation.");
140-
layoutSet = true;
141-
}
142-
else
143-
{
144-
if (instance->getBusCount(true) > 1)
145-
instance->getBus(true, 1)->enable(false);
146-
147-
const auto stereoToStereo = juce::AudioProcessor::BusesLayout{ { juce::AudioChannelSet::stereo() }, { juce::AudioChannelSet::stereo() } };
148-
if (instance->checkBusesLayoutSupported(stereoToStereo))
149-
{
150-
layoutSet = instance->setBusesLayout(stereoToStereo);
151-
}
152-
153-
if (!layoutSet)
154-
{
155-
const auto monoToStereo = juce::AudioProcessor::BusesLayout{ { juce::AudioChannelSet::mono() }, { juce::AudioChannelSet::stereo() } };
156-
if (instance->checkBusesLayoutSupported(monoToStereo))
157-
{
158-
layoutSet = instance->setBusesLayout(monoToStereo);
159-
}
160-
}
161-
}
162-
163-
if (!layoutSet)
164-
{
165-
DBG("ERROR: Plugin from preset failed layout negotiation: " << instance->getName());
166-
continue;
167-
}
168-
130+
// <<< FIX: REMOVED ALL I/O NEGOTIATION LOGIC >>>
131+
// We just prepare the plugin and then set its internal state.
169132
instance->prepareToPlay(processSpec.sampleRate, (int)processSpec.maximumBlockSize);
170-
instance->reset();
171133

172134
try
173135
{
174136
auto base64State = pluginState.getProperty(IDs::state).toString();
175137
juce::MemoryBlock internalState;
176138
if (internalState.fromBase64Encoding(base64State))
177-
{
178139
instance->setStateInformation(internalState.getData(), (int)internalState.getSize());
179-
}
180140
}
181141
catch (...)
182142
{
@@ -189,11 +149,6 @@ void ProcessorBase::setState(const juce::ValueTree& newState)
189149
pluginBypassState.insert(pluginChain.size());
190150

191151
pluginChain.add(std::move(instance));
192-
193-
if (auto* addedInstance = pluginChain.getLast())
194-
{
195-
addedInstance->suspendProcessing(false);
196-
}
197152
}
198153
}
199154

@@ -311,46 +266,11 @@ void ProcessorBase::addPlugin(std::unique_ptr<juce::AudioPluginInstance> newPlug
311266

312267
if (processSpec.sampleRate > 0)
313268
{
314-
newPlugin->suspendProcessing(true);
315-
316-
const auto pluginName = newPlugin->getName().toLowerCase();
317-
const bool isPickyPlugin = pluginName.contains("auto-tune") || pluginName.contains("antares");
318-
319-
bool layoutSet = false;
320-
321-
if (isPickyPlugin)
322-
{
323-
DBG("Picky plugin detected: " << newPlugin->getName() << ". Skipping layout negotiation.");
324-
layoutSet = true;
325-
}
326-
else
327-
{
328-
if (newPlugin->getBusCount(true) > 1)
329-
newPlugin->getBus(true, 1)->enable(false);
330-
331-
const auto stereoToStereo = juce::AudioProcessor::BusesLayout{ { juce::AudioChannelSet::stereo() }, { juce::AudioChannelSet::stereo() } };
332-
const auto monoToStereo = juce::AudioProcessor::BusesLayout{ { juce::AudioChannelSet::mono() }, { juce::AudioChannelSet::stereo() } };
333-
334-
if (newPlugin->checkBusesLayoutSupported(stereoToStereo))
335-
layoutSet = newPlugin->setBusesLayout(stereoToStereo);
336-
337-
if (!layoutSet && newPlugin->checkBusesLayoutSupported(monoToStereo))
338-
layoutSet = newPlugin->setBusesLayout(monoToStereo);
339-
}
340-
341-
if (!layoutSet)
342-
{
343-
juce::AlertWindow::showMessageBoxAsync(juce::AlertWindow::WarningIcon,
344-
"Plugin Load Failed",
345-
"The selected plugin has an I/O configuration that is not compatible with this application: " + newPlugin->getName());
346-
347-
newPlugin->suspendProcessing(false);
348-
return;
349-
}
350-
269+
// <<< FIX: REMOVED ALL I/O NEGOTIATION LOGIC >>>
270+
// We simply prepare the plugin and trust it to use its default layout.
271+
// The process() method is already robust enough to handle channel differences.
351272
newPlugin->prepareToPlay(processSpec.sampleRate, (int)processSpec.maximumBlockSize);
352273
newPlugin->reset();
353-
newPlugin->suspendProcessing(false);
354274
}
355275

356276
pluginChain.add(std::move(newPlugin));

Source/Components/CustomLookAndFeel.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,16 @@ void CustomLookAndFeel::drawLinearSlider(juce::Graphics& g, int x, int y, int wi
2525

2626
g.setColour(juce::Colour(0xff007acc));
2727
g.fillRoundedRectangle(valueBounds, 3.0f);
28+
29+
const float thumbRadius = 10.0f;
30+
const float thumbX = sliderPos - thumbRadius * 0.5f;
31+
const float thumbY = y + height * 0.5f - thumbRadius * 0.5f;
32+
33+
g.setColour(juce::Colours::white);
34+
g.fillEllipse(thumbX, thumbY, thumbRadius, thumbRadius);
35+
36+
g.setColour(juce::Colours::black.withAlpha(0.4f));
37+
g.drawEllipse(thumbX, thumbY, thumbRadius, thumbRadius, 1.0f);
2838
}
2939
else
3040
{

Source/Data/SoundboardProfileManager.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,15 @@ juce::var SoundboardProfileManager::soundboardSlotToVar(const SoundboardSlot& sl
200200
auto slotObject = new juce::DynamicObject();
201201
slotObject->setProperty("slotId", slot.slotId);
202202
slotObject->setProperty("displayName", slot.displayName);
203-
slotObject->setProperty("audioFilePath", slot.audioFile.getFullPathName());
203+
204+
// <<< FIX: Save only the filename, not the full path >>>
205+
// This makes the profile portable.
206+
if (slot.audioFile.existsAsFile())
207+
slotObject->setProperty("audioFileName", slot.audioFile.getFileName());
208+
else
209+
slotObject->setProperty("audioFileName", juce::String());
210+
211+
204212
slotObject->setProperty("hotkeyCode", slot.hotkey.getKeyCode());
205213
slotObject->setProperty("hotkeyModifiers", slot.hotkey.getModifiers().getRawFlags());
206214
return juce::var(slotObject);
@@ -213,7 +221,14 @@ SoundboardSlot SoundboardProfileManager::varToSoundboardSlot(const juce::var& sl
213221
{
214222
slot.slotId = obj->getProperty("slotId");
215223
slot.displayName = obj->getProperty("displayName");
216-
slot.audioFile = juce::File(obj->getProperty("audioFilePath").toString());
224+
225+
// <<< FIX: Reconstruct the full path from the filename >>>
226+
// This ensures the app looks for the audio file inside the current profile directory.
227+
juce::String audioFileName = obj->getProperty("audioFileName").toString();
228+
if (audioFileName.isNotEmpty())
229+
{
230+
slot.audioFile = getProfileDirectory().getChildFile(audioFileName);
231+
}
217232

218233
int keyCode = obj->getProperty("hotkeyCode");
219234
int modifiers = obj->getProperty("hotkeyModifiers");

Source/GUI/Layout/MasterUtilityComponent.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/*
1+
/*
22
==============================================================================
33
44
MasterUtilityComponent.cpp
@@ -64,9 +64,14 @@ MasterUtilityComponent::MasterUtilityComponent(AudioEngine& engine)
6464
};
6565

6666
masterVolumeSlider.setSliderStyle(juce::Slider::LinearHorizontal);
67-
masterVolumeSlider.setTextBoxStyle(juce::Slider::NoTextBox, true, 0, 0);
67+
masterVolumeSlider.setTextBoxStyle(juce::Slider::TextBoxRight, false, 50, 20);
6868
masterVolumeSlider.setRange(-60.0, 6.0, 0.1);
6969
masterVolumeSlider.setValue(0.0);
70+
71+
masterVolumeSlider.setColour(juce::Slider::textBoxTextColourId, juce::Colours::white);
72+
masterVolumeSlider.setColour(juce::Slider::textBoxOutlineColourId, juce::Colours::black.withAlpha(0.5f));
73+
masterVolumeSlider.setColour(juce::Slider::textBoxBackgroundColourId, juce::Colour(0xff2d2d2d));
74+
7075
masterVolumeSlider.onValueChange = [this]
7176
{
7277
if (masterProcessor != nullptr)
@@ -172,4 +177,14 @@ void MasterUtilityComponent::changeListenerCallback(juce::ChangeBroadcaster* sou
172177
{
173178
if (source == &LanguageManager::getInstance())
174179
updateTexts();
180+
}
181+
182+
void MasterUtilityComponent::closeAllPluginWindows()
183+
{
184+
// Nếu cửa sổ plugin kênh tổng đang mở, hãy đóng nó lại.
185+
// Thao tác này sẽ kích hoạt destructor và dọn dẹp các cửa sổ editor bên trong.
186+
if (masterPluginsWindow != nullptr)
187+
{
188+
masterPluginsWindow.reset();
189+
}
175190
}

Source/GUI/Layout/MasterUtilityComponent.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class MasterUtilityComponent : public juce::Component,
3030

3131
/** Restores the open plugin windows for the master track from a saved state. */
3232
void restoreOpenWindows(const juce::ValueTree& state);
33+
void closeAllPluginWindows();
3334

3435

3536
private:

Source/GUI/Layout/PresetBarComponent.cpp

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
1-
#include "PresetBarComponent.h"
1+
#include "PresetBarComponent.h"
22
#include "../../Components/Helpers.h"
33
#include "../../Application/Application.h"
44
#include "../Windows/PresetManagerWindow.h"
55
#include "../../Data/AppState.h"
66

7+
// <<< FIX: Đường dẫn include chính xác đến MainComponent.h >>>
8+
#include "../MainComponent/MainComponent.h"
9+
#include "TrackComponent.h"
10+
#include "MasterUtilityComponent.h"
11+
712
PresetBarComponent::PresetBarComponent(AudioEngine& engine)
813
: audioEngine(engine)
914
{
@@ -25,7 +30,7 @@ PresetBarComponent::PresetBarComponent(AudioEngine& engine)
2530
quickChoiceLabel.setFont(IdolUIHelpers::createRegularFont(14.0f));
2631

2732
savePresetButton.onClick = [this] { savePreset(); };
28-
loadButton.onClick = [this] { loadPresetFromButton(); }; // Changed this to call the UI-specific method
33+
loadButton.onClick = [this] { loadPresetFromButton(); };
2934

3035
managePresetsButton.onClick = [] {
3136
if (auto* app = dynamic_cast<idolLiveAudioApplication*>(juce::JUCEApplication::getInstance()))
@@ -148,7 +153,6 @@ void PresetBarComponent::savePreset()
148153
}
149154
}
150155

151-
// Renamed method for clarity
152156
void PresetBarComponent::loadPresetFromButton()
153157
{
154158
if (AppState::getInstance().isPresetDirty())
@@ -183,7 +187,6 @@ void PresetBarComponent::loadPresetFromButton()
183187
{
184188
performLoadTask();
185189
}
186-
// Result 3 is Cancel, do nothing.
187190
}), true);
188191
}
189192
else
@@ -192,44 +195,43 @@ void PresetBarComponent::loadPresetFromButton()
192195
}
193196
}
194197

195-
// NEW: Core logic for loading, can be called from anywhere
196198
void PresetBarComponent::performLoadTask()
197199
{
198200
auto selectedId = quickChoiceBox.getSelectedId();
199201
if (selectedId == 0) return;
200202

201-
auto presetName = quickChoiceBox.getText();
202-
auto& presetManager = getSharedPresetManager();
203-
auto presetFile = presetManager.getPresetDirectory().getChildFile(presetName + ".xml");
204-
205-
if (presetFile.existsAsFile())
203+
if (auto* mainComp = findParentComponentOfClass<MainComponent>())
206204
{
207-
presetManager.loadPreset(audioEngine, presetFile);
208-
AppState::getInstance().markAsSaved(presetName);
205+
mainComp->getVocalTrack().closeAllPluginWindows();
206+
mainComp->getMusicTrack().closeAllPluginWindows();
207+
mainComp->getMasterUtilityComponent().closeAllPluginWindows();
208+
209+
auto presetName = quickChoiceBox.getText();
210+
auto& presetManager = getSharedPresetManager();
211+
auto presetFile = presetManager.getPresetDirectory().getChildFile(presetName + ".xml");
212+
213+
if (presetFile.existsAsFile())
214+
{
215+
presetManager.loadPreset(audioEngine, presetFile);
216+
AppState::getInstance().markAsSaved(presetName);
217+
}
209218
}
210219
}
211220

212-
213-
// NEW: Public method to be called from AppState
214221
void PresetBarComponent::loadPresetByName(const juce::String& name)
215222
{
216-
// Find the ID corresponding to the preset name
217223
for (int i = 1; i <= quickChoiceBox.getNumItems(); ++i)
218224
{
219225
if (quickChoiceBox.getItemText(i - 1) == name)
220226
{
221227
quickChoiceBox.setSelectedId(i, juce::dontSendNotification);
222-
223-
// Directly perform the load task, bypassing the "dirty" check dialog
224228
performLoadTask();
225229
return;
226230
}
227231
}
228-
229232
DBG("Preset not found in ComboBox: " + name);
230233
}
231234

232-
233235
void PresetBarComponent::updateTexts()
234236
{
235237
auto& lang = LanguageManager::getInstance();

Source/GUI/Layout/SoundboardComponent.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,14 @@ SoundboardComponent::SoundboardComponent(AudioEngine& engine)
2525
addAndMakeVisible(volumeLabel);
2626
addAndMakeVisible(volumeSlider);
2727
volumeSlider.setSliderStyle(juce::Slider::LinearHorizontal);
28-
volumeSlider.setTextBoxStyle(juce::Slider::NoTextBox, true, 0, 0);
28+
volumeSlider.setTextBoxStyle(juce::Slider::TextBoxRight, false, 50, 20);
2929
volumeSlider.setRange(0.0, 1.0, 0.01);
3030
volumeSlider.setValue(0.75);
31+
32+
volumeSlider.setColour(juce::Slider::textBoxTextColourId, juce::Colours::white);
33+
volumeSlider.setColour(juce::Slider::textBoxOutlineColourId, juce::Colours::black.withAlpha(0.5f));
34+
volumeSlider.setColour(juce::Slider::textBoxBackgroundColourId, juce::Colour(0xff2d2d2d));
35+
3136
volumeSlider.onValueChange = [this]
3237
{
3338
audioEngine.getSoundPlayer().setGain(static_cast<float>(volumeSlider.getValue()));

Source/GUI/Layout/StatusBarComponent.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,16 @@ void StatusBarComponent::changeListenerCallback(juce::ChangeBroadcaster* source)
4949
{
5050
(void)source; // Báo cho compiler biết: có lý do để nó ở đây
5151
}
52+
53+
void StatusBarComponent::updateStatus(double cpuUsage, double latencyMs, double sampleRate)
54+
{
55+
// Định dạng chuỗi để hiển thị
56+
juce::String cpuText = "CPU: " + juce::String(cpuUsage, 1) + " %";
57+
juce::String latencyText = "Latency: " + juce::String(latencyMs, 2) + " ms";
58+
juce::String rateText = "Rate: " + juce::String(sampleRate / 1000.0, 1) + " kHz";
59+
60+
// Cập nhật các label
61+
cpuLabel.setText(cpuText, juce::dontSendNotification);
62+
latencyLabel.setText(latencyText, juce::dontSendNotification);
63+
sampleRateLabel.setText(rateText, juce::dontSendNotification);
64+
}

Source/GUI/Layout/StatusBarComponent.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ class StatusBarComponent : public juce::Component, public juce::ChangeListener {
1212
void changeListenerCallback(juce::ChangeBroadcaster* source) override;
1313

1414
void setStatusMessage(const juce::String& message, bool isError);
15+
void updateStatus(double cpuUsage, double latencyMs, double sampleRate);
1516

1617
private:
1718
void updateTexts();

0 commit comments

Comments
 (0)