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

SDL driver's input and output device configuration via combo box #7421

Merged
merged 12 commits into from
Aug 10, 2024
10 changes: 8 additions & 2 deletions include/AudioSdl.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
#include "AudioDevice.h"
#include "AudioDeviceSetupWidget.h"

class QLineEdit;
class QComboBox;
Rossmaxx marked this conversation as resolved.
Show resolved Hide resolved

namespace lmms
{
Expand All @@ -64,10 +64,16 @@ class AudioSdl : public AudioDevice
~setupWidget() override = default;

void saveSettings() override;

private:
void populatePlaybackDeviceComboBox();
void populateInputDeviceComboBox();

private:
QLineEdit * m_device;
QComboBox* m_playbackDeviceComboBox = nullptr;
QComboBox* m_inputDeviceComboBox = nullptr;

static QString s_systemDefaultDevice;
} ;


Expand Down
125 changes: 110 additions & 15 deletions src/core/audio/AudioSdl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

#include <QFormLayout>
#include <QLineEdit>
#include <QComboBox>
#include <SDL.h>

#include "AudioEngine.h"
Expand All @@ -37,6 +38,10 @@
namespace lmms
{

constexpr char const* const SectionSDL = "audiosdl";
constexpr char const* const PlaybackDeviceSDL = "device";
constexpr char const* const InputDeviceSDL = "inputdevice";

AudioSdl::AudioSdl( bool & _success_ful, AudioEngine* _audioEngine ) :
AudioDevice( DEFAULT_CHANNELS, _audioEngine ),
m_outBuf(new SampleFrame[audioEngine()->framesPerPeriod()])
Expand Down Expand Up @@ -78,11 +83,19 @@ AudioSdl::AudioSdl( bool & _success_ful, AudioEngine* _audioEngine ) :
SDL_AudioSpec actual;

#ifdef LMMS_HAVE_SDL2
m_outputDevice = SDL_OpenAudioDevice (nullptr,
0,
&m_audioHandle,
&actual,
0);
const auto playbackDevice = ConfigManager::inst()->value(SectionSDL, PlaybackDeviceSDL).toStdString();
const bool isDefaultPlayback = playbackDevice.empty();

// Try with the configured device
const auto playbackDeviceCStr = isDefaultPlayback ? nullptr : playbackDevice.c_str();
m_outputDevice = SDL_OpenAudioDevice(playbackDeviceCStr, 0, &m_audioHandle, &actual, 0);

// If we did not get a device ID try again with the default device if we did not try that before
if (m_outputDevice == 0 && !isDefaultPlayback)
{
m_outputDevice = SDL_OpenAudioDevice(nullptr, 0, &m_audioHandle, &actual, 0);
}

if (m_outputDevice == 0) {
qCritical( "Couldn't open SDL-audio: %s\n", SDL_GetError() );
return;
Expand All @@ -108,11 +121,19 @@ AudioSdl::AudioSdl( bool & _success_ful, AudioEngine* _audioEngine ) :
m_inputAudioHandle = m_audioHandle;
m_inputAudioHandle.callback = sdlInputAudioCallback;

m_inputDevice = SDL_OpenAudioDevice (nullptr,
1,
&m_inputAudioHandle,
&actual,
0);
const auto inputDevice = ConfigManager::inst()->value(SectionSDL, InputDeviceSDL).toStdString();
const bool isDefaultInput = inputDevice.empty();

// Try with the configured device
const auto inputDeviceCStr = isDefaultInput ? nullptr : inputDevice.c_str();
m_inputDevice = SDL_OpenAudioDevice (inputDeviceCStr, 1, &m_inputAudioHandle, &actual, 0);

// If we did not get a device ID try again with the default device if we did not try that before
if (m_inputDevice == 0 && !isDefaultInput)
{
m_inputDevice = SDL_OpenAudioDevice(nullptr, 1, &m_inputAudioHandle, &actual, 0);
}

if (m_inputDevice != 0) {
m_supportsCapture = true;
} else {
Expand Down Expand Up @@ -283,24 +304,98 @@ void AudioSdl::sdlInputAudioCallback(Uint8 *_buf, int _len) {

#endif

QString AudioSdl::setupWidget::s_systemDefaultDevice = QObject::tr("[System Default]");
michaelgregorius marked this conversation as resolved.
Show resolved Hide resolved

AudioSdl::setupWidget::setupWidget( QWidget * _parent ) :
AudioDeviceSetupWidget( AudioSdl::name(), _parent )
{
QFormLayout * form = new QFormLayout(this);
form->setRowWrapPolicy(QFormLayout::WrapLongRows);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reasons for this change?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because otherwise the labels might get hidden if the content of the combo boxes becomes very long (which is the case for my sound devices). See commit 94b43f5.


QString dev = ConfigManager::inst()->value( "audiosdl", "device" );
m_device = new QLineEdit( dev, this );
m_playbackDeviceComboBox = new QComboBox(this);

form->addRow(tr("Device"), m_device);
populatePlaybackDeviceComboBox();

form->addRow(tr("Playback device"), m_playbackDeviceComboBox);

m_inputDeviceComboBox = new QComboBox(this);

populateInputDeviceComboBox();

form->addRow(tr("Input device"), m_inputDeviceComboBox);
}




void AudioSdl::setupWidget::saveSettings()
{
ConfigManager::inst()->setValue( "audiosdl", "device",
m_device->text() );
const auto currentPlaybackDevice = m_playbackDeviceComboBox->currentText();
if (currentPlaybackDevice == s_systemDefaultDevice)
{
// Represent the default input device with an empty string
michaelgregorius marked this conversation as resolved.
Show resolved Hide resolved
ConfigManager::inst()->setValue(SectionSDL, PlaybackDeviceSDL, "");
}
else if (!currentPlaybackDevice.isEmpty())
{
ConfigManager::inst()->setValue(SectionSDL, PlaybackDeviceSDL, currentPlaybackDevice);
}

const auto currentInputDevice = m_inputDeviceComboBox->currentText();
if (currentInputDevice == s_systemDefaultDevice)
{
// Represent the default input device with an empty string
ConfigManager::inst()->setValue(SectionSDL, InputDeviceSDL, "");
}
else if (!currentInputDevice.isEmpty())
{
ConfigManager::inst()->setValue(SectionSDL, InputDeviceSDL, currentInputDevice);
}
}

void AudioSdl::setupWidget::populatePlaybackDeviceComboBox()
{
#ifdef LMMS_HAVE_SDL2
m_playbackDeviceComboBox->addItem(s_systemDefaultDevice);

QStringList playbackDevices;
const int numberOfPlaybackDevices = SDL_GetNumAudioDevices(0);
for (int i = 0; i < numberOfPlaybackDevices; ++i)
{
const QString deviceName = SDL_GetAudioDeviceName(i, 0);
playbackDevices.append(deviceName);
}

playbackDevices.sort();

m_playbackDeviceComboBox->addItems(playbackDevices);

const auto playbackDevice = ConfigManager::inst()->value(SectionSDL, PlaybackDeviceSDL);
m_playbackDeviceComboBox->setCurrentText(playbackDevice.isEmpty() ? s_systemDefaultDevice : playbackDevice);
#endif
}

void AudioSdl::setupWidget::populateInputDeviceComboBox()
{
#ifdef LMMS_HAVE_SDL2
m_inputDeviceComboBox->addItem(s_systemDefaultDevice);

QStringList inputDevices;
const int numberOfInputDevices = SDL_GetNumAudioDevices(1);
for (int i = 0; i < numberOfInputDevices; ++i)
{
const QString deviceName = SDL_GetAudioDeviceName(i, 1);
inputDevices.append(deviceName);
}

inputDevices.sort();

m_inputDeviceComboBox->addItems(inputDevices);

// Set the current device to the one in the configuration
const auto inputDevice = ConfigManager::inst()->value(SectionSDL, InputDeviceSDL);
m_inputDeviceComboBox->setCurrentText(inputDevice.isEmpty() ? s_systemDefaultDevice : inputDevice);
#endif
}


Expand Down
Loading