Skip to content

Commit 292d3a5

Browse files
committed
Implement a setting in the sound preferences, to apply a manual sync latency offset
1 parent 8e1b43d commit 292d3a5

7 files changed

Lines changed: 81 additions & 13 deletions

File tree

src/engine/enginemixer.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,14 @@ EngineMixer::EngineMixer(UserSettingsPointer pConfig,
9393
ConfigKey(group, "boothDelay"))),
9494
m_pLatencyCompensationDelay(std::make_unique<EngineDelay>(
9595
ConfigKey(group, "microphoneLatencyCompensation"))),
96+
m_pExternalSyncLatencyCompensation(std::make_unique<ControlPotmeter>(
97+
ConfigKey(group, "externalSyncLatencyCompensation"),
98+
-100.0, // min
99+
100.0, // max
100+
true, // allowOutOfBounds
101+
true, // bIgnoreNops
102+
false, // bTrack
103+
true)), // bPersist
96104
m_pVumeter(std::make_unique<EngineVuMeter>(kMainGroup, kLegacyGroup)),
97105
// Starts a thread for recording and broadcast
98106
m_pEngineSideChain(bEnableSidechain

src/engine/enginemixer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ class EngineMixer : public QObject, public AudioSource {
313313
std::unique_ptr<EngineDelay> m_pHeadDelay;
314314
std::unique_ptr<EngineDelay> m_pBoothDelay;
315315
std::unique_ptr<EngineDelay> m_pLatencyCompensationDelay;
316+
std::unique_ptr<ControlPotmeter> m_pExternalSyncLatencyCompensation;
316317

317318
std::unique_ptr<EngineVuMeter> m_pVumeter;
318319
std::unique_ptr<EngineSideChain> m_pEngineSideChain;

src/preferences/dialog/dlgprefsound.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ DlgPrefSound::DlgPrefSound(QWidget* pParent,
7575
m_pSettings(pSettings),
7676
m_config(pSoundManager.get()),
7777
m_pLatencyCompensation(kMasterGroup, QStringLiteral("microphoneLatencyCompensation")),
78+
m_pExternalSyncLatencyCompensation(
79+
kMasterGroup, QStringLiteral("externalSyncLatencyCompensation")),
7880
m_pMainDelay(kMasterGroup, QStringLiteral("delay")),
7981
m_pHeadDelay(kMasterGroup, QStringLiteral("headDelay")),
8082
m_pBoothDelay(kMasterGroup, QStringLiteral("boothDelay")),
@@ -155,6 +157,8 @@ DlgPrefSound::DlgPrefSound(QWidget* pParent,
155157
}
156158

157159
latencyCompensationSpinBox->setValue(m_pLatencyCompensation.get());
160+
externalSyncLatencyCompensationSpinBox->setValue(
161+
m_pExternalSyncLatencyCompensation.get());
158162
latencyCompensationWarningLabel->setWordWrap(true);
159163
mainDelaySpinBox->setValue(m_pMainDelay.get());
160164
headDelaySpinBox->setValue(m_pHeadDelay.get());
@@ -167,6 +171,10 @@ DlgPrefSound::DlgPrefSound(QWidget* pParent,
167171
QOverload<double>::of(&QDoubleSpinBox::valueChanged),
168172
this,
169173
&DlgPrefSound::latencyCompensationSpinboxChanged);
174+
connect(externalSyncLatencyCompensationSpinBox,
175+
QOverload<double>::of(&QDoubleSpinBox::valueChanged),
176+
this,
177+
&DlgPrefSound::externalSyncLatencyCompensationSpinboxChanged);
170178
connect(mainDelaySpinBox,
171179
QOverload<double>::of(&QDoubleSpinBox::valueChanged),
172180
this,
@@ -953,6 +961,8 @@ void DlgPrefSound::slotResetToDefaults() {
953961
static_cast<int>(EngineMixer::MicMonitorMode::Main)));
954962

955963
latencyCompensationSpinBox->setValue(latencyCompensationSpinBox->minimum());
964+
externalSyncLatencyCompensationSpinBox->setValue(0.0);
965+
m_pExternalSyncLatencyCompensation.set(0.0);
956966

957967
settingChanged();
958968
#ifdef __RUBBERBAND__
@@ -975,6 +985,10 @@ void DlgPrefSound::latencyCompensationSpinboxChanged(double value) {
975985
checkLatencyCompensation();
976986
}
977987

988+
void DlgPrefSound::externalSyncLatencyCompensationSpinboxChanged(double value) {
989+
m_pExternalSyncLatencyCompensation.set(value);
990+
}
991+
978992
void DlgPrefSound::mainDelaySpinboxChanged(double value) {
979993
m_pMainDelay.set(value);
980994
}

src/preferences/dialog/dlgprefsound.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ class DlgPrefSound : public DlgPreferencePage, public Ui::DlgPrefSoundDlg {
5252
void bufferUnderflow(double count);
5353
void outputLatencyChanged(double latency);
5454
void latencyCompensationSpinboxChanged(double value);
55+
void externalSyncLatencyCompensationSpinboxChanged(double value);
5556
void mainDelaySpinboxChanged(double value);
5657
void headDelaySpinboxChanged(double value);
5758
void boothDelaySpinboxChanged(double value);
@@ -95,6 +96,7 @@ class DlgPrefSound : public DlgPreferencePage, public Ui::DlgPrefSoundDlg {
9596
SoundManagerConfig m_config;
9697

9798
PollingControlProxy m_pLatencyCompensation;
99+
PollingControlProxy m_pExternalSyncLatencyCompensation;
98100
PollingControlProxy m_pMainDelay;
99101
PollingControlProxy m_pHeadDelay;
100102
PollingControlProxy m_pBoothDelay;

src/preferences/dialog/dlgprefsounddlg.ui

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -151,14 +151,43 @@
151151
</property>
152152
</widget>
153153
</item>
154-
<item row="11" column="0">
154+
<item row="10" column="0">
155+
<widget class="QLabel" name="externalSyncLatencyCompensationLabel">
156+
<property name="text">
157+
<string>External Sync Latency Compensation</string>
158+
</property>
159+
<property name="buddy">
160+
<cstring>externalSyncLatencyCompensationSpinBox</cstring>
161+
</property>
162+
</widget>
163+
</item>
164+
<item row="10" column="1">
165+
<widget class="QDoubleSpinBox" name="externalSyncLatencyCompensationSpinBox">
166+
<property name="suffix">
167+
<string> ms</string>
168+
</property>
169+
<property name="decimals">
170+
<number>3</number>
171+
</property>
172+
<property name="minimum">
173+
<double>-100.000000000000000</double>
174+
</property>
175+
<property name="maximum">
176+
<double>100.000000000000000</double>
177+
</property>
178+
<property name="singleStep">
179+
<double>0.100000000000000</double>
180+
</property>
181+
</widget>
182+
</item>
183+
<item row="12" column="0">
155184
<widget class="QLabel" name="mainDelayLabel">
156185
<property name="text">
157186
<string>Main Output Delay</string>
158187
</property>
159188
</widget>
160189
</item>
161-
<item row="11" column="1">
190+
<item row="12" column="1">
162191
<widget class="QDoubleSpinBox" name="mainDelaySpinBox">
163192
<property name="suffix">
164193
<string extracomment="milliseconds"> ms</string>
@@ -174,14 +203,14 @@
174203
</property>
175204
</widget>
176205
</item>
177-
<item row="12" column="0">
206+
<item row="13" column="0">
178207
<widget class="QLabel" name="headDelayLabel">
179208
<property name="text">
180209
<string>Headphone Output Delay</string>
181210
</property>
182211
</widget>
183212
</item>
184-
<item row="12" column="1">
213+
<item row="13" column="1">
185214
<widget class="QDoubleSpinBox" name="headDelaySpinBox">
186215
<property name="suffix">
187216
<string extracomment="milliseconds"> ms</string>
@@ -197,14 +226,14 @@
197226
</property>
198227
</widget>
199228
</item>
200-
<item row="13" column="0">
229+
<item row="14" column="0">
201230
<widget class="QLabel" name="boothDelayLabel">
202231
<property name="text">
203232
<string>Booth Output Delay</string>
204233
</property>
205234
</widget>
206235
</item>
207-
<item row="13" column="1">
236+
<item row="14" column="1">
208237
<widget class="QDoubleSpinBox" name="boothDelaySpinBox">
209238
<property name="suffix">
210239
<string extracomment="milliseconds"> ms</string>
@@ -213,14 +242,17 @@
213242
<number>3</number>
214243
</property>
215244
<property name="maximum">
216-
<double>500.000000000000000</double>
245+
<double>-100.000000000000000</double>
246+
</property>
247+
<property name="maximum">
248+
<double>100.000000000000000</double>
217249
</property>
218250
<property name="singleStep">
219251
<double>0.100000000000000</double>
220252
</property>
221253
</widget>
222254
</item>
223-
<item row="14" column="0" colspan="2">
255+
<item row="15" column="0" colspan="2">
224256
<widget class="QLabel" name="latencyCompensationWarningLabel">
225257
<property name="text">
226258
<string notr="true">warning goes here</string>

src/soundio/sounddeviceportaudio.cpp

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <cstddef>
99

1010
#include "control/controlobject.h"
11+
#include "control/controlproxy.h"
1112
#include "sounddevicenetwork.h"
1213
#include "soundio/sounddevice.h"
1314
#include "soundio/soundmanager.h"
@@ -120,7 +121,10 @@ SoundDevicePortAudio::SoundDevicePortAudio(UserSettingsPointer config,
120121
m_callbackResult(paAbort),
121122
m_hostTimeFilter(kNumPointsInHostTimeFilter),
122123
m_cummulatedBufferTime(0),
123-
m_meanOutputLatency(MovingInterquartileMean(128)) {
124+
m_meanOutputLatency(MovingInterquartileMean(128)),
125+
m_pExternalSyncLatencyCompensation(std::make_unique<ControlProxy>(
126+
QStringLiteral("[Master]"),
127+
QStringLiteral("externalSyncLatencyCompensation"))) {
124128
// Setting parent class members:
125129
m_hostAPI = Pa_GetHostApiInfo(deviceInfo->hostApi)->name;
126130
m_sampleRate = mixxx::audio::SampleRate::fromDouble(deviceInfo->defaultSampleRate);
@@ -1182,17 +1186,22 @@ void SoundDevicePortAudio::updateCallbackEntryToDacTime(
11821186

11831187
// Only use latency from PortAudios timeInfo, if it's in reasonable range,
11841188
// otherwise use latency value from PortAudios streamInfo
1189+
auto externalSyncLatencyUs = std::chrono::duration_cast<std::chrono::microseconds>(
1190+
std::chrono::duration<double, std::milli>(m_pExternalSyncLatencyCompensation->get()));
1191+
11851192
if (callbackEntrytoDacSecs > kMinReasonableAudioLatencySecs &&
11861193
timeSinceLastCbSecs < bufferSizeSec * 2) {
11871194
m_meanOutputLatency.insert(timeInfo->outputBufferDacTime - soundCardTimeNow);
11881195

11891196
m_absTimeWhenPrevOutputBufferReachesDac = filteredHostTimeNow +
1190-
std::chrono::microseconds(static_cast<long long>(
1191-
m_meanOutputLatency.mean() * 1000000));
1197+
std::chrono::duration_cast<std::chrono::microseconds>(
1198+
std::chrono::duration<double>(m_meanOutputLatency.mean())) +
1199+
externalSyncLatencyUs;
11921200
} else {
11931201
m_absTimeWhenPrevOutputBufferReachesDac = filteredHostTimeNow +
1194-
std::chrono::microseconds(
1195-
static_cast<long long>(m_outputLatencyMillis * 1000));
1202+
std::chrono::duration_cast<std::chrono::microseconds>(
1203+
std::chrono::duration<double, std::milli>(m_outputLatencyMillis)) +
1204+
externalSyncLatencyUs;
11961205
}
11971206

11981207
double diff = (timeSinceLastCbSecs + callbackEntrytoDacSecs) -

src/soundio/sounddeviceportaudio.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,4 +100,6 @@ class SoundDevicePortAudio : public SoundDevice {
100100
HostTimeFilter m_hostTimeFilter;
101101
double m_cummulatedBufferTime;
102102
MovingInterquartileMean m_meanOutputLatency;
103+
104+
std::unique_ptr<ControlProxy> m_pExternalSyncLatencyCompensation;
103105
};

0 commit comments

Comments
 (0)