Merge pull request #2135 from michaelgregorius/alsa-combobox

Partial fix for #1600: ALSA device can be selected using a combo box
This commit is contained in:
Colin Wallace
2015-08-26 03:21:48 +00:00
21 changed files with 378 additions and 107 deletions

View File

@@ -37,12 +37,33 @@
#include "AudioDevice.h"
class LcdSpinBox;
class QLineEdit;
class AudioAlsa : public AudioDevice, public QThread
{
// Public classes and enums
public:
/**
* @brief Contains the relevant information about available ALSA devices
*/
class DeviceInfo
{
public:
DeviceInfo(QString const & deviceName, QString const & deviceDescription) :
m_deviceName(deviceName),
m_deviceDescription(deviceDescription)
{}
~DeviceInfo() {}
QString const & getDeviceName() const { return m_deviceName; }
QString const & getDeviceDescription() const { return m_deviceDescription; }
private:
QString m_deviceName;
QString m_deviceDescription;
};
typedef std::vector<DeviceInfo> DeviceInfoCollection;
public:
AudioAlsa( bool & _success_ful, Mixer* mixer );
virtual ~AudioAlsa();
@@ -55,21 +76,7 @@ public:
static QString probeDevice();
class setupWidget : public AudioDevice::setupWidget
{
public:
setupWidget( QWidget * _parent );
virtual ~setupWidget();
virtual void saveSettings();
private:
QLineEdit * m_device;
LcdSpinBox * m_channels;
} ;
static DeviceInfoCollection getAvailableDevices();
private:
virtual void startProcessing();

View File

@@ -0,0 +1,64 @@
/*
* AudioAlsaSetupWidget.h - Implements a setup widget for ALSA-PCM-output
*
* Copyright (c) 2004-2015 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of LMMS - http://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#ifndef AUDIO_ALSA_SETUP_WIDGET_H
#define AUDIO_ALSA_SETUP_WIDGET_H
#include "lmmsconfig.h"
#ifdef LMMS_HAVE_ALSA
#include "AudioDeviceSetupWidget.h"
#include "AudioAlsa.h"
class QComboBox;
class LcdSpinBox;
class AudioAlsaSetupWidget : public AudioDeviceSetupWidget
{
Q_OBJECT
public:
AudioAlsaSetupWidget( QWidget * _parent );
virtual ~AudioAlsaSetupWidget();
virtual void saveSettings();
public slots:
void onCurrentIndexChanged(int index);
private:
QComboBox * m_deviceComboBox;
LcdSpinBox * m_channels;
int m_selectedDevice;
AudioAlsa::DeviceInfoCollection m_deviceInfos;
};
#endif
#endif

View File

@@ -90,32 +90,6 @@ public:
class setupWidget : public TabWidget
{
public:
setupWidget( const QString & _caption, QWidget * _parent ) :
TabWidget( TabWidget::tr( "Settings for %1" ).arg(
TabWidget::tr( _caption.toLatin1() ) ).
toUpper(), _parent )
{
}
virtual ~setupWidget()
{
}
virtual void saveSettings() = 0;
virtual void show()
{
parentWidget()->show();
QWidget::show();
}
} ;
protected:
// subclasses can re-implement this for being used in conjunction with
// processNextBuffer()

View File

@@ -0,0 +1,44 @@
/*
* AudioDeviceSetupWidget.h - Base class for audio device setup widgets
*
* Copyright (c) 2004-2015 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of LMMS - http://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#ifndef AUDIO_DEVICE_SETUP_WIDGET_H
#define AUDIO_DEVICE_SETUP_WIDGET_H
#include "TabWidget.h"
class AudioDeviceSetupWidget : public TabWidget
{
public:
AudioDeviceSetupWidget( const QString & _caption, QWidget * _parent );
virtual ~AudioDeviceSetupWidget();
virtual void saveSettings() = 0;
virtual void show();
};
#endif

View File

@@ -26,6 +26,7 @@
#define AUDIO_DUMMY_H
#include "AudioDevice.h"
#include "AudioDeviceSetupWidget.h"
#include "MicroTimer.h"
@@ -49,11 +50,11 @@ public:
}
class setupWidget : public AudioDevice::setupWidget
class setupWidget : public AudioDeviceSetupWidget
{
public:
setupWidget( QWidget * _parent ) :
AudioDevice::setupWidget( AudioDummy::name(), _parent )
AudioDeviceSetupWidget( AudioDummy::name(), _parent )
{
}

View File

@@ -35,6 +35,7 @@
#include <QtCore/QMap>
#include "AudioDevice.h"
#include "AudioDeviceSetupWidget.h"
class QLineEdit;
@@ -55,7 +56,7 @@ public:
}
class setupWidget : public AudioDevice::setupWidget
class setupWidget : public AudioDeviceSetupWidget
{
public:
setupWidget( QWidget * _parent );

View File

@@ -30,6 +30,7 @@
#ifdef LMMS_HAVE_OSS
#include "AudioDevice.h"
#include "AudioDeviceSetupWidget.h"
class LcdSpinBox;
@@ -50,7 +51,7 @@ public:
static QString probeDevice();
class setupWidget : public AudioDevice::setupWidget
class setupWidget : public AudioDeviceSetupWidget
{
public:
setupWidget( QWidget * _parent );

View File

@@ -52,6 +52,7 @@ public:
#endif
#include "AudioDevice.h"
#include "AudioDeviceSetupWidget.h"
#if defined paNeverDropInput || defined paNonInterleaved
# define PORTAUDIO_V19
@@ -81,7 +82,7 @@ public:
unsigned long _framesPerBuffer );
class setupWidget : public AudioDevice::setupWidget
class setupWidget : public AudioDeviceSetupWidget
{
public:
setupWidget( QWidget * _parent );

View File

@@ -32,6 +32,7 @@
#include <pulse/pulseaudio.h>
#include "AudioDevice.h"
#include "AudioDeviceSetupWidget.h"
class LcdSpinBox;
@@ -52,7 +53,7 @@ public:
static QString probeDevice();
class setupWidget : public AudioDevice::setupWidget
class setupWidget : public AudioDeviceSetupWidget
{
public:
setupWidget( QWidget * _parent );

View File

@@ -33,6 +33,7 @@
#include <SDL/SDL_audio.h>
#include "AudioDevice.h"
#include "AudioDeviceSetupWidget.h"
class QLineEdit;
@@ -50,7 +51,7 @@ public:
}
class setupWidget : public AudioDevice::setupWidget
class setupWidget : public AudioDeviceSetupWidget
{
public:
setupWidget( QWidget * _parent );

View File

@@ -33,6 +33,8 @@
#include "AudioDevice.h"
#include "MidiClient.h"
#include "AudioDeviceSetupWidget.h"
class QComboBox;
class QLabel;
@@ -178,7 +180,7 @@ private:
bool m_displayWaveform;
bool m_disableAutoQuit;
typedef QMap<QString, AudioDevice::setupWidget *> AswMap;
typedef QMap<QString, AudioDeviceSetupWidget *> AswMap;
typedef QMap<QString, MidiClient::setupWidget *> MswMap;
typedef QMap<QString, QString> trMap;

View File

@@ -22,6 +22,7 @@
*
*/
#include <QComboBox>
#include <QLineEdit>
#include <QLabel>
@@ -36,6 +37,8 @@
#include "gui_templates.h"
#include "templates.h"
#include <iostream>
#include <vector>
AudioAlsa::AudioAlsa( bool & _success_ful, Mixer* _mixer ) :
@@ -139,6 +142,59 @@ QString AudioAlsa::probeDevice()
/**
* @brief Creates a list of all available devices.
*
* Uses the hints API of ALSA to collect all devices. This also includes plug
* devices. The reason to collect these and not the raw hardware devices
* (e.g. hw:0,0) is that hardware devices often have a very limited number of
* supported formats, etc. Plugs on the other hand are software components that
* map all types of formats and inputs to the hardware and therefore they are
* much more flexible and more what we want.
*
* Further helpful info http://jan.newmarch.name/LinuxSound/Sampled/Alsa/.
*
* @return A collection of devices found on the system.
*/
AudioAlsa::DeviceInfoCollection AudioAlsa::getAvailableDevices()
{
DeviceInfoCollection deviceInfos;
char **hints;
/* Enumerate sound devices */
int err = snd_device_name_hint(-1, "pcm", (void***)&hints);
if (err != 0)
{
return deviceInfos;
}
char** n = hints;
while (*n != NULL)
{
char *name = snd_device_name_get_hint(*n, "NAME");
char *description = snd_device_name_get_hint(*n, "DESC");
if (name != 0 && description != 0)
{
deviceInfos.push_back(DeviceInfo(QString(name), QString(description)));
}
free(name);
free(description);
n++;
}
//Free the hint buffer
snd_device_name_free_hint((void**)hints);
return deviceInfos;
}
int AudioAlsa::handleError( int _err )
{
if( _err == -EPIPE )
@@ -491,52 +547,4 @@ int AudioAlsa::setSWParams()
return 0; // all ok
}
AudioAlsa::setupWidget::setupWidget( QWidget * _parent ) :
AudioDevice::setupWidget( AudioAlsa::name(), _parent )
{
m_device = new QLineEdit( AudioAlsa::probeDevice(), this );
m_device->setGeometry( 10, 20, 160, 20 );
QLabel * dev_lbl = new QLabel( tr( "DEVICE" ), this );
dev_lbl->setFont( pointSize<7>( dev_lbl->font() ) );
dev_lbl->setGeometry( 10, 40, 160, 10 );
LcdSpinBoxModel * m = new LcdSpinBoxModel( /* this */ );
m->setRange( DEFAULT_CHANNELS, SURROUND_CHANNELS );
m->setStep( 2 );
m->setValue( ConfigManager::inst()->value( "audioalsa",
"channels" ).toInt() );
m_channels = new LcdSpinBox( 1, this );
m_channels->setModel( m );
m_channels->setLabel( tr( "CHANNELS" ) );
m_channels->move( 180, 20 );
}
AudioAlsa::setupWidget::~setupWidget()
{
delete m_channels->model();
}
void AudioAlsa::setupWidget::saveSettings()
{
ConfigManager::inst()->setValue( "audioalsa", "device",
m_device->text() );
ConfigManager::inst()->setValue( "audioalsa", "channels",
QString::number( m_channels->value<int>() ) );
}
#endif

View File

@@ -425,7 +425,7 @@ void AudioJack::shutdownCallback( void * _udata )
AudioJack::setupWidget::setupWidget( QWidget * _parent ) :
AudioDevice::setupWidget( AudioJack::name(), _parent )
AudioDeviceSetupWidget( AudioJack::name(), _parent )
{
QString cn = ConfigManager::inst()->value( "audiojack", "clientname" );
if( cn.isEmpty() )

View File

@@ -329,7 +329,7 @@ void AudioOss::run()
AudioOss::setupWidget::setupWidget( QWidget * _parent ) :
AudioDevice::setupWidget( AudioOss::name(), _parent )
AudioDeviceSetupWidget( AudioOss::name(), _parent )
{
m_device = new QLineEdit( probeDevice(), this );
m_device->setGeometry( 10, 20, 160, 20 );

View File

@@ -389,7 +389,7 @@ void AudioPortAudioSetupUtil::updateChannels()
AudioPortAudio::setupWidget::setupWidget( QWidget * _parent ) :
AudioDevice::setupWidget( AudioPortAudio::name(), _parent )
AudioDeviceSetupWidget( AudioPortAudio::name(), _parent )
{
m_backend = new ComboBox( this, "BACKEND" );
m_backend->setGeometry( 64, 15, 260, 20 );

View File

@@ -280,7 +280,7 @@ void AudioPulseAudio::streamWriteCallback( pa_stream *s, size_t length )
AudioPulseAudio::setupWidget::setupWidget( QWidget * _parent ) :
AudioDevice::setupWidget( AudioPulseAudio::name(), _parent )
AudioDeviceSetupWidget( AudioPulseAudio::name(), _parent )
{
m_device = new QLineEdit( AudioPulseAudio::probeDevice(), this );
m_device->setGeometry( 10, 20, 160, 20 );

View File

@@ -203,7 +203,7 @@ void AudioSdl::sdlAudioCallback( Uint8 * _buf, int _len )
AudioSdl::setupWidget::setupWidget( QWidget * _parent ) :
AudioDevice::setupWidget( AudioSdl::name(), _parent )
AudioDeviceSetupWidget( AudioSdl::name(), _parent )
{
QString dev = ConfigManager::inst()->value( "audiosdl", "device" );
m_device = new QLineEdit( dev, this );

View File

@@ -0,0 +1,122 @@
/*
* AudioAlsaSetupWidget.cpp - Implements a setup widget for ALSA-PCM-output
*
* Copyright (c) 2004-2015 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of LMMS - http://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#include <QComboBox>
#include <QLabel>
#include "AudioAlsaSetupWidget.h"
#ifdef LMMS_HAVE_ALSA
#include "ConfigManager.h"
#include "LcdSpinBox.h"
#include "gui_templates.h"
#include <iostream>
AudioAlsaSetupWidget::AudioAlsaSetupWidget( QWidget * _parent ) :
AudioDeviceSetupWidget( AudioAlsa::name(), _parent ),
m_selectedDevice(-1)
{
m_deviceInfos = AudioAlsa::getAvailableDevices();
QString deviceText = ConfigManager::inst()->value( "audioalsa", "device" );
m_deviceComboBox = new QComboBox(this);
for (size_t i = 0; i < m_deviceInfos.size(); ++i)
{
AudioAlsa::DeviceInfo const & currentDeviceInfo = m_deviceInfos[i];
QString comboBoxText = currentDeviceInfo.getDeviceName();
m_deviceComboBox->addItem(comboBoxText, QVariant(static_cast<uint>(i)));
QString toolTipText = currentDeviceInfo.getDeviceDescription();
m_deviceComboBox->setItemData(i, toolTipText, Qt::ToolTipRole);
if (currentDeviceInfo.getDeviceName() == deviceText)
{
m_deviceComboBox->setCurrentIndex(static_cast<int>(i));
}
}
m_selectedDevice = m_deviceComboBox->currentIndex();
m_deviceComboBox->setGeometry( 10, 20, 160, 20 );
connect(m_deviceComboBox,
SIGNAL(currentIndexChanged(int)),
SLOT(onCurrentIndexChanged(int)));
QLabel * dev_lbl = new QLabel( tr( "DEVICE" ), this );
dev_lbl->setFont( pointSize<7>( dev_lbl->font() ) );
dev_lbl->setGeometry( 10, 40, 160, 10 );
LcdSpinBoxModel * m = new LcdSpinBoxModel( /* this */ );
m->setRange( DEFAULT_CHANNELS, SURROUND_CHANNELS );
m->setStep( 2 );
m->setValue( ConfigManager::inst()->value( "audioalsa",
"channels" ).toInt() );
m_channels = new LcdSpinBox( 1, this );
m_channels->setModel( m );
m_channels->setLabel( tr( "CHANNELS" ) );
m_channels->move( 180, 20 );
}
AudioAlsaSetupWidget::~AudioAlsaSetupWidget()
{
delete m_channels->model();
}
void AudioAlsaSetupWidget::saveSettings()
{
QString deviceText;
if (m_selectedDevice != -1)
{
AudioAlsa::DeviceInfo const & selectedDevice = m_deviceInfos[m_selectedDevice];
deviceText = selectedDevice.getDeviceName();
}
ConfigManager::inst()->setValue( "audioalsa", "device", deviceText );
ConfigManager::inst()->setValue( "audioalsa", "channels",
QString::number( m_channels->value<int>() ) );
}
void AudioAlsaSetupWidget::onCurrentIndexChanged(int index)
{
m_selectedDevice = index;
}
#endif

View File

@@ -0,0 +1,41 @@
/*
* AudioDeviceSetupWidget.cpp - Base class for audio device setup widgets
*
* Copyright (c) 2004-2015 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of LMMS - http://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#include "AudioDeviceSetupWidget.h"
AudioDeviceSetupWidget::AudioDeviceSetupWidget( const QString & _caption, QWidget * _parent ) :
TabWidget( TabWidget::tr( "Settings for %1" ).arg(TabWidget::tr( _caption.toLatin1() ) ).toUpper(),
_parent )
{
}
AudioDeviceSetupWidget::~AudioDeviceSetupWidget()
{
}
void AudioDeviceSetupWidget::show()
{
parentWidget()->show();
QWidget::show();
}

View File

@@ -2,6 +2,8 @@ SET(LMMS_SRCS
${LMMS_SRCS}
gui/AboutDialog.cpp
gui/ActionGroup.cpp
gui/AudioAlsaSetupWidget.cpp
gui/AudioDeviceSetupWidget.cpp
gui/AutomatableModelView.cpp
gui/AutomationPatternView.cpp
gui/ControllerConnectionDialog.cpp

View File

@@ -51,6 +51,7 @@
// platform-specific audio-interface-classes
#include "AudioAlsa.h"
#include "AudioAlsaSetupWidget.h"
#include "AudioJack.h"
#include "AudioOss.h"
#include "AudioPortAudio.h"
@@ -720,7 +721,7 @@ SetupDialog::SetupDialog( ConfigTabs _tab_to_open ) :
#ifdef LMMS_HAVE_ALSA
m_audioIfaceSetupWidgets[AudioAlsa::name()] =
new AudioAlsa::setupWidget( asw );
new AudioAlsaSetupWidget( asw );
#endif
#ifdef LMMS_HAVE_PULSEAUDIO