From 359ca7b63f275760526ee32872a477b844d2d11c Mon Sep 17 00:00:00 2001 From: saker Date: Sat, 10 Aug 2024 21:22:44 -0400 Subject: [PATCH 01/23] Suggest the default low latency --- src/core/audio/AudioPortAudio.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/core/audio/AudioPortAudio.cpp b/src/core/audio/AudioPortAudio.cpp index eb5058bc6b5..6e363543f80 100644 --- a/src/core/audio/AudioPortAudio.cpp +++ b/src/core/audio/AudioPortAudio.cpp @@ -118,25 +118,20 @@ AudioPortAudio::AudioPortAudio( bool & _success_ful, AudioEngine * _audioEngine return; } - double inLatency = 0;//(double)audioEngine()->framesPerPeriod() / (double)sampleRate(); - double outLatency = 0;//(double)audioEngine()->framesPerPeriod() / (double)sampleRate(); - - //inLatency = Pa_GetDeviceInfo( inDevIdx )->defaultLowInputLatency; - //outLatency = Pa_GetDeviceInfo( outDevIdx )->defaultLowOutputLatency; const int samples = audioEngine()->framesPerPeriod(); // Configure output parameters. m_outputParameters.device = outDevIdx; m_outputParameters.channelCount = channels(); m_outputParameters.sampleFormat = paFloat32; // 32 bit floating point output - m_outputParameters.suggestedLatency = outLatency; + m_outputParameters.suggestedLatency = Pa_GetDeviceInfo(outDevIdx)->defaultLowOutputLatency; m_outputParameters.hostApiSpecificStreamInfo = nullptr; - + // Configure input parameters. m_inputParameters.device = inDevIdx; m_inputParameters.channelCount = DEFAULT_CHANNELS; m_inputParameters.sampleFormat = paFloat32; // 32 bit floating point input - m_inputParameters.suggestedLatency = inLatency; + m_inputParameters.suggestedLatency = Pa_GetDeviceInfo(inDevIdx)->defaultLowInputLatency; m_inputParameters.hostApiSpecificStreamInfo = nullptr; // Open an audio I/O stream. From 44da0036e50cc689a1937e6dc316329f66e0ad3a Mon Sep 17 00:00:00 2001 From: saker Date: Sat, 10 Aug 2024 21:31:11 -0400 Subject: [PATCH 02/23] Remove verbose comments --- src/core/audio/AudioPortAudio.cpp | 50 ++++++------------------------- 1 file changed, 9 insertions(+), 41 deletions(-) diff --git a/src/core/audio/AudioPortAudio.cpp b/src/core/audio/AudioPortAudio.cpp index 6e363543f80..c0f6bcac0b2 100644 --- a/src/core/audio/AudioPortAudio.cpp +++ b/src/core/audio/AudioPortAudio.cpp @@ -120,30 +120,20 @@ AudioPortAudio::AudioPortAudio( bool & _success_ful, AudioEngine * _audioEngine const int samples = audioEngine()->framesPerPeriod(); - // Configure output parameters. m_outputParameters.device = outDevIdx; m_outputParameters.channelCount = channels(); - m_outputParameters.sampleFormat = paFloat32; // 32 bit floating point output + m_outputParameters.sampleFormat = paFloat32; m_outputParameters.suggestedLatency = Pa_GetDeviceInfo(outDevIdx)->defaultLowOutputLatency; m_outputParameters.hostApiSpecificStreamInfo = nullptr; - // Configure input parameters. m_inputParameters.device = inDevIdx; m_inputParameters.channelCount = DEFAULT_CHANNELS; - m_inputParameters.sampleFormat = paFloat32; // 32 bit floating point input + m_inputParameters.sampleFormat = paFloat32; m_inputParameters.suggestedLatency = Pa_GetDeviceInfo(inDevIdx)->defaultLowInputLatency; m_inputParameters.hostApiSpecificStreamInfo = nullptr; - - // Open an audio I/O stream. - err = Pa_OpenStream( - &m_paStream, - supportsCapture() ? &m_inputParameters : nullptr, // The input parameter - &m_outputParameters, // The outputparameter - sampleRate(), - samples, - paNoFlag, // Don't use any flags - _process_callback, // our callback function - this ); + + err = Pa_OpenStream(&m_paStream, supportsCapture() ? &m_inputParameters : nullptr, &m_outputParameters, + sampleRate(), samples, paNoFlag, _process_callback, this); if( err == paInvalidDevice && sampleRate() < 48000 ) { @@ -153,12 +143,12 @@ AudioPortAudio::AudioPortAudio( bool & _success_ful, AudioEngine * _audioEngine setSampleRate( 48000 ); err = Pa_OpenStream( &m_paStream, - supportsCapture() ? &m_inputParameters : nullptr, // The input parameter - &m_outputParameters, // The outputparameter + supportsCapture() ? &m_inputParameters : nullptr, + &m_outputParameters, sampleRate(), samples, - paNoFlag, // Don't use any flags - _process_callback, // our callback function + paNoFlag, + _process_callback, this ); } @@ -171,9 +161,6 @@ AudioPortAudio::AudioPortAudio( bool & _success_ful, AudioEngine * _audioEngine printf( "Input device: '%s' backend: '%s'\n", Pa_GetDeviceInfo( inDevIdx )->name, Pa_GetHostApiInfo( Pa_GetDeviceInfo( inDevIdx )->hostApi )->name ); printf( "Output device: '%s' backend: '%s'\n", Pa_GetDeviceInfo( outDevIdx )->name, Pa_GetHostApiInfo( Pa_GetDeviceInfo( outDevIdx )->hostApi )->name ); - // TODO: debug AudioEngine::pushInputFrames() - //m_supportsCapture = true; - _success_ful = true; } @@ -242,7 +229,6 @@ int AudioPortAudio::process_callback(const float* _inputBuffer, float* _outputBu { if( m_outBufPos == 0 ) { - // frames depend on the sample rate const fpp_t frames = getNextBuffer( m_outBuf ); if( !frames ) { @@ -321,7 +307,6 @@ void AudioPortAudioSetupUtil::updateDevices() return; } - // get active backend const QString& backend = m_backendModel.currentText(); int hostApi = 0; for( int i = 0; i < Pa_GetHostApiCount(); ++i ) @@ -334,7 +319,6 @@ void AudioPortAudioSetupUtil::updateDevices() } } - // get devices for selected backend m_deviceModel.clear(); for( int i = 0; i < Pa_GetDeviceCount(); ++i ) { @@ -357,7 +341,6 @@ void AudioPortAudioSetupUtil::updateChannels() printf( "Couldn't initialize PortAudio: %s\n", Pa_GetErrorText( err ) ); return; } - // get active backend Pa_Terminate(); } @@ -376,17 +359,6 @@ AudioPortAudio::setupWidget::setupWidget( QWidget * _parent ) : m_device = new ComboBox( this, "DEVICE" ); form->addRow(tr("Device"), m_device); - -/* LcdSpinBoxModel * m = new LcdSpinBoxModel( ); - m->setRange( DEFAULT_CHANNELS, DEFAULT_CHANNELS ); - m->setStep( 2 ); - m->setValue( ConfigManager::inst()->value( "audioportaudio", - "channels" ).toInt() ); - - m_channels = new LcdSpinBox( 1, this ); - m_channels->setModel( m ); - m_channels->setLabel( tr( "Channels" ) ); - m_channels->move( 308, 20 );*/ connect( &m_setupUtil.m_backendModel, SIGNAL(dataChanged()), &m_setupUtil, SLOT(updateDevices())); @@ -415,14 +387,10 @@ AudioPortAudio::setupWidget::~setupWidget() void AudioPortAudio::setupWidget::saveSettings() { - ConfigManager::inst()->setValue( "audioportaudio", "backend", m_setupUtil.m_backendModel.currentText() ); ConfigManager::inst()->setValue( "audioportaudio", "device", m_setupUtil.m_deviceModel.currentText() ); -/* ConfigManager::inst()->setValue( "audioportaudio", "channels", - QString::number( m_channels->value() ) );*/ - } From 8af8bcb0014ccf4a58fad91b2906579cba70fb3a Mon Sep 17 00:00:00 2001 From: saker Date: Sat, 10 Aug 2024 21:39:23 -0400 Subject: [PATCH 03/23] Completely remove old PortAudio < v19 code --- include/AudioPortAudio.h | 52 ++++------------------------------------ 1 file changed, 5 insertions(+), 47 deletions(-) diff --git a/include/AudioPortAudio.h b/include/AudioPortAudio.h index fbfa9b60dd6..02fa77eff4a 100644 --- a/include/AudioPortAudio.h +++ b/include/AudioPortAudio.h @@ -25,26 +25,16 @@ #ifndef LMMS_AUDIO_PORTAUDIO_H #define LMMS_AUDIO_PORTAUDIO_H -#include - #include "lmmsconfig.h" -#include "ComboBoxModel.h" #ifdef LMMS_HAVE_PORTAUDIO -# include - -# include "AudioDevice.h" -# include "AudioDeviceSetupWidget.h" - -# if defined paNeverDropInput || defined paNonInterleaved -# define PORTAUDIO_V19 -# else -# define PORTAUDIO_V18 -# endif - -#endif +#include +#include "ComboBoxModel.h" +#include +#include "AudioDevice.h" +#include "AudioDeviceSetupWidget.h" namespace lmms { @@ -62,10 +52,6 @@ public slots: ComboBoxModel m_deviceModel; }; - -#ifdef LMMS_HAVE_PORTAUDIO - - namespace gui { class ComboBox; @@ -106,40 +92,12 @@ class AudioPortAudio : public AudioDevice void startProcessing() override; void stopProcessing() override; -#ifdef PORTAUDIO_V19 static int _process_callback( const void *_inputBuffer, void * _outputBuffer, unsigned long _framesPerBuffer, const PaStreamCallbackTimeInfo * _timeInfo, PaStreamCallbackFlags _statusFlags, void *arg ); -#else - -#define paContinue 0 -#define paComplete 1 -#define Pa_GetDeviceCount Pa_CountDevices -#define Pa_GetDefaultInputDevice Pa_GetDefaultInputDeviceID -#define Pa_GetDefaultOutputDevice Pa_GetDefaultOutputDeviceID -#define Pa_IsStreamActive Pa_StreamActive - - static int _process_callback( void * _inputBuffer, void * _outputBuffer, - unsigned long _framesPerBuffer, PaTimestamp _outTime, void * _arg ); - - - using PaTime = double; - using PaDeviceIndex = PaDeviceID; - - using PaStreamParameters = struct - { - PaDeviceIndex device; - int channelCount; - PaSampleFormat sampleFormat; - PaTime suggestedLatency; - void *hostApiSpecificStreamInfo; - - } PaStreamParameters; -#endif // PORTAUDIO_V19 - PaStream * m_paStream; PaStreamParameters m_outputParameters; PaStreamParameters m_inputParameters; From f14188ad52410a4c7ad4b2388bc2b61c153be0c7 Mon Sep 17 00:00:00 2001 From: saker Date: Sat, 10 Aug 2024 21:41:49 -0400 Subject: [PATCH 04/23] Remove redundant header guard If PortAudio is not found, then nothing should be defined here anyways. --- src/core/audio/AudioPortAudio.cpp | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/src/core/audio/AudioPortAudio.cpp b/src/core/audio/AudioPortAudio.cpp index c0f6bcac0b2..875a7dbeb6c 100644 --- a/src/core/audio/AudioPortAudio.cpp +++ b/src/core/audio/AudioPortAudio.cpp @@ -26,27 +26,6 @@ #include "AudioPortAudio.h" -#ifndef LMMS_HAVE_PORTAUDIO -namespace lmms -{ - - -void AudioPortAudioSetupUtil::updateBackends() -{ -} - -void AudioPortAudioSetupUtil::updateDevices() -{ -} - -void AudioPortAudioSetupUtil::updateChannels() -{ -} - - -} // namespace lmms -#endif - #ifdef LMMS_HAVE_PORTAUDIO #include From 5a6c2ffeb94387516ed0ece43403350b00e710f4 Mon Sep 17 00:00:00 2001 From: saker Date: Sat, 10 Aug 2024 21:51:23 -0400 Subject: [PATCH 05/23] Rename and move setup widget into gui namespace We should do this for any of the other applicable audio devices in the future (to encourage separation of GUI and Core). --- include/AudioPortAudio.h | 36 +++++++++++++++---------------- src/core/audio/AudioPortAudio.cpp | 13 +++++------ src/gui/modals/SetupDialog.cpp | 2 +- 3 files changed, 23 insertions(+), 28 deletions(-) diff --git a/include/AudioPortAudio.h b/include/AudioPortAudio.h index 02fa77eff4a..9ad96b67a79 100644 --- a/include/AudioPortAudio.h +++ b/include/AudioPortAudio.h @@ -52,12 +52,26 @@ public slots: ComboBoxModel m_deviceModel; }; -namespace gui -{ +namespace gui { + class ComboBox; class LcdSpinBox; -} +class AudioPortAudioSetupWidget : public gui::AudioDeviceSetupWidget +{ +public: + AudioPortAudioSetupWidget(QWidget* _parent); + ~AudioPortAudioSetupWidget() override; + + void saveSettings() override; + void show() override; + +private: + ComboBox* m_backend; + ComboBox* m_device; + AudioPortAudioSetupUtil m_setupUtil; +}; +} // namespace gui class AudioPortAudio : public AudioDevice { @@ -72,22 +86,6 @@ class AudioPortAudio : public AudioDevice int process_callback(const float* _inputBuffer, float* _outputBuffer, f_cnt_t _framesPerBuffer); - class setupWidget : public gui::AudioDeviceSetupWidget - { - public: - setupWidget( QWidget * _parent ); - ~setupWidget() override; - - void saveSettings() override; - void show() override; - - private: - gui::ComboBox * m_backend; - gui::ComboBox * m_device; - AudioPortAudioSetupUtil m_setupUtil; - - } ; - private: void startProcessing() override; void stopProcessing() override; diff --git a/src/core/audio/AudioPortAudio.cpp b/src/core/audio/AudioPortAudio.cpp index 875a7dbeb6c..a84f6fd9438 100644 --- a/src/core/audio/AudioPortAudio.cpp +++ b/src/core/audio/AudioPortAudio.cpp @@ -323,11 +323,8 @@ void AudioPortAudioSetupUtil::updateChannels() Pa_Terminate(); } - - - -AudioPortAudio::setupWidget::setupWidget( QWidget * _parent ) : - AudioDeviceSetupWidget( AudioPortAudio::name(), _parent ) +gui::AudioPortAudioSetupWidget::AudioPortAudioSetupWidget(QWidget* _parent) + : AudioDeviceSetupWidget(AudioPortAudio::name(), _parent) { using gui::ComboBox; @@ -352,7 +349,7 @@ AudioPortAudio::setupWidget::setupWidget( QWidget * _parent ) : -AudioPortAudio::setupWidget::~setupWidget() +gui::AudioPortAudioSetupWidget::~AudioPortAudioSetupWidget() { disconnect( &m_setupUtil.m_backendModel, SIGNAL(dataChanged()), &m_setupUtil, SLOT(updateDevices())); @@ -364,7 +361,7 @@ AudioPortAudio::setupWidget::~setupWidget() -void AudioPortAudio::setupWidget::saveSettings() +void gui::AudioPortAudioSetupWidget::saveSettings() { ConfigManager::inst()->setValue( "audioportaudio", "backend", m_setupUtil.m_backendModel.currentText() ); @@ -375,7 +372,7 @@ void AudioPortAudio::setupWidget::saveSettings() -void AudioPortAudio::setupWidget::show() +void gui::AudioPortAudioSetupWidget::show() { if( m_setupUtil.m_backendModel.size() == 0 ) { diff --git a/src/gui/modals/SetupDialog.cpp b/src/gui/modals/SetupDialog.cpp index 6f05433b782..09eb20b64e2 100644 --- a/src/gui/modals/SetupDialog.cpp +++ b/src/gui/modals/SetupDialog.cpp @@ -496,7 +496,7 @@ SetupDialog::SetupDialog(ConfigTab tab_to_open) : #ifdef LMMS_HAVE_PORTAUDIO m_audioIfaceSetupWidgets[AudioPortAudio::name()] = - new AudioPortAudio::setupWidget(as_w); + new AudioPortAudioSetupWidget(as_w); #endif #ifdef LMMS_HAVE_SOUNDIO From f9c5c4adf5324d04ecc4b53cb47d702debcc918f Mon Sep 17 00:00:00 2001 From: saker Date: Sat, 10 Aug 2024 22:00:08 -0400 Subject: [PATCH 06/23] Fix naming of callback functions --- include/AudioPortAudio.h | 10 +++------- src/core/audio/AudioPortAudio.cpp | 20 ++++++-------------- 2 files changed, 9 insertions(+), 21 deletions(-) diff --git a/include/AudioPortAudio.h b/include/AudioPortAudio.h index 9ad96b67a79..b506b72594f 100644 --- a/include/AudioPortAudio.h +++ b/include/AudioPortAudio.h @@ -84,17 +84,13 @@ class AudioPortAudio : public AudioDevice return QT_TRANSLATE_NOOP( "AudioDeviceSetupWidget", "PortAudio" ); } - int process_callback(const float* _inputBuffer, float* _outputBuffer, f_cnt_t _framesPerBuffer); - private: void startProcessing() override; void stopProcessing() override; - static int _process_callback( const void *_inputBuffer, void * _outputBuffer, - unsigned long _framesPerBuffer, - const PaStreamCallbackTimeInfo * _timeInfo, - PaStreamCallbackFlags _statusFlags, - void *arg ); + int processCallback(const float* _inputBuffer, float* _outputBuffer, f_cnt_t _framesPerBuffer); + static int processCallback(const void* _inputBuffer, void* _outputBuffer, unsigned long _framesPerBuffer, + const PaStreamCallbackTimeInfo* _timeInfo, PaStreamCallbackFlags _statusFlags, void* arg); PaStream * m_paStream; PaStreamParameters m_outputParameters; diff --git a/src/core/audio/AudioPortAudio.cpp b/src/core/audio/AudioPortAudio.cpp index a84f6fd9438..b7f3fac757e 100644 --- a/src/core/audio/AudioPortAudio.cpp +++ b/src/core/audio/AudioPortAudio.cpp @@ -112,7 +112,7 @@ AudioPortAudio::AudioPortAudio( bool & _success_ful, AudioEngine * _audioEngine m_inputParameters.hostApiSpecificStreamInfo = nullptr; err = Pa_OpenStream(&m_paStream, supportsCapture() ? &m_inputParameters : nullptr, &m_outputParameters, - sampleRate(), samples, paNoFlag, _process_callback, this); + sampleRate(), samples, paNoFlag, processCallback, this); if( err == paInvalidDevice && sampleRate() < 48000 ) { @@ -120,15 +120,8 @@ AudioPortAudio::AudioPortAudio( bool & _success_ful, AudioEngine * _audioEngine // some backends or drivers do not allow 32 bit floating point data // with a samplerate of 44100 Hz setSampleRate( 48000 ); - err = Pa_OpenStream( - &m_paStream, - supportsCapture() ? &m_inputParameters : nullptr, - &m_outputParameters, - sampleRate(), - samples, - paNoFlag, - _process_callback, - this ); + err = Pa_OpenStream(&m_paStream, supportsCapture() ? &m_inputParameters : nullptr, &m_outputParameters, + sampleRate(), samples, paNoFlag, processCallback, this); } if( err != paNoError ) @@ -190,7 +183,7 @@ void AudioPortAudio::stopProcessing() } -int AudioPortAudio::process_callback(const float* _inputBuffer, float* _outputBuffer, f_cnt_t _framesPerBuffer) +int AudioPortAudio::processCallback(const float* _inputBuffer, float* _outputBuffer, f_cnt_t _framesPerBuffer) { if( supportsCapture() ) { @@ -239,7 +232,7 @@ int AudioPortAudio::process_callback(const float* _inputBuffer, float* _outputBu -int AudioPortAudio::_process_callback( +int AudioPortAudio::processCallback( const void *_inputBuffer, void * _outputBuffer, unsigned long _framesPerBuffer, @@ -251,8 +244,7 @@ int AudioPortAudio::_process_callback( Q_UNUSED(_statusFlags); auto _this = static_cast(_arg); - return _this->process_callback( (const float*)_inputBuffer, - (float*)_outputBuffer, _framesPerBuffer ); + return _this->processCallback((const float*)_inputBuffer, (float*)_outputBuffer, _framesPerBuffer); } From 5badd592d704d80af5ffd113918fcbae20b93dba Mon Sep 17 00:00:00 2001 From: saker Date: Sat, 10 Aug 2024 22:07:41 -0400 Subject: [PATCH 07/23] Merge AudioPortAudioSetupWidget and AudioPortAudioSetupUtil --- include/AudioPortAudio.h | 20 ++++-------- src/core/audio/AudioPortAudio.cpp | 52 +++++++++++++------------------ 2 files changed, 28 insertions(+), 44 deletions(-) diff --git a/include/AudioPortAudio.h b/include/AudioPortAudio.h index b506b72594f..32ebf3b2d63 100644 --- a/include/AudioPortAudio.h +++ b/include/AudioPortAudio.h @@ -39,19 +39,6 @@ namespace lmms { -class AudioPortAudioSetupUtil : public QObject -{ -Q_OBJECT -public slots: - void updateBackends(); - void updateDevices(); - void updateChannels(); - -public: - ComboBoxModel m_backendModel; - ComboBoxModel m_deviceModel; -}; - namespace gui { class ComboBox; @@ -63,13 +50,18 @@ class AudioPortAudioSetupWidget : public gui::AudioDeviceSetupWidget AudioPortAudioSetupWidget(QWidget* _parent); ~AudioPortAudioSetupWidget() override; + void updateBackends(); + void updateDevices(); + void updateChannels(); + void saveSettings() override; void show() override; private: ComboBox* m_backend; ComboBox* m_device; - AudioPortAudioSetupUtil m_setupUtil; + ComboBoxModel m_backendModel; + ComboBoxModel m_deviceModel; }; } // namespace gui diff --git a/src/core/audio/AudioPortAudio.cpp b/src/core/audio/AudioPortAudio.cpp index b7f3fac757e..d755f9f5f11 100644 --- a/src/core/audio/AudioPortAudio.cpp +++ b/src/core/audio/AudioPortAudio.cpp @@ -250,7 +250,7 @@ int AudioPortAudio::processCallback( -void AudioPortAudioSetupUtil::updateBackends() +void gui::AudioPortAudioSetupWidget::updateBackends() { PaError err = Pa_Initialize(); if( err != paNoError ) { @@ -270,7 +270,7 @@ void AudioPortAudioSetupUtil::updateBackends() -void AudioPortAudioSetupUtil::updateDevices() +void gui::AudioPortAudioSetupWidget::updateDevices() { PaError err = Pa_Initialize(); if( err != paNoError ) { @@ -305,7 +305,7 @@ void AudioPortAudioSetupUtil::updateDevices() -void AudioPortAudioSetupUtil::updateChannels() +void gui::AudioPortAudioSetupWidget::updateChannels() { PaError err = Pa_Initialize(); if( err != paNoError ) { @@ -328,14 +328,11 @@ gui::AudioPortAudioSetupWidget::AudioPortAudioSetupWidget(QWidget* _parent) m_device = new ComboBox( this, "DEVICE" ); form->addRow(tr("Device"), m_device); - connect( &m_setupUtil.m_backendModel, SIGNAL(dataChanged()), - &m_setupUtil, SLOT(updateDevices())); - - connect( &m_setupUtil.m_deviceModel, SIGNAL(dataChanged()), - &m_setupUtil, SLOT(updateChannels())); - - m_backend->setModel( &m_setupUtil.m_backendModel ); - m_device->setModel( &m_setupUtil.m_deviceModel ); + connect(&m_backendModel, &ComboBoxModel::dataChanged, this, &AudioPortAudioSetupWidget::updateDevices); + connect(&m_deviceModel, &ComboBoxModel::dataChanged, this, &AudioPortAudioSetupWidget::updateChannels); + + m_backend->setModel(&m_backendModel); + m_device->setModel(&m_deviceModel); } @@ -343,11 +340,8 @@ gui::AudioPortAudioSetupWidget::AudioPortAudioSetupWidget(QWidget* _parent) gui::AudioPortAudioSetupWidget::~AudioPortAudioSetupWidget() { - disconnect( &m_setupUtil.m_backendModel, SIGNAL(dataChanged()), - &m_setupUtil, SLOT(updateDevices())); - - disconnect( &m_setupUtil.m_deviceModel, SIGNAL(dataChanged()), - &m_setupUtil, SLOT(updateChannels())); + disconnect(&m_backendModel, &ComboBoxModel::dataChanged, this, &AudioPortAudioSetupWidget::updateDevices); + disconnect(&m_deviceModel, &ComboBoxModel::dataChanged, this, &AudioPortAudioSetupWidget::updateChannels); } @@ -355,10 +349,8 @@ gui::AudioPortAudioSetupWidget::~AudioPortAudioSetupWidget() void gui::AudioPortAudioSetupWidget::saveSettings() { - ConfigManager::inst()->setValue( "audioportaudio", "backend", - m_setupUtil.m_backendModel.currentText() ); - ConfigManager::inst()->setValue( "audioportaudio", "device", - m_setupUtil.m_deviceModel.currentText() ); + ConfigManager::inst()->setValue("audioportaudio", "backend", m_backendModel.currentText()); + ConfigManager::inst()->setValue("audioportaudio", "device", m_deviceModel.currentText()); } @@ -366,23 +358,23 @@ void gui::AudioPortAudioSetupWidget::saveSettings() void gui::AudioPortAudioSetupWidget::show() { - if( m_setupUtil.m_backendModel.size() == 0 ) + if (m_backendModel.size() == 0) { // populate the backend model the first time we are shown - m_setupUtil.updateBackends(); + updateBackends(); const QString& backend = ConfigManager::inst()->value( "audioportaudio", "backend" ); const QString& device = ConfigManager::inst()->value( "audioportaudio", "device" ); - - int i = std::max(0, m_setupUtil.m_backendModel.findText(backend)); - m_setupUtil.m_backendModel.setValue( i ); - - m_setupUtil.updateDevices(); - - i = std::max(0, m_setupUtil.m_deviceModel.findText(device)); - m_setupUtil.m_deviceModel.setValue( i ); + + int i = std::max(0, m_backendModel.findText(backend)); + m_backendModel.setValue(i); + + updateDevices(); + + i = std::max(0, m_deviceModel.findText(device)); + m_deviceModel.setValue(i); } AudioDeviceSetupWidget::show(); From 7433c15300484a220ada6fc75567d9d93d873e11 Mon Sep 17 00:00:00 2001 From: saker Date: Sat, 10 Aug 2024 22:11:36 -0400 Subject: [PATCH 08/23] Fix naming in constructor --- include/AudioPortAudio.h | 2 +- src/core/audio/AudioPortAudio.cpp | 23 ++++++++++------------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/include/AudioPortAudio.h b/include/AudioPortAudio.h index 32ebf3b2d63..75056e479b4 100644 --- a/include/AudioPortAudio.h +++ b/include/AudioPortAudio.h @@ -68,7 +68,7 @@ class AudioPortAudioSetupWidget : public gui::AudioDeviceSetupWidget class AudioPortAudio : public AudioDevice { public: - AudioPortAudio( bool & _success_ful, AudioEngine* audioEngine ); + AudioPortAudio(bool& successful, AudioEngine* engine); ~AudioPortAudio() override; inline static QString name() diff --git a/src/core/audio/AudioPortAudio.cpp b/src/core/audio/AudioPortAudio.cpp index d755f9f5f11..673bdda6969 100644 --- a/src/core/audio/AudioPortAudio.cpp +++ b/src/core/audio/AudioPortAudio.cpp @@ -38,19 +38,16 @@ namespace lmms { - -AudioPortAudio::AudioPortAudio( bool & _success_ful, AudioEngine * _audioEngine ) : - AudioDevice(std::clamp( - ConfigManager::inst()->value("audioportaudio", "channels").toInt(), - DEFAULT_CHANNELS, - DEFAULT_CHANNELS), _audioEngine), - m_paStream( nullptr ), - m_wasPAInitError( false ), - m_outBuf(new SampleFrame[audioEngine()->framesPerPeriod()]), - m_outBufPos( 0 ) +AudioPortAudio::AudioPortAudio(bool& successful, AudioEngine* engine) + : AudioDevice(std::clamp(ConfigManager::inst()->value("audioportaudio", "channels").toInt(), + DEFAULT_CHANNELS, DEFAULT_CHANNELS), + engine) + , m_paStream(nullptr) + , m_wasPAInitError(false) + , m_outBuf(new SampleFrame[audioEngine()->framesPerPeriod()]) + , m_outBufPos(0) { - _success_ful = false; - + successful = false; m_outBufSize = audioEngine()->framesPerPeriod(); PaError err = Pa_Initialize(); @@ -133,7 +130,7 @@ AudioPortAudio::AudioPortAudio( bool & _success_ful, AudioEngine * _audioEngine printf( "Input device: '%s' backend: '%s'\n", Pa_GetDeviceInfo( inDevIdx )->name, Pa_GetHostApiInfo( Pa_GetDeviceInfo( inDevIdx )->hostApi )->name ); printf( "Output device: '%s' backend: '%s'\n", Pa_GetDeviceInfo( outDevIdx )->name, Pa_GetHostApiInfo( Pa_GetDeviceInfo( outDevIdx )->hostApi )->name ); - _success_ful = true; + successful = true; } From 7eb6089bd2a168786cae42e8888f79922a8fa3b3 Mon Sep 17 00:00:00 2001 From: saker Date: Sat, 10 Aug 2024 22:37:04 -0400 Subject: [PATCH 09/23] Fix naming for parameters of callback functions --- include/AudioPortAudio.h | 6 ++--- src/core/audio/AudioPortAudio.cpp | 43 ++++++++++++------------------- 2 files changed, 19 insertions(+), 30 deletions(-) diff --git a/include/AudioPortAudio.h b/include/AudioPortAudio.h index 75056e479b4..aa981407db1 100644 --- a/include/AudioPortAudio.h +++ b/include/AudioPortAudio.h @@ -80,9 +80,9 @@ class AudioPortAudio : public AudioDevice void startProcessing() override; void stopProcessing() override; - int processCallback(const float* _inputBuffer, float* _outputBuffer, f_cnt_t _framesPerBuffer); - static int processCallback(const void* _inputBuffer, void* _outputBuffer, unsigned long _framesPerBuffer, - const PaStreamCallbackTimeInfo* _timeInfo, PaStreamCallbackFlags _statusFlags, void* arg); + int processCallback(const float* inputBuffer, float* outputBuffer, f_cnt_t framesPerBuffer); + static int processCallback(const void* inputBuffer, void* outputBuffer, unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void* arg); PaStream * m_paStream; PaStreamParameters m_outputParameters; diff --git a/src/core/audio/AudioPortAudio.cpp b/src/core/audio/AudioPortAudio.cpp index 673bdda6969..6bcd840bd4c 100644 --- a/src/core/audio/AudioPortAudio.cpp +++ b/src/core/audio/AudioPortAudio.cpp @@ -180,21 +180,17 @@ void AudioPortAudio::stopProcessing() } -int AudioPortAudio::processCallback(const float* _inputBuffer, float* _outputBuffer, f_cnt_t _framesPerBuffer) +int AudioPortAudio::processCallback(const float* inputBuffer, float* outputBuffer, f_cnt_t framesPerBuffer) { - if( supportsCapture() ) - { - audioEngine()->pushInputFrames( (SampleFrame*)_inputBuffer, _framesPerBuffer ); - } + if (supportsCapture()) { audioEngine()->pushInputFrames((SampleFrame*)inputBuffer, framesPerBuffer); } if( m_stopped ) { - memset( _outputBuffer, 0, _framesPerBuffer * - channels() * sizeof(float) ); + memset(outputBuffer, 0, framesPerBuffer * channels() * sizeof(float)); return paComplete; } - while( _framesPerBuffer ) + while (framesPerBuffer) { if( m_outBufPos == 0 ) { @@ -202,24 +198,23 @@ int AudioPortAudio::processCallback(const float* _inputBuffer, float* _outputBuf if( !frames ) { m_stopped = true; - memset( _outputBuffer, 0, _framesPerBuffer * - channels() * sizeof(float) ); + memset(outputBuffer, 0, framesPerBuffer * channels() * sizeof(float)); return paComplete; } m_outBufSize = frames; } - const auto min_len = std::min(_framesPerBuffer, m_outBufSize - m_outBufPos); + const auto min_len = std::min(framesPerBuffer, m_outBufSize - m_outBufPos); for( fpp_t frame = 0; frame < min_len; ++frame ) { for( ch_cnt_t chnl = 0; chnl < channels(); ++chnl ) { - (_outputBuffer + frame * channels())[chnl] = AudioEngine::clip(m_outBuf[frame][chnl]); + (outputBuffer + frame * channels())[chnl] = AudioEngine::clip(m_outBuf[frame][chnl]); } } - _outputBuffer += min_len * channels(); - _framesPerBuffer -= min_len; + outputBuffer += min_len * channels(); + framesPerBuffer -= min_len; m_outBufPos += min_len; m_outBufPos %= m_outBufSize; } @@ -227,21 +222,15 @@ int AudioPortAudio::processCallback(const float* _inputBuffer, float* _outputBuf return paContinue; } - - -int AudioPortAudio::processCallback( - const void *_inputBuffer, - void * _outputBuffer, - unsigned long _framesPerBuffer, - const PaStreamCallbackTimeInfo * _timeInfo, - PaStreamCallbackFlags _statusFlags, - void * _arg ) +int AudioPortAudio::processCallback(const void* inputBuffer, void* outputBuffer, unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void* arg) { - Q_UNUSED(_timeInfo); - Q_UNUSED(_statusFlags); + Q_UNUSED(timeInfo); + Q_UNUSED(statusFlags); - auto _this = static_cast(_arg); - return _this->processCallback((const float*)_inputBuffer, (float*)_outputBuffer, _framesPerBuffer); + auto _this = static_cast(arg); + return _this->processCallback( + static_cast(inputBuffer), static_cast(outputBuffer), framesPerBuffer); } From a342db7219fca3e4515be995060a2bd9abb3c373 Mon Sep 17 00:00:00 2001 From: saker Date: Sat, 10 Aug 2024 22:56:35 -0400 Subject: [PATCH 10/23] Move closing brace up --- include/AudioPortAudio.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/include/AudioPortAudio.h b/include/AudioPortAudio.h index aa981407db1..e00ef526a25 100644 --- a/include/AudioPortAudio.h +++ b/include/AudioPortAudio.h @@ -95,11 +95,10 @@ class AudioPortAudio : public AudioDevice fpp_t m_outBufSize; bool m_stopped; +}; -} ; +} // namespace lmms #endif // LMMS_HAVE_PORTAUDIO -} // namespace lmms - #endif // LMMS_AUDIO_PORTAUDIO_H From 71a4ab22afeb882e5c2787f80aa92718071ad11e Mon Sep 17 00:00:00 2001 From: saker Date: Sun, 11 Aug 2024 08:51:51 -0400 Subject: [PATCH 11/23] Clean up constructor --- src/core/audio/AudioPortAudio.cpp | 105 ++++++++++++++---------------- 1 file changed, 50 insertions(+), 55 deletions(-) diff --git a/src/core/audio/AudioPortAudio.cpp b/src/core/audio/AudioPortAudio.cpp index 6bcd840bd4c..9949db5aa64 100644 --- a/src/core/audio/AudioPortAudio.cpp +++ b/src/core/audio/AudioPortAudio.cpp @@ -29,6 +29,7 @@ #ifdef LMMS_HAVE_PORTAUDIO #include +#include #include "Engine.h" #include "ConfigManager.h" @@ -44,91 +45,85 @@ AudioPortAudio::AudioPortAudio(bool& successful, AudioEngine* engine) engine) , m_paStream(nullptr) , m_wasPAInitError(false) - , m_outBuf(new SampleFrame[audioEngine()->framesPerPeriod()]) + , m_outBuf(new SampleFrame[engine->framesPerPeriod()]) , m_outBufPos(0) + , m_outBufSize(engine->framesPerPeriod()) { successful = false; - m_outBufSize = audioEngine()->framesPerPeriod(); PaError err = Pa_Initialize(); - if( err != paNoError ) { - printf( "Couldn't initialize PortAudio: %s\n", Pa_GetErrorText( err ) ); + std::cerr << "Couldn't initialize PortAudio: " << Pa_GetErrorText(err) << '\n'; m_wasPAInitError = true; return; } - if( Pa_GetDeviceCount() <= 0 ) - { - return; - } - const QString& backend = ConfigManager::inst()->value( "audioportaudio", "backend" ); const QString& device = ConfigManager::inst()->value( "audioportaudio", "device" ); - - PaDeviceIndex inDevIdx = -1; - PaDeviceIndex outDevIdx = -1; + + PaDeviceIndex inputDeviceIndex = Pa_GetDefaultInputDevice(); + PaDeviceIndex outputDeviceIndex = Pa_GetDefaultOutputDevice(); for( int i = 0; i < Pa_GetDeviceCount(); ++i ) { - const auto di = Pa_GetDeviceInfo(i); - if( di->name == device && - Pa_GetHostApiInfo( di->hostApi )->name == backend ) + const auto deviceInfo = Pa_GetDeviceInfo(i); + if (deviceInfo->name == device && Pa_GetHostApiInfo(deviceInfo->hostApi)->name == backend) { - inDevIdx = i; - outDevIdx = i; + inputDeviceIndex = i; + outputDeviceIndex = i; } } - if( inDevIdx < 0 ) - { - inDevIdx = Pa_GetDefaultInputDevice(); - } - - if( outDevIdx < 0 ) - { - outDevIdx = Pa_GetDefaultOutputDevice(); - } + PaStreamParameters* inputParameters = nullptr; + PaStreamParameters* outputParameters = nullptr; - if( inDevIdx < 0 || outDevIdx < 0 ) + if (outputDeviceIndex >= 0) { - return; + m_outputParameters.device = outputDeviceIndex; + m_outputParameters.channelCount = channels(); + m_outputParameters.sampleFormat = paFloat32; + m_outputParameters.suggestedLatency = Pa_GetDeviceInfo(outputDeviceIndex)->defaultLowOutputLatency; + m_outputParameters.hostApiSpecificStreamInfo = nullptr; + outputParameters = &m_outputParameters; } + else { return; } - const int samples = audioEngine()->framesPerPeriod(); - - m_outputParameters.device = outDevIdx; - m_outputParameters.channelCount = channels(); - m_outputParameters.sampleFormat = paFloat32; - m_outputParameters.suggestedLatency = Pa_GetDeviceInfo(outDevIdx)->defaultLowOutputLatency; - m_outputParameters.hostApiSpecificStreamInfo = nullptr; - - m_inputParameters.device = inDevIdx; - m_inputParameters.channelCount = DEFAULT_CHANNELS; - m_inputParameters.sampleFormat = paFloat32; - m_inputParameters.suggestedLatency = Pa_GetDeviceInfo(inDevIdx)->defaultLowInputLatency; - m_inputParameters.hostApiSpecificStreamInfo = nullptr; - - err = Pa_OpenStream(&m_paStream, supportsCapture() ? &m_inputParameters : nullptr, &m_outputParameters, - sampleRate(), samples, paNoFlag, processCallback, this); - - if( err == paInvalidDevice && sampleRate() < 48000 ) + if (inputDeviceIndex >= 0) { - printf("Pa_OpenStream() failed with 44,1 KHz, trying again with 48 KHz\n"); - // some backends or drivers do not allow 32 bit floating point data - // with a samplerate of 44100 Hz - setSampleRate( 48000 ); - err = Pa_OpenStream(&m_paStream, supportsCapture() ? &m_inputParameters : nullptr, &m_outputParameters, - sampleRate(), samples, paNoFlag, processCallback, this); + m_inputParameters.device = inputDeviceIndex; + m_inputParameters.channelCount = channels(); + m_inputParameters.sampleFormat = paFloat32; + m_inputParameters.suggestedLatency = Pa_GetDeviceInfo(inputDeviceIndex)->defaultLowInputLatency; + m_inputParameters.hostApiSpecificStreamInfo = nullptr; + inputParameters = &m_inputParameters; + m_supportsCapture = true; } + else { m_supportsCapture = false; } + + err = Pa_OpenStream(&m_paStream, + inputParameters, + outputParameters, + sampleRate(), + engine->framesPerPeriod(), + paNoFlag, + processCallback, + this); if( err != paNoError ) { - printf( "Couldn't open PortAudio: %s\n", Pa_GetErrorText( err ) ); + std::cerr << "Couldn't open PortAudio: " << Pa_GetErrorText(err) << '\n'; return; } - printf( "Input device: '%s' backend: '%s'\n", Pa_GetDeviceInfo( inDevIdx )->name, Pa_GetHostApiInfo( Pa_GetDeviceInfo( inDevIdx )->hostApi )->name ); - printf( "Output device: '%s' backend: '%s'\n", Pa_GetDeviceInfo( outDevIdx )->name, Pa_GetHostApiInfo( Pa_GetDeviceInfo( outDevIdx )->hostApi )->name ); + const auto inputDeviceInfo = Pa_GetDeviceInfo(inputDeviceIndex); + const auto inputDeviceName = inputDeviceInfo->name; + const auto inputDeviceBackend = Pa_GetHostApiInfo(inputDeviceInfo->hostApi)->name; + + const auto outputDeviceInfo = Pa_GetDeviceInfo(outputDeviceIndex); + const auto outputDeviceName = outputDeviceInfo->name; + const auto outputDeviceBackend = Pa_GetHostApiInfo(outputDeviceInfo->hostApi)->name; + + std::cout << "Input device: " << inputDeviceName << ", backend: " << inputDeviceBackend << '\n'; + std::cout << "Output device: " << outputDeviceName << ", backend: " << outputDeviceBackend << '\n'; successful = true; } From 12b9de4775a5b3c673c114d3f641fc9989ad3a5b Mon Sep 17 00:00:00 2001 From: saker Date: Sun, 11 Aug 2024 08:57:57 -0400 Subject: [PATCH 12/23] Replace printf calls on error with std::cerr --- src/core/audio/AudioPortAudio.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/core/audio/AudioPortAudio.cpp b/src/core/audio/AudioPortAudio.cpp index 9949db5aa64..79e2cf88af4 100644 --- a/src/core/audio/AudioPortAudio.cpp +++ b/src/core/audio/AudioPortAudio.cpp @@ -153,7 +153,7 @@ void AudioPortAudio::startProcessing() if( err != paNoError ) { m_stopped = true; - printf( "PortAudio error: %s\n", Pa_GetErrorText( err ) ); + std::cerr << "Failed to start PortAudio stream: " << Pa_GetErrorText(err) << '\n'; } } @@ -166,11 +166,8 @@ void AudioPortAudio::stopProcessing() { m_stopped = true; PaError err = Pa_StopStream( m_paStream ); - - if( err != paNoError ) - { - printf( "PortAudio error: %s\n", Pa_GetErrorText( err ) ); - } + + if (err != paNoError) { std::cerr << "Failed to stop PortAudio stream: " << Pa_GetErrorText(err) << '\n'; } } } @@ -235,7 +232,7 @@ void gui::AudioPortAudioSetupWidget::updateBackends() { PaError err = Pa_Initialize(); if( err != paNoError ) { - printf( "Couldn't initialize PortAudio: %s\n", Pa_GetErrorText( err ) ); + std::cerr << "Couldn't initialize PortAudio: " << Pa_GetErrorText(err) << '\n'; return; } @@ -255,7 +252,7 @@ void gui::AudioPortAudioSetupWidget::updateDevices() { PaError err = Pa_Initialize(); if( err != paNoError ) { - printf( "Couldn't initialize PortAudio: %s\n", Pa_GetErrorText( err ) ); + std::cerr << "Couldn't initialize PortAudio: " << Pa_GetErrorText(err) << '\n'; return; } @@ -290,7 +287,7 @@ void gui::AudioPortAudioSetupWidget::updateChannels() { PaError err = Pa_Initialize(); if( err != paNoError ) { - printf( "Couldn't initialize PortAudio: %s\n", Pa_GetErrorText( err ) ); + std::cerr << "Couldn't initialize PortAudio: " << Pa_GetErrorText(err) << '\n'; return; } Pa_Terminate(); From 261642d580bfb4ed2b21eafe5665acf00c484666 Mon Sep 17 00:00:00 2001 From: saker Date: Sun, 11 Aug 2024 09:07:02 -0400 Subject: [PATCH 13/23] Use unique_ptr for m_outBuf --- include/AudioPortAudio.h | 2 +- src/core/audio/AudioPortAudio.cpp | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/include/AudioPortAudio.h b/include/AudioPortAudio.h index e00ef526a25..92d9eb85391 100644 --- a/include/AudioPortAudio.h +++ b/include/AudioPortAudio.h @@ -90,7 +90,7 @@ class AudioPortAudio : public AudioDevice bool m_wasPAInitError; - SampleFrame* m_outBuf; + std::unique_ptr m_outBuf; std::size_t m_outBufPos; fpp_t m_outBufSize; diff --git a/src/core/audio/AudioPortAudio.cpp b/src/core/audio/AudioPortAudio.cpp index 79e2cf88af4..6fd205e78fe 100644 --- a/src/core/audio/AudioPortAudio.cpp +++ b/src/core/audio/AudioPortAudio.cpp @@ -45,7 +45,7 @@ AudioPortAudio::AudioPortAudio(bool& successful, AudioEngine* engine) engine) , m_paStream(nullptr) , m_wasPAInitError(false) - , m_outBuf(new SampleFrame[engine->framesPerPeriod()]) + , m_outBuf(std::make_unique(engine->framesPerPeriod())) , m_outBufPos(0) , m_outBufSize(engine->framesPerPeriod()) { @@ -139,7 +139,6 @@ AudioPortAudio::~AudioPortAudio() { Pa_Terminate(); } - delete[] m_outBuf; } @@ -186,7 +185,7 @@ int AudioPortAudio::processCallback(const float* inputBuffer, float* outputBuffe { if( m_outBufPos == 0 ) { - const fpp_t frames = getNextBuffer( m_outBuf ); + const fpp_t frames = getNextBuffer(m_outBuf.get()); if( !frames ) { m_stopped = true; From 9952bf81e30d9b4a1dc81c462ca309e593b583d0 Mon Sep 17 00:00:00 2001 From: saker Date: Mon, 12 Aug 2024 11:47:19 -0400 Subject: [PATCH 14/23] Do not use multiple techniques to start and stop the stream Returning paComplete from the audio callback, as well as using our own stop variable may conflict in complex ways. One such example is if the stop boolean is set and the device is required to read the nullptr buffer when the audio FIFO thread is closing. Also, PortAudio's says using paComplete and paAbort is an alternative technique to calling Pa_StopStream, so using both isn't necessary and thus avoids streams being stopped or started unexpectedly. --- include/AudioPortAudio.h | 2 -- src/core/audio/AudioPortAudio.cpp | 14 +------------- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/include/AudioPortAudio.h b/include/AudioPortAudio.h index 92d9eb85391..a6e641920ca 100644 --- a/include/AudioPortAudio.h +++ b/include/AudioPortAudio.h @@ -93,8 +93,6 @@ class AudioPortAudio : public AudioDevice std::unique_ptr m_outBuf; std::size_t m_outBufPos; fpp_t m_outBufSize; - - bool m_stopped; }; } // namespace lmms diff --git a/src/core/audio/AudioPortAudio.cpp b/src/core/audio/AudioPortAudio.cpp index 6fd205e78fe..9c0612b398b 100644 --- a/src/core/audio/AudioPortAudio.cpp +++ b/src/core/audio/AudioPortAudio.cpp @@ -146,12 +146,9 @@ AudioPortAudio::~AudioPortAudio() void AudioPortAudio::startProcessing() { - m_stopped = false; PaError err = Pa_StartStream( m_paStream ); - if( err != paNoError ) { - m_stopped = true; std::cerr << "Failed to start PortAudio stream: " << Pa_GetErrorText(err) << '\n'; } } @@ -163,9 +160,7 @@ void AudioPortAudio::stopProcessing() { if( m_paStream && Pa_IsStreamActive( m_paStream ) ) { - m_stopped = true; PaError err = Pa_StopStream( m_paStream ); - if (err != paNoError) { std::cerr << "Failed to stop PortAudio stream: " << Pa_GetErrorText(err) << '\n'; } } } @@ -175,12 +170,6 @@ int AudioPortAudio::processCallback(const float* inputBuffer, float* outputBuffe { if (supportsCapture()) { audioEngine()->pushInputFrames((SampleFrame*)inputBuffer, framesPerBuffer); } - if( m_stopped ) - { - memset(outputBuffer, 0, framesPerBuffer * channels() * sizeof(float)); - return paComplete; - } - while (framesPerBuffer) { if( m_outBufPos == 0 ) @@ -188,9 +177,8 @@ int AudioPortAudio::processCallback(const float* inputBuffer, float* outputBuffe const fpp_t frames = getNextBuffer(m_outBuf.get()); if( !frames ) { - m_stopped = true; memset(outputBuffer, 0, framesPerBuffer * channels() * sizeof(float)); - return paComplete; + return paContinue; } m_outBufSize = frames; } From a7620426f6200e169975d277eee63fb3dcd5d6ac Mon Sep 17 00:00:00 2001 From: saker Date: Mon, 12 Aug 2024 12:57:10 -0400 Subject: [PATCH 15/23] Move back to using paComplete Made a misunderstanding. Pa_StopStream requires that we return paComplete when we are done to tell it that no more new buffers are being rendered for now and it can play any pending audio buffers. --- src/core/audio/AudioPortAudio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/audio/AudioPortAudio.cpp b/src/core/audio/AudioPortAudio.cpp index 9c0612b398b..fbf7339761a 100644 --- a/src/core/audio/AudioPortAudio.cpp +++ b/src/core/audio/AudioPortAudio.cpp @@ -178,7 +178,7 @@ int AudioPortAudio::processCallback(const float* inputBuffer, float* outputBuffe if( !frames ) { memset(outputBuffer, 0, framesPerBuffer * channels() * sizeof(float)); - return paContinue; + return paComplete; } m_outBufSize = frames; } From bb21cf40ad52609fae6d34ec9f25acc1f1de1534 Mon Sep 17 00:00:00 2001 From: saker Date: Mon, 12 Aug 2024 13:13:52 -0400 Subject: [PATCH 16/23] Fix naming style --- src/core/audio/AudioPortAudio.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/core/audio/AudioPortAudio.cpp b/src/core/audio/AudioPortAudio.cpp index fbf7339761a..a7fc5bca369 100644 --- a/src/core/audio/AudioPortAudio.cpp +++ b/src/core/audio/AudioPortAudio.cpp @@ -182,9 +182,9 @@ int AudioPortAudio::processCallback(const float* inputBuffer, float* outputBuffe } m_outBufSize = frames; } - const auto min_len = std::min(framesPerBuffer, m_outBufSize - m_outBufPos); - for( fpp_t frame = 0; frame < min_len; ++frame ) + const auto minLen = std::min(framesPerBuffer, m_outBufSize - m_outBufPos); + for (fpp_t frame = 0; frame < minLen; ++frame) { for( ch_cnt_t chnl = 0; chnl < channels(); ++chnl ) { @@ -192,9 +192,9 @@ int AudioPortAudio::processCallback(const float* inputBuffer, float* outputBuffe } } - outputBuffer += min_len * channels(); - framesPerBuffer -= min_len; - m_outBufPos += min_len; + outputBuffer += minLen * channels(); + framesPerBuffer -= minLen; + m_outBufPos += minLen; m_outBufPos %= m_outBufSize; } From b7963c73ed770c8046fc82a1b10f9e7d5d107fce Mon Sep 17 00:00:00 2001 From: saker Date: Mon, 12 Aug 2024 13:32:44 -0400 Subject: [PATCH 17/23] Replace memset with std::fill_n --- src/core/audio/AudioPortAudio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/audio/AudioPortAudio.cpp b/src/core/audio/AudioPortAudio.cpp index a7fc5bca369..87184c2d3a9 100644 --- a/src/core/audio/AudioPortAudio.cpp +++ b/src/core/audio/AudioPortAudio.cpp @@ -177,7 +177,7 @@ int AudioPortAudio::processCallback(const float* inputBuffer, float* outputBuffe const fpp_t frames = getNextBuffer(m_outBuf.get()); if( !frames ) { - memset(outputBuffer, 0, framesPerBuffer * channels() * sizeof(float)); + std::fill_n(outputBuffer, framesPerBuffer * channels(), 0.0f); return paComplete; } m_outBufSize = frames; From 4ff2725fca589c3db1787074520cebff3e18ddd5 Mon Sep 17 00:00:00 2001 From: saker Date: Mon, 12 Aug 2024 13:41:38 -0400 Subject: [PATCH 18/23] Remove redundant frames variable --- src/core/audio/AudioPortAudio.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/core/audio/AudioPortAudio.cpp b/src/core/audio/AudioPortAudio.cpp index 87184c2d3a9..e6a11a6d20c 100644 --- a/src/core/audio/AudioPortAudio.cpp +++ b/src/core/audio/AudioPortAudio.cpp @@ -174,13 +174,12 @@ int AudioPortAudio::processCallback(const float* inputBuffer, float* outputBuffe { if( m_outBufPos == 0 ) { - const fpp_t frames = getNextBuffer(m_outBuf.get()); - if( !frames ) + m_outBufSize = getNextBuffer(m_outBuf.get()); + if (m_outBufSize == 0) { std::fill_n(outputBuffer, framesPerBuffer * channels(), 0.0f); return paComplete; } - m_outBufSize = frames; } const auto minLen = std::min(framesPerBuffer, m_outBufSize - m_outBufPos); From 333c08126073679dbaec11a209aa8a9db7657f8b Mon Sep 17 00:00:00 2001 From: saker Date: Mon, 12 Aug 2024 13:52:11 -0400 Subject: [PATCH 19/23] Simplify nested for loop No need for AudioEngine::clip since PortAudio already clips the signal for us. --- src/core/audio/AudioPortAudio.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/core/audio/AudioPortAudio.cpp b/src/core/audio/AudioPortAudio.cpp index e6a11a6d20c..4fc47046f2d 100644 --- a/src/core/audio/AudioPortAudio.cpp +++ b/src/core/audio/AudioPortAudio.cpp @@ -183,12 +183,9 @@ int AudioPortAudio::processCallback(const float* inputBuffer, float* outputBuffe } const auto minLen = std::min(framesPerBuffer, m_outBufSize - m_outBufPos); - for (fpp_t frame = 0; frame < minLen; ++frame) + for (auto sample = 0; sample < framesPerBuffer * channels(); ++sample) { - for( ch_cnt_t chnl = 0; chnl < channels(); ++chnl ) - { - (outputBuffer + frame * channels())[chnl] = AudioEngine::clip(m_outBuf[frame][chnl]); - } + outputBuffer[sample] = m_outBuf[sample / channels()][sample % channels()]; } outputBuffer += minLen * channels(); From 6c7c25c28290fd2a3149368cbf9eac8337292eec Mon Sep 17 00:00:00 2001 From: saker Date: Mon, 12 Aug 2024 14:05:20 -0400 Subject: [PATCH 20/23] Fix unsigned comparison --- src/core/audio/AudioPortAudio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/audio/AudioPortAudio.cpp b/src/core/audio/AudioPortAudio.cpp index 4fc47046f2d..39b487bd752 100644 --- a/src/core/audio/AudioPortAudio.cpp +++ b/src/core/audio/AudioPortAudio.cpp @@ -183,7 +183,7 @@ int AudioPortAudio::processCallback(const float* inputBuffer, float* outputBuffe } const auto minLen = std::min(framesPerBuffer, m_outBufSize - m_outBufPos); - for (auto sample = 0; sample < framesPerBuffer * channels(); ++sample) + for (auto sample = std::size_t{0}; sample < framesPerBuffer * channels(); ++sample) { outputBuffer[sample] = m_outBuf[sample / channels()][sample % channels()]; } From 0647ddc34e1bec2bf2907830b4359ebd79cd48fd Mon Sep 17 00:00:00 2001 From: saker Date: Mon, 12 Aug 2024 16:08:37 -0400 Subject: [PATCH 21/23] Use Qt's combo boxes --- include/AudioPortAudio.h | 11 +++--- src/core/audio/AudioPortAudio.cpp | 60 ++++++++++--------------------- 2 files changed, 23 insertions(+), 48 deletions(-) diff --git a/include/AudioPortAudio.h b/include/AudioPortAudio.h index a6e641920ca..7348640f373 100644 --- a/include/AudioPortAudio.h +++ b/include/AudioPortAudio.h @@ -30,25 +30,24 @@ #ifdef LMMS_HAVE_PORTAUDIO #include -#include "ComboBoxModel.h" #include #include "AudioDevice.h" #include "AudioDeviceSetupWidget.h" +class QComboBox; + namespace lmms { namespace gui { -class ComboBox; class LcdSpinBox; class AudioPortAudioSetupWidget : public gui::AudioDeviceSetupWidget { public: AudioPortAudioSetupWidget(QWidget* _parent); - ~AudioPortAudioSetupWidget() override; void updateBackends(); void updateDevices(); @@ -58,10 +57,8 @@ class AudioPortAudioSetupWidget : public gui::AudioDeviceSetupWidget void show() override; private: - ComboBox* m_backend; - ComboBox* m_device; - ComboBoxModel m_backendModel; - ComboBoxModel m_deviceModel; + QComboBox* m_backendComboBox; + QComboBox* m_deviceComboBox; }; } // namespace gui diff --git a/src/core/audio/AudioPortAudio.cpp b/src/core/audio/AudioPortAudio.cpp index 39b487bd752..c5c05d633f3 100644 --- a/src/core/audio/AudioPortAudio.cpp +++ b/src/core/audio/AudioPortAudio.cpp @@ -28,13 +28,13 @@ #ifdef LMMS_HAVE_PORTAUDIO +#include #include #include -#include "Engine.h" -#include "ConfigManager.h" -#include "ComboBox.h" #include "AudioEngine.h" +#include "ConfigManager.h" +#include "Engine.h" namespace lmms { @@ -222,7 +222,7 @@ void gui::AudioPortAudioSetupWidget::updateBackends() for( int i = 0; i < Pa_GetHostApiCount(); ++i ) { const auto hi = Pa_GetHostApiInfo(i); - m_backendModel.addItem( hi->name ); + m_backendComboBox->addItem(hi->name); } Pa_Terminate(); @@ -239,7 +239,7 @@ void gui::AudioPortAudioSetupWidget::updateDevices() return; } - const QString& backend = m_backendModel.currentText(); + const QString& backend = m_backendComboBox->currentText(); int hostApi = 0; for( int i = 0; i < Pa_GetHostApiCount(); ++i ) { @@ -251,14 +251,11 @@ void gui::AudioPortAudioSetupWidget::updateDevices() } } - m_deviceModel.clear(); + m_deviceComboBox->clear(); for( int i = 0; i < Pa_GetDeviceCount(); ++i ) { const auto di = Pa_GetDeviceInfo(i); - if( di->hostApi == hostApi ) - { - m_deviceModel.addItem( di->name ); - } + if (di->hostApi == hostApi) { m_deviceComboBox->addItem(di->name); } } Pa_Terminate(); } @@ -279,39 +276,20 @@ void gui::AudioPortAudioSetupWidget::updateChannels() gui::AudioPortAudioSetupWidget::AudioPortAudioSetupWidget(QWidget* _parent) : AudioDeviceSetupWidget(AudioPortAudio::name(), _parent) { - using gui::ComboBox; - QFormLayout * form = new QFormLayout(this); + form->setRowWrapPolicy(QFormLayout::WrapLongRows); - m_backend = new ComboBox( this, "BACKEND" ); - form->addRow(tr("Backend"), m_backend); - - m_device = new ComboBox( this, "DEVICE" ); - form->addRow(tr("Device"), m_device); - - connect(&m_backendModel, &ComboBoxModel::dataChanged, this, &AudioPortAudioSetupWidget::updateDevices); - connect(&m_deviceModel, &ComboBoxModel::dataChanged, this, &AudioPortAudioSetupWidget::updateChannels); + m_backendComboBox = new QComboBox(this); + form->addRow(tr("Backend"), m_backendComboBox); - m_backend->setModel(&m_backendModel); - m_device->setModel(&m_deviceModel); + m_deviceComboBox = new QComboBox(this); + form->addRow(tr("Device"), m_deviceComboBox); } - - - -gui::AudioPortAudioSetupWidget::~AudioPortAudioSetupWidget() -{ - disconnect(&m_backendModel, &ComboBoxModel::dataChanged, this, &AudioPortAudioSetupWidget::updateDevices); - disconnect(&m_deviceModel, &ComboBoxModel::dataChanged, this, &AudioPortAudioSetupWidget::updateChannels); -} - - - - void gui::AudioPortAudioSetupWidget::saveSettings() { - ConfigManager::inst()->setValue("audioportaudio", "backend", m_backendModel.currentText()); - ConfigManager::inst()->setValue("audioportaudio", "device", m_deviceModel.currentText()); + ConfigManager::inst()->setValue("audioportaudio", "backend", m_backendComboBox->currentText()); + ConfigManager::inst()->setValue("audioportaudio", "device", m_deviceComboBox->currentText()); } @@ -319,7 +297,7 @@ void gui::AudioPortAudioSetupWidget::saveSettings() void gui::AudioPortAudioSetupWidget::show() { - if (m_backendModel.size() == 0) + if (m_backendComboBox->count() == 0) { // populate the backend model the first time we are shown updateBackends(); @@ -329,13 +307,13 @@ void gui::AudioPortAudioSetupWidget::show() const QString& device = ConfigManager::inst()->value( "audioportaudio", "device" ); - int i = std::max(0, m_backendModel.findText(backend)); - m_backendModel.setValue(i); + const auto backendIndex = std::max(0, m_backendComboBox->findText(backend)); + m_backendComboBox->setCurrentIndex(backendIndex); updateDevices(); - i = std::max(0, m_deviceModel.findText(device)); - m_deviceModel.setValue(i); + const auto deviceIndex = std::max(0, m_deviceComboBox->findText(device)); + m_deviceComboBox->setCurrentIndex(deviceIndex); } AudioDeviceSetupWidget::show(); From 88aaaceb4644679510350caede5aa17e7577bf47 Mon Sep 17 00:00:00 2001 From: saker Date: Mon, 12 Aug 2024 17:22:55 -0400 Subject: [PATCH 22/23] Include memory header --- include/AudioPortAudio.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/AudioPortAudio.h b/include/AudioPortAudio.h index 7348640f373..1171312974f 100644 --- a/include/AudioPortAudio.h +++ b/include/AudioPortAudio.h @@ -30,8 +30,9 @@ #ifdef LMMS_HAVE_PORTAUDIO #include - +#include #include + #include "AudioDevice.h" #include "AudioDeviceSetupWidget.h" From c43246bec5c66d9885398064613db7fecd3775ca Mon Sep 17 00:00:00 2001 From: saker Date: Mon, 12 Aug 2024 17:23:44 -0400 Subject: [PATCH 23/23] Remove LcdSpinBox forward declaration --- include/AudioPortAudio.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/AudioPortAudio.h b/include/AudioPortAudio.h index 1171312974f..843a9afd7c1 100644 --- a/include/AudioPortAudio.h +++ b/include/AudioPortAudio.h @@ -43,8 +43,6 @@ namespace lmms namespace gui { -class LcdSpinBox; - class AudioPortAudioSetupWidget : public gui::AudioDeviceSetupWidget { public: