diff --git a/include/AudioAlsa.h b/include/AudioAlsa.h index 88438a105..570b86005 100644 --- a/include/AudioAlsa.h +++ b/include/AudioAlsa.h @@ -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 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(); diff --git a/include/AudioAlsaSetupWidget.h b/include/AudioAlsaSetupWidget.h new file mode 100644 index 000000000..304870f22 --- /dev/null +++ b/include/AudioAlsaSetupWidget.h @@ -0,0 +1,64 @@ +/* + * AudioAlsaSetupWidget.h - Implements a setup widget for ALSA-PCM-output + * + * Copyright (c) 2004-2015 Tobias Doerffel + * + * 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 diff --git a/include/AudioDevice.h b/include/AudioDevice.h index 298279ddb..0782035b7 100644 --- a/include/AudioDevice.h +++ b/include/AudioDevice.h @@ -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() diff --git a/include/AudioDeviceSetupWidget.h b/include/AudioDeviceSetupWidget.h new file mode 100644 index 000000000..6e23b3153 --- /dev/null +++ b/include/AudioDeviceSetupWidget.h @@ -0,0 +1,44 @@ +/* + * AudioDeviceSetupWidget.h - Base class for audio device setup widgets + * + * Copyright (c) 2004-2015 Tobias Doerffel + * + * 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 diff --git a/include/AudioDummy.h b/include/AudioDummy.h index 31781e049..993dbccae 100644 --- a/include/AudioDummy.h +++ b/include/AudioDummy.h @@ -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 ) { } diff --git a/include/AudioJack.h b/include/AudioJack.h index 35801ef03..ec4fc5819 100644 --- a/include/AudioJack.h +++ b/include/AudioJack.h @@ -35,6 +35,7 @@ #include #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 ); diff --git a/include/AudioOss.h b/include/AudioOss.h index b40edd58e..76dbeecb8 100644 --- a/include/AudioOss.h +++ b/include/AudioOss.h @@ -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 ); diff --git a/include/AudioPortAudio.h b/include/AudioPortAudio.h index a52ba52be..ab9be60c1 100644 --- a/include/AudioPortAudio.h +++ b/include/AudioPortAudio.h @@ -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 ); diff --git a/include/AudioPulseAudio.h b/include/AudioPulseAudio.h index 5a8504d1f..fc2f77bd4 100644 --- a/include/AudioPulseAudio.h +++ b/include/AudioPulseAudio.h @@ -32,6 +32,7 @@ #include #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 ); diff --git a/include/AudioSdl.h b/include/AudioSdl.h index 15facb52a..ba2f09faa 100644 --- a/include/AudioSdl.h +++ b/include/AudioSdl.h @@ -33,6 +33,7 @@ #include #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 ); diff --git a/include/SetupDialog.h b/include/SetupDialog.h index 3357bf54c..d5e1b6e57 100644 --- a/include/SetupDialog.h +++ b/include/SetupDialog.h @@ -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 AswMap; + typedef QMap AswMap; typedef QMap MswMap; typedef QMap trMap; diff --git a/src/core/audio/AudioAlsa.cpp b/src/core/audio/AudioAlsa.cpp index 240674bce..e903b436c 100644 --- a/src/core/audio/AudioAlsa.cpp +++ b/src/core/audio/AudioAlsa.cpp @@ -22,6 +22,7 @@ * */ +#include #include #include @@ -36,6 +37,8 @@ #include "gui_templates.h" #include "templates.h" +#include +#include 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() ) ); -} - - #endif - diff --git a/src/core/audio/AudioJack.cpp b/src/core/audio/AudioJack.cpp index b491ea826..137c5b445 100644 --- a/src/core/audio/AudioJack.cpp +++ b/src/core/audio/AudioJack.cpp @@ -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() ) diff --git a/src/core/audio/AudioOss.cpp b/src/core/audio/AudioOss.cpp index f280da0f9..4a92b3cf5 100644 --- a/src/core/audio/AudioOss.cpp +++ b/src/core/audio/AudioOss.cpp @@ -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 ); diff --git a/src/core/audio/AudioPortAudio.cpp b/src/core/audio/AudioPortAudio.cpp index d23baf277..b2ddf1d97 100644 --- a/src/core/audio/AudioPortAudio.cpp +++ b/src/core/audio/AudioPortAudio.cpp @@ -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 ); diff --git a/src/core/audio/AudioPulseAudio.cpp b/src/core/audio/AudioPulseAudio.cpp index a1d1e740f..4463bab8a 100644 --- a/src/core/audio/AudioPulseAudio.cpp +++ b/src/core/audio/AudioPulseAudio.cpp @@ -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 ); diff --git a/src/core/audio/AudioSdl.cpp b/src/core/audio/AudioSdl.cpp index 6285b4d4b..4587a61f3 100644 --- a/src/core/audio/AudioSdl.cpp +++ b/src/core/audio/AudioSdl.cpp @@ -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 ); diff --git a/src/gui/AudioAlsaSetupWidget.cpp b/src/gui/AudioAlsaSetupWidget.cpp new file mode 100644 index 000000000..43fe828f3 --- /dev/null +++ b/src/gui/AudioAlsaSetupWidget.cpp @@ -0,0 +1,122 @@ +/* + * AudioAlsaSetupWidget.cpp - Implements a setup widget for ALSA-PCM-output + * + * Copyright (c) 2004-2015 Tobias Doerffel + * + * 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 +#include + +#include "AudioAlsaSetupWidget.h" + +#ifdef LMMS_HAVE_ALSA + +#include "ConfigManager.h" +#include "LcdSpinBox.h" +#include "gui_templates.h" + +#include + + + +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(i))); + + QString toolTipText = currentDeviceInfo.getDeviceDescription(); + m_deviceComboBox->setItemData(i, toolTipText, Qt::ToolTipRole); + + if (currentDeviceInfo.getDeviceName() == deviceText) + { + m_deviceComboBox->setCurrentIndex(static_cast(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() ) ); +} + + + +void AudioAlsaSetupWidget::onCurrentIndexChanged(int index) +{ + m_selectedDevice = index; +} + + +#endif diff --git a/src/gui/AudioDeviceSetupWidget.cpp b/src/gui/AudioDeviceSetupWidget.cpp new file mode 100644 index 000000000..85515aab9 --- /dev/null +++ b/src/gui/AudioDeviceSetupWidget.cpp @@ -0,0 +1,41 @@ +/* + * AudioDeviceSetupWidget.cpp - Base class for audio device setup widgets + * + * Copyright (c) 2004-2015 Tobias Doerffel + * + * 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(); +} diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 4cbf4013b..a5897adf9 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -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 diff --git a/src/gui/SetupDialog.cpp b/src/gui/SetupDialog.cpp index e93db546e..1006c84a3 100644 --- a/src/gui/SetupDialog.cpp +++ b/src/gui/SetupDialog.cpp @@ -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