Skip to content

Commit 28ce5c5

Browse files
Merge pull request #16693 from daschuer/gh10516
AdjustReplayGainTest.AdjustReplayGainUpdates fix
2 parents aa9f1fd + 885db76 commit 28ce5c5

10 files changed

Lines changed: 258 additions & 299 deletions

src/engine/enginemixer.cpp

Lines changed: 135 additions & 173 deletions
Large diffs are not rendered by default.

src/engine/enginemixer.h

Lines changed: 51 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
#include <QObject>
44
#include <QVarLengthArray>
5+
#include <array>
56
#include <atomic>
7+
#include <memory>
68

79
#include "audio/types.h"
810
#include "control/controlobject.h"
@@ -15,6 +17,7 @@
1517
#include "recording/recordingmanager.h"
1618
#include "soundio/soundmanager.h"
1719
#include "soundio/soundmanagerutil.h"
20+
#include "util/parented_ptr.h"
1821
#include "util/samplebuffer.h"
1922

2023
class EngineWorkerScheduler;
@@ -68,6 +71,7 @@ class EngineMixer : public QObject, public AudioSource {
6871

6972
// Add an EngineChannel to the mixing engine. This is not thread safe --
7073
// only call it before the engine has started mixing.
74+
// TODO: take std::unique_ptr<EngineChannel> instead.
7175
void addChannel(EngineChannel* pChannel);
7276
EngineChannel* getChannel(const QString& group);
7377
static inline CSAMPLE_GAIN gainForOrientation(EngineChannel::ChannelOrientation orientation,
@@ -87,7 +91,7 @@ class EngineMixer : public QObject, public AudioSource {
8791

8892
// Provide access to the sync lock so enginebuffers can know what their rate controller is.
8993
EngineSync* getEngineSync() const{
90-
return m_pEngineSync;
94+
return m_pEngineSync.get();
9195
}
9296

9397
// These are really only exposed for tests to use.
@@ -100,23 +104,20 @@ class EngineMixer : public QObject, public AudioSource {
100104
const CSAMPLE* getSidechainBuffer() const;
101105

102106
EngineSideChain* getSideChain() const {
103-
return m_pEngineSideChain;
107+
return m_pEngineSideChain.get();
104108
}
105109

106110
CSAMPLE_GAIN getMainGain(int channelIndex) const;
107111

108112
struct ChannelInfo {
109113
ChannelInfo(int index)
110-
: m_pChannel(NULL),
111-
m_pVolumeControl(NULL),
112-
m_pMuteControl(NULL),
113-
m_index(index) {
114+
: m_index(index) {
114115
}
115116
ChannelHandle m_handle;
116-
EngineChannel* m_pChannel;
117+
std::unique_ptr<EngineChannel> m_pChannel;
117118
mixxx::SampleBuffer m_pBuffer;
118-
ControlObject* m_pVolumeControl;
119-
ControlPushButton* m_pMuteControl;
119+
std::unique_ptr<ControlObject> m_pVolumeControl;
120+
std::unique_ptr<ControlPushButton> m_pMuteControl;
120121
GroupFeatureState m_features;
121122
int m_index;
122123
};
@@ -242,9 +243,9 @@ class EngineMixer : public QObject, public AudioSource {
242243

243244
// ControlObjects for switching off unnecessary processing
244245
// These are protected so tests can set them
245-
ControlObject* m_pMainEnabled;
246-
ControlObject* m_pHeadphoneEnabled;
247-
ControlObject* m_pBoothEnabled;
246+
std::unique_ptr<ControlObject> m_pMainEnabled;
247+
std::unique_ptr<ControlObject> m_pHeadphoneEnabled;
248+
std::unique_ptr<ControlObject> m_pBoothEnabled;
248249

249250
private:
250251
// Processes active channels. The sync lock channel (if any) is processed
@@ -261,11 +262,9 @@ class EngineMixer : public QObject, public AudioSource {
261262
int iBufferSize);
262263
bool sidechainMixRequired() const;
263264

265+
// non-owning. lifetime bound to EffectsManager
264266
EngineEffectsManager* m_pEngineEffectsManager;
265267

266-
// List of channels added to the engine.
267-
QVarLengthArray<ChannelInfo*, kPreallocatedChannels> m_channels;
268-
269268
// The previous gain of each channel for each mixing output (main,
270269
// headphone, talkover).
271270
QVarLengthArray<GainCache, kPreallocatedChannels> m_channelMainGainCache;
@@ -281,42 +280,42 @@ class EngineMixer : public QObject, public AudioSource {
281280
mixxx::audio::SampleRate m_sampleRate;
282281

283282
// Mixing buffers for each output.
284-
mixxx::SampleBuffer m_outputBusBuffers[3];
283+
std::array<mixxx::SampleBuffer, 3> m_outputBusBuffers;
285284
mixxx::SampleBuffer m_booth;
286285
mixxx::SampleBuffer m_head;
287286
mixxx::SampleBuffer m_talkover;
288287
mixxx::SampleBuffer m_talkoverHeadphones;
289288
mixxx::SampleBuffer m_sidechainMix;
290289

291-
EngineWorkerScheduler* m_pWorkerScheduler;
292-
EngineSync* m_pEngineSync;
293-
294-
ControlObject* m_pMainGain;
295-
ControlObject* m_pBoothGain;
296-
ControlObject* m_pHeadGain;
297-
ControlObject* m_pSampleRate;
298-
ControlObject* m_pOutputLatencyMs;
299-
ControlObject* m_pAudioLatencyOverloadCount;
300-
ControlObject* m_pAudioLatencyUsage;
301-
ControlObject* m_pAudioLatencyOverload;
302-
EngineTalkoverDucking* m_pTalkoverDucking;
303-
EngineDelay* m_pMainDelay;
304-
EngineDelay* m_pHeadDelay;
305-
EngineDelay* m_pBoothDelay;
306-
EngineDelay* m_pLatencyCompensationDelay;
307-
308-
EngineVuMeter* m_pVumeter;
309-
EngineSideChain* m_pEngineSideChain;
310-
311-
ControlPotmeter* m_pCrossfader;
312-
ControlPotmeter* m_pHeadMix;
313-
ControlPotmeter* m_pBalance;
314-
ControlPushButton* m_pXFaderMode;
315-
ControlPotmeter* m_pXFaderCurve;
316-
ControlPotmeter* m_pXFaderCalibration;
317-
ControlPushButton* m_pXFaderReverse;
318-
ControlPushButton* m_pHeadSplitEnabled;
319-
ControlObject* m_pKeylockEngine;
290+
parented_ptr<EngineWorkerScheduler> m_pWorkerScheduler;
291+
std::unique_ptr<EngineSync> m_pEngineSync;
292+
293+
std::unique_ptr<ControlObject> m_pMainGain;
294+
std::unique_ptr<ControlObject> m_pBoothGain;
295+
std::unique_ptr<ControlObject> m_pHeadGain;
296+
std::unique_ptr<ControlObject> m_pSampleRate;
297+
std::unique_ptr<ControlObject> m_pOutputLatencyMs;
298+
std::unique_ptr<ControlObject> m_pAudioLatencyOverloadCount;
299+
std::unique_ptr<ControlObject> m_pAudioLatencyUsage;
300+
std::unique_ptr<ControlObject> m_pAudioLatencyOverload;
301+
std::unique_ptr<EngineTalkoverDucking> m_pTalkoverDucking;
302+
std::unique_ptr<EngineDelay> m_pMainDelay;
303+
std::unique_ptr<EngineDelay> m_pHeadDelay;
304+
std::unique_ptr<EngineDelay> m_pBoothDelay;
305+
std::unique_ptr<EngineDelay> m_pLatencyCompensationDelay;
306+
307+
std::unique_ptr<EngineVuMeter> m_pVumeter;
308+
std::unique_ptr<EngineSideChain> m_pEngineSideChain;
309+
310+
std::unique_ptr<ControlPotmeter> m_pCrossfader;
311+
std::unique_ptr<ControlPotmeter> m_pHeadMix;
312+
std::unique_ptr<ControlPotmeter> m_pBalance;
313+
std::unique_ptr<ControlPushButton> m_pXFaderMode;
314+
std::unique_ptr<ControlPotmeter> m_pXFaderCurve;
315+
std::unique_ptr<ControlPotmeter> m_pXFaderCalibration;
316+
std::unique_ptr<ControlPushButton> m_pXFaderReverse;
317+
std::unique_ptr<ControlPushButton> m_pHeadSplitEnabled;
318+
std::unique_ptr<ControlObject> m_pKeylockEngine;
320319

321320
PflGainCalculator m_headphoneGain;
322321
TalkoverGainCalculator m_talkoverGain;
@@ -338,9 +337,14 @@ class EngineMixer : public QObject, public AudioSource {
338337
const ChannelHandleAndGroup m_busCrossfaderRightHandle;
339338

340339
// Mix two Mono channels. This is useful for outdoor gigs
341-
ControlObject* m_pMainMonoMixdown;
342-
ControlObject* m_pMicMonitorMode;
340+
std::unique_ptr<ControlObject> m_pMainMonoMixdown;
341+
std::unique_ptr<ControlObject> m_pMicMonitorMode;
343342

343+
// TODO (Swiftb0y): remove volatile (probably supposed to be std::atomic instead).
344344
volatile bool m_bBusOutputConnected[3];
345345
bool m_bExternalRecordBroadcastInputConnected;
346+
347+
// Owning list of channels added to the engine.
348+
// Keep at last position, it needs to be destroyed first
349+
QVarLengthArray<std::unique_ptr<ChannelInfo>, kPreallocatedChannels> m_channels;
346350
};

src/engine/engineworkerscheduler.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
#include "util/event.h"
77

88
EngineWorkerScheduler::EngineWorkerScheduler(QObject* pParent)
9-
: m_bWakeScheduler(false),
9+
: QThread(pParent),
10+
m_bWakeScheduler(false),
1011
m_bQuit(false) {
11-
Q_UNUSED(pParent);
1212
}
1313

1414
EngineWorkerScheduler::~EngineWorkerScheduler() {

src/engine/engineworkerscheduler.h

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,23 @@
33
#include <QMutex>
44
#include <QThread>
55
#include <QWaitCondition>
6-
7-
// The max engine workers that can be expected to run within a callback
8-
// (e.g. the max that we will schedule). Must be a power of 2.
9-
#define MAX_ENGINE_WORKERS 32
6+
#include <atomic>
7+
#include <vector>
108

119
class EngineWorker;
1210

1311
class EngineWorkerScheduler : public QThread {
1412
Q_OBJECT
1513
public:
16-
EngineWorkerScheduler(QObject* pParent=NULL);
17-
virtual ~EngineWorkerScheduler();
14+
EngineWorkerScheduler(QObject* pParent = nullptr);
15+
~EngineWorkerScheduler() override;
1816

1917
void addWorker(EngineWorker* pWorker);
2018
void runWorkers();
2119
void workerReady();
2220

2321
protected:
24-
void run();
22+
void run() override;
2523

2624
private:
2725
// Indicates whether workerReady has been called since the last time
@@ -32,6 +30,7 @@ class EngineWorkerScheduler : public QThread {
3230

3331
// mutex protects m_workers and m_bQuit
3432
QMutex m_mutex;
33+
// containing pointers are non-owning
3534
std::vector<EngineWorker*> m_workers;
36-
bool m_bQuit;
35+
std::atomic<bool> m_bQuit;
3736
};

src/test/cuecontrol_test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class CueControlTest : public BaseSignalPathTest {
3939
}
4040

4141
void loadTrack(TrackPointer pTrack) {
42-
BaseSignalPathTest::loadTrack(m_pMixerDeck1, pTrack);
42+
BaseSignalPathTest::loadTrack(m_pMixerDeck1.get(), pTrack);
4343
ProcessBuffer();
4444
}
4545

src/test/enginemicrophonetest.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class EngineMicrophoneTest : public SignalPathTest {
2424

2525
// No need for a real handle in this test.
2626
m_pMicrophone = new EngineMicrophone(
27-
ChannelHandleAndGroup(ChannelHandle(), "[Microphone]"), m_pEffectsManager);
27+
ChannelHandleAndGroup(ChannelHandle(), "[Microphone]"), m_pEffectsManager.get());
2828
m_pTalkover = ControlObject::getControl(ConfigKey("[Microphone]", "talkover"));
2929
}
3030

src/test/enginemixertest.cpp

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ TEST_F(EngineMixerTest, SingleChannelOutputWorks) {
6262
const QString testName = "SingleChannelOutputWorks";
6363

6464
EngineChannelMock* pChannel = new EngineChannelMock(
65-
"[Test1]", EngineChannel::CENTER, m_pEngineMixer);
65+
"[Test1]", EngineChannel::CENTER, m_pEngineMixer.get());
6666
m_pEngineMixer->addChannel(pChannel);
6767

6868
// Pretend that the channel processed the buffer by stuffing it with 1.0's
@@ -106,7 +106,7 @@ TEST_F(EngineMixerTest, SingleChannelPFLOutputWorks) {
106106
const QString testName = "SingleChannelPFLOutputWorks";
107107

108108
EngineChannelMock* pChannel = new EngineChannelMock(
109-
"[Test1]", EngineChannel::CENTER, m_pEngineMixer);
109+
"[Test1]", EngineChannel::CENTER, m_pEngineMixer.get());
110110
m_pEngineMixer->addChannel(pChannel);
111111

112112
// Pretend that the channel processed the buffer by stuffing it with 1.0's
@@ -150,10 +150,10 @@ TEST_F(EngineMixerTest, TwoChannelOutputWorks) {
150150
const QString testName = "TwoChannelOutputWorks";
151151

152152
EngineChannelMock* pChannel1 = new EngineChannelMock(
153-
"[Test1]", EngineChannel::CENTER, m_pEngineMixer);
153+
"[Test1]", EngineChannel::CENTER, m_pEngineMixer.get());
154154
m_pEngineMixer->addChannel(pChannel1);
155155
EngineChannelMock* pChannel2 = new EngineChannelMock(
156-
"[Test2]", EngineChannel::CENTER, m_pEngineMixer);
156+
"[Test2]", EngineChannel::CENTER, m_pEngineMixer.get());
157157
m_pEngineMixer->addChannel(pChannel2);
158158

159159
// Pretend that the channel processed the buffer by stuffing it with 1.0's
@@ -221,10 +221,10 @@ TEST_F(EngineMixerTest, TwoChannelPFLOutputWorks) {
221221
const QString testName = "TwoChannelPFLOutputWorks";
222222

223223
EngineChannelMock* pChannel1 = new EngineChannelMock(
224-
"[Test1]", EngineChannel::CENTER, m_pEngineMixer);
224+
"[Test1]", EngineChannel::CENTER, m_pEngineMixer.get());
225225
m_pEngineMixer->addChannel(pChannel1);
226226
EngineChannelMock* pChannel2 = new EngineChannelMock(
227-
"[Test2]", EngineChannel::CENTER, m_pEngineMixer);
227+
"[Test2]", EngineChannel::CENTER, m_pEngineMixer.get());
228228
m_pEngineMixer->addChannel(pChannel2);
229229

230230
// Pretend that the channel processed the buffer by stuffing it with 1.0's
@@ -292,13 +292,13 @@ TEST_F(EngineMixerTest, ThreeChannelOutputWorks) {
292292
const QString testName = "ThreeChannelOutputWorks";
293293

294294
EngineChannelMock* pChannel1 = new EngineChannelMock(
295-
"[Test1]", EngineChannel::CENTER, m_pEngineMixer);
295+
"[Test1]", EngineChannel::CENTER, m_pEngineMixer.get());
296296
m_pEngineMixer->addChannel(pChannel1);
297297
EngineChannelMock* pChannel2 = new EngineChannelMock(
298-
"[Test2]", EngineChannel::CENTER, m_pEngineMixer);
298+
"[Test2]", EngineChannel::CENTER, m_pEngineMixer.get());
299299
m_pEngineMixer->addChannel(pChannel2);
300300
EngineChannelMock* pChannel3 = new EngineChannelMock(
301-
"[Test3]", EngineChannel::CENTER, m_pEngineMixer);
301+
"[Test3]", EngineChannel::CENTER, m_pEngineMixer.get());
302302
m_pEngineMixer->addChannel(pChannel3);
303303

304304
// Pretend that the channel processed the buffer by stuffing it with 1.0's
@@ -389,13 +389,13 @@ TEST_F(EngineMixerTest, ThreeChannelPFLOutputWorks) {
389389
const QString testName = "ThreeChannelPFLOutputWorks";
390390

391391
EngineChannelMock* pChannel1 = new EngineChannelMock(
392-
"[Test1]", EngineChannel::CENTER, m_pEngineMixer);
392+
"[Test1]", EngineChannel::CENTER, m_pEngineMixer.get());
393393
m_pEngineMixer->addChannel(pChannel1);
394394
EngineChannelMock* pChannel2 = new EngineChannelMock(
395-
"[Test2]", EngineChannel::CENTER, m_pEngineMixer);
395+
"[Test2]", EngineChannel::CENTER, m_pEngineMixer.get());
396396
m_pEngineMixer->addChannel(pChannel2);
397397
EngineChannelMock* pChannel3 = new EngineChannelMock(
398-
"[Test3]", EngineChannel::CENTER, m_pEngineMixer);
398+
"[Test3]", EngineChannel::CENTER, m_pEngineMixer.get());
399399
m_pEngineMixer->addChannel(pChannel3);
400400

401401
// Pretend that the channel processed the buffer by stuffing it with 1.0's

src/test/hotcuecontrol_test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ class HotcueControlTest : public BaseSignalPathTest {
5656
}
5757

5858
void loadTrack(TrackPointer pTrack) {
59-
BaseSignalPathTest::loadTrack(m_pMixerDeck1, pTrack);
59+
BaseSignalPathTest::loadTrack(m_pMixerDeck1.get(), pTrack);
6060
ProcessBuffer();
6161
}
6262

src/test/replaygaintest.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,8 @@ TEST_F(AdjustReplayGainTest, AdjustReplayGainUpdatesPregain) {
165165

166166
// Load the same track in decks 1 and 2 so we can see that the pregain is adjusted on both
167167
// decks.
168-
loadTrack(m_pMixerDeck1, pTrack);
169-
loadTrack(m_pMixerDeck2, pTrack);
168+
loadTrack(m_pMixerDeck1.get(), pTrack);
169+
loadTrack(m_pMixerDeck2.get(), pTrack);
170170

171171
// Initialize fake track replaygain so it's not zero.
172172
mixxx::ReplayGain replayGain;

0 commit comments

Comments
 (0)