Skip to content

Commit

Permalink
Add libao audio driver
Browse files Browse the repository at this point in the history
It serves as example for output using threaded generic audio
  • Loading branch information
carstene1ns committed May 25, 2024
1 parent 8b52d67 commit b55c906
Show file tree
Hide file tree
Showing 6 changed files with 168 additions and 22 deletions.
50 changes: 32 additions & 18 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS ON)

# Must be at global scope, otherwise breaks -DPLAYER_BUILD_LIBLCF (see CMP0077)
option(BUILD_SHARED_LIBS "Build shared easyrpg_libretro core" ON)
option(BUILD_SHARED_LIBS "Build shared libary, e.g. easyrpg_libretro core" ON)

option(CMAKE_FIND_PACKAGE_PREFER_CONFIG "Prefer config files over bundled FindXXX files. Set this to OFF when configuration fails and report a bug." ON)

Expand Down Expand Up @@ -551,8 +551,6 @@ endif()

if(${PLAYER_TARGET_PLATFORM} STREQUAL "SDL2")
target_sources(${PROJECT_NAME} PRIVATE
src/platform/sdl/sdl_audio.cpp
src/platform/sdl/sdl_audio.h
src/platform/sdl/sdl2_ui.cpp
src/platform/sdl/sdl2_ui.h)
target_compile_definitions(${PROJECT_NAME} PUBLIC USE_SDL=2)
Expand Down Expand Up @@ -886,31 +884,45 @@ player_find_package(NAME lhasa

# Sound system to use
if(${PLAYER_TARGET_PLATFORM} STREQUAL "SDL2")
set(PLAYER_AUDIO_BACKEND "SDL2" CACHE STRING "Audio system to use. Options: SDL2 OFF")
set_property(CACHE PLAYER_AUDIO_BACKEND PROPERTY STRINGS SDL2 OFF)
set(PLAYER_AUDIO_BACKEND "SDL2" CACHE STRING "Audio system to use. Options: SDL2 libao OFF")
set_property(CACHE PLAYER_AUDIO_BACKEND PROPERTY STRINGS SDL2 libao OFF)

if(${PLAYER_AUDIO_BACKEND} STREQUAL "SDL2_mixer")
message(FATAL_ERROR "SDL2_mixer is not supported anymore. Use SDL2 instead.")
endif()
elseif(${PLAYER_TARGET_PLATFORM} STREQUAL "SDL1")
set(PLAYER_AUDIO_BACKEND "SDL1" CACHE STRING "Audio system to use. Options: SDL1 OFF")
set_property(CACHE PLAYER_AUDIO_BACKEND PROPERTY STRINGS SDL1 OFF)

if(${PLAYER_AUDIO_BACKEND} STREQUAL "SDL2")
target_compile_definitions(${PROJECT_NAME} PUBLIC PLAYER_AUDIO=SdlAudio)
target_sources(${PROJECT_NAME} PRIVATE
src/platform/sdl/sdl_audio.cpp
src/platform/sdl/sdl_audio.h)
endif()

if(${PLAYER_AUDIO_BACKEND} STREQUAL "libao")
find_package(PkgConfig QUIET)
pkg_check_modules(LIBAO ao REQUIRED)
target_compile_definitions(${PROJECT_NAME} PUBLIC PLAYER_AUDIO=AoAudio)
target_sources(${PROJECT_NAME} PRIVATE
src/platform/generic/ao_audio.cpp
src/platform/generic/ao_audio.h)
target_include_directories(${PROJECT_NAME} PUBLIC ${LIBAO_INCLUDEDIR})
target_link_libraries(${PROJECT_NAME} ${LIBAO_LIBRARIES})
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
find_package(Threads REQUIRED)
target_link_libraries(${PROJECT_NAME} Threads::Threads)
endif()
else()
# Assuming that all platforms not targeting SDL have only one audio backend
set(PLAYER_AUDIO_BACKEND "Default" CACHE STRING "Audio system to use. Options: Default OFF")
set_property(CACHE PLAYER_AUDIO_BACKEND PROPERTY STRINGS Default OFF)

if(${PLAYER_AUDIO_BACKEND} STREQUAL "Default")
# Assuming that all platforms not targeting SDL have only one audio backend
set(PLAYER_AUDIO_BACKEND ${PLAYER_TARGET_PLATFORM})
endif()
endif()

# Configure Audio backends
if(${PLAYER_AUDIO_BACKEND} MATCHES "^(SDL2|SDL1|libretro|psvita|3ds|switch|wii|amigaos4)$")
if(${PLAYER_AUDIO_BACKEND} MATCHES "^(SDL2|libao|Default)$")
set(PLAYER_HAS_AUDIO ON)
target_compile_definitions(${PROJECT_NAME} PUBLIC SUPPORT_AUDIO=1)

if(${PLAYER_AUDIO_BACKEND} STREQUAL "libretro")
if(${PLAYER_TARGET_PLATFORM} STREQUAL "libretro")
if (WIN32 OR UNIX OR APPLE)
set(SUPPORT_NATIVE_MIDI ON)
endif()
Expand Down Expand Up @@ -965,7 +977,7 @@ CMAKE_DEPENDENT_OPTION(PLAYER_WITH_FLUIDLITE "Play MIDI audio with fluidlite" ON
CMAKE_DEPENDENT_OPTION(PLAYER_WITH_XMP "Play MOD audio with libxmp" ON "PLAYER_HAS_AUDIO" OFF)
CMAKE_DEPENDENT_OPTION(PLAYER_ENABLE_DRWAV "Play WAV audio with dr_wav (built-in). Unsupported files are played by libsndfile." ON "PLAYER_HAS_AUDIO" OFF)

if(${PLAYER_AUDIO_BACKEND} MATCHES "^(SDL2|SDL1|libretro|psvita|3ds|switch|wii|amigaos4)$")
if(${PLAYER_AUDIO_BACKEND} MATCHES "^(SDL2|libao|Default)$")
set(PLAYER_AUDIO_RESAMPLER "Auto" CACHE STRING "Audio resampler to use. Options: Auto speexdsp samplerate OFF")
set_property(CACHE PLAYER_AUDIO_RESAMPLER PROPERTY STRINGS Auto speexdsp samplerate OFF)

Expand Down Expand Up @@ -1484,8 +1496,10 @@ if(PLAYER_BUILD_LIBLCF)
message(STATUS "")
endif()

message(STATUS "Audio backend: ${PLAYER_AUDIO_BACKEND}")
if(${PLAYER_AUDIO_BACKEND} MATCHES "^(SDL2|SDL1|libretro|psvita|3ds|switch|wii)$")
if(NOT ${PLAYER_AUDIO_BACKEND} MATCHES "^(SDL2|Default)$")
message(STATUS "Audio backend: ${PLAYER_AUDIO_BACKEND}")
endif()
if(${PLAYER_AUDIO_BACKEND} MATCHES "^(SDL2|Default|libao)$")
message(STATUS "")

set(WAV_LIBS)
Expand Down
1 change: 1 addition & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ PKG_CHECK_MODULES([SDL],[sdl2 >= 2.0.5],[sdl_version=2],[
AC_DEFINE_UNQUOTED([USE_SDL],[$sdl_version],[Enable SDL, version 2 or 1.2])
AM_CONDITIONAL([HAVE_SDL2], [test "x$sdl_version" = "x2"])
AM_CONDITIONAL([HAVE_SDL1], [test "x$sdl_version" = "x1"])
AC_DEFINE([PLAYER_AUDIO],[SdlAudio],[Enable SDL audio])
EP_PKG_CHECK([FREETYPE],[freetype2],[Custom Font rendering.])
AS_IF([test "$with_freetype" = "yes"],[
EP_PKG_CHECK([HARFBUZZ],[harfbuzz],[Custom Font text shaping.])
Expand Down
99 changes: 99 additions & 0 deletions src/platform/generic/ao_audio.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* This file is part of EasyRPG Player.
*
* EasyRPG Player 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 3 of the License, or
* (at your option) any later version.
*
* EasyRPG Player 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 EasyRPG Player. If not, see <http://www.gnu.org/licenses/>.
*/

#include "system.h"

#ifdef SUPPORT_AUDIO

#include <cassert>
#include <ao/ao.h>
#include <thread>
#include <mutex>
#include "ao_audio.h"
#include "output.h"

namespace {
std::thread audio_thread;
std::mutex audio_mutex;
bool stop_audio;
ao_device *device = nullptr;
int buf_size = 1024;
}

void AudioThread(AoAudio* instance) {
std::vector<uint8_t> buffer;
buffer.resize(buf_size);
size_t i=0;

while (!stop_audio) {
instance->LockMutex();
instance->Decode(buffer.data(), buf_size);
instance->UnlockMutex();

if (!ao_play(device, reinterpret_cast<char*>(buffer.data()), buf_size)) {
Output::Warning("Couldn't play audio.");
return;
}
}
}

AoAudio::AoAudio(const Game_ConfigAudio& cfg) :
GenericAudio(cfg)
{
ao_initialize();

ao_sample_format format = {};
format.bits = 16;
format.channels = 2;
format.rate = 44100;
format.byte_format = AO_FMT_LITTLE;

device = ao_open_live(ao_default_driver_id(), &format, nullptr);
if (device == nullptr) {
Output::Warning("Couldn't open audio: errno={}", errno);
return;
}
SetFormat(format.rate, AudioDecoder::Format::S16, format.channels);

// Start Audio
stop_audio = false;
audio_thread = std::thread(AudioThread, this);
if(!audio_thread.joinable()) {
Output::Warning("Couldn't start audio thread.");
}
}

AoAudio::~AoAudio() {
stop_audio = true;
if (audio_thread.joinable())
audio_thread.join();

if(!ao_close(device)) {
Output::Warning("Problem closing audio device.");
}
ao_shutdown();
}

void AoAudio::LockMutex() const {
audio_mutex.lock();
}

void AoAudio::UnlockMutex() const {
audio_mutex.unlock();
}

#endif
32 changes: 32 additions & 0 deletions src/platform/generic/ao_audio.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* This file is part of EasyRPG Player.
*
* EasyRPG Player 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 3 of the License, or
* (at your option) any later version.
*
* EasyRPG Player 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 EasyRPG Player. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef EP_AO_AUDIO_H
#define EP_AO_AUDIO_H

#include "audio_generic.h"

class AoAudio : public GenericAudio {
public:
AoAudio(const Game_ConfigAudio& cfg);
~AoAudio();

void LockMutex() const override;
void UnlockMutex() const override;
};

#endif
4 changes: 2 additions & 2 deletions src/platform/sdl/sdl2_ui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@

#ifdef SUPPORT_AUDIO
# include "sdl_audio.h"
# include "platform/generic/ao_audio.h"

AudioInterface& Sdl2Ui::GetAudio() {
return *audio_;
Expand Down Expand Up @@ -187,8 +188,7 @@ Sdl2Ui::Sdl2Ui(long width, long height, const Game_Config& cfg) : BaseUi(cfg)

#ifdef SUPPORT_AUDIO
if (!Player::no_audio_flag) {
audio_ = std::make_unique<SdlAudio>(cfg.audio);
return;
audio_ = std::make_unique<PLAYER_AUDIO>(cfg.audio);
}
#endif
}
Expand Down
4 changes: 2 additions & 2 deletions src/platform/sdl/sdl_ui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
# else
# include "sdl_audio.h"
# endif
# include "platform/generic/ao_audio.h"

AudioInterface& SdlUi::GetAudio() {
return *audio_;
Expand Down Expand Up @@ -170,9 +171,8 @@ SdlUi::SdlUi(long width, long height, const Game_Config& cfg) : BaseUi(cfg)
# ifdef __wii__
audio_ = std::make_unique<WiiAudio>(cfg.audio);
# else
audio_ = std::make_unique<SdlAudio>(cfg.audio);
audio_ = std::make_unique<PLAYER_AUDIO>(cfg.audio);
# endif
return;
}
#endif
}
Expand Down

0 comments on commit b55c906

Please sign in to comment.