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

add libsoundio audio backend #2339

Merged
merged 3 commits into from
Sep 14, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .travis/linux..before_install.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
sudo add-apt-repository ppa:kalakris/cmake -y;
sudo add-apt-repository ppa:andrewrk/libgroove -y;
if [ $QT5 ]
then
sudo add-apt-repository ppa:ubuntu-sdk-team/ppa -y
Expand Down
2 changes: 1 addition & 1 deletion .travis/linux..install.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PACKAGES="cmake libsndfile-dev fftw3-dev libvorbis-dev libogg-dev
libasound2-dev libjack-dev libsdl-dev libsamplerate0-dev libstk0-dev
libfluidsynth-dev portaudio19-dev wine-dev g++-multilib libfltk1.3-dev
libgig-dev"
libgig-dev libsoundio-dev"

if [ $QT5 ]
then
Expand Down
16 changes: 16 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ 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_SOUNDIO "Include libsoundio support" ON)
OPTION(WANT_SDL "Include SDL (Simple DirectMedia Layer) support" ON)
OPTION(WANT_SF2 "Include SoundFont2 player plugin" ON)
OPTION(WANT_GIG "Include GIG player plugin" ON)
Expand Down Expand Up @@ -260,6 +261,20 @@ IF(WANT_PORTAUDIO)
ENDIF(PORTAUDIO_FOUND)
ENDIF(WANT_PORTAUDIO)

# check for libsoundio
IF(WANT_SOUNDIO)
FIND_PACKAGE(SoundIo)
IF(SOUNDIO_FOUND)
SET(LMMS_HAVE_SOUNDIO TRUE)
SET(STATUS_SOUNDIO "OK")
INCLUDE_DIRECTORIES("${SOUNDIO_INCLUDE_DIR}")
Copy link
Member

Choose a reason for hiding this comment

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

Not sure how big of a deal this is, but all the other audio/midi backends configure their includes in /src/CMakeLists.txt instead of /CMakeLists.txt so as not to affect the building of plugins.

Copy link
Member Author

Choose a reason for hiding this comment

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

The first thing I tried was using PortAudio's CMake lines as a template but that lead to inability to build if the library is not installed. Instead of trying to figure out why that wasn't working, I opted to just do it how I do it in my own projects, since I know that will work.

Copy link
Member

Choose a reason for hiding this comment

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

Ok. Probably not a big deal - I wouldn't sink any time into changing that then.

Copy link
Member

Choose a reason for hiding this comment

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

The first thing I tried was using PortAudio's CMake lines as a template but that lead to inability to build if the library is not installed. Instead of trying to figure out why that wasn't working, I opted to just do it how I do it in my own projects, since I know that will work.

In regards to the CMakeLists lines, I'll be the odd man out and say I'd prefer we keep this consistent -- speaking less about where it should be but rather on behalf of the recent cleanup efforts.

From my experience, variable scope and order of operations is what seems to cause most CMakeLists.txt problems. At a glance, LMMS_REQUIRED_LIBS adds ${PORTAUDIO_LIBRARIES} to parent scope. In my experience, the PARENT_SCOPE related issues are usually the cause of ADD_SUBDIRECTORY headaches and this is because a local variable in cmake isn't exposed to its parent.

Anyway, happy to help. 👍

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not sure I understand what you're suggesting. I basically grepped for portaudio, copied all the cmake configuration, then replaced portudio with soundio. The only difference is the cmake/modules/Find*.cmake file, which I suspect is the culprit. But I'm sure that the FindSoundIo.cmake is OK and the PortAudio one looks complicated and not how I would do it.

Copy link
Member

Choose a reason for hiding this comment

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

grepped for portaudio, copied all the cmake configuration, then replaced portudio with soundio

That's what I get for only reading the comments. 😄

I see now that it's a single line... INCLUDE_DIRECTORIES. Did you clone the IF(NOT ("${PULSEAUDIO_INCLUDE_DIR}" STREQUAL "")) logic? Because if you don't define SOUNDIO_INCLUDE_DIR, you're better off doing an IF(WANT_SOUNDIO AND SOUNDIO_FOUND), right (in src/CMakeLists.txt that is)?

Edit: Hmm... I see you do define SOUNDIO_INCLUDE_DIR in FindSoundIo.cmake. I'm confused now too.

Copy link
Member Author

Choose a reason for hiding this comment

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

Did you clone the IF(NOT ("${PULSEAUDIO_INCLUDE_DIR}" STREQUAL "")) logic?

Yes I cloned that logic too.

ELSE(SOUNDIO_FOUND)
SET(SOUNDIO_INCLUDE_DIR "")
SET(STATUS_SOUNDIO "not found, please install libsoundio if you require libsoundio support")
SET(SOUNDIO_LIBRARY "")
ENDIF(SOUNDIO_FOUND)
ENDIF(WANT_SOUNDIO)


# check for PulseAudio
IF(WANT_PULSEAUDIO)
Expand Down Expand Up @@ -522,6 +537,7 @@ MESSAGE(
"* JACK : ${STATUS_JACK}\n"
"* OSS : ${STATUS_OSS}\n"
"* PortAudio : ${STATUS_PORTAUDIO}\n"
"* libsoundio : ${STATUS_SOUNDIO}\n"
"* PulseAudio : ${STATUS_PULSEAUDIO}\n"
"* SDL : ${STATUS_SDL}\n"
)
Expand Down
16 changes: 16 additions & 0 deletions cmake/modules/FindSoundIo.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copyright (c) 2015 Andrew Kelley
# This file is MIT licensed.
# See http://opensource.org/licenses/MIT

# SOUNDIO_FOUND
# SOUNDIO_INCLUDE_DIR
# SOUNDIO_LIBRARY

find_path(SOUNDIO_INCLUDE_DIR NAMES soundio/soundio.h)

find_library(SOUNDIO_LIBRARY NAMES soundio)

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(SOUNDIO DEFAULT_MSG SOUNDIO_LIBRARY SOUNDIO_INCLUDE_DIR)

mark_as_advanced(SOUNDIO_INCLUDE_DIR SOUNDIO_LIBRARY)
134 changes: 134 additions & 0 deletions include/AudioSoundIo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/*
* AudioSoundIo.h - device-class that performs PCM-output via libsoundio
*
* Copyright (c) 2015 Andrew Kelley <[email protected]>
*
* 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_SOUNDIO_H
#define AUDIO_SOUNDIO_H

#include <QtCore/QObject>

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

#ifdef LMMS_HAVE_SOUNDIO

#include <soundio/soundio.h>

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

class ComboBox;
class LcdSpinBox;

// Exists only to work around "Error: Meta object features not supported for nested classes"
class AudioSoundIoSetupUtil : public QObject
{
Q_OBJECT
public:
void *m_setupWidget;
public slots:
void updateDevices();
void reconnectSoundIo();
};

class AudioSoundIo : public AudioDevice
{
public:
AudioSoundIo( bool & _success_ful, Mixer* mixer );
virtual ~AudioSoundIo();

inline static QString name()
{
return QT_TRANSLATE_NOOP( "setupWidget", "soundio" );
}

class setupWidget : public AudioDeviceSetupWidget
{
public:
setupWidget( QWidget * _parent );
virtual ~setupWidget();

virtual void saveSettings();

void updateDevices();
void reconnectSoundIo();

private:

AudioSoundIoSetupUtil m_setupUtil;
ComboBox * m_backend;
ComboBox * m_device;

ComboBoxModel m_backendModel;
ComboBoxModel m_deviceModel;

SoundIo * m_soundio;

struct DeviceId {
QString id;
bool is_raw;
};
QList<DeviceId> m_deviceList;

int m_defaultOutIndex;
bool m_isFirst;

} ;

private:
virtual void startProcessing();
virtual void stopProcessing();

SoundIo *m_soundio;
SoundIoOutStream *m_outstream;

surroundSampleFrame * m_outBuf;
int m_outBufSize;
fpp_t m_outBufFramesTotal;
fpp_t m_outBufFrameIndex;

int m_disconnectErr;
void onBackendDisconnect(int err);

void writeCallback(int frame_count_min, int frame_count_max);
void errorCallback(int err);
void underflowCallback();

static void staticWriteCallback(SoundIoOutStream *outstream, int frame_count_min, int frame_count_max) {
return ((AudioSoundIo *)outstream->userdata)->writeCallback(frame_count_min, frame_count_max);
}
static void staticErrorCallback(SoundIoOutStream *outstream, int err) {
return ((AudioSoundIo *)outstream->userdata)->errorCallback(err);
}
static void staticUnderflowCallback(SoundIoOutStream *outstream) {
return ((AudioSoundIo *)outstream->userdata)->underflowCallback();
}
static void staticOnBackendDisconnect(SoundIo *soundio, int err) {
return ((AudioSoundIo *)soundio->userdata)->onBackendDisconnect(err);
}

};

#endif

#endif
2 changes: 2 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ SET(LMMS_REQUIRED_LIBS
${ASOUND_LIBRARY}
${SDL_LIBRARY}
${PORTAUDIO_LIBRARIES}
${SOUNDIO_LIBRARY}
${PULSEAUDIO_LIBRARIES}
${JACK_LIBRARIES}
${OGGVORBIS_LIBRARIES}
Expand Down Expand Up @@ -182,6 +183,7 @@ IF(LMMS_BUILD_WIN32)
"${MINGW_PREFIX}/bin/libfftw3f-3.dll"
"${MINGW_PREFIX}/bin/libFLAC-8.dll"
"${MINGW_PREFIX}/bin/libportaudio-2.dll"
"${MINGW_PREFIX}/bin/libsoundio.dll"
"${MINGW_PREFIX}/bin/libpng16-16.dll"
"${MINGW_PREFIX}/bin/SDL.dll"
"${MINGW_PREFIX}/bin/libglib-2.0-0.dll"
Expand Down
1 change: 1 addition & 0 deletions src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ set(LMMS_SRCS
core/audio/AudioOss.cpp
core/audio/AudioPort.cpp
core/audio/AudioPortAudio.cpp
core/audio/AudioSoundIo.cpp
core/audio/AudioPulseAudio.cpp
core/audio/AudioSampleRecorder.cpp
core/audio/AudioSdl.cpp
Expand Down
20 changes: 17 additions & 3 deletions src/core/Mixer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include "AudioJack.h"
#include "AudioOss.h"
#include "AudioPortAudio.h"
#include "AudioSoundIo.h"
#include "AudioPulseAudio.h"
#include "AudioSdl.h"
#include "AudioDummy.h"
Expand Down Expand Up @@ -220,11 +221,10 @@ void Mixer::stopProcessing()
if( m_fifoWriter != NULL )
{
m_fifoWriter->finish();
m_audioDev->stopProcessing();
m_fifoWriter->wait( 1000 );
m_fifoWriter->terminate();
m_fifoWriter->wait();
delete m_fifoWriter;
m_fifoWriter = NULL;
m_audioDev->stopProcessing();
}
else
{
Expand Down Expand Up @@ -831,6 +831,20 @@ AudioDevice * Mixer::tryAudioDevices()
#endif


#ifdef LMMS_HAVE_SOUNDIO
if( dev_name == AudioSoundIo::name() || dev_name == "" )
{
dev = new AudioSoundIo( success_ful, this );
if( success_ful )
{
m_audioDevName = AudioSoundIo::name();
return dev;
}
delete dev;
}
#endif


// add more device-classes here...
//dev = new audioXXXX( SAMPLE_RATES[m_qualityLevel], success_ful, this );
//if( sucess_ful )
Expand Down
Loading