From 22d03481a5ecaeacca60abc48b68388543236f78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Fri, 17 Mar 2023 13:17:44 +0100 Subject: [PATCH 01/13] Use a range based loop --- src/preferences/dialog/dlgprefsound.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/preferences/dialog/dlgprefsound.cpp b/src/preferences/dialog/dlgprefsound.cpp index 4da9ebc1b14..2a07af980fa 100644 --- a/src/preferences/dialog/dlgprefsound.cpp +++ b/src/preferences/dialog/dlgprefsound.cpp @@ -47,7 +47,7 @@ DlgPrefSound::DlgPrefSound(QWidget* pParent, &DlgPrefSound::apiChanged); sampleRateComboBox->clear(); - foreach (unsigned int srate, m_pSoundManager->getSampleRates()) { + for (auto& srate : m_pSoundManager->getSampleRates()) { if (srate > 0) { // no ridiculous sample rate values. prohibiting zero means // avoiding a potential div-by-0 error in ::updateLatencies From 053f47519302c329fb26d4f40e9128b7882796a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Fri, 17 Mar 2023 13:18:29 +0100 Subject: [PATCH 02/13] Remove redundant connection the the sample rate combo box --- src/preferences/dialog/dlgprefsound.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/preferences/dialog/dlgprefsound.cpp b/src/preferences/dialog/dlgprefsound.cpp index 2a07af980fa..fb9ee68b805 100644 --- a/src/preferences/dialog/dlgprefsound.cpp +++ b/src/preferences/dialog/dlgprefsound.cpp @@ -58,10 +58,6 @@ DlgPrefSound::DlgPrefSound(QWidget* pParent, QOverload::of(&QComboBox::currentIndexChanged), this, &DlgPrefSound::sampleRateChanged); - connect(sampleRateComboBox, - QOverload::of(&QComboBox::currentIndexChanged), - this, - &DlgPrefSound::updateAudioBufferSizes); connect(audioBufferComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, @@ -562,6 +558,7 @@ void DlgPrefSound::sampleRateChanged(int index) { m_config.setSampleRate( sampleRateComboBox->itemData(index).toUInt()); m_bLatencyChanged = true; + updateAudioBufferSizes(index); checkLatencyCompensation(); } From ba755dcada4adf2bc5b6680635920f135ba9e9ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sat, 18 Mar 2023 09:50:12 +0100 Subject: [PATCH 03/13] Reanable Audio Buffer selection for Jack and populate it with auto and values above 1024 where auto does not work. --- src/preferences/dialog/dlgprefsound.cpp | 70 +++++++++++++++---------- 1 file changed, 43 insertions(+), 27 deletions(-) diff --git a/src/preferences/dialog/dlgprefsound.cpp b/src/preferences/dialog/dlgprefsound.cpp index fb9ee68b805..398c362bc15 100644 --- a/src/preferences/dialog/dlgprefsound.cpp +++ b/src/preferences/dialog/dlgprefsound.cpp @@ -512,22 +512,24 @@ void DlgPrefSound::apiChanged(int index) { m_config.setAPI(apiComboBox->itemData(index).toString()); refreshDevices(); // JACK sets its own buffer size and sample rate that Mixxx cannot change. + // PortAudio is able to chop/combine the buffer but that will mess up the + // timing in Mixxx. When we request 0 (paFramesPerBufferUnspecified) + // https://github.com/PortAudio/portaudio/blob/v19.7.0/src/common/pa_process.c#L54 + // PortAudio passes buffers up to 1024 frames through. + // For bigger buffers the user has to manually match the value with Jack. // TODO(Be): Get the buffer size from JACK and update audioBufferComboBox. - // PortAudio does not have a way to get the buffer size from JACK as of July 2017. + // PortAudio as off v19.7.0 does not have a way to get the buffer size from JACK. if (m_config.getAPI() == MIXXX_PORTAUDIO_JACK_STRING) { sampleRateComboBox->setEnabled(false); - latencyLabel->setEnabled(false); - audioBufferComboBox->setEnabled(false); deviceSyncComboBox->setEnabled(false); engineClockComboBox->setEnabled(false); } else { sampleRateComboBox->setEnabled(true); - latencyLabel->setEnabled(true); - audioBufferComboBox->setEnabled(true); deviceSyncComboBox->setEnabled(true); engineClockComboBox->setEnabled(true); } + updateAudioBufferSizes(sampleRateComboBox->currentIndex()); } /** @@ -602,30 +604,44 @@ void DlgPrefSound::engineClockChanged(int index) { // of 2 (so the values displayed in ms won't be constant between sample rates, // but they'll be close). void DlgPrefSound::updateAudioBufferSizes(int sampleRateIndex) { - double sampleRate = sampleRateComboBox->itemData(sampleRateIndex).toDouble(); - int oldSizeIndex = audioBufferComboBox->currentIndex(); - unsigned int framesPerBuffer = 1; // start this at 0 and inf loop happens - // we don't want to display any sub-1ms buffer sizes (well maybe we do but I - // don't right now!), so we iterate over all the buffer sizes until we - // find the first that gives us a buffer size >= 1 ms -- bkgood - // no div-by-0 in the next line because we don't allow srates of 0 in our - // srate list when we construct it in the ctor -- bkgood - for (; framesPerBuffer / sampleRate * 1000 < 1.0; framesPerBuffer *= 2) { - } + QVariant oldSizeIndex = audioBufferComboBox->currentData(); audioBufferComboBox->clear(); - for (unsigned int i = 0; i < SoundManagerConfig::kMaxAudioBufferSizeIndex; ++i) { - const auto latency = static_cast(framesPerBuffer / sampleRate * 1000); - // i + 1 in the next line is a latency index as described in SSConfig - audioBufferComboBox->addItem(tr("%1 ms").arg(latency,0,'g',3), i + 1); - framesPerBuffer <<= 1; // *= 2 - } - if (oldSizeIndex < audioBufferComboBox->count() && oldSizeIndex >= 0) { - audioBufferComboBox->setCurrentIndex(oldSizeIndex); + if (m_config.getAPI() == MIXXX_PORTAUDIO_JACK_STRING) { + // in case of jack we configure the frames/period + // we cannot calc the resulting buffer size in ms because the + // Sample rate is not known yet. We assume 48000 KHz here + // to calculate the buffer size index + audioBufferComboBox->addItem(tr("auto (<= 1024 frames/period)"), 5); + audioBufferComboBox->addItem(tr("2048 frames/period"), 6); + audioBufferComboBox->addItem(tr("4096 frames/period"), 7); } else { - // set it to the max, let the user dig if they need better latency. better - // than having a user get the pops on first use and thinking poorly of mixxx - // because of it -- bkgood - audioBufferComboBox->setCurrentIndex(audioBufferComboBox->count() - 1); + double sampleRate = sampleRateComboBox->itemData(sampleRateIndex).toDouble(); + unsigned int framesPerBuffer = 1; // start this at 0 and inf loop happens + // we don't want to display any sub-1ms buffer sizes (well maybe we do but I + // don't right now!), so we iterate over all the buffer sizes until we + // find the first that gives us a buffer size >= 1 ms -- bkgood + // no div-by-0 in the next line because we don't allow srates of 0 in our + // srate list when we construct it in the ctor -- bkgood + for (; framesPerBuffer / sampleRate * 1000 < 1.0; framesPerBuffer *= 2) { + } + for (unsigned int i = 0; i < SoundManagerConfig::kMaxAudioBufferSizeIndex; ++i) { + const auto latency = static_cast(framesPerBuffer / sampleRate * 1000); + // i + 1 in the next line is a latency index as described in SSConfig + audioBufferComboBox->addItem(tr("%1 ms").arg(latency, 0, 'g', 3), i + 1); + framesPerBuffer <<= 1; // *= 2 + } + } + int selectionIndex = audioBufferComboBox->findData(oldSizeIndex); + if (selectionIndex > -1) { + audioBufferComboBox->setCurrentIndex(selectionIndex); + } else { + // use our default of 5 (23 ms @ 48 kHz) + selectionIndex = audioBufferComboBox->findData( + SoundManagerConfig::kDefaultAudioBufferSizeIndex); + VERIFY_OR_DEBUG_ASSERT(selectionIndex > -1) { + return; + } + audioBufferComboBox->setCurrentIndex(selectionIndex); } } From 5768eba2c5d18713f51d2099c2b5e73a30357147 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sat, 18 Mar 2023 10:18:48 +0100 Subject: [PATCH 04/13] Make SoundManagerConfig::getFramesPerBuffer() Sample rate independent in case of JACK --- src/soundio/soundmanagerconfig.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/soundio/soundmanagerconfig.cpp b/src/soundio/soundmanagerconfig.cpp index 0b0c1cabea3..ac2f27f1fc8 100644 --- a/src/soundio/soundmanagerconfig.cpp +++ b/src/soundio/soundmanagerconfig.cpp @@ -393,6 +393,21 @@ unsigned int SoundManagerConfig::getAudioBufferSizeIndex() const { // This reflects the configured value only. In case of JACK the // setting of the JACK server is used. unsigned int SoundManagerConfig::getFramesPerBuffer() const { + if (m_api == MIXXX_PORTAUDIO_JACK_STRING) { + // in case of jack we configure the frames/period + if (m_audioBufferSizeIndex == 7) { + return 4096; + } else if (m_audioBufferSizeIndex == 7) { + return 2048; + } + // default is auto <= 1024 + // The Jack buffer size can change at any time, so we + // need buffers for the maximum of 1024 (limited by Portaudio). + return 1024; + } + + // With the other APIs we calc the frames per buffer form the sample rate + // endless loop otherwise unsigned int audioBufferSizeIndex = m_audioBufferSizeIndex; VERIFY_OR_DEBUG_ASSERT(audioBufferSizeIndex > 0) { From d48b27965aee1f9dcc5d5432f0fb77ac2c293956 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sat, 18 Mar 2023 11:30:31 +0100 Subject: [PATCH 05/13] Use paFramesPerBufferUnspecified only if <= 1024 frames/period is selected --- src/soundio/sounddeviceportaudio.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/soundio/sounddeviceportaudio.cpp b/src/soundio/sounddeviceportaudio.cpp index 476b822035b..df33924b067 100644 --- a/src/soundio/sounddeviceportaudio.cpp +++ b/src/soundio/sounddeviceportaudio.cpp @@ -213,14 +213,17 @@ SoundDeviceError SoundDevicePortAudio::open(bool isClkRefDevice, int syncBuffers } SINT framesPerBuffer = m_configFramesPerBuffer; - if (m_deviceTypeId == paJACK) { - // PortAudio's JACK back end has its own buffering to split or merge the buffer - // received from JACK to the desired size. - // However, we use here paFramesPerBufferUnspecified to use the JACK buffer size + if (m_deviceTypeId == paJACK && framesPerBuffer <= 1024) { + // Up to a Jack buffer size of 1024 frames/period, PortAudio is able to + // follow the Jack buffer size dynamically. + // We make use of it by requesting paFramesPerBufferUnspecified // which offers the best response time without additional jitter due to two // successive callback without the expected pause. framesPerBuffer = paFramesPerBufferUnspecified; qDebug() << "Using JACK server's frames per period"; + // in case of bigger buffers, the user need to select the same buffers + // size in Mixxx and Jack to avoid buffer underflow/overflow during broadcasting + // This fixes https://github.com/mixxxdj/mixxx/issues/11341 } else { qDebug() << "framesPerBuffer:" << framesPerBuffer; } From c4e482630aa32007218e80087a703cac2851f78b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Mon, 13 Mar 2023 20:05:45 +0100 Subject: [PATCH 06/13] Assert network device buffers size --- src/soundio/sounddevicenetwork.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/soundio/sounddevicenetwork.cpp b/src/soundio/sounddevicenetwork.cpp index 2c9e6d7dde2..1ed7d8ceeed 100644 --- a/src/soundio/sounddevicenetwork.cpp +++ b/src/soundio/sounddevicenetwork.cpp @@ -30,9 +30,10 @@ const int kNetworkLatencyFrames = 8192; // 185 ms @ 44100 Hz const mixxx::Logger kLogger("SoundDeviceNetwork"); } // namespace -SoundDeviceNetwork::SoundDeviceNetwork(UserSettingsPointer config, - SoundManager *sm, - QSharedPointer pNetworkStream) +SoundDeviceNetwork::SoundDeviceNetwork( + UserSettingsPointer config, + SoundManager* sm, + QSharedPointer pNetworkStream) : SoundDevice(config, sm), m_pNetworkStream(pNetworkStream), m_inputDrift(false), @@ -132,6 +133,7 @@ void SoundDeviceNetwork::readProcess(SINT framesPerBuffer) { if (!m_inputFifo || !m_pNetworkStream || !m_iNumInputChannels) { return; } + DEBUG_ASSERT(m_configFramesPerBuffer >= framesPerBuffer); int inChunkSize = framesPerBuffer * m_iNumInputChannels; int readAvailable = m_pNetworkStream->getReadExpected() @@ -223,9 +225,10 @@ void SoundDeviceNetwork::readProcess(SINT framesPerBuffer) { } void SoundDeviceNetwork::writeProcess(SINT framesPerBuffer) { - if (!m_outputFifo || !m_pNetworkStream) { + if (!m_outputFifo || !m_pNetworkStream || !m_iNumOutputChannels) { return; } + DEBUG_ASSERT(m_configFramesPerBuffer >= framesPerBuffer); int outChunkSize = framesPerBuffer * m_iNumOutputChannels; int writeAvailable = m_outputFifo->writeAvailable(); From 57d1f6031145c2fc560177e214ed1565f3a6f966 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Wed, 15 Mar 2023 16:56:33 +0100 Subject: [PATCH 07/13] Adjust disabled debug output in sounddevicenetwork.cpp --- src/soundio/sounddevicenetwork.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/soundio/sounddevicenetwork.cpp b/src/soundio/sounddevicenetwork.cpp index 1ed7d8ceeed..f2451cd477b 100644 --- a/src/soundio/sounddevicenetwork.cpp +++ b/src/soundio/sounddevicenetwork.cpp @@ -298,7 +298,7 @@ void SoundDeviceNetwork::workerWriteProcess(NetworkOutputStreamWorkerPtr pWorker if (copyCount > 0) { if (writeAvailable - copyCount > outChunkSize) { // Underflow - //kLogger.debug() << "workerWriteProcess: buffer empty"; + // kLogger.debug() << "workerWriteProcess: buffer empty"; // catch up by filling buffer until we are synced workerWriteSilence(pWorker, writeAvailable - copyCount); m_pSoundManager->underflowHappened(24); @@ -306,8 +306,9 @@ void SoundDeviceNetwork::workerWriteProcess(NetworkOutputStreamWorkerPtr pWorker // try to keep PAs buffer filled up to 0.5 chunks if (pWorker->outputDrift()) { // duplicate one frame - //kLogger.debug() << "workerWriteProcess() duplicate one frame" - // << (float)writeAvailable / outChunkSize << (float)readAvailable / outChunkSize; + // kLogger.debug() << "workerWriteProcess() duplicate one frame" + // << (float)writeAvailable / outChunkSize << + // (float)readAvailable / outChunkSize; workerWrite(pWorker, dataPtr1, 1); } else { pWorker->setOutputDrift(true); @@ -318,8 +319,10 @@ void SoundDeviceNetwork::workerWriteProcess(NetworkOutputStreamWorkerPtr pWorker // We are not able to store at least the half of the new frames // or we have a risk of an m_outputFifo overflow if (pWorker->outputDrift()) { - //kLogger.debug() << "SoundDeviceNetwork::workerWriteProcess() skip one frame" - // << (float)writeAvailable / outChunkSize << (float)readAvailable / outChunkSize; + // kLogger.debug() << "SoundDeviceNetwork::workerWriteProcess() + // skip one frame" + // << (float)writeAvailable / outChunkSize << + // (float)readAvailable / outChunkSize; copyCount = qMin(readAvailable, copyCount + m_iNumOutputChannels); } else { pWorker->setOutputDrift(true); From 752a17d386736d947d1ca76771db48b96c3b365f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sat, 18 Mar 2023 11:55:45 +0100 Subject: [PATCH 08/13] Fix dropping samples in case of an overflow risk condition --- src/soundio/sounddevicenetwork.cpp | 37 +++++++++++++++--------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/src/soundio/sounddevicenetwork.cpp b/src/soundio/sounddevicenetwork.cpp index f2451cd477b..702e67bb99c 100644 --- a/src/soundio/sounddevicenetwork.cpp +++ b/src/soundio/sounddevicenetwork.cpp @@ -290,40 +290,41 @@ void SoundDeviceNetwork::workerWriteProcess(NetworkOutputStreamWorkerPtr pWorker int outChunkSize, int readAvailable, CSAMPLE* dataPtr1, ring_buffer_size_t size1, CSAMPLE* dataPtr2, ring_buffer_size_t size2) { - int writeExpected = static_cast(pWorker->getStreamTimeFrames() - pWorker->framesWritten()); + int writeExpectedFrames = static_cast( + pWorker->getStreamTimeFrames() - pWorker->framesWritten()); - int writeAvailable = writeExpected * m_iNumOutputChannels; - int copyCount = qMin(readAvailable, writeAvailable); + int writeExpected = writeExpectedFrames * m_iNumOutputChannels; + int copyCount = qMin(readAvailable, writeExpected); if (copyCount > 0) { - if (writeAvailable - copyCount > outChunkSize) { + if (writeExpected - copyCount > outChunkSize) { // Underflow // kLogger.debug() << "workerWriteProcess: buffer empty"; // catch up by filling buffer until we are synced - workerWriteSilence(pWorker, writeAvailable - copyCount); + workerWriteSilence(pWorker, writeExpected - copyCount); m_pSoundManager->underflowHappened(24); - } else if (writeAvailable - copyCount > outChunkSize / 2) { + } else if (writeExpected - copyCount > outChunkSize / 2) { // try to keep PAs buffer filled up to 0.5 chunks if (pWorker->outputDrift()) { // duplicate one frame // kLogger.debug() << "workerWriteProcess() duplicate one frame" - // << (float)writeAvailable / outChunkSize << - // (float)readAvailable / outChunkSize; + // << (float)writeExpected / outChunkSize + // << (float)readAvailable / outChunkSize; workerWrite(pWorker, dataPtr1, 1); } else { pWorker->setOutputDrift(true); } - } else if (writeAvailable < outChunkSize / 2 || - readAvailable > outChunkSize * 1.5 - ) { - // We are not able to store at least the half of the new frames - // or we have a risk of an m_outputFifo overflow + } else if (writeExpected < outChunkSize / 2) { + // We are will overshoot by more than a half of the new frames if (pWorker->outputDrift()) { - // kLogger.debug() << "SoundDeviceNetwork::workerWriteProcess() - // skip one frame" - // << (float)writeAvailable / outChunkSize << - // (float)readAvailable / outChunkSize; - copyCount = qMin(readAvailable, copyCount + m_iNumOutputChannels); + // kLogger.debug() << "SoundDeviceNetwork::workerWriteProcess() " + // "skip one frame" + // << (float)writeAvailable / outChunkSize + // << (float)readAvailable / outChunkSize; + if (size1 >= m_iNumOutputChannels) { + dataPtr1 += m_iNumOutputChannels; + size1 -= m_iNumOutputChannels; + } } else { pWorker->setOutputDrift(true); } From 4e6514fd7e0f4ad00b003fd0adc02ab5129b03f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sat, 18 Mar 2023 11:57:21 +0100 Subject: [PATCH 09/13] detect and report an SoundDeviceNetwork overflow --- src/soundio/sounddevicenetwork.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/soundio/sounddevicenetwork.cpp b/src/soundio/sounddevicenetwork.cpp index 702e67bb99c..ea9d56ab59d 100644 --- a/src/soundio/sounddevicenetwork.cpp +++ b/src/soundio/sounddevicenetwork.cpp @@ -294,6 +294,16 @@ void SoundDeviceNetwork::workerWriteProcess(NetworkOutputStreamWorkerPtr pWorker pWorker->getStreamTimeFrames() - pWorker->framesWritten()); int writeExpected = writeExpectedFrames * m_iNumOutputChannels; + + if (writeExpected <= 0) { + // Overflow + // kLogger.debug() << "workerWriteProcess: buffer full" + // << "outChunkSize" << outChunkSize + // << "readAvailable" << readAvailable + // << "writeExpected" << writeExpected << pWorker->getStreamTimeFrames(); + // catch up by skipping chunk + m_pSoundManager->underflowHappened(25); + } int copyCount = qMin(readAvailable, writeExpected); if (copyCount > 0) { From 55158274bcdde1b7ddf44e29fbb064daa076687e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sat, 18 Mar 2023 17:28:03 +0100 Subject: [PATCH 10/13] Intoduce enum classes for the audio buffer size indexes --- src/soundio/soundmanagerconfig.cpp | 13 ++++++------- src/soundio/soundmanagerconfig.h | 30 ++++++++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/soundio/soundmanagerconfig.cpp b/src/soundio/soundmanagerconfig.cpp index ac2f27f1fc8..c147d444321 100644 --- a/src/soundio/soundmanagerconfig.cpp +++ b/src/soundio/soundmanagerconfig.cpp @@ -8,16 +8,11 @@ #include "util/cmdlineargs.h" #include "util/math.h" -// this (7) represents latency values from 1 ms to about 80 ms -- bkgood -const unsigned int SoundManagerConfig::kMaxAudioBufferSizeIndex = 7; - const QString SoundManagerConfig::kDefaultAPI = QStringLiteral("None"); const QString SoundManagerConfig::kEmptyComboBox = QStringLiteral("---"); // Sample Rate even the cheap sound Devices will support most likely const unsigned int SoundManagerConfig::kFallbackSampleRate = 48000; const unsigned int SoundManagerConfig::kDefaultDeckCount = 2; -// audioBufferSizeIndex=5 means about 21 ms of latency which is default in trunk r2453 -- bkgood -const int SoundManagerConfig::kDefaultAudioBufferSizeIndex = 5; const int SoundManagerConfig::kDefaultSyncBuffers = 2; @@ -395,9 +390,13 @@ unsigned int SoundManagerConfig::getAudioBufferSizeIndex() const { unsigned int SoundManagerConfig::getFramesPerBuffer() const { if (m_api == MIXXX_PORTAUDIO_JACK_STRING) { // in case of jack we configure the frames/period - if (m_audioBufferSizeIndex == 7) { + if (m_audioBufferSizeIndex == + static_cast( + JackAudioBufferSizeIndex::Size4096fpp)) { return 4096; - } else if (m_audioBufferSizeIndex == 7) { + } else if (m_audioBufferSizeIndex == + static_cast( + JackAudioBufferSizeIndex::Size2048fpp)) { return 2048; } // default is auto <= 1024 diff --git a/src/soundio/soundmanagerconfig.h b/src/soundio/soundmanagerconfig.h index 86bab5ff2eb..dbcddb7f365 100644 --- a/src/soundio/soundmanagerconfig.h +++ b/src/soundio/soundmanagerconfig.h @@ -23,12 +23,38 @@ class SoundManagerConfig { OTHER = (1 << 2), ALL = (API | DEVICES | OTHER), }; - static const unsigned int kMaxAudioBufferSizeIndex; + + // Size1xms presents the first buffer size of 2^X + // that results in a buffer time above 1 ms + // It is 1.45 ms @ 44.1 kHz + // The other values are representing the following 2^X sizes. + enum class AudioBufferSizeIndex { + Size1xms = 1, + Size2xms = 2, + Size5xms = 3, + Size10xms = 4, + Size20xms = 5, + Size40xms = 6, + Size80xms = 7, + }; + + // Represents the sample rate independent frame/period + // index values in case of Jack + enum class JackAudioBufferSizeIndex { + SizeAuto = 5, + Size2048fpp = 6, + Size4096fpp = 7, + }; + + static constexpr auto kMaxAudioBufferSizeIndex = + static_cast(AudioBufferSizeIndex::Size80xms); + static constexpr auto kDefaultAudioBufferSizeIndex = + static_cast(AudioBufferSizeIndex::Size20xms); + static const QString kDefaultAPI; static const QString kEmptyComboBox; static const unsigned int kFallbackSampleRate; static const unsigned int kDefaultDeckCount; - static const int kDefaultAudioBufferSizeIndex; static const int kDefaultSyncBuffers; SoundManagerConfig(); From 6a4c5df43702e1808583a824d7eb48512a3c98b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sat, 18 Mar 2023 19:20:12 +0100 Subject: [PATCH 11/13] Use SoundManagerConfig::JackAudioBufferSizeIndex in DlgPrefSound::updateAudioBufferSizes() --- src/preferences/dialog/dlgprefsound.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/preferences/dialog/dlgprefsound.cpp b/src/preferences/dialog/dlgprefsound.cpp index 398c362bc15..6338b9aa40a 100644 --- a/src/preferences/dialog/dlgprefsound.cpp +++ b/src/preferences/dialog/dlgprefsound.cpp @@ -611,9 +611,15 @@ void DlgPrefSound::updateAudioBufferSizes(int sampleRateIndex) { // we cannot calc the resulting buffer size in ms because the // Sample rate is not known yet. We assume 48000 KHz here // to calculate the buffer size index - audioBufferComboBox->addItem(tr("auto (<= 1024 frames/period)"), 5); - audioBufferComboBox->addItem(tr("2048 frames/period"), 6); - audioBufferComboBox->addItem(tr("4096 frames/period"), 7); + audioBufferComboBox->addItem(tr("auto (<= 1024 frames/period)"), + static_cast(SoundManagerConfig:: + JackAudioBufferSizeIndex::SizeAuto)); + audioBufferComboBox->addItem(tr("2048 frames/period"), + static_cast(SoundManagerConfig:: + JackAudioBufferSizeIndex::Size2048fpp)); + audioBufferComboBox->addItem(tr("4096 frames/period"), + static_cast(SoundManagerConfig:: + JackAudioBufferSizeIndex::Size4096fpp)); } else { double sampleRate = sampleRateComboBox->itemData(sampleRateIndex).toDouble(); unsigned int framesPerBuffer = 1; // start this at 0 and inf loop happens From e6938957fce5840ea31fb646de051c43607a26e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sat, 18 Mar 2023 22:55:38 +0100 Subject: [PATCH 12/13] Improved debug output of SoundDeviceNetwork --- src/soundio/sounddevicenetwork.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/soundio/sounddevicenetwork.cpp b/src/soundio/sounddevicenetwork.cpp index ea9d56ab59d..b95ff0a3329 100644 --- a/src/soundio/sounddevicenetwork.cpp +++ b/src/soundio/sounddevicenetwork.cpp @@ -65,12 +65,8 @@ SoundDeviceError SoundDeviceNetwork::open(bool isClkRefDevice, int syncBuffers) } const SINT framesPerBuffer = m_configFramesPerBuffer; - qDebug() << "framesPerBuffer:" << framesPerBuffer; - const auto requestedBufferTime = mixxx::Duration::fromSeconds( framesPerBuffer / m_dSampleRate); - qDebug() << "Requested sample rate: " << m_dSampleRate << "Hz, latency:" - << requestedBufferTime; // Feed the network device buffer directly from the // clock reference device callback @@ -88,6 +84,9 @@ SoundDeviceError SoundDeviceNetwork::open(bool isClkRefDevice, int syncBuffers) // Create the callback Thread if requested if (isClkRefDevice) { + kLogger.debug() << "Clock Reference with:" << framesPerBuffer << "frames/buffer @" + << m_dSampleRate << "Hz =" << requestedBufferTime.formatMillisWithUnit(); + // Update the samplerate and latency ControlObjects, which allow the // waveform view to properly correct for the latency. ControlObject::set(ConfigKey("[Master]", "latency"), @@ -101,8 +100,10 @@ SoundDeviceError SoundDeviceNetwork::open(bool isClkRefDevice, int syncBuffers) m_pThread = std::make_unique(this); m_pThread->start(QThread::TimeCriticalPriority); + } else { + kLogger.debug() << "Maximum:" << framesPerBuffer << "frames/buffer @" + << m_dSampleRate << "Hz =" << requestedBufferTime.formatMillisWithUnit(); } - return SOUNDDEVICE_ERROR_OK; } From e2b4be817177e95da722e490f773ccadb04ec4a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 19 Mar 2023 00:08:59 +0100 Subject: [PATCH 13/13] Fix typo in comment Co-authored-by: JoergAtGithub <64457745+JoergAtGithub@users.noreply.github.com> --- src/soundio/sounddevicenetwork.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/soundio/sounddevicenetwork.cpp b/src/soundio/sounddevicenetwork.cpp index b95ff0a3329..aff65b9dc01 100644 --- a/src/soundio/sounddevicenetwork.cpp +++ b/src/soundio/sounddevicenetwork.cpp @@ -326,7 +326,7 @@ void SoundDeviceNetwork::workerWriteProcess(NetworkOutputStreamWorkerPtr pWorker pWorker->setOutputDrift(true); } } else if (writeExpected < outChunkSize / 2) { - // We are will overshoot by more than a half of the new frames + // We will overshoot by more than a half of the new frames if (pWorker->outputDrift()) { // kLogger.debug() << "SoundDeviceNetwork::workerWriteProcess() " // "skip one frame"