Skip to content

Commit 538eb4b

Browse files
committed
Split In/Out Port Selector component | Fix abnormal Master volume | Fix UI window crashes | Fix wrong Output display
1 parent 7d1e395 commit 538eb4b

16 files changed

+406
-355
lines changed

Source/AudioEngine/AudioEngine.cpp

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,6 @@ void AudioEngine::audioDeviceStopped()
105105
musicInputRightChannel.store(-1);
106106
selectedOutputLeftChannel.store(-1);
107107
selectedOutputRightChannel.store(-1);
108-
109-
if (vocalTrackComponent != nullptr)
110-
vocalTrackComponent->populateInputChannels({}, {});
111-
if (musicTrackComponent != nullptr)
112-
musicTrackComponent->populateInputChannels({}, {});
113108
}
114109

115110
// <<< MODIFIED: Full audio callback logic with send/return levels >>>
@@ -129,7 +124,6 @@ void AudioEngine::audioDeviceIOCallbackWithContext(const float* const* inputChan
129124
for (auto& buffer : vocalFxReturnBuffers) buffer.clear();
130125
for (auto& buffer : musicFxReturnBuffers) buffer.clear();
131126

132-
// Tạo và xóa các buffer tạm cho player của từng track
133127
vocalPlayerBuffer.setSize(2, numSamples);
134128
musicPlayerBuffer.setSize(2, numSamples);
135129
vocalPlayerBuffer.clear();
@@ -148,21 +142,14 @@ void AudioEngine::audioDeviceIOCallbackWithContext(const float* const* inputChan
148142
const int currentVocalIn = vocalInputChannel.load();
149143
if (juce::isPositiveAndBelow(currentVocalIn, numInputChannels))
150144
{
151-
// Lấy tín hiệu RAW từ input
152145
juce::AudioBuffer<float> rawInput(const_cast<float**>(inputChannelData) + currentVocalIn, 1, numSamples);
153146
vocalBuffer.copyFrom(0, 0, rawInput, 0, 0, numSamples);
154147
vocalBuffer.copyFrom(1, 0, rawInput, 0, 0, numSamples);
155-
156-
// Ghi âm RAW ngay lập tức
157148
rawVocalRecorder->processBlock(vocalBuffer, currentSampleRate);
158149
}
159-
// Cộng tín hiệu từ Vocal Player vào buffer
160150
vocalBuffer.addFrom(0, 0, vocalPlayerBuffer, 0, 0, numSamples);
161151
vocalBuffer.addFrom(1, 0, vocalPlayerBuffer, 1, 0, numSamples);
162-
163-
// Xử lý qua plugin của track
164152
vocalProcessor.process(vocalBuffer);
165-
// Ghi âm tín hiệu đã qua xử lý (Post-FX)
166153
vocalTrackRecorder->processBlock(vocalBuffer, currentSampleRate);
167154

168155

@@ -175,14 +162,10 @@ void AudioEngine::audioDeviceIOCallbackWithContext(const float* const* inputChan
175162
juce::AudioBuffer<float> rawInput(const_cast<float**>(inputChannelData) + currentMusicLeftIn, 2, numSamples);
176163
musicStereoBuffer.copyFrom(0, 0, rawInput, 0, 0, numSamples);
177164
musicStereoBuffer.copyFrom(1, 0, rawInput, 1, 0, numSamples);
178-
179165
rawMusicRecorder->processBlock(musicStereoBuffer, currentSampleRate);
180166
}
181-
// Cộng tín hiệu từ Music Player vào buffer
182167
musicStereoBuffer.addFrom(0, 0, musicPlayerBuffer, 0, 0, numSamples);
183168
musicStereoBuffer.addFrom(1, 0, musicPlayerBuffer, 1, 0, numSamples);
184-
185-
// Xử lý qua plugin của track
186169
musicProcessor.process(musicStereoBuffer);
187170
musicTrackRecorder->processBlock(musicStereoBuffer, currentSampleRate);
188171

@@ -216,22 +199,28 @@ void AudioEngine::audioDeviceIOCallbackWithContext(const float* const* inputChan
216199

217200

218201
// --- 7. Tổng hợp tất cả vào Kênh Master ---
219-
mixBuffer.addFrom(0, 0, vocalBuffer, 0, 0, numSamples);
220-
mixBuffer.addFrom(1, 0, vocalBuffer, 1, 0, numSamples);
202+
mixBuffer.clear();
203+
204+
mixBuffer.copyFrom(0, 0, vocalBuffer, 0, 0, numSamples);
205+
mixBuffer.copyFrom(1, 0, vocalBuffer, 1, 0, numSamples);
206+
221207
mixBuffer.addFrom(0, 0, musicStereoBuffer, 0, 0, numSamples);
222208
mixBuffer.addFrom(1, 0, musicStereoBuffer, 1, 0, numSamples);
209+
223210
mixBuffer.addFrom(0, 0, soundboardBuffer, 0, 0, numSamples);
224211
mixBuffer.addFrom(1, 0, soundboardBuffer, 1, 0, numSamples);
225212

226213
for (int i = 0; i < 4; ++i)
227214
{
228215
mixBuffer.addFrom(0, 0, vocalFxReturnBuffers[i], 0, 0, numSamples);
229216
mixBuffer.addFrom(1, 0, vocalFxReturnBuffers[i], 1, 0, numSamples);
217+
}
218+
for (int i = 0; i < 4; ++i)
219+
{
230220
mixBuffer.addFrom(0, 0, musicFxReturnBuffers[i], 0, 0, numSamples);
231221
mixBuffer.addFrom(1, 0, musicFxReturnBuffers[i], 1, 0, numSamples);
232222
}
233223

234-
// Xử lý qua plugin Master và ghi âm kênh Master
235224
masterProcessor.process(mixBuffer);
236225
audioRecorder->processBlock(mixBuffer, currentSampleRate);
237226

@@ -416,8 +405,9 @@ void AudioEngine::updateActiveInputChannels(juce::AudioDeviceManager& manager)
416405
activeMonoIndices.add(i);
417406
}
418407
}
419-
if (vocalTrackComponent != nullptr)
420-
vocalTrackComponent->populateInputChannels(activeMonoNames, activeMonoIndices);
408+
// XÓA DÒNG NÀY
409+
// if (vocalTrackComponent != nullptr)
410+
// vocalTrackComponent->populateInputChannels(activeMonoNames, activeMonoIndices);
421411

422412
juce::StringArray activeStereoNames;
423413
juce::Array<int> activeStereoStartIndices;
@@ -429,8 +419,9 @@ void AudioEngine::updateActiveInputChannels(juce::AudioDeviceManager& manager)
429419
activeStereoStartIndices.add(i);
430420
}
431421
}
432-
if (musicTrackComponent != nullptr)
433-
musicTrackComponent->populateInputChannels(activeStereoNames, activeStereoStartIndices);
422+
// VÀ XÓA DÒNG NÀY
423+
// if (musicTrackComponent != nullptr)
424+
// musicTrackComponent->populateInputChannels(activeStereoNames, activeStereoStartIndices);
434425
}
435426

436427

@@ -639,14 +630,23 @@ void AudioEngine::playLoadedProject()
639630

640631
void AudioEngine::stopLoadedProject()
641632
{
642-
// Dừng và reset vị trí các transport source như cũ
633+
// Dừng phát nhạc
643634
vocalTrackSource.stop();
644635
musicTrackSource.stop();
636+
637+
// <<< THÊM VÀO: Giải phóng hoàn toàn các source để đóng file handles >>>
638+
vocalTrackSource.setSource(nullptr);
639+
musicTrackSource.setSource(nullptr);
640+
vocalTrackReader.reset();
641+
musicTrackReader.reset();
642+
643+
// Reset vị trí cho chắc chắn
645644
vocalTrackSource.setPosition(0);
646645
musicTrackSource.setPosition(0);
647646

648647
isProjectPlaybackMode = false;
649648

649+
// Xóa trạng thái project
650650
projectState.setProperty(ProjectStateIDs::name, {}, nullptr);
651651
projectState.setProperty(ProjectStateIDs::isPlaying, false, nullptr);
652652
}

Source/AudioEngine/ProcessorBase.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ class ProcessorBase : public juce::ChangeBroadcaster
5252
std::unordered_set<int> pluginBypassState;
5353
juce::AudioBuffer<float> tempBuffer;
5454

55-
std::atomic<float> sendLevel{ 1.0f };
55+
std::atomic<float> sendLevel{ 0.0f };
5656
std::atomic<float> returnLevel{ 1.0f };
5757

5858
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ProcessorBase)

Source/Data/AppState.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -161,16 +161,25 @@ void AppState::loadPostDeviceState(MainComponent& mainComponent)
161161
auto musicInputName = routingStateXml->getStringAttribute(SessionIds::MUSIC_INPUT);
162162
auto appOutputName = routingStateXml->getStringAttribute(SessionIds::APP_OUTPUT);
163163

164+
// Cập nhật AudioEngine (không đổi)
164165
mainComponent.getAudioEngine().setVocalInputChannelByName(vocalInputName);
165166
mainComponent.getAudioEngine().setMusicInputChannelByName(musicInputName);
166167
mainComponent.getAudioEngine().setSelectedOutputChannelsByName(appOutputName);
167168

168-
mainComponent.getVocalTrack().setSelectedInputChannelByName(vocalInputName);
169-
mainComponent.getMusicTrack().setSelectedInputChannelByName(musicInputName);
169+
// Cập nhật giao diện thông qua các component mới
170+
if (auto* vocalSelector = mainComponent.getVocalTrack().getChannelSelector())
171+
vocalSelector->setSelectedChannelByName(vocalInputName);
172+
173+
if (auto* musicSelector = mainComponent.getMusicTrack().getChannelSelector())
174+
musicSelector->setSelectedChannelByName(musicInputName);
175+
176+
// <<< SỬA: Cách cập nhật MenubarComponent >>>
170177
if (auto* menubar = mainComponent.getMenubarComponent())
171-
menubar->setSelectedOutputChannelPairByName(appOutputName);
178+
if (auto* outputSelector = menubar->getOutputSelector())
179+
outputSelector->setSelectedChannelByName(appOutputName);
172180
}
173181

182+
// ... (phần còn lại của hàm không đổi) ...
174183
auto* presetStateXml = xml->getChildByName(SessionIds::ACTIVE_PRESET);
175184
if (presetStateXml != nullptr)
176185
{
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
#include "ChannelSelectorComponent.h"
2+
3+
ChannelSelectorComponent::ChannelSelectorComponent(juce::AudioDeviceManager& manager, AudioEngine& engine, ChannelType type, const juce::String& labelTextKey)
4+
: deviceManager(manager),
5+
audioEngine(engine),
6+
channelType(type),
7+
labelKey(labelTextKey)
8+
{
9+
deviceManager.addChangeListener(this);
10+
LanguageManager::getInstance().addChangeListener(this);
11+
12+
addAndMakeVisible(label);
13+
label.setText(LanguageManager::getInstance().get(labelKey), juce::dontSendNotification);
14+
15+
addAndMakeVisible(selector);
16+
selector.setTextWhenNothingSelected(LanguageManager::getInstance().get("tracks.pleaseSelectDevice"));
17+
selector.onChange = [this] { handleSelectionChange(); };
18+
19+
updateChannelList();
20+
}
21+
22+
ChannelSelectorComponent::~ChannelSelectorComponent()
23+
{
24+
deviceManager.removeChangeListener(this);
25+
LanguageManager::getInstance().removeChangeListener(this);
26+
}
27+
28+
void ChannelSelectorComponent::resized()
29+
{
30+
auto bounds = getLocalBounds();
31+
label.setBounds(bounds.removeFromLeft(80));
32+
bounds.removeFromLeft(5);
33+
selector.setBounds(bounds);
34+
}
35+
36+
void ChannelSelectorComponent::changeListenerCallback(juce::ChangeBroadcaster* source)
37+
{
38+
if (source == &deviceManager)
39+
{
40+
updateChannelList();
41+
}
42+
else if (source == &LanguageManager::getInstance())
43+
{
44+
label.setText(LanguageManager::getInstance().get(labelKey), juce::dontSendNotification);
45+
selector.setTextWhenNothingSelected(LanguageManager::getInstance().get("tracks.pleaseSelectDevice"));
46+
}
47+
}
48+
49+
void ChannelSelectorComponent::updateChannelList()
50+
{
51+
// Tạm thời vô hiệu hóa callback để tránh bị gọi lại khi đang cập nhật
52+
juce::ScopedValueSetter<std::function<void()>> svs(selector.onChange, nullptr);
53+
54+
switch (channelType)
55+
{
56+
case ChannelType::AudioInputMono:
57+
populateAudioInputChannels(false);
58+
break;
59+
case ChannelType::AudioInputStereo:
60+
populateAudioInputChannels(true);
61+
break;
62+
case ChannelType::AudioOutputStereo:
63+
populateAudioOutputChannels();
64+
break;
65+
}
66+
}
67+
68+
void ChannelSelectorComponent::setSelectedChannelByName(const juce::String& channelName)
69+
{
70+
for (int i = 0; i < selector.getNumItems(); ++i)
71+
{
72+
if (selector.getItemText(i) == channelName)
73+
{
74+
// Chọn đúng mục mà không kích hoạt callback
75+
selector.setSelectedId(selector.getItemId(i), juce::dontSendNotification);
76+
return;
77+
}
78+
}
79+
}
80+
81+
void ChannelSelectorComponent::populateAudioInputChannels(bool isStereo)
82+
{
83+
selector.clear(juce::dontSendNotification);
84+
availableChannelIndices.clear();
85+
86+
if (auto* currentDevice = deviceManager.getCurrentAudioDevice())
87+
{
88+
auto activeChannels = deviceManager.getAudioDeviceSetup().inputChannels;
89+
auto channelNames = currentDevice->getInputChannelNames();
90+
int itemId = 1;
91+
92+
if (isStereo)
93+
{
94+
for (int i = 0; i < channelNames.size() - 1; i += 2)
95+
{
96+
if (activeChannels[i] && activeChannels[i + 1])
97+
{
98+
selector.addItem(channelNames[i] + " / " + channelNames[i + 1], itemId);
99+
availableChannelIndices.add(i);
100+
itemId++;
101+
}
102+
}
103+
}
104+
else // Mono
105+
{
106+
for (int i = 0; i < channelNames.size(); ++i)
107+
{
108+
if (activeChannels[i])
109+
{
110+
selector.addItem(channelNames[i], itemId);
111+
availableChannelIndices.add(i);
112+
itemId++;
113+
}
114+
}
115+
}
116+
}
117+
}
118+
119+
void ChannelSelectorComponent::populateAudioOutputChannels()
120+
{
121+
selector.clear(juce::dontSendNotification);
122+
availableChannelIndices.clear();
123+
124+
selector.addItem(LanguageManager::getInstance().get("menubar.noOutput"), -1);
125+
126+
if (auto* device = deviceManager.getCurrentAudioDevice())
127+
{
128+
auto deviceSetup = deviceManager.getAudioDeviceSetup();
129+
auto channelNames = device->getOutputChannelNames();
130+
int itemId = 1;
131+
132+
for (int i = 0; i < channelNames.size() - 1; i += 2)
133+
{
134+
if (deviceSetup.outputChannels[i] && deviceSetup.outputChannels[i + 1])
135+
{
136+
selector.addItem(channelNames[i] + " / " + channelNames[i + 1], itemId);
137+
availableChannelIndices.add(i); // Lưu chỉ số kênh trái
138+
itemId++;
139+
}
140+
}
141+
}
142+
}
143+
144+
145+
void ChannelSelectorComponent::handleSelectionChange()
146+
{
147+
if (onSelectionChange == nullptr) return;
148+
149+
const int selectedId = selector.getSelectedId();
150+
if (selectedId > 0 && (selectedId - 1) < availableChannelIndices.size())
151+
{
152+
// Lấy chỉ số kênh phần cứng thực sự từ map
153+
const int selectedChannelIndex = availableChannelIndices[selectedId - 1];
154+
onSelectionChange(selectedChannelIndex);
155+
}
156+
else if (selectedId == -1) // "No Output" được chọn
157+
{
158+
onSelectionChange(-1);
159+
}
160+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#pragma once
2+
3+
#include <JuceHeader.h>
4+
#include "../../Data/LanguageManager/LanguageManager.h"
5+
#include "../../AudioEngine/AudioEngine.h"
6+
7+
class ChannelSelectorComponent : public juce::Component,
8+
private juce::ChangeListener
9+
{
10+
public:
11+
enum class ChannelType
12+
{
13+
AudioInputMono,
14+
AudioInputStereo,
15+
AudioOutputStereo
16+
};
17+
18+
// <<< SỬA LỖI 1: Khai báo callback bằng std::function >>>
19+
// Đây là cách làm hiện đại, an toàn và linh hoạt trong C++.
20+
using OnChangeCallback = std::function<void(int newChannelIndex)>;
21+
22+
ChannelSelectorComponent(juce::AudioDeviceManager& manager, AudioEngine& engine, ChannelType type, const juce::String& labelTextKey);
23+
~ChannelSelectorComponent() override;
24+
25+
void resized() override;
26+
27+
void updateChannelList();
28+
29+
// <<< SỬA LỖI 2: Thêm khoảng trắng cho tên hàm >>>
30+
void setSelectedChannelByName(const juce::String& channelName);
31+
32+
// <<< SỬA LỖI 3: Khai báo đúng biến thành viên cho callback >>>
33+
OnChangeCallback onSelectionChange = nullptr;
34+
35+
private:
36+
void changeListenerCallback(juce::ChangeBroadcaster* source) override;
37+
38+
void populateAudioInputChannels(bool isStereo);
39+
void populateAudioOutputChannels();
40+
void handleSelectionChange();
41+
42+
juce::AudioDeviceManager& deviceManager;
43+
AudioEngine& audioEngine;
44+
const ChannelType channelType;
45+
const juce::String labelKey;
46+
47+
juce::Label label;
48+
juce::ComboBox selector;
49+
50+
juce::Array<int> availableChannelIndices;
51+
52+
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ChannelSelectorComponent)
53+
};

0 commit comments

Comments
 (0)