From d1283bc54e004af80cd8a621fff913436d68510e Mon Sep 17 00:00:00 2001 From: Tobias Doerffel Date: Wed, 27 Aug 2008 13:51:39 +0000 Subject: [PATCH] added support for PortAudio git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/trunk/lmms@1507 0778d3d1-df1d-0410-868b-ea421aaaa00d --- CMakeLists.txt | 24 +- cmake/modules/FindPortaudio.cmake | 65 ++++ include/audio_portaudio.h | 119 ++++++++ lmmsconfig.h.in | 1 + src/core/audio/audio_portaudio.cpp | 472 +++++++++++++++++++++++++++++ src/gui/setup_dialog.cpp | 6 + 6 files changed, 684 insertions(+), 3 deletions(-) create mode 100644 cmake/modules/FindPortaudio.cmake create mode 100644 include/audio_portaudio.h create mode 100644 src/core/audio/audio_portaudio.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 650666bcf..53ef39695 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,6 +34,7 @@ OPTION(WANT_FFTW3F "Include SpectrumAnalyzer plugin" ON) OPTION(WANT_JACK "Include JACK (Jack Audio Connection Kit) support" ON) OPTION(WANT_OGGVORBIS "Include OGG/Vorbis support" ON) OPTION(WANT_PULSEAUDIO "Include PulseAudio support" ON) +OPTION(WANT_PORTAUDIO "Include PortAudio support" ON) OPTION(WANT_SDL "Include SDL (Simple DirectMedia Layer) support" ON) OPTION(WANT_SF2 "Include SoundFont2 player plugin" ON) OPTION(WANT_STK "Include Stk (Synthesis Toolkit) support" ON) @@ -150,6 +151,22 @@ IF(WANT_STK) ENDIF(WANT_STK) +# check for PortAudio +IF(WANT_PORTAUDIO) + FIND_PACKAGE(Portaudio) + IF(PORTAUDIO_FOUND) + SET(LMMS_HAVE_PORTAUDIO TRUE) + SET(STATUS_PORTAUDIO "OK") + ELSE(PORTAUDIO_FOUND) + SET(STATUS_PORTAUDIO "not found, please install portaudio19-dev (or similiar, version >= 1.9)") + ENDIF(PORTAUDIO_FOUND) +ENDIF(WANT_PORTAUDIO) +IF(NOT LMMS_HAVE_PORTAUDIO) + SET(PORTAUDIO_INCLUDE_DIR "") + SET(PORTAUDIO_LIBRARIES "") +ENDIF(NOT LMMS_HAVE_PORTAUDIO) + + # check for PulseAudio IF(WANT_PULSEAUDIO) FIND_PACKAGE(PulseAudio) @@ -343,11 +360,11 @@ ADD_SUBDIRECTORY(data) # # build LMMS-binary # -ADD_DEFINITIONS(-D'LIB_DIR="${CMAKE_INSTALL_PREFIX}/${LIB_DIR}/"' -D'PLUGIN_DIR="${CMAKE_INSTALL_PREFIX}/${LIB_DIR}/lmms/"' ${PULSEAUDIO_DEFINITIONS}) +ADD_DEFINITIONS(-D'LIB_DIR="${CMAKE_INSTALL_PREFIX}/${LIB_DIR}/"' -D'PLUGIN_DIR="${CMAKE_INSTALL_PREFIX}/${LIB_DIR}/lmms/"' ${PULSEAUDIO_DEFINITIONS} ${PORTAUDIO_DEFINITIONS}) -INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR} ${CMAKE_BINARY_DIR}/include ${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/include ${SDL_INCLUDE_DIR} ${PULSEAUDIO_INCLUDE_DIR} ${JACK_INCLUDE_DIRS} ${OGGVORBIS_INCLUDE_DIR} ${SAMPLERATE_INCLUDE_DIRS} ${SNDFILE_INCLUDE_DIRS}) +INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR} ${CMAKE_BINARY_DIR}/include ${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/include ${SDL_INCLUDE_DIR} ${PORTAUDIO_INCLUDE_DIR} ${PULSEAUDIO_INCLUDE_DIR} ${JACK_INCLUDE_DIRS} ${OGGVORBIS_INCLUDE_DIR} ${SAMPLERATE_INCLUDE_DIRS} ${SNDFILE_INCLUDE_DIRS}) LINK_DIRECTORIES(${CMAKE_INSTALL_PREFIX}/lib ${ASOUND_LIBRARY_DIR} ${JACK_LIBRARY_DIRS} ${SAMPLERATE_LIBRARY_DIRS} ${SNDFILE_LIBRARY_DIRS}) -LINK_LIBRARIES(${QT_LIBRARIES} ${ASOUND_LIBRARY} ${SDL_LIBRARY} ${PULSEAUDIO_LIBRARIES} ${JACK_LIBRARIES} ${OGGVORBIS_LIBRARIES} ${SAMPLERATE_LIBRARIES} ${SNDFILE_LIBRARIES}) +LINK_LIBRARIES(${QT_LIBRARIES} ${ASOUND_LIBRARY} ${SDL_LIBRARY} ${PORTAUDIO_LIBRARIES} ${PULSEAUDIO_LIBRARIES} ${JACK_LIBRARIES} ${OGGVORBIS_LIBRARIES} ${SAMPLERATE_LIBRARIES} ${SNDFILE_LIBRARIES}) ADD_EXECUTABLE(lmms ${lmms_SOURCES} ${lmms_INCLUDES} ${LIBSAMPLERATE_SOURCES} ${LMMS_ER_H} ${lmms_UI_out} lmmsconfig.h ${WINRC}) IF(LMMS_BUILD_WIN32) @@ -472,6 +489,7 @@ MESSAGE( "* ALSA : ${STATUS_ALSA}\n" "* JACK : ${STATUS_JACK}\n" "* OSS : ${STATUS_OSS}\n" +"* PortAudio : ${STATUS_PORTAUDIO}\n" "* PulseAudio : ${STATUS_PULSEAUDIO}\n" "* SDL : ${STATUS_SDL}\n" ) diff --git a/cmake/modules/FindPortaudio.cmake b/cmake/modules/FindPortaudio.cmake new file mode 100644 index 000000000..238a4b96e --- /dev/null +++ b/cmake/modules/FindPortaudio.cmake @@ -0,0 +1,65 @@ +# - Try to find Portaudio +# Once done this will define +# +# PORTAUDIO_FOUND - system has Portaudio +# PORTAUDIO_INCLUDE_DIRS - the Portaudio include directory +# PORTAUDIO_LIBRARIES - Link these to use Portaudio +# PORTAUDIO_DEFINITIONS - Compiler switches required for using Portaudio +# +# Copyright (c) 2006 Andreas Schneider +# +# Redistribution and use is allowed according to the terms of the New BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + + +if (PORTAUDIO_LIBRARIES AND PORTAUDIO_INCLUDE_DIRS) + # in cache already + set(PORTAUDIO_FOUND TRUE) +else (PORTAUDIO_LIBRARIES AND PORTAUDIO_INCLUDE_DIRS) + find_path(PORTAUDIO_INCLUDE_DIR + NAMES + portaudio.h + PATHS + /usr/include + /usr/local/include + /opt/local/include + /sw/include + ) + + find_library(PORTAUDIO_LIBRARY + NAMES + portaudio + PATHS + /usr/lib + /usr/local/lib + /opt/local/lib + /sw/lib + ) + + set(PORTAUDIO_INCLUDE_DIRS + ${PORTAUDIO_INCLUDE_DIR} + ) + set(PORTAUDIO_LIBRARIES + ${PORTAUDIO_LIBRARY} +) + + if (PORTAUDIO_INCLUDE_DIRS AND PORTAUDIO_LIBRARIES) + set(PORTAUDIO_FOUND TRUE) + endif (PORTAUDIO_INCLUDE_DIRS AND PORTAUDIO_LIBRARIES) + + if (PORTAUDIO_FOUND) + if (NOT Portaudio_FIND_QUIETLY) + message(STATUS "Found Portaudio: ${PORTAUDIO_LIBRARIES}") + endif (NOT Portaudio_FIND_QUIETLY) + else (PORTAUDIO_FOUND) + if (Portaudio_FIND_REQUIRED) + message(FATAL_ERROR "Could not find Portaudio") + endif (Portaudio_FIND_REQUIRED) + endif (PORTAUDIO_FOUND) + + # show the PORTAUDIO_INCLUDE_DIRS and PORTAUDIO_LIBRARIES variables only in the advanced view + mark_as_advanced(PORTAUDIO_INCLUDE_DIRS PORTAUDIO_LIBRARIES) + +endif (PORTAUDIO_LIBRARIES AND PORTAUDIO_INCLUDE_DIRS) + diff --git a/include/audio_portaudio.h b/include/audio_portaudio.h new file mode 100644 index 000000000..9f6c639ef --- /dev/null +++ b/include/audio_portaudio.h @@ -0,0 +1,119 @@ +/* + * audio_portaudio.h - device-class that performs PCM-output via PortAudio + * + * Copyright (c) 2008 Csaba Hruska + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * 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_PORTAUDIO_H +#define _AUDIO_PORTAUDIO_H + +#include + +#include "lmmsconfig.h" +#include "combobox_model.h" + +class audioPortAudioSetupUtil : public QObject +{ + Q_OBJECT +public slots: + void updateDevices( void ); + void updateChannels( void ); + +public: + comboBoxModel m_backendModel; + comboBoxModel m_deviceModel; +} ; + + +#ifdef LMMS_HAVE_PORTAUDIO + +#include + +#include "audio_device.h" + + +class comboBox; +class lcdSpinBox; + + +class audioPortAudio : public audioDevice +{ +public: + audioPortAudio( bool & _success_ful, mixer * _mixer ); + virtual ~audioPortAudio(); + + inline static QString name( void ) + { + return( QT_TRANSLATE_NOOP( "setupWidget", + "PortAudio" ) ); + } + + + int process_callback( const float *_inputBuffer, + float * _outputBuffer, + unsigned long _framesPerBuffer ); + + + class setupWidget : public audioDevice::setupWidget + { + public: + setupWidget( QWidget * _parent ); + virtual ~setupWidget(); + + virtual void saveSettings( void ); + + private: + comboBox * m_backend; + comboBox * m_device; + lcdSpinBox * m_channels; + audioPortAudioSetupUtil m_setupUtil; + + } ; + +private: + virtual void startProcessing( void ); + virtual void stopProcessing( void ); + virtual void applyQualitySettings( void ); + + static int _process_callback( const void *_inputBuffer, void *_outputBuffer, + unsigned long _framesPerBuffer, + const PaStreamCallbackTimeInfo* _timeInfo, + PaStreamCallbackFlags _statusFlags, + void *arg ); + + PaStream * m_paStream; + PaStreamParameters m_outputParameters; + PaStreamParameters m_inputParameters; + bool m_wasPAInitError; + + surroundSampleFrame * m_outBuf; + int m_outBuf_pos; + int m_outBuf_size; + + bool m_stopped; + QSemaphore m_stop_semaphore; + +} ; + +#endif + +#endif diff --git a/lmmsconfig.h.in b/lmmsconfig.h.in index d8bda7a72..9b31ece75 100644 --- a/lmmsconfig.h.in +++ b/lmmsconfig.h.in @@ -10,6 +10,7 @@ #cmakedefine LMMS_HAVE_JACK #cmakedefine LMMS_HAVE_OGGVORBIS #cmakedefine LMMS_HAVE_OSS +#cmakedefine LMMS_HAVE_PORTAUDIO #cmakedefine LMMS_HAVE_PULSEAUDIO #cmakedefine LMMS_HAVE_SDL #cmakedefine LMMS_HAVE_STK diff --git a/src/core/audio/audio_portaudio.cpp b/src/core/audio/audio_portaudio.cpp new file mode 100644 index 000000000..c27134285 --- /dev/null +++ b/src/core/audio/audio_portaudio.cpp @@ -0,0 +1,472 @@ +#ifndef SINGLE_SOURCE_COMPILE + +/* + * audio_portaudio.cpp - device-class that performs PCM-output via PortAudio + * + * Copyright (c) 2008 Csaba Hruska + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * 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 "audio_portaudio.h" + + +#ifndef LMMS_HAVE_PORTAUDIO +void audioPortAudioSetupUtil::updateDevices( void ) +{ +} + +void audioPortAudioSetupUtil::updateChannels( void ) +{ +} +#endif + +#ifdef LMMS_HAVE_PORTAUDIO + +#include +#include + +#include "engine.h" +#include "debug.h" +#include "config_mgr.h" +#include "gui_templates.h" +#include "templates.h" +#include "combobox.h" +#include "lcd_spinbox.h" + + + + +audioPortAudio::audioPortAudio( bool & _success_ful, mixer * _mixer ) : + audioDevice( tLimit( + configManager::inst()->value( "audioportaudio", "channels" ).toInt(), + DEFAULT_CHANNELS, SURROUND_CHANNELS ), + _mixer ), + m_outBuf( new surroundSampleFrame[getMixer()->framesPerPeriod()] ), + m_outBuf_pos( 0 ), + m_stop_semaphore( 1 ), + m_wasPAInitError( FALSE ) +{ + _success_ful = FALSE; + + m_outBuf_size = getMixer()->framesPerPeriod(); + + PaError err = Pa_Initialize(); + + if( err != paNoError ) { + printf( "Couldn't initialize PortAudio: %s\n", Pa_GetErrorText( err ) ); + 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; + const PaDeviceInfo * di; + for( int i = 0; i < Pa_GetDeviceCount(); ++i ) + { + di = Pa_GetDeviceInfo( i ); + if( di->name == device && + Pa_GetHostApiInfo( di->hostApi )->name == backend ) + { + inDevIdx = i; + outDevIdx = i; + } + } + + if( inDevIdx < 0 ) + { + inDevIdx = Pa_GetDefaultInputDevice(); + } + + if( outDevIdx < 0 ) + { + outDevIdx = Pa_GetDefaultOutputDevice(); + } + + double inLatency = (double)getMixer()->framesPerPeriod() / (double)sampleRate(); + double outLatency = (double)getMixer()->framesPerPeriod() / (double)sampleRate(); + + // FIXME: remove this + inLatency = Pa_GetDeviceInfo( inDevIdx )->defaultLowInputLatency; + outLatency = Pa_GetDeviceInfo( outDevIdx )->defaultLowOutputLatency; + int samples = qMax( 1024, (int)getMixer()->framesPerPeriod() ); + + // Configure output parameters. + m_outputParameters.device = outDevIdx; + m_outputParameters.channelCount = channels(); + m_outputParameters.sampleFormat = paFloat32; // 32 bit floating point output + m_outputParameters.suggestedLatency = inLatency; + m_outputParameters.hostApiSpecificStreamInfo = NULL; + + // Configure input parameters. + m_inputParameters.device = inDevIdx; + m_inputParameters.channelCount = DEFAULT_CHANNELS; + m_inputParameters.sampleFormat = paFloat32; // 32 bit floating point input + m_inputParameters.suggestedLatency = outLatency; + m_inputParameters.hostApiSpecificStreamInfo = NULL; + + // Open an audio I/O stream. + err = Pa_OpenStream( + &m_paStream, + &m_inputParameters, // The input parameter + &m_outputParameters, // The outputparameter + sampleRate(), + samples, + paNoFlag, // Don't use any flags + _process_callback, // our callback function + this ); + + if( err != paNoError ) + { + printf( "Couldn't open PortAudio: %s\n", Pa_GetErrorText( err ) ); + 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 ); + + m_stop_semaphore.acquire(); + + m_supportsCapture = TRUE; + _success_ful = TRUE; +} + + + + +audioPortAudio::~audioPortAudio() +{ + stopProcessing(); + m_stop_semaphore.release(); + + if( !m_wasPAInitError ) + { + Pa_Terminate(); + } + delete[] m_outBuf; +} + + + + +void audioPortAudio::startProcessing( void ) +{ + PaError err = Pa_StartStream( m_paStream ); + + if( err != paNoError ) + { + printf( "PortAudio error: %s\n", Pa_GetErrorText( err ) ); + return; + } + + m_stopped = FALSE; +} + + + + +void audioPortAudio::stopProcessing( void ) +{ + + if( Pa_IsStreamActive( m_paStream ) ) + { + m_stop_semaphore.acquire(); + + PaError err = Pa_CloseStream( m_paStream ); + + if( err != paNoError ) + { + printf( "PortAudio error: %s\n", Pa_GetErrorText( err ) ); + } + } +} + + + + +void audioPortAudio::applyQualitySettings( void ) +{ + if( hqAudio() ) + { + + setSampleRate( engine::getMixer()->processingSampleRate() ); + int samples = qMax( 1024, (int)getMixer()->framesPerPeriod() ); + + PaError err = Pa_OpenStream( + &m_paStream, + &m_inputParameters, // The input parameter + &m_outputParameters, // The outputparameter + sampleRate(), + samples, + paNoFlag, // Don't use any flags + _process_callback, // our callback function + this ); + + if( err != paNoError ) + { + printf( "Couldn't open PortAudio: %s\n", Pa_GetErrorText( err ) ); + return; + } + } + + audioDevice::applyQualitySettings(); +} + +int audioPortAudio::process_callback( + const float *_inputBuffer, + float * _outputBuffer, + unsigned long _framesPerBuffer ) +{ + getMixer()->pushInputFrames( (sampleFrame*)_inputBuffer, _framesPerBuffer ); + + if( m_stopped ) + { + memset( _outputBuffer, 0, _framesPerBuffer * + channels() * sizeof(float) ); + return 0; + } + + while( _framesPerBuffer ) + { + if( m_outBuf_pos == 0 ) + { + // frames depend on the sample rate + const fpp_t frames = getNextBuffer( m_outBuf ); + if( !frames ) + { + m_stopped = TRUE; + m_stop_semaphore.release(); + memset( _outputBuffer, 0, _framesPerBuffer * + channels() * sizeof(float) ); + return 0; + } + m_outBuf_size = frames; + } + const int min_len = tMin( (int)_framesPerBuffer, + m_outBuf_size - m_outBuf_pos ); + + float master_gain = getMixer()->masterGain(); + + for( fpp_t frame = 0; frame < min_len; ++frame ) + { + for( ch_cnt_t chnl = 0; chnl < channels(); ++chnl ) + { + ( _outputBuffer + frame * channels() )[chnl] = + mixer::clip( m_outBuf[frame][chnl] * + master_gain ); + } + } + + _outputBuffer += min_len * channels(); + _framesPerBuffer -= min_len; + m_outBuf_pos += min_len; + m_outBuf_pos %= m_outBuf_size; + } + +} + + + +int audioPortAudio::_process_callback( + const void *_inputBuffer, + void * _outputBuffer, + unsigned long _framesPerBuffer, + const PaStreamCallbackTimeInfo * _timeInfo, + PaStreamCallbackFlags _statusFlags, + void * _arg ) +{ + Q_UNUSED(_timeInfo); + Q_UNUSED(_statusFlags); + + audioPortAudio * _this = static_cast (_arg); + _this->process_callback( (const float*)_inputBuffer, + (float*)_outputBuffer, _framesPerBuffer ); + + return 0; +} + + + + +void audioPortAudioSetupUtil::updateDevices( void ) +{ + PaError err = Pa_Initialize(); + if( err != paNoError ) { + printf( "Couldn't initialize PortAudio: %s\n", Pa_GetErrorText( err ) ); + return; + } + // get active backend + const QString& backend = m_backendModel.currentText(); + int hostApi = 0; + const PaHostApiInfo * hi; + for( int i = 0; i < Pa_GetHostApiCount(); ++i ) + { + hi = Pa_GetHostApiInfo( i ); + if( backend == hi->name ) + { + hostApi = i; + break; + } + } + + // get devices for selected backend + m_deviceModel.clear(); + const PaDeviceInfo * di; + for( int i = 0; i < Pa_GetDeviceCount(); ++i ) + { + di = Pa_GetDeviceInfo( i ); + if( di->hostApi == hostApi ) + { + m_deviceModel.addItem( di->name ); + } + } + Pa_Terminate(); +} + + + + +void audioPortAudioSetupUtil::updateChannels( void ) +{ + PaError err = Pa_Initialize(); + if( err != paNoError ) { + printf( "Couldn't initialize PortAudio: %s\n", Pa_GetErrorText( err ) ); + return; + } + // get active backend + Pa_Terminate(); +} + + + + +audioPortAudio::setupWidget::setupWidget( QWidget * _parent ) : + audioDevice::setupWidget( audioPortAudio::name(), _parent ) +{ + m_backend = new comboBox( this, "BACKEND" ); + m_backend->setGeometry( 52, 15, 120, 20 ); + + QLabel * backend_lbl = new QLabel( tr( "BACKEND" ), this ); + backend_lbl->setFont( pointSize<6>( backend_lbl->font() ) ); + backend_lbl->move( 10, 17 ); + + m_device = new comboBox( this, "DEVICE" ); + m_device->setGeometry( 52, 35, 250, 20 ); + + QLabel * dev_lbl = new QLabel( tr( "DEVICE" ), this ); + dev_lbl->setFont( pointSize<6>( dev_lbl->font() ) ); + dev_lbl->move( 10, 37 ); + + lcdSpinBoxModel * m = new lcdSpinBoxModel( ); + m->setRange( DEFAULT_CHANNELS, SURROUND_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 ); + + // Setup models + PaError err = Pa_Initialize(); + if( err != paNoError ) { + printf( "Couldn't initialize PortAudio: %s\n", Pa_GetErrorText( err ) ); + return; + } + + // todo: setup backend model + const PaHostApiInfo * hi; + for( int i = 0; i < Pa_GetHostApiCount(); ++i ) + { + hi = Pa_GetHostApiInfo( i ); + m_setupUtil.m_backendModel.addItem( hi->name ); + } + + Pa_Terminate(); + + + const QString& backend = configManager::inst()->value( "audioportaudio", + "backend" ); + const QString& device = configManager::inst()->value( "audioportaudio", + "device" ); + + int i = tMax( 0, m_setupUtil.m_backendModel.findText( backend ) ); + m_setupUtil.m_backendModel.setValue( i ); + + m_setupUtil.updateDevices(); + + i = tMax( 0, m_setupUtil.m_deviceModel.findText( device ) ); + m_setupUtil.m_deviceModel.setValue( i ); + + 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 ); +} + + + + +audioPortAudio::setupWidget::~setupWidget() +{ + disconnect( &m_setupUtil.m_backendModel, SIGNAL( dataChanged() ), + &m_setupUtil, SLOT( updateDevices() ) ); + + disconnect( &m_setupUtil.m_deviceModel, SIGNAL( dataChanged() ), + &m_setupUtil, SLOT( updateChannels() ) ); +} + + + + +void audioPortAudio::setupWidget::saveSettings( void ) +{ + + 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() ) ); + +} + + +#endif + +#include "moc_audio_portaudio.cxx" + +#endif diff --git a/src/gui/setup_dialog.cpp b/src/gui/setup_dialog.cpp index 6f8873bfc..669522f23 100644 --- a/src/gui/setup_dialog.cpp +++ b/src/gui/setup_dialog.cpp @@ -55,6 +55,7 @@ #include "audio_alsa.h" #include "audio_jack.h" #include "audio_oss.h" +#include "audio_portaudio.h" #include "audio_pulseaudio.h" #include "audio_sdl.h" #include "audio_dummy.h" @@ -455,6 +456,11 @@ setupDialog::setupDialog( ConfigTabs _tab_to_open ) : new audioPulseAudio::setupWidget( asw ); #endif +#ifdef LMMS_HAVE_PORTAUDIO + m_audioIfaceSetupWidgets[audioPortAudio::name()] = + new audioPortAudio::setupWidget( asw ); +#endif + #ifdef LMMS_HAVE_SDL m_audioIfaceSetupWidgets[audioSDL::name()] = new audioSDL::setupWidget( asw );