Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor PortAudio backend #7444

Draft
wants to merge 73 commits into
base: master
Choose a base branch
from
Draft
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
6278746
Suggest the default low latency
sakertooth Aug 11, 2024
c3902ce
Remove verbose comments
sakertooth Aug 11, 2024
0e51917
Completely remove old PortAudio < v19 code
sakertooth Aug 11, 2024
916aa1f
Remove redundant header guard
sakertooth Aug 11, 2024
dc5b01c
Rename and move setup widget into gui namespace
sakertooth Aug 11, 2024
0a3fcd1
Fix naming of callback functions
sakertooth Aug 11, 2024
b66a281
Merge AudioPortAudioSetupWidget and AudioPortAudioSetupUtil
sakertooth Aug 11, 2024
53cbe47
Fix naming in constructor
sakertooth Aug 11, 2024
fbdb591
Fix naming for parameters of callback functions
sakertooth Aug 11, 2024
9af62b0
Move closing brace up
sakertooth Aug 11, 2024
df2af4d
Clean up constructor
sakertooth Aug 11, 2024
2258eb7
Replace printf calls on error with std::cerr
sakertooth Aug 11, 2024
88949fc
Use unique_ptr for m_outBuf
sakertooth Aug 11, 2024
501056b
Do not use multiple techniques to start and stop the stream
sakertooth Aug 12, 2024
3f5ce10
Move back to using paComplete
sakertooth Aug 12, 2024
3cc20ee
Fix naming style
sakertooth Aug 12, 2024
4c8ba0d
Replace memset with std::fill_n
sakertooth Aug 12, 2024
0e51ae1
Remove redundant frames variable
sakertooth Aug 12, 2024
6f27d17
Simplify nested for loop
sakertooth Aug 12, 2024
44d0ca9
Fix unsigned comparison
sakertooth Aug 12, 2024
22442ef
Use Qt's combo boxes
sakertooth Aug 12, 2024
cb1bbe0
Include memory header
sakertooth Aug 12, 2024
e115ed3
Remove LcdSpinBox forward declaration
sakertooth Aug 12, 2024
e205701
Stop searching for devices when the correct device is found
sakertooth Jan 15, 2025
ee1716b
Fix formatting
sakertooth Jan 15, 2025
b7def39
Set suggestedLatency to the correct values
sakertooth Jan 15, 2025
bb085cc
Stop clamping channel count to 2
sakertooth Jan 16, 2025
6c87246
Use default number of channels when no amount is specified in the config
sakertooth Jan 18, 2025
8be5793
Simplify construction logic
sakertooth Jan 27, 2025
a5a0c02
Use QString::number instead of trying to construct string from number
sakertooth Jan 27, 2025
e7ae83c
Stop calculating latency twice
sakertooth Jan 27, 2025
9039b5d
Add whitespace
sakertooth Jan 27, 2025
d98c166
Remove input device
sakertooth Jan 27, 2025
f19fc65
Apply adjustments
sakertooth Jan 30, 2025
222c601
Update devices when backend changes
sakertooth Jan 30, 2025
3d805da
Add PortAudio initialization RAII guard
sakertooth Jan 30, 2025
e72bfec
Improve backend, device, and channel finding and selection logic
sakertooth Jan 31, 2025
cc1a14d
Early return when no backend or device is selected, update both devic…
sakertooth Jan 31, 2025
e001a9c
Set sample rate and channel count lazily
sakertooth Jan 31, 2025
8bdc051
Support downmixing to mono
sakertooth Jan 31, 2025
6ebccb2
Remove anonymous namespace
sakertooth Jan 31, 2025
be901c5
Fix audio processing to work with any number of channels
sakertooth Jan 31, 2025
9221724
Fix audio glitches when playing wiith buffer sizes other than 256
sakertooth Feb 4, 2025
78e49c3
Set sample rate and channel count even on failure to open device
sakertooth Feb 4, 2025
90402f7
Make adjustment
sakertooth Feb 4, 2025
deee77a
Check for errors in PortAudioInitializationGuard
sakertooth Feb 9, 2025
80257ba
PortAudioInitializationGuard: Print error message in the constructor
sakertooth Feb 9, 2025
b50e385
Simplify/fix callback processing
sakertooth Feb 16, 2025
7d8b058
Update backend, devices, and channel count without early returns
sakertooth Feb 16, 2025
161d756
Fix formatting
sakertooth Feb 16, 2025
aee24f9
More formatting
sakertooth Feb 16, 2025
f091077
Remove use of Q_UNUSED
sakertooth Feb 17, 2025
b7b0489
Simplify starting and stopping stream
sakertooth Feb 17, 2025
2b721a4
Close stream on call to destructor
sakertooth Feb 17, 2025
7c1e089
Check for errors when terminating PortAudio
sakertooth Feb 17, 2025
7dc0f62
Check if PortAudio format is supported
sakertooth Feb 17, 2025
ac0819f
Fix invalid stream pointer error when closing the stream
sakertooth Feb 17, 2025
8064086
Print more diagnostics
sakertooth Feb 17, 2025
60d3282
Print out even more diagnostics
sakertooth Feb 17, 2025
c212bd8
Iterate the devices with the associated host API instead of all avail…
sakertooth Feb 17, 2025
2bf8504
Update channel count in the config
sakertooth Feb 17, 2025
cab5d57
Change order
sakertooth Feb 17, 2025
1fb3fde
Skip backends and devices when enumerating where possible
sakertooth Feb 17, 2025
6ae01ea
Start over
sakertooth Feb 28, 2025
00d0bd6
Improve naming, fix crash
sakertooth Feb 28, 2025
49b868e
Remove error handling when starting and stopping stream
sakertooth Feb 28, 2025
f54f483
Simplify callback declaration
sakertooth Feb 28, 2025
7f73b81
Add UI elements
sakertooth Feb 28, 2025
7c7e234
Implement functionality to fill in UI elements
sakertooth Feb 28, 2025
d13d1a4
Implement updating channels
sakertooth Feb 28, 2025
8a24685
Set the number of channels after opening stream
sakertooth Feb 28, 2025
1fee7a6
Make error handling more descriptive
sakertooth Feb 28, 2025
d58a271
Use only single backend
sakertooth Feb 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions include/AudioDevice.h
Original file line number Diff line number Diff line change
@@ -113,6 +113,11 @@ class AudioDevice
m_sampleRate = _new_sr;
}

void setChannels(const ch_cnt_t channels)
{
m_channels = channels;
}

AudioEngine* audioEngine()
{
return m_audioEngine;
148 changes: 40 additions & 108 deletions include/AudioPortAudio.h
Original file line number Diff line number Diff line change
@@ -25,137 +25,69 @@
#ifndef LMMS_AUDIO_PORTAUDIO_H
#define LMMS_AUDIO_PORTAUDIO_H

#include <QObject>

#include "lmmsconfig.h"
#include "ComboBoxModel.h"

#ifdef LMMS_HAVE_PORTAUDIO

# include <portaudio.h>

# include "AudioDevice.h"
# include "AudioDeviceSetupWidget.h"

# if defined paNeverDropInput || defined paNonInterleaved
# define PORTAUDIO_V19
# else
# define PORTAUDIO_V18
# endif

#endif


namespace lmms
{

class AudioPortAudioSetupUtil : public QObject
{
Q_OBJECT
public slots:
void updateBackends();
void updateDevices();
void updateChannels();

public:
ComboBoxModel m_backendModel;
ComboBoxModel m_deviceModel;
};


#ifdef LMMS_HAVE_PORTAUDIO

#include <QComboBox>
#include <QFormLayout>
#include <QString>
#include <QWidget>
#include <portaudio.h>

namespace gui
{
class ComboBox;
class LcdSpinBox;
}

#include "AudioDevice.h"
#include "AudioDeviceSetupWidget.h"
#include "LcdSpinBox.h"

namespace lmms {
class AudioPortAudio : public AudioDevice
{
public:
AudioPortAudio( bool & _success_ful, AudioEngine* audioEngine );
AudioPortAudio(AudioEngine* engine);
~AudioPortAudio() override;

inline static QString name()
{
return QT_TRANSLATE_NOOP( "AudioDeviceSetupWidget", "PortAudio" );
}

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;

#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 );

static auto name() -> QString { return QT_TRANSLATE_NOOP("AudioDeviceSetupWidget", "PortAudio"); }

using PaTime = double;
using PaDeviceIndex = PaDeviceID;
private:
static int processCallback(const void* input, void* output, unsigned long frameCount,
const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void* userData);

using PaStreamParameters = struct
{
PaDeviceIndex device;
int channelCount;
PaSampleFormat sampleFormat;
PaTime suggestedLatency;
void *hostApiSpecificStreamInfo;
PaStream* m_paStream = nullptr;
std::vector<SampleFrame> m_outBuf;
std::size_t m_outBufPos = 0;
};
} // namespace lmms

} PaStreamParameters;
#endif // PORTAUDIO_V19
namespace lmms::gui {
class AudioPortAudioSetupWidget : public AudioDeviceSetupWidget
{
public:
AudioPortAudioSetupWidget(QWidget* parent);
~AudioPortAudioSetupWidget();

PaStream * m_paStream;
PaStreamParameters m_outputParameters;
PaStreamParameters m_inputParameters;
void show() override;
void saveSettings() override;

bool m_wasPAInitError;
private:
void updateBackends();
void updateDevices(bool updateInput = true, bool updateOutput = true);
void updateChannels(bool updateInput = true, bool updateOutput = true);

SampleFrame* m_outBuf;
std::size_t m_outBufPos;
fpp_t m_outBufSize;
QComboBox* m_backendComboBox = nullptr;

bool m_stopped;
QComboBox* m_outputDeviceComboBox = nullptr;
IntModel m_outputChannelsModel;
LcdSpinBox* m_outputChannelsSpinBox = nullptr;

} ;
QComboBox* m_inputDeviceComboBox = nullptr;
IntModel m_inputChannelsModel;
LcdSpinBox* m_inputChannelsSpinBox = nullptr;
};
} // namespace lmms::gui

#endif // LMMS_HAVE_PORTAUDIO

} // namespace lmms

#endif // LMMS_AUDIO_PORTAUDIO_H
16 changes: 13 additions & 3 deletions src/core/AudioEngine.cpp
Original file line number Diff line number Diff line change
@@ -23,6 +23,7 @@
*/

#include "AudioEngine.h"
#include <iostream>

#include "MixHelpers.h"
#include "denormals.h"
@@ -907,14 +908,23 @@ AudioDevice * AudioEngine::tryAudioDevices()


#ifdef LMMS_HAVE_PORTAUDIO
if( dev_name == AudioPortAudio::name() || dev_name == "" )
// TODO: Eventually move all devices to use exception handling instead of passing in a boolean parameter
// to the constructor
try
{
dev = new AudioPortAudio( success_ful, this );
if( success_ful )
if (dev_name == AudioPortAudio::name() || dev_name == "")
{
dev = new AudioPortAudio(this);
m_audioDevName = AudioPortAudio::name();
return dev;
}

success_ful = true;
}
catch (std::runtime_error& error)
{
std::cerr << error.what() << '\n';
success_ful = false;
delete dev;
}
#endif
Loading