When multiple soundcards are used via the JACK backend (on pipewire) a lot of distortion happens because the buffers are not completely filled.
I found out about this because I'm using a Denon MC7000 controller for DVS vinyl input and a Focusrite Scarlett 18i20 for output.
The two soundcards are handled by pipewire with a common sample rate (44100 Hz), and I setup it so that the controller's input is the driver of the graph.
The solution I found is to apply the following patch:
diff --git a/src/soundio/soundmanager.cpp b/src/soundio/soundmanager.cpp
index b27cd17485..5a65e27fa2 100644
--- a/src/soundio/soundmanager.cpp
+++ b/src/soundio/soundmanager.cpp
@@ -353,9 +353,7 @@ SoundDeviceStatus SoundManager::setupDevices() {
// all found devices are removed below
QSet<SoundDeviceId> devicesNotFound = m_config.getDevices();
- // pair is isInput, isOutput
QVector<DeviceMode> toOpen;
- bool haveOutput = false;
// loop over all available devices
for (const auto& pDevice : std::as_const(m_devices)) {
DeviceMode mode = {pDevice, false, false};
@@ -399,9 +397,6 @@ SoundDeviceStatus SoundManager::setupDevices() {
for (const auto& out : std::as_const(outputs)) {
mode.isOutput = true;
- if (pDevice->getDeviceId().name != kNetworkDeviceInternalName) {
- haveOutput = true;
- }
// following keeps us from asking for a channel buffer EngineMixer
// doesn't have -- bkgood
const CSAMPLE* pBuffer = m_registeredSources.value(out)->buffer(out);
@@ -416,16 +411,6 @@ SoundDeviceStatus SoundManager::setupDevices() {
goto closeAndError;
}
- if (!m_config.getForceNetworkClock() || jackApiUsed()) {
- if (out.getType() == AudioPathType::Main) {
- pNewMainClockRef = pDevice;
- } else if ((out.getType() == AudioPathType::Deck ||
- out.getType() == AudioPathType::Bus) &&
- !pNewMainClockRef) {
- pNewMainClockRef = pDevice;
- }
- }
-
// Check if any AudioSource is registered for this AudioOutput and
// call the onOutputConnected method.
for (auto it = m_registeredSources.find(out);
@@ -447,11 +432,10 @@ SoundDeviceStatus SoundManager::setupDevices() {
m_pErrorDevice = pDevice;
// If we have not yet set a clock source then we use the first
- // output pDevice
- if (pNewMainClockRef.isNull() &&
- (!haveOutput || mode.isOutput)) {
+ // input pDevice
+ if (pNewMainClockRef.isNull() && mode.isInput) {
pNewMainClockRef = pDevice;
- qWarning() << "Output sound device clock reference not set! Using"
+ qWarning() << "Sound device clock reference not set! Using"
<< pDevice->getDisplayName();
}
@@ -474,11 +458,24 @@ SoundDeviceStatus SoundManager::setupDevices() {
}
}
+ for (const auto& mode: toOpen) {
+ SoundDevicePointer pDevice = mode.pDevice;
+ m_pErrorDevice = pDevice;
+
+ // If we have not yet set a clock source then we use the first
+ // output pDevice
+ if (pNewMainClockRef.isNull() && mode.isOutput) {
+ pNewMainClockRef = pDevice;
+ qWarning() << "Sound device clock reference not set! Using"
+ << pDevice->getDisplayName();
+ }
+ }
+
if (pNewMainClockRef) {
qDebug() << "Using" << pNewMainClockRef->getDisplayName()
- << "as output sound device clock reference";
+ << "as sound device clock reference";
} else {
- qWarning() << "No output devices opened, no clock reference device set";
+ qWarning() << "No devices opened, no clock reference device set";
}
qDebug() << outputDevicesOpened << "output sound devices opened";
With the above patch applied, Mixxx uses the first input soundcard as the clock source instead of the output one, and this magically solved my problem, but only because the first input that Mixxx opens is the controller's one (which is the driver of the graph). If I add more inputs to Mixxx from the Scarlett card so that Mixxx selects it as its clock reference, the issue happens again. Strangely enough, if I set the Focusrite's input as the driver, and then make sure that also Mixxx selects it as its clock reference, the distortion still occurs...
Bug Description
When multiple soundcards are used via the JACK backend (on pipewire) a lot of distortion happens because the buffers are not completely filled.
I found out about this because I'm using a Denon MC7000 controller for DVS vinyl input and a Focusrite Scarlett 18i20 for output.
The two soundcards are handled by pipewire with a common sample rate (44100 Hz), and I setup it so that the controller's input is the driver of the graph.
The solution I found is to apply the following patch:
With the above patch applied, Mixxx uses the first input soundcard as the clock source instead of the output one, and this magically solved my problem, but only because the first input that Mixxx opens is the controller's one (which is the driver of the graph). If I add more inputs to Mixxx from the Scarlett card so that Mixxx selects it as its clock reference, the issue happens again. Strangely enough, if I set the Focusrite's input as the driver, and then make sure that also Mixxx selects it as its clock reference, the distortion still occurs...
See also the discussion on Zulip: https://mixxx.zulipchat.com/#narrow/channel/109171-development/topic/Wrong.20synchronization.20of.20multiple.20soundcards.20on.20Pipewire
Finally, I tried to disable the multi soundcard sync'ing option in the configuration, but it doesn't seem to actually disable it.
Version
2.4.1
OS
Arch Linux