Replaced OpenAL with miniaudio.

Co-authored-by: Chris Thrasher <chrisjthrasher@gmail.com>
Co-authored-by: kimci86 <kimci86@hotmail.fr>
Co-authored-by: vittorioromeo <mail@vittorioromeo.com>
This commit is contained in:
binary1248 2023-04-16 16:12:31 +02:00 committed by Lukas Dürrenberger
parent b0e45cfaba
commit 34fde883b9
84 changed files with 95681 additions and 4046 deletions

View File

@ -112,7 +112,7 @@ IncludeCategories:
- Priority: 8 - Priority: 8
Regex: '^<SFML\/System' Regex: '^<SFML\/System'
- Priority: 9 - Priority: 9
Regex: '^<(glad|gl|X11|jni|android|stb_|GLES2|vorbis|catch2)' Regex: '^<(glad|gl|X11|jni|android|stb_|GLES2|vorbis|miniaudio|catch2)'
- Priority: 10 - Priority: 10
Regex: '^<([^c](.+)|coroutine|charconv|chrono|complex|concepts|condition_variable)>$' Regex: '^<([^c](.+)|coroutine|charconv|chrono|complex|concepts|condition_variable)>$'
- Priority: 11 - Priority: 11

View File

@ -105,7 +105,7 @@ jobs:
run: | run: |
CLANG_VERSION=$(clang++ --version | sed -n 's/.*version \([0-9]\+\)\..*/\1/p') CLANG_VERSION=$(clang++ --version | sed -n 's/.*version \([0-9]\+\)\..*/\1/p')
echo "CLANG_VERSION=$CLANG_VERSION" >> $GITHUB_ENV echo "CLANG_VERSION=$CLANG_VERSION" >> $GITHUB_ENV
sudo apt-get update && sudo apt-get install xorg-dev libxrandr-dev libxcursor-dev libudev-dev libopenal-dev libflac-dev libvorbis-dev libgl1-mesa-dev libegl1-mesa-dev libdrm-dev libgbm-dev xvfb fluxbox ccache gcovr ${{ matrix.platform.name == 'Linux Clang' && 'llvm-$CLANG_VERSION' || '' }} sudo apt-get update && sudo apt-get install xorg-dev libxrandr-dev libxcursor-dev libudev-dev libflac-dev libvorbis-dev libgl1-mesa-dev libegl1-mesa-dev libdrm-dev libgbm-dev xvfb fluxbox ccache gcovr ${{ matrix.platform.name == 'Linux Clang' && 'llvm-$CLANG_VERSION' || '' }}
- name: Install Android Components - name: Install Android Components
if: matrix.platform.name == 'Android' if: matrix.platform.name == 'Android'
@ -288,7 +288,7 @@ jobs:
- name: Install Linux Dependencies - name: Install Linux Dependencies
if: runner.os == 'Linux' if: runner.os == 'Linux'
run: sudo apt-get update && sudo apt-get install libxrandr-dev libxcursor-dev libudev-dev libopenal-dev libflac-dev libvorbis-dev libgl1-mesa-dev libegl1-mesa-dev libdrm-dev libgbm-dev run: sudo apt-get update && sudo apt-get install libxrandr-dev libxcursor-dev libudev-dev libflac-dev libvorbis-dev libgl1-mesa-dev libegl1-mesa-dev libdrm-dev libgbm-dev
- name: Install macOS Dependencies - name: Install macOS Dependencies
if: runner.os == 'macOS' if: runner.os == 'macOS'
@ -327,7 +327,7 @@ jobs:
- name: Install Linux Dependencies - name: Install Linux Dependencies
if: runner.os == 'Linux' if: runner.os == 'Linux'
run: sudo apt-get update && sudo apt-get install xorg-dev libxrandr-dev libxcursor-dev libudev-dev libopenal-dev libflac-dev libvorbis-dev libgl1-mesa-dev libegl1-mesa-dev libdrm-dev libgbm-dev xvfb fluxbox run: sudo apt-get update && sudo apt-get install xorg-dev libxrandr-dev libxcursor-dev libudev-dev libflac-dev libvorbis-dev libgl1-mesa-dev libegl1-mesa-dev libdrm-dev libgbm-dev xvfb fluxbox
- name: Configure - name: Configure
run: cmake --preset dev -GNinja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=clang++ -DSFML_BUILD_EXAMPLES=OFF -DSFML_ENABLE_SANITIZERS=ON ${{matrix.platform.flags}} run: cmake --preset dev -GNinja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=clang++ -DSFML_BUILD_EXAMPLES=OFF -DSFML_ENABLE_SANITIZERS=ON ${{matrix.platform.flags}}

View File

@ -378,14 +378,12 @@ if(SFML_OS_WINDOWS)
if(NOT SFML_USE_SYSTEM_DEPS) if(NOT SFML_USE_SYSTEM_DEPS)
# install the binaries of SFML dependencies # install the binaries of SFML dependencies
if(ARCH_32BITS) if(ARCH_32BITS)
install(DIRECTORY extlibs/bin/x86/ DESTINATION ${CMAKE_INSTALL_BINDIR})
if(SFML_COMPILER_MSVC OR (SFML_COMPILER_CLANG AND NOT MINGW)) if(SFML_COMPILER_MSVC OR (SFML_COMPILER_CLANG AND NOT MINGW))
install(DIRECTORY extlibs/libs-msvc-universal/x86/ DESTINATION ${CMAKE_INSTALL_LIBDIR}) install(DIRECTORY extlibs/libs-msvc-universal/x86/ DESTINATION ${CMAKE_INSTALL_LIBDIR})
else() else()
install(DIRECTORY extlibs/libs-mingw/x86/ DESTINATION ${CMAKE_INSTALL_LIBDIR}) install(DIRECTORY extlibs/libs-mingw/x86/ DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif() endif()
elseif(ARCH_64BITS) elseif(ARCH_64BITS)
install(DIRECTORY extlibs/bin/x64/ DESTINATION ${CMAKE_INSTALL_BINDIR})
if(SFML_COMPILER_MSVC OR (SFML_COMPILER_CLANG AND NOT MINGW)) if(SFML_COMPILER_MSVC OR (SFML_COMPILER_CLANG AND NOT MINGW))
install(DIRECTORY extlibs/libs-msvc-universal/x64/ DESTINATION ${CMAKE_INSTALL_LIBDIR}) install(DIRECTORY extlibs/libs-msvc-universal/x64/ DESTINATION ${CMAKE_INSTALL_LIBDIR})
else() else()
@ -422,10 +420,6 @@ elseif(SFML_OS_MACOS)
if(VORBISFILE_LIBRARY STREQUAL "${PROJECT_SOURCE_DIR}/extlibs/libs-macos/Frameworks/vorbisfile.framework") if(VORBISFILE_LIBRARY STREQUAL "${PROJECT_SOURCE_DIR}/extlibs/libs-macos/Frameworks/vorbisfile.framework")
install(DIRECTORY extlibs/libs-macos/Frameworks/vorbisfile.framework DESTINATION ${CMAKE_INSTALL_LIBDIR}) install(DIRECTORY extlibs/libs-macos/Frameworks/vorbisfile.framework DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif() endif()
if(OPENAL_LIBRARY STREQUAL "${PROJECT_SOURCE_DIR}/extlibs/libs-macos/Frameworks/OpenAL.framework")
install(DIRECTORY "${OPENAL_LIBRARY}" DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif()
endif() endif()
# install the Xcode templates if requested # install the Xcode templates if requested

View File

@ -1,120 +0,0 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
#[=======================================================================[.rst:
FindOpenAL
----------
Finds Open Audio Library (OpenAL).
Projects using this module should use ``#include "al.h"`` to include the OpenAL
header file, **not** ``#include <AL/al.h>``. The reason for this is that the
latter is not entirely portable. Windows/Creative Labs does not by default put
their headers in ``AL/`` and macOS uses the convention ``<OpenAL/al.h>``.
Hints
^^^^^
Environment variable ``$OPENALDIR`` can be used to set the prefix of OpenAL
installation to be found.
By default on macOS, system framework is search first. In other words,
OpenAL is searched in the following order:
1. System framework: ``/System/Library/Frameworks``, whose priority can be
changed via setting the :variable:`CMAKE_FIND_FRAMEWORK` variable.
2. Environment variable ``$OPENALDIR``.
3. System paths.
4. User-compiled framework: ``~/Library/Frameworks``.
5. Manually compiled framework: ``/Library/Frameworks``.
6. Add-on package: ``/opt``.
IMPORTED Targets
^^^^^^^^^^^^^^^^
.. versionadded:: 3.25
This module defines the :prop_tgt:`IMPORTED` target:
``OpenAL::OpenAL``
The OpenAL library, if found.
Result Variables
^^^^^^^^^^^^^^^^
This module defines the following variables:
``OPENAL_FOUND``
If false, do not try to link to OpenAL
``OPENAL_INCLUDE_DIR``
OpenAL include directory
``OPENAL_LIBRARY``
Path to the OpenAL library
``OPENAL_VERSION_STRING``
Human-readable string containing the version of OpenAL
#]=======================================================================]
# For Windows, Creative Labs seems to have added a registry key for their
# OpenAL 1.1 installer. I have added that key to the list of search paths,
# however, the key looks like it could be a little fragile depending on
# if they decide to change the 1.00.0000 number for bug fix releases.
# Also, they seem to have laid down groundwork for multiple library platforms
# which puts the library in an extra subdirectory. Currently there is only
# Win32 and I have hardcoded that here. This may need to be adjusted as
# platforms are introduced.
# The OpenAL 1.0 installer doesn't seem to have a useful key I can use.
# I do not know if the Nvidia OpenAL SDK has a registry key.
find_path(OPENAL_INCLUDE_DIR al.h
HINTS
ENV OPENALDIR
PATHS
~/Library/Frameworks
/Library/Frameworks
/opt
[HKEY_LOCAL_MACHINE\\SOFTWARE\\Creative\ Labs\\OpenAL\ 1.1\ Software\ Development\ Kit\\1.00.0000;InstallDir]
PATH_SUFFIXES include/AL include/OpenAL include AL OpenAL
)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(_OpenAL_ARCH_DIR libs/Win64)
else()
set(_OpenAL_ARCH_DIR libs/Win32)
endif()
find_library(OPENAL_LIBRARY
NAMES OpenAL al openal OpenAL32
HINTS
ENV OPENALDIR
PATHS
~/Library/Frameworks
/Library/Frameworks
/opt
[HKEY_LOCAL_MACHINE\\SOFTWARE\\Creative\ Labs\\OpenAL\ 1.1\ Software\ Development\ Kit\\1.00.0000;InstallDir]
PATH_SUFFIXES libx32 lib64 lib libs64 libs ${_OpenAL_ARCH_DIR}
)
unset(_OpenAL_ARCH_DIR)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(
OpenAL
REQUIRED_VARS OPENAL_LIBRARY OPENAL_INCLUDE_DIR
VERSION_VAR OPENAL_VERSION_STRING
)
mark_as_advanced(OPENAL_LIBRARY OPENAL_INCLUDE_DIR)
if(NOT TARGET OpenAL::OpenAL)
if(OPENAL_LIBRARY MATCHES "/([^/]+)\\.framework$")
add_library(OpenAL::OpenAL INTERFACE IMPORTED)
set_target_properties(OpenAL::OpenAL PROPERTIES
INTERFACE_LINK_LIBRARIES "${OPENAL_LIBRARY}")
else()
add_library(OpenAL::OpenAL UNKNOWN IMPORTED)
set_target_properties(OpenAL::OpenAL PROPERTIES
IMPORTED_LOCATION "${OPENAL_LIBRARY}")
endif()
set_target_properties(OpenAL::OpenAL PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${OPENAL_INCLUDE_DIR}")
endif()

View File

@ -60,7 +60,6 @@ if(SFML_STATIC_LIBRARIES)
# SFML::Audio # SFML::Audio
list(FIND SFML_FIND_COMPONENTS "Audio" FIND_SFML_AUDIO_COMPONENT_INDEX) list(FIND SFML_FIND_COMPONENTS "Audio" FIND_SFML_AUDIO_COMPONENT_INDEX)
if(FIND_SFML_AUDIO_COMPONENT_INDEX GREATER -1) if(FIND_SFML_AUDIO_COMPONENT_INDEX GREATER -1)
find_package(OpenAL)
find_package(Vorbis) find_package(Vorbis)
find_package(FLAC) find_package(FLAC)
endif() endif()

View File

@ -23,6 +23,30 @@ int main()
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
// List the available capture devices
auto devices = sf::SoundRecorder::getAvailableDevices();
std::cout << "Available capture devices:\n" << std::endl;
for (auto i = 0u; i < devices.size(); ++i)
std::cout << i << ": " << devices[i] << '\n';
std::cout << std::endl;
std::size_t deviceIndex = 0;
// Choose the capture device
if (devices.size() > 1)
{
deviceIndex = devices.size();
std::cout << "Please choose the capture device to use [0-" << devices.size() - 1 << "]: ";
do
{
std::cin >> deviceIndex;
std::cin.ignore(10000, '\n');
} while (deviceIndex >= devices.size());
}
// Choose the sample rate // Choose the sample rate
unsigned int sampleRate; unsigned int sampleRate;
std::cout << "Please choose the sample rate for sound capture (44100 is CD quality): "; std::cout << "Please choose the sample rate for sound capture (44100 is CD quality): ";
@ -36,6 +60,12 @@ int main()
// Here we'll use an integrated custom recorder, which saves the captured data into a SoundBuffer // Here we'll use an integrated custom recorder, which saves the captured data into a SoundBuffer
sf::SoundBufferRecorder recorder; sf::SoundBufferRecorder recorder;
if (!recorder.setDevice(devices[deviceIndex]))
{
std::cerr << "Failed to set the capture device" << std::endl;
return EXIT_FAILURE;
}
// Audio capture is done in a separate thread, so we can block the main thread while it is capturing // Audio capture is done in a separate thread, so we can block the main thread while it is capturing
if (!recorder.start(sampleRate)) if (!recorder.start(sampleRate))
{ {

View File

@ -32,7 +32,7 @@ public:
NetworkAudioStream() NetworkAudioStream()
{ {
// Set the sound parameters // Set the sound parameters
initialize(1, 44100); initialize(1, 44100, {sf::SoundChannel::Mono});
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

Binary file not shown.

Binary file not shown.

View File

@ -1,656 +0,0 @@
#ifndef AL_AL_H
#define AL_AL_H
#if defined(__cplusplus)
extern "C" {
#endif
#ifndef AL_API
#if defined(AL_LIBTYPE_STATIC)
#define AL_API
#elif defined(_WIN32)
#define AL_API __declspec(dllimport)
#else
#define AL_API extern
#endif
#endif
#if defined(_WIN32)
#define AL_APIENTRY __cdecl
#else
#define AL_APIENTRY
#endif
/** Deprecated macro. */
#define OPENAL
#define ALAPI AL_API
#define ALAPIENTRY AL_APIENTRY
#define AL_INVALID (-1)
#define AL_ILLEGAL_ENUM AL_INVALID_ENUM
#define AL_ILLEGAL_COMMAND AL_INVALID_OPERATION
/** Supported AL version. */
#define AL_VERSION_1_0
#define AL_VERSION_1_1
/** 8-bit boolean */
typedef char ALboolean;
/** character */
typedef char ALchar;
/** signed 8-bit 2's complement integer */
typedef signed char ALbyte;
/** unsigned 8-bit integer */
typedef unsigned char ALubyte;
/** signed 16-bit 2's complement integer */
typedef short ALshort;
/** unsigned 16-bit integer */
typedef unsigned short ALushort;
/** signed 32-bit 2's complement integer */
typedef int ALint;
/** unsigned 32-bit integer */
typedef unsigned int ALuint;
/** non-negative 32-bit binary integer size */
typedef int ALsizei;
/** enumerated 32-bit value */
typedef int ALenum;
/** 32-bit IEEE754 floating-point */
typedef float ALfloat;
/** 64-bit IEEE754 floating-point */
typedef double ALdouble;
/** void type (for opaque pointers only) */
typedef void ALvoid;
/* Enumerant values begin at column 50. No tabs. */
/** "no distance model" or "no buffer" */
#define AL_NONE 0
/** Boolean False. */
#define AL_FALSE 0
/** Boolean True. */
#define AL_TRUE 1
/**
* Relative source.
* Type: ALboolean
* Range: [AL_TRUE, AL_FALSE]
* Default: AL_FALSE
*
* Specifies if the Source has relative coordinates.
*/
#define AL_SOURCE_RELATIVE 0x202
/**
* Inner cone angle, in degrees.
* Type: ALint, ALfloat
* Range: [0 - 360]
* Default: 360
*
* The angle covered by the inner cone, where the source will not attenuate.
*/
#define AL_CONE_INNER_ANGLE 0x1001
/**
* Outer cone angle, in degrees.
* Range: [0 - 360]
* Default: 360
*
* The angle covered by the outer cone, where the source will be fully
* attenuated.
*/
#define AL_CONE_OUTER_ANGLE 0x1002
/**
* Source pitch.
* Type: ALfloat
* Range: [0.5 - 2.0]
* Default: 1.0
*
* A multiplier for the frequency (sample rate) of the source's buffer.
*/
#define AL_PITCH 0x1003
/**
* Source or listener position.
* Type: ALfloat[3], ALint[3]
* Default: {0, 0, 0}
*
* The source or listener location in three dimensional space.
*
* OpenAL, like OpenGL, uses a right handed coordinate system, where in a
* frontal default view X (thumb) points right, Y points up (index finger), and
* Z points towards the viewer/camera (middle finger).
*
* To switch from a left handed coordinate system, flip the sign on the Z
* coordinate.
*/
#define AL_POSITION 0x1004
/**
* Source direction.
* Type: ALfloat[3], ALint[3]
* Default: {0, 0, 0}
*
* Specifies the current direction in local space.
* A zero-length vector specifies an omni-directional source (cone is ignored).
*/
#define AL_DIRECTION 0x1005
/**
* Source or listener velocity.
* Type: ALfloat[3], ALint[3]
* Default: {0, 0, 0}
*
* Specifies the current velocity in local space.
*/
#define AL_VELOCITY 0x1006
/**
* Source looping.
* Type: ALboolean
* Range: [AL_TRUE, AL_FALSE]
* Default: AL_FALSE
*
* Specifies whether source is looping.
*/
#define AL_LOOPING 0x1007
/**
* Source buffer.
* Type: ALuint
* Range: any valid Buffer.
*
* Specifies the buffer to provide sound samples.
*/
#define AL_BUFFER 0x1009
/**
* Source or listener gain.
* Type: ALfloat
* Range: [0.0 - ]
*
* A value of 1.0 means unattenuated. Each division by 2 equals an attenuation
* of about -6dB. Each multiplicaton by 2 equals an amplification of about
* +6dB.
*
* A value of 0.0 is meaningless with respect to a logarithmic scale; it is
* silent.
*/
#define AL_GAIN 0x100A
/**
* Minimum source gain.
* Type: ALfloat
* Range: [0.0 - 1.0]
*
* The minimum gain allowed for a source, after distance and cone attenation is
* applied (if applicable).
*/
#define AL_MIN_GAIN 0x100D
/**
* Maximum source gain.
* Type: ALfloat
* Range: [0.0 - 1.0]
*
* The maximum gain allowed for a source, after distance and cone attenation is
* applied (if applicable).
*/
#define AL_MAX_GAIN 0x100E
/**
* Listener orientation.
* Type: ALfloat[6]
* Default: {0.0, 0.0, -1.0, 0.0, 1.0, 0.0}
*
* Effectively two three dimensional vectors. The first vector is the front (or
* "at") and the second is the top (or "up").
*
* Both vectors are in local space.
*/
#define AL_ORIENTATION 0x100F
/**
* Source state (query only).
* Type: ALint
* Range: [AL_INITIAL, AL_PLAYING, AL_PAUSED, AL_STOPPED]
*/
#define AL_SOURCE_STATE 0x1010
/** Source state value. */
#define AL_INITIAL 0x1011
#define AL_PLAYING 0x1012
#define AL_PAUSED 0x1013
#define AL_STOPPED 0x1014
/**
* Source Buffer Queue size (query only).
* Type: ALint
*
* The number of buffers queued using alSourceQueueBuffers, minus the buffers
* removed with alSourceUnqueueBuffers.
*/
#define AL_BUFFERS_QUEUED 0x1015
/**
* Source Buffer Queue processed count (query only).
* Type: ALint
*
* The number of queued buffers that have been fully processed, and can be
* removed with alSourceUnqueueBuffers.
*
* Looping sources will never fully process buffers because they will be set to
* play again for when the source loops.
*/
#define AL_BUFFERS_PROCESSED 0x1016
/**
* Source reference distance.
* Type: ALfloat
* Range: [0.0 - ]
* Default: 1.0
*
* The distance in units that no attenuation occurs.
*
* At 0.0, no distance attenuation ever occurs on non-linear attenuation models.
*/
#define AL_REFERENCE_DISTANCE 0x1020
/**
* Source rolloff factor.
* Type: ALfloat
* Range: [0.0 - ]
* Default: 1.0
*
* Multiplier to exaggerate or diminish distance attenuation.
*
* At 0.0, no distance attenuation ever occurs.
*/
#define AL_ROLLOFF_FACTOR 0x1021
/**
* Outer cone gain.
* Type: ALfloat
* Range: [0.0 - 1.0]
* Default: 0.0
*
* The gain attenuation applied when the listener is outside of the source's
* outer cone.
*/
#define AL_CONE_OUTER_GAIN 0x1022
/**
* Source maximum distance.
* Type: ALfloat
* Range: [0.0 - ]
* Default: +inf
*
* The distance above which the source is not attenuated any further with a
* clamped distance model, or where attenuation reaches 0.0 gain for linear
* distance models with a default rolloff factor.
*/
#define AL_MAX_DISTANCE 0x1023
/** Source buffer position, in seconds */
#define AL_SEC_OFFSET 0x1024
/** Source buffer position, in sample frames */
#define AL_SAMPLE_OFFSET 0x1025
/** Source buffer position, in bytes */
#define AL_BYTE_OFFSET 0x1026
/**
* Source type (query only).
* Type: ALint
* Range: [AL_STATIC, AL_STREAMING, AL_UNDETERMINED]
*
* A Source is Static if a Buffer has been attached using AL_BUFFER.
*
* A Source is Streaming if one or more Buffers have been attached using
* alSourceQueueBuffers.
*
* A Source is Undetermined when it has the NULL buffer attached using
* AL_BUFFER.
*/
#define AL_SOURCE_TYPE 0x1027
/** Source type value. */
#define AL_STATIC 0x1028
#define AL_STREAMING 0x1029
#define AL_UNDETERMINED 0x1030
/** Buffer format specifier. */
#define AL_FORMAT_MONO8 0x1100
#define AL_FORMAT_MONO16 0x1101
#define AL_FORMAT_STEREO8 0x1102
#define AL_FORMAT_STEREO16 0x1103
/** Buffer frequency (query only). */
#define AL_FREQUENCY 0x2001
/** Buffer bits per sample (query only). */
#define AL_BITS 0x2002
/** Buffer channel count (query only). */
#define AL_CHANNELS 0x2003
/** Buffer data size (query only). */
#define AL_SIZE 0x2004
/**
* Buffer state.
*
* Not for public use.
*/
#define AL_UNUSED 0x2010
#define AL_PENDING 0x2011
#define AL_PROCESSED 0x2012
/** No error. */
#define AL_NO_ERROR 0
/** Invalid name paramater passed to AL call. */
#define AL_INVALID_NAME 0xA001
/** Invalid enum parameter passed to AL call. */
#define AL_INVALID_ENUM 0xA002
/** Invalid value parameter passed to AL call. */
#define AL_INVALID_VALUE 0xA003
/** Illegal AL call. */
#define AL_INVALID_OPERATION 0xA004
/** Not enough memory. */
#define AL_OUT_OF_MEMORY 0xA005
/** Context string: Vendor ID. */
#define AL_VENDOR 0xB001
/** Context string: Version. */
#define AL_VERSION 0xB002
/** Context string: Renderer ID. */
#define AL_RENDERER 0xB003
/** Context string: Space-separated extension list. */
#define AL_EXTENSIONS 0xB004
/**
* Doppler scale.
* Type: ALfloat
* Range: [0.0 - ]
* Default: 1.0
*
* Scale for source and listener velocities.
*/
#define AL_DOPPLER_FACTOR 0xC000
AL_API void AL_APIENTRY alDopplerFactor(ALfloat value);
/**
* Doppler velocity (deprecated).
*
* A multiplier applied to the Speed of Sound.
*/
#define AL_DOPPLER_VELOCITY 0xC001
AL_API void AL_APIENTRY alDopplerVelocity(ALfloat value);
/**
* Speed of Sound, in units per second.
* Type: ALfloat
* Range: [0.0001 - ]
* Default: 343.3
*
* The speed at which sound waves are assumed to travel, when calculating the
* doppler effect.
*/
#define AL_SPEED_OF_SOUND 0xC003
AL_API void AL_APIENTRY alSpeedOfSound(ALfloat value);
/**
* Distance attenuation model.
* Type: ALint
* Range: [AL_NONE, AL_INVERSE_DISTANCE, AL_INVERSE_DISTANCE_CLAMPED,
* AL_LINEAR_DISTANCE, AL_LINEAR_DISTANCE_CLAMPED,
* AL_EXPONENT_DISTANCE, AL_EXPONENT_DISTANCE_CLAMPED]
* Default: AL_INVERSE_DISTANCE_CLAMPED
*
* The model by which sources attenuate with distance.
*
* None - No distance attenuation.
* Inverse - Doubling the distance halves the source gain.
* Linear - Linear gain scaling between the reference and max distances.
* Exponent - Exponential gain dropoff.
*
* Clamped variations work like the non-clamped counterparts, except the
* distance calculated is clamped between the reference and max distances.
*/
#define AL_DISTANCE_MODEL 0xD000
AL_API void AL_APIENTRY alDistanceModel(ALenum distanceModel);
/** Distance model value. */
#define AL_INVERSE_DISTANCE 0xD001
#define AL_INVERSE_DISTANCE_CLAMPED 0xD002
#define AL_LINEAR_DISTANCE 0xD003
#define AL_LINEAR_DISTANCE_CLAMPED 0xD004
#define AL_EXPONENT_DISTANCE 0xD005
#define AL_EXPONENT_DISTANCE_CLAMPED 0xD006
/** Renderer State management. */
AL_API void AL_APIENTRY alEnable(ALenum capability);
AL_API void AL_APIENTRY alDisable(ALenum capability);
AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability);
/** State retrieval. */
AL_API const ALchar* AL_APIENTRY alGetString(ALenum param);
AL_API void AL_APIENTRY alGetBooleanv(ALenum param, ALboolean *values);
AL_API void AL_APIENTRY alGetIntegerv(ALenum param, ALint *values);
AL_API void AL_APIENTRY alGetFloatv(ALenum param, ALfloat *values);
AL_API void AL_APIENTRY alGetDoublev(ALenum param, ALdouble *values);
AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum param);
AL_API ALint AL_APIENTRY alGetInteger(ALenum param);
AL_API ALfloat AL_APIENTRY alGetFloat(ALenum param);
AL_API ALdouble AL_APIENTRY alGetDouble(ALenum param);
/**
* Error retrieval.
*
* Obtain the first error generated in the AL context since the last check.
*/
AL_API ALenum AL_APIENTRY alGetError(void);
/**
* Extension support.
*
* Query for the presence of an extension, and obtain any appropriate function
* pointers and enum values.
*/
AL_API ALboolean AL_APIENTRY alIsExtensionPresent(const ALchar *extname);
AL_API void* AL_APIENTRY alGetProcAddress(const ALchar *fname);
AL_API ALenum AL_APIENTRY alGetEnumValue(const ALchar *ename);
/** Set Listener parameters */
AL_API void AL_APIENTRY alListenerf(ALenum param, ALfloat value);
AL_API void AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3);
AL_API void AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values);
AL_API void AL_APIENTRY alListeneri(ALenum param, ALint value);
AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, ALint value3);
AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values);
/** Get Listener parameters */
AL_API void AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value);
AL_API void AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3);
AL_API void AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values);
AL_API void AL_APIENTRY alGetListeneri(ALenum param, ALint *value);
AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *value2, ALint *value3);
AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint *values);
/** Create Source objects. */
AL_API void AL_APIENTRY alGenSources(ALsizei n, ALuint *sources);
/** Delete Source objects. */
AL_API void AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources);
/** Verify a handle is a valid Source. */
AL_API ALboolean AL_APIENTRY alIsSource(ALuint source);
/** Set Source parameters. */
AL_API void AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value);
AL_API void AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3);
AL_API void AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values);
AL_API void AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value);
AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3);
AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values);
/** Get Source parameters. */
AL_API void AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value);
AL_API void AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3);
AL_API void AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values);
AL_API void AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value);
AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3);
AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values);
/** Play, replay, or resume (if paused) a list of Sources */
AL_API void AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources);
/** Stop a list of Sources */
AL_API void AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources);
/** Rewind a list of Sources */
AL_API void AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources);
/** Pause a list of Sources */
AL_API void AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources);
/** Play, replay, or resume a Source */
AL_API void AL_APIENTRY alSourcePlay(ALuint source);
/** Stop a Source */
AL_API void AL_APIENTRY alSourceStop(ALuint source);
/** Rewind a Source (set playback postiton to beginning) */
AL_API void AL_APIENTRY alSourceRewind(ALuint source);
/** Pause a Source */
AL_API void AL_APIENTRY alSourcePause(ALuint source);
/** Queue buffers onto a source */
AL_API void AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei nb, const ALuint *buffers);
/** Unqueue processed buffers from a source */
AL_API void AL_APIENTRY alSourceUnqueueBuffers(ALuint source, ALsizei nb, ALuint *buffers);
/** Create Buffer objects */
AL_API void AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers);
/** Delete Buffer objects */
AL_API void AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers);
/** Verify a handle is a valid Buffer */
AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer);
/** Specifies the data to be copied into a buffer */
AL_API void AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq);
/** Set Buffer parameters, */
AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat value);
AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3);
AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum param, const ALfloat *values);
AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value);
AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param, ALint value1, ALint value2, ALint value3);
AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *values);
/** Get Buffer parameters. */
AL_API void AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *value);
AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3);
AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *values);
AL_API void AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value);
AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3);
AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values);
/** Pointer-to-function type, useful for dynamically getting AL entry points. */
typedef void (AL_APIENTRY *LPALENABLE)(ALenum capability);
typedef void (AL_APIENTRY *LPALDISABLE)(ALenum capability);
typedef ALboolean (AL_APIENTRY *LPALISENABLED)(ALenum capability);
typedef const ALchar* (AL_APIENTRY *LPALGETSTRING)(ALenum param);
typedef void (AL_APIENTRY *LPALGETBOOLEANV)(ALenum param, ALboolean *values);
typedef void (AL_APIENTRY *LPALGETINTEGERV)(ALenum param, ALint *values);
typedef void (AL_APIENTRY *LPALGETFLOATV)(ALenum param, ALfloat *values);
typedef void (AL_APIENTRY *LPALGETDOUBLEV)(ALenum param, ALdouble *values);
typedef ALboolean (AL_APIENTRY *LPALGETBOOLEAN)(ALenum param);
typedef ALint (AL_APIENTRY *LPALGETINTEGER)(ALenum param);
typedef ALfloat (AL_APIENTRY *LPALGETFLOAT)(ALenum param);
typedef ALdouble (AL_APIENTRY *LPALGETDOUBLE)(ALenum param);
typedef ALenum (AL_APIENTRY *LPALGETERROR)(void);
typedef ALboolean (AL_APIENTRY *LPALISEXTENSIONPRESENT)(const ALchar *extname);
typedef void* (AL_APIENTRY *LPALGETPROCADDRESS)(const ALchar *fname);
typedef ALenum (AL_APIENTRY *LPALGETENUMVALUE)(const ALchar *ename);
typedef void (AL_APIENTRY *LPALLISTENERF)(ALenum param, ALfloat value);
typedef void (AL_APIENTRY *LPALLISTENER3F)(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3);
typedef void (AL_APIENTRY *LPALLISTENERFV)(ALenum param, const ALfloat *values);
typedef void (AL_APIENTRY *LPALLISTENERI)(ALenum param, ALint value);
typedef void (AL_APIENTRY *LPALLISTENER3I)(ALenum param, ALint value1, ALint value2, ALint value3);
typedef void (AL_APIENTRY *LPALLISTENERIV)(ALenum param, const ALint *values);
typedef void (AL_APIENTRY *LPALGETLISTENERF)(ALenum param, ALfloat *value);
typedef void (AL_APIENTRY *LPALGETLISTENER3F)(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3);
typedef void (AL_APIENTRY *LPALGETLISTENERFV)(ALenum param, ALfloat *values);
typedef void (AL_APIENTRY *LPALGETLISTENERI)(ALenum param, ALint *value);
typedef void (AL_APIENTRY *LPALGETLISTENER3I)(ALenum param, ALint *value1, ALint *value2, ALint *value3);
typedef void (AL_APIENTRY *LPALGETLISTENERIV)(ALenum param, ALint *values);
typedef void (AL_APIENTRY *LPALGENSOURCES)(ALsizei n, ALuint *sources);
typedef void (AL_APIENTRY *LPALDELETESOURCES)(ALsizei n, const ALuint *sources);
typedef ALboolean (AL_APIENTRY *LPALISSOURCE)(ALuint source);
typedef void (AL_APIENTRY *LPALSOURCEF)(ALuint source, ALenum param, ALfloat value);
typedef void (AL_APIENTRY *LPALSOURCE3F)(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3);
typedef void (AL_APIENTRY *LPALSOURCEFV)(ALuint source, ALenum param, const ALfloat *values);
typedef void (AL_APIENTRY *LPALSOURCEI)(ALuint source, ALenum param, ALint value);
typedef void (AL_APIENTRY *LPALSOURCE3I)(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3);
typedef void (AL_APIENTRY *LPALSOURCEIV)(ALuint source, ALenum param, const ALint *values);
typedef void (AL_APIENTRY *LPALGETSOURCEF)(ALuint source, ALenum param, ALfloat *value);
typedef void (AL_APIENTRY *LPALGETSOURCE3F)(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3);
typedef void (AL_APIENTRY *LPALGETSOURCEFV)(ALuint source, ALenum param, ALfloat *values);
typedef void (AL_APIENTRY *LPALGETSOURCEI)(ALuint source, ALenum param, ALint *value);
typedef void (AL_APIENTRY *LPALGETSOURCE3I)(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3);
typedef void (AL_APIENTRY *LPALGETSOURCEIV)(ALuint source, ALenum param, ALint *values);
typedef void (AL_APIENTRY *LPALSOURCEPLAYV)(ALsizei n, const ALuint *sources);
typedef void (AL_APIENTRY *LPALSOURCESTOPV)(ALsizei n, const ALuint *sources);
typedef void (AL_APIENTRY *LPALSOURCEREWINDV)(ALsizei n, const ALuint *sources);
typedef void (AL_APIENTRY *LPALSOURCEPAUSEV)(ALsizei n, const ALuint *sources);
typedef void (AL_APIENTRY *LPALSOURCEPLAY)(ALuint source);
typedef void (AL_APIENTRY *LPALSOURCESTOP)(ALuint source);
typedef void (AL_APIENTRY *LPALSOURCEREWIND)(ALuint source);
typedef void (AL_APIENTRY *LPALSOURCEPAUSE)(ALuint source);
typedef void (AL_APIENTRY *LPALSOURCEQUEUEBUFFERS)(ALuint source, ALsizei nb, const ALuint *buffers);
typedef void (AL_APIENTRY *LPALSOURCEUNQUEUEBUFFERS)(ALuint source, ALsizei nb, ALuint *buffers);
typedef void (AL_APIENTRY *LPALGENBUFFERS)(ALsizei n, ALuint *buffers);
typedef void (AL_APIENTRY *LPALDELETEBUFFERS)(ALsizei n, const ALuint *buffers);
typedef ALboolean (AL_APIENTRY *LPALISBUFFER)(ALuint buffer);
typedef void (AL_APIENTRY *LPALBUFFERDATA)(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq);
typedef void (AL_APIENTRY *LPALBUFFERF)(ALuint buffer, ALenum param, ALfloat value);
typedef void (AL_APIENTRY *LPALBUFFER3F)(ALuint buffer, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3);
typedef void (AL_APIENTRY *LPALBUFFERFV)(ALuint buffer, ALenum param, const ALfloat *values);
typedef void (AL_APIENTRY *LPALBUFFERI)(ALuint buffer, ALenum param, ALint value);
typedef void (AL_APIENTRY *LPALBUFFER3I)(ALuint buffer, ALenum param, ALint value1, ALint value2, ALint value3);
typedef void (AL_APIENTRY *LPALBUFFERIV)(ALuint buffer, ALenum param, const ALint *values);
typedef void (AL_APIENTRY *LPALGETBUFFERF)(ALuint buffer, ALenum param, ALfloat *value);
typedef void (AL_APIENTRY *LPALGETBUFFER3F)(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3);
typedef void (AL_APIENTRY *LPALGETBUFFERFV)(ALuint buffer, ALenum param, ALfloat *values);
typedef void (AL_APIENTRY *LPALGETBUFFERI)(ALuint buffer, ALenum param, ALint *value);
typedef void (AL_APIENTRY *LPALGETBUFFER3I)(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3);
typedef void (AL_APIENTRY *LPALGETBUFFERIV)(ALuint buffer, ALenum param, ALint *values);
typedef void (AL_APIENTRY *LPALDOPPLERFACTOR)(ALfloat value);
typedef void (AL_APIENTRY *LPALDOPPLERVELOCITY)(ALfloat value);
typedef void (AL_APIENTRY *LPALSPEEDOFSOUND)(ALfloat value);
typedef void (AL_APIENTRY *LPALDISTANCEMODEL)(ALenum distanceModel);
#if defined(__cplusplus)
} /* extern "C" */
#endif
#endif /* AL_AL_H */

View File

@ -1,237 +0,0 @@
#ifndef AL_ALC_H
#define AL_ALC_H
#if defined(__cplusplus)
extern "C" {
#endif
#ifndef ALC_API
#if defined(AL_LIBTYPE_STATIC)
#define ALC_API
#elif defined(_WIN32)
#define ALC_API __declspec(dllimport)
#else
#define ALC_API extern
#endif
#endif
#if defined(_WIN32)
#define ALC_APIENTRY __cdecl
#else
#define ALC_APIENTRY
#endif
/** Deprecated macro. */
#define ALCAPI ALC_API
#define ALCAPIENTRY ALC_APIENTRY
#define ALC_INVALID 0
/** Supported ALC version? */
#define ALC_VERSION_0_1 1
/** Opaque device handle */
typedef struct ALCdevice_struct ALCdevice;
/** Opaque context handle */
typedef struct ALCcontext_struct ALCcontext;
/** 8-bit boolean */
typedef char ALCboolean;
/** character */
typedef char ALCchar;
/** signed 8-bit 2's complement integer */
typedef signed char ALCbyte;
/** unsigned 8-bit integer */
typedef unsigned char ALCubyte;
/** signed 16-bit 2's complement integer */
typedef short ALCshort;
/** unsigned 16-bit integer */
typedef unsigned short ALCushort;
/** signed 32-bit 2's complement integer */
typedef int ALCint;
/** unsigned 32-bit integer */
typedef unsigned int ALCuint;
/** non-negative 32-bit binary integer size */
typedef int ALCsizei;
/** enumerated 32-bit value */
typedef int ALCenum;
/** 32-bit IEEE754 floating-point */
typedef float ALCfloat;
/** 64-bit IEEE754 floating-point */
typedef double ALCdouble;
/** void type (for opaque pointers only) */
typedef void ALCvoid;
/* Enumerant values begin at column 50. No tabs. */
/** Boolean False. */
#define ALC_FALSE 0
/** Boolean True. */
#define ALC_TRUE 1
/** Context attribute: <int> Hz. */
#define ALC_FREQUENCY 0x1007
/** Context attribute: <int> Hz. */
#define ALC_REFRESH 0x1008
/** Context attribute: AL_TRUE or AL_FALSE. */
#define ALC_SYNC 0x1009
/** Context attribute: <int> requested Mono (3D) Sources. */
#define ALC_MONO_SOURCES 0x1010
/** Context attribute: <int> requested Stereo Sources. */
#define ALC_STEREO_SOURCES 0x1011
/** No error. */
#define ALC_NO_ERROR 0
/** Invalid device handle. */
#define ALC_INVALID_DEVICE 0xA001
/** Invalid context handle. */
#define ALC_INVALID_CONTEXT 0xA002
/** Invalid enum parameter passed to an ALC call. */
#define ALC_INVALID_ENUM 0xA003
/** Invalid value parameter passed to an ALC call. */
#define ALC_INVALID_VALUE 0xA004
/** Out of memory. */
#define ALC_OUT_OF_MEMORY 0xA005
/** Runtime ALC version. */
#define ALC_MAJOR_VERSION 0x1000
#define ALC_MINOR_VERSION 0x1001
/** Context attribute list properties. */
#define ALC_ATTRIBUTES_SIZE 0x1002
#define ALC_ALL_ATTRIBUTES 0x1003
/** String for the default device specifier. */
#define ALC_DEFAULT_DEVICE_SPECIFIER 0x1004
/**
* String for the given device's specifier.
*
* If device handle is NULL, it is instead a null-char separated list of
* strings of known device specifiers (list ends with an empty string).
*/
#define ALC_DEVICE_SPECIFIER 0x1005
/** String for space-separated list of ALC extensions. */
#define ALC_EXTENSIONS 0x1006
/** Capture extension */
#define ALC_EXT_CAPTURE 1
/**
* String for the given capture device's specifier.
*
* If device handle is NULL, it is instead a null-char separated list of
* strings of known capture device specifiers (list ends with an empty string).
*/
#define ALC_CAPTURE_DEVICE_SPECIFIER 0x310
/** String for the default capture device specifier. */
#define ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER 0x311
/** Number of sample frames available for capture. */
#define ALC_CAPTURE_SAMPLES 0x312
/** Enumerate All extension */
#define ALC_ENUMERATE_ALL_EXT 1
/** String for the default extended device specifier. */
#define ALC_DEFAULT_ALL_DEVICES_SPECIFIER 0x1012
/**
* String for the given extended device's specifier.
*
* If device handle is NULL, it is instead a null-char separated list of
* strings of known extended device specifiers (list ends with an empty string).
*/
#define ALC_ALL_DEVICES_SPECIFIER 0x1013
/** Context management. */
ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint* attrlist);
ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context);
ALC_API void ALC_APIENTRY alcProcessContext(ALCcontext *context);
ALC_API void ALC_APIENTRY alcSuspendContext(ALCcontext *context);
ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context);
ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void);
ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *context);
/** Device management. */
ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename);
ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device);
/**
* Error support.
*
* Obtain the most recent Device error.
*/
ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device);
/**
* Extension support.
*
* Query for the presence of an extension, and obtain any appropriate
* function pointers and enum values.
*/
ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extname);
ALC_API void* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcname);
ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumname);
/** Query function. */
ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum param);
ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values);
/** Capture function. */
ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize);
ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device);
ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device);
ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device);
ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples);
/** Pointer-to-function type, useful for dynamically getting ALC entry points. */
typedef ALCcontext* (ALC_APIENTRY *LPALCCREATECONTEXT)(ALCdevice *device, const ALCint *attrlist);
typedef ALCboolean (ALC_APIENTRY *LPALCMAKECONTEXTCURRENT)(ALCcontext *context);
typedef void (ALC_APIENTRY *LPALCPROCESSCONTEXT)(ALCcontext *context);
typedef void (ALC_APIENTRY *LPALCSUSPENDCONTEXT)(ALCcontext *context);
typedef void (ALC_APIENTRY *LPALCDESTROYCONTEXT)(ALCcontext *context);
typedef ALCcontext* (ALC_APIENTRY *LPALCGETCURRENTCONTEXT)(void);
typedef ALCdevice* (ALC_APIENTRY *LPALCGETCONTEXTSDEVICE)(ALCcontext *context);
typedef ALCdevice* (ALC_APIENTRY *LPALCOPENDEVICE)(const ALCchar *devicename);
typedef ALCboolean (ALC_APIENTRY *LPALCCLOSEDEVICE)(ALCdevice *device);
typedef ALCenum (ALC_APIENTRY *LPALCGETERROR)(ALCdevice *device);
typedef ALCboolean (ALC_APIENTRY *LPALCISEXTENSIONPRESENT)(ALCdevice *device, const ALCchar *extname);
typedef void* (ALC_APIENTRY *LPALCGETPROCADDRESS)(ALCdevice *device, const ALCchar *funcname);
typedef ALCenum (ALC_APIENTRY *LPALCGETENUMVALUE)(ALCdevice *device, const ALCchar *enumname);
typedef const ALCchar* (ALC_APIENTRY *LPALCGETSTRING)(ALCdevice *device, ALCenum param);
typedef void (ALC_APIENTRY *LPALCGETINTEGERV)(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values);
typedef ALCdevice* (ALC_APIENTRY *LPALCCAPTUREOPENDEVICE)(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize);
typedef ALCboolean (ALC_APIENTRY *LPALCCAPTURECLOSEDEVICE)(ALCdevice *device);
typedef void (ALC_APIENTRY *LPALCCAPTURESTART)(ALCdevice *device);
typedef void (ALC_APIENTRY *LPALCCAPTURESTOP)(ALCdevice *device);
typedef void (ALC_APIENTRY *LPALCCAPTURESAMPLES)(ALCdevice *device, ALCvoid *buffer, ALCsizei samples);
#if defined(__cplusplus)
}
#endif
#endif /* AL_ALC_H */

View File

@ -1,355 +0,0 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 2008 by authors.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#ifndef AL_ALEXT_H
#define AL_ALEXT_H
#include <stddef.h>
/* Define int64_t and uint64_t types */
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
#include <inttypes.h>
#elif defined(_WIN32) && defined(__GNUC__)
#include <stdint.h>
#elif defined(_WIN32)
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
#else
/* Fallback if nothing above works */
#include <inttypes.h>
#endif
#include "alc.h"
#include "al.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifndef AL_LOKI_IMA_ADPCM_format
#define AL_LOKI_IMA_ADPCM_format 1
#define AL_FORMAT_IMA_ADPCM_MONO16_EXT 0x10000
#define AL_FORMAT_IMA_ADPCM_STEREO16_EXT 0x10001
#endif
#ifndef AL_LOKI_WAVE_format
#define AL_LOKI_WAVE_format 1
#define AL_FORMAT_WAVE_EXT 0x10002
#endif
#ifndef AL_EXT_vorbis
#define AL_EXT_vorbis 1
#define AL_FORMAT_VORBIS_EXT 0x10003
#endif
#ifndef AL_LOKI_quadriphonic
#define AL_LOKI_quadriphonic 1
#define AL_FORMAT_QUAD8_LOKI 0x10004
#define AL_FORMAT_QUAD16_LOKI 0x10005
#endif
#ifndef AL_EXT_float32
#define AL_EXT_float32 1
#define AL_FORMAT_MONO_FLOAT32 0x10010
#define AL_FORMAT_STEREO_FLOAT32 0x10011
#endif
#ifndef AL_EXT_double
#define AL_EXT_double 1
#define AL_FORMAT_MONO_DOUBLE_EXT 0x10012
#define AL_FORMAT_STEREO_DOUBLE_EXT 0x10013
#endif
#ifndef AL_EXT_MULAW
#define AL_EXT_MULAW 1
#define AL_FORMAT_MONO_MULAW_EXT 0x10014
#define AL_FORMAT_STEREO_MULAW_EXT 0x10015
#endif
#ifndef AL_EXT_ALAW
#define AL_EXT_ALAW 1
#define AL_FORMAT_MONO_ALAW_EXT 0x10016
#define AL_FORMAT_STEREO_ALAW_EXT 0x10017
#endif
#ifndef ALC_LOKI_audio_channel
#define ALC_LOKI_audio_channel 1
#define ALC_CHAN_MAIN_LOKI 0x500001
#define ALC_CHAN_PCM_LOKI 0x500002
#define ALC_CHAN_CD_LOKI 0x500003
#endif
#ifndef AL_EXT_MCFORMATS
#define AL_EXT_MCFORMATS 1
#define AL_FORMAT_QUAD8 0x1204
#define AL_FORMAT_QUAD16 0x1205
#define AL_FORMAT_QUAD32 0x1206
#define AL_FORMAT_REAR8 0x1207
#define AL_FORMAT_REAR16 0x1208
#define AL_FORMAT_REAR32 0x1209
#define AL_FORMAT_51CHN8 0x120A
#define AL_FORMAT_51CHN16 0x120B
#define AL_FORMAT_51CHN32 0x120C
#define AL_FORMAT_61CHN8 0x120D
#define AL_FORMAT_61CHN16 0x120E
#define AL_FORMAT_61CHN32 0x120F
#define AL_FORMAT_71CHN8 0x1210
#define AL_FORMAT_71CHN16 0x1211
#define AL_FORMAT_71CHN32 0x1212
#endif
#ifndef AL_EXT_MULAW_MCFORMATS
#define AL_EXT_MULAW_MCFORMATS 1
#define AL_FORMAT_MONO_MULAW 0x10014
#define AL_FORMAT_STEREO_MULAW 0x10015
#define AL_FORMAT_QUAD_MULAW 0x10021
#define AL_FORMAT_REAR_MULAW 0x10022
#define AL_FORMAT_51CHN_MULAW 0x10023
#define AL_FORMAT_61CHN_MULAW 0x10024
#define AL_FORMAT_71CHN_MULAW 0x10025
#endif
#ifndef AL_EXT_IMA4
#define AL_EXT_IMA4 1
#define AL_FORMAT_MONO_IMA4 0x1300
#define AL_FORMAT_STEREO_IMA4 0x1301
#endif
#ifndef AL_EXT_STATIC_BUFFER
#define AL_EXT_STATIC_BUFFER 1
typedef ALvoid (AL_APIENTRY*PFNALBUFFERDATASTATICPROC)(const ALint,ALenum,ALvoid*,ALsizei,ALsizei);
#ifdef AL_ALEXT_PROTOTYPES
AL_API ALvoid AL_APIENTRY alBufferDataStatic(const ALint buffer, ALenum format, ALvoid *data, ALsizei len, ALsizei freq);
#endif
#endif
#ifndef ALC_EXT_EFX
#define ALC_EXT_EFX 1
#include "efx.h"
#endif
#ifndef ALC_EXT_disconnect
#define ALC_EXT_disconnect 1
#define ALC_CONNECTED 0x313
#endif
#ifndef ALC_EXT_thread_local_context
#define ALC_EXT_thread_local_context 1
typedef ALCboolean (ALC_APIENTRY*PFNALCSETTHREADCONTEXTPROC)(ALCcontext *context);
typedef ALCcontext* (ALC_APIENTRY*PFNALCGETTHREADCONTEXTPROC)(void);
#ifdef AL_ALEXT_PROTOTYPES
ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context);
ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void);
#endif
#endif
#ifndef AL_EXT_source_distance_model
#define AL_EXT_source_distance_model 1
#define AL_SOURCE_DISTANCE_MODEL 0x200
#endif
#ifndef AL_SOFT_buffer_sub_data
#define AL_SOFT_buffer_sub_data 1
#define AL_BYTE_RW_OFFSETS_SOFT 0x1031
#define AL_SAMPLE_RW_OFFSETS_SOFT 0x1032
typedef ALvoid (AL_APIENTRY*PFNALBUFFERSUBDATASOFTPROC)(ALuint,ALenum,const ALvoid*,ALsizei,ALsizei);
#ifdef AL_ALEXT_PROTOTYPES
AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer,ALenum format,const ALvoid *data,ALsizei offset,ALsizei length);
#endif
#endif
#ifndef AL_SOFT_loop_points
#define AL_SOFT_loop_points 1
#define AL_LOOP_POINTS_SOFT 0x2015
#endif
#ifndef AL_EXT_FOLDBACK
#define AL_EXT_FOLDBACK 1
#define AL_EXT_FOLDBACK_NAME "AL_EXT_FOLDBACK"
#define AL_FOLDBACK_EVENT_BLOCK 0x4112
#define AL_FOLDBACK_EVENT_START 0x4111
#define AL_FOLDBACK_EVENT_STOP 0x4113
#define AL_FOLDBACK_MODE_MONO 0x4101
#define AL_FOLDBACK_MODE_STEREO 0x4102
typedef void (AL_APIENTRY*LPALFOLDBACKCALLBACK)(ALenum,ALsizei);
typedef void (AL_APIENTRY*LPALREQUESTFOLDBACKSTART)(ALenum,ALsizei,ALsizei,ALfloat*,LPALFOLDBACKCALLBACK);
typedef void (AL_APIENTRY*LPALREQUESTFOLDBACKSTOP)(void);
#ifdef AL_ALEXT_PROTOTYPES
AL_API void AL_APIENTRY alRequestFoldbackStart(ALenum mode,ALsizei count,ALsizei length,ALfloat *mem,LPALFOLDBACKCALLBACK callback);
AL_API void AL_APIENTRY alRequestFoldbackStop(void);
#endif
#endif
#ifndef ALC_EXT_DEDICATED
#define ALC_EXT_DEDICATED 1
#define AL_DEDICATED_GAIN 0x0001
#define AL_EFFECT_DEDICATED_DIALOGUE 0x9001
#define AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT 0x9000
#endif
#ifndef AL_SOFT_buffer_samples
#define AL_SOFT_buffer_samples 1
/* Channel configurations */
#define AL_MONO_SOFT 0x1500
#define AL_STEREO_SOFT 0x1501
#define AL_REAR_SOFT 0x1502
#define AL_QUAD_SOFT 0x1503
#define AL_5POINT1_SOFT 0x1504
#define AL_6POINT1_SOFT 0x1505
#define AL_7POINT1_SOFT 0x1506
/* Sample types */
#define AL_BYTE_SOFT 0x1400
#define AL_UNSIGNED_BYTE_SOFT 0x1401
#define AL_SHORT_SOFT 0x1402
#define AL_UNSIGNED_SHORT_SOFT 0x1403
#define AL_INT_SOFT 0x1404
#define AL_UNSIGNED_INT_SOFT 0x1405
#define AL_FLOAT_SOFT 0x1406
#define AL_DOUBLE_SOFT 0x1407
#define AL_BYTE3_SOFT 0x1408
#define AL_UNSIGNED_BYTE3_SOFT 0x1409
/* Storage formats */
#define AL_MONO8_SOFT 0x1100
#define AL_MONO16_SOFT 0x1101
#define AL_MONO32F_SOFT 0x10010
#define AL_STEREO8_SOFT 0x1102
#define AL_STEREO16_SOFT 0x1103
#define AL_STEREO32F_SOFT 0x10011
#define AL_QUAD8_SOFT 0x1204
#define AL_QUAD16_SOFT 0x1205
#define AL_QUAD32F_SOFT 0x1206
#define AL_REAR8_SOFT 0x1207
#define AL_REAR16_SOFT 0x1208
#define AL_REAR32F_SOFT 0x1209
#define AL_5POINT1_8_SOFT 0x120A
#define AL_5POINT1_16_SOFT 0x120B
#define AL_5POINT1_32F_SOFT 0x120C
#define AL_6POINT1_8_SOFT 0x120D
#define AL_6POINT1_16_SOFT 0x120E
#define AL_6POINT1_32F_SOFT 0x120F
#define AL_7POINT1_8_SOFT 0x1210
#define AL_7POINT1_16_SOFT 0x1211
#define AL_7POINT1_32F_SOFT 0x1212
/* Buffer attributes */
#define AL_INTERNAL_FORMAT_SOFT 0x2008
#define AL_BYTE_LENGTH_SOFT 0x2009
#define AL_SAMPLE_LENGTH_SOFT 0x200A
#define AL_SEC_LENGTH_SOFT 0x200B
typedef void (AL_APIENTRY*LPALBUFFERSAMPLESSOFT)(ALuint,ALuint,ALenum,ALsizei,ALenum,ALenum,const ALvoid*);
typedef void (AL_APIENTRY*LPALBUFFERSUBSAMPLESSOFT)(ALuint,ALsizei,ALsizei,ALenum,ALenum,const ALvoid*);
typedef void (AL_APIENTRY*LPALGETBUFFERSAMPLESSOFT)(ALuint,ALsizei,ALsizei,ALenum,ALenum,ALvoid*);
typedef ALboolean (AL_APIENTRY*LPALISBUFFERFORMATSUPPORTEDSOFT)(ALenum);
#ifdef AL_ALEXT_PROTOTYPES
AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer, ALuint samplerate, ALenum internalformat, ALsizei samples, ALenum channels, ALenum type, const ALvoid *data);
AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint buffer, ALsizei offset, ALsizei samples, ALenum channels, ALenum type, const ALvoid *data);
AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer, ALsizei offset, ALsizei samples, ALenum channels, ALenum type, ALvoid *data);
AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format);
#endif
#endif
#ifndef AL_SOFT_direct_channels
#define AL_SOFT_direct_channels 1
#define AL_DIRECT_CHANNELS_SOFT 0x1033
#endif
#ifndef ALC_SOFT_loopback
#define ALC_SOFT_loopback 1
#define ALC_FORMAT_CHANNELS_SOFT 0x1990
#define ALC_FORMAT_TYPE_SOFT 0x1991
/* Sample types */
#define ALC_BYTE_SOFT 0x1400
#define ALC_UNSIGNED_BYTE_SOFT 0x1401
#define ALC_SHORT_SOFT 0x1402
#define ALC_UNSIGNED_SHORT_SOFT 0x1403
#define ALC_INT_SOFT 0x1404
#define ALC_UNSIGNED_INT_SOFT 0x1405
#define ALC_FLOAT_SOFT 0x1406
/* Channel configurations */
#define ALC_MONO_SOFT 0x1500
#define ALC_STEREO_SOFT 0x1501
#define ALC_QUAD_SOFT 0x1503
#define ALC_5POINT1_SOFT 0x1504
#define ALC_6POINT1_SOFT 0x1505
#define ALC_7POINT1_SOFT 0x1506
typedef ALCdevice* (ALC_APIENTRY*LPALCLOOPBACKOPENDEVICESOFT)(const ALCchar*);
typedef ALCboolean (ALC_APIENTRY*LPALCISRENDERFORMATSUPPORTEDSOFT)(ALCdevice*,ALCsizei,ALCenum,ALCenum);
typedef void (ALC_APIENTRY*LPALCRENDERSAMPLESSOFT)(ALCdevice*,ALCvoid*,ALCsizei);
#ifdef AL_ALEXT_PROTOTYPES
ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceName);
ALC_API ALCboolean ALC_APIENTRY alcIsRenderFormatSupportedSOFT(ALCdevice *device, ALCsizei freq, ALCenum channels, ALCenum type);
ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, ALCvoid *buffer, ALCsizei samples);
#endif
#endif
#ifndef AL_EXT_STEREO_ANGLES
#define AL_EXT_STEREO_ANGLES 1
#define AL_STEREO_ANGLES 0x1030
#endif
#ifndef AL_EXT_SOURCE_RADIUS
#define AL_EXT_SOURCE_RADIUS 1
#define AL_SOURCE_RADIUS 0x1031
#endif
#ifndef AL_SOFT_source_latency
#define AL_SOFT_source_latency 1
#define AL_SAMPLE_OFFSET_LATENCY_SOFT 0x1200
#define AL_SEC_OFFSET_LATENCY_SOFT 0x1201
typedef int64_t ALint64SOFT;
typedef uint64_t ALuint64SOFT;
typedef void (AL_APIENTRY*LPALSOURCEDSOFT)(ALuint,ALenum,ALdouble);
typedef void (AL_APIENTRY*LPALSOURCE3DSOFT)(ALuint,ALenum,ALdouble,ALdouble,ALdouble);
typedef void (AL_APIENTRY*LPALSOURCEDVSOFT)(ALuint,ALenum,const ALdouble*);
typedef void (AL_APIENTRY*LPALGETSOURCEDSOFT)(ALuint,ALenum,ALdouble*);
typedef void (AL_APIENTRY*LPALGETSOURCE3DSOFT)(ALuint,ALenum,ALdouble*,ALdouble*,ALdouble*);
typedef void (AL_APIENTRY*LPALGETSOURCEDVSOFT)(ALuint,ALenum,ALdouble*);
typedef void (AL_APIENTRY*LPALSOURCEI64SOFT)(ALuint,ALenum,ALint64SOFT);
typedef void (AL_APIENTRY*LPALSOURCE3I64SOFT)(ALuint,ALenum,ALint64SOFT,ALint64SOFT,ALint64SOFT);
typedef void (AL_APIENTRY*LPALSOURCEI64VSOFT)(ALuint,ALenum,const ALint64SOFT*);
typedef void (AL_APIENTRY*LPALGETSOURCEI64SOFT)(ALuint,ALenum,ALint64SOFT*);
typedef void (AL_APIENTRY*LPALGETSOURCE3I64SOFT)(ALuint,ALenum,ALint64SOFT*,ALint64SOFT*,ALint64SOFT*);
typedef void (AL_APIENTRY*LPALGETSOURCEI64VSOFT)(ALuint,ALenum,ALint64SOFT*);
#ifdef AL_ALEXT_PROTOTYPES
AL_API void AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value);
AL_API void AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3);
AL_API void AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values);
AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value);
AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3);
AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values);
AL_API void AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value);
AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3);
AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values);
AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value);
AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3);
AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values);
#endif
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,3 +0,0 @@
/* The tokens that would be defined here are already defined in efx.h. This
* empty file is here to provide compatibility with Windows-based projects
* that would include it. */

View File

@ -1,402 +0,0 @@
/* Reverb presets for EFX */
#ifndef EFX_PRESETS_H
#define EFX_PRESETS_H
#ifndef EFXEAXREVERBPROPERTIES_DEFINED
#define EFXEAXREVERBPROPERTIES_DEFINED
typedef struct {
float flDensity;
float flDiffusion;
float flGain;
float flGainHF;
float flGainLF;
float flDecayTime;
float flDecayHFRatio;
float flDecayLFRatio;
float flReflectionsGain;
float flReflectionsDelay;
float flReflectionsPan[3];
float flLateReverbGain;
float flLateReverbDelay;
float flLateReverbPan[3];
float flEchoTime;
float flEchoDepth;
float flModulationTime;
float flModulationDepth;
float flAirAbsorptionGainHF;
float flHFReference;
float flLFReference;
float flRoomRolloffFactor;
int iDecayHFLimit;
} EFXEAXREVERBPROPERTIES, *LPEFXEAXREVERBPROPERTIES;
#endif
/* Default Presets */
#define EFX_REVERB_PRESET_GENERIC \
{ 1.0000f, 1.0000f, 0.3162f, 0.8913f, 1.0000f, 1.4900f, 0.8300f, 1.0000f, 0.0500f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_PADDEDCELL \
{ 0.1715f, 1.0000f, 0.3162f, 0.0010f, 1.0000f, 0.1700f, 0.1000f, 1.0000f, 0.2500f, 0.0010f, { 0.0000f, 0.0000f, 0.0000f }, 1.2691f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_ROOM \
{ 0.4287f, 1.0000f, 0.3162f, 0.5929f, 1.0000f, 0.4000f, 0.8300f, 1.0000f, 0.1503f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 1.0629f, 0.0030f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_BATHROOM \
{ 0.1715f, 1.0000f, 0.3162f, 0.2512f, 1.0000f, 1.4900f, 0.5400f, 1.0000f, 0.6531f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 3.2734f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_LIVINGROOM \
{ 0.9766f, 1.0000f, 0.3162f, 0.0010f, 1.0000f, 0.5000f, 0.1000f, 1.0000f, 0.2051f, 0.0030f, { 0.0000f, 0.0000f, 0.0000f }, 0.2805f, 0.0040f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_STONEROOM \
{ 1.0000f, 1.0000f, 0.3162f, 0.7079f, 1.0000f, 2.3100f, 0.6400f, 1.0000f, 0.4411f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1003f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_AUDITORIUM \
{ 1.0000f, 1.0000f, 0.3162f, 0.5781f, 1.0000f, 4.3200f, 0.5900f, 1.0000f, 0.4032f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.7170f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_CONCERTHALL \
{ 1.0000f, 1.0000f, 0.3162f, 0.5623f, 1.0000f, 3.9200f, 0.7000f, 1.0000f, 0.2427f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.9977f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_CAVE \
{ 1.0000f, 1.0000f, 0.3162f, 1.0000f, 1.0000f, 2.9100f, 1.3000f, 1.0000f, 0.5000f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.7063f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_ARENA \
{ 1.0000f, 1.0000f, 0.3162f, 0.4477f, 1.0000f, 7.2400f, 0.3300f, 1.0000f, 0.2612f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.0186f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_HANGAR \
{ 1.0000f, 1.0000f, 0.3162f, 0.3162f, 1.0000f, 10.0500f, 0.2300f, 1.0000f, 0.5000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.2560f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_CARPETEDHALLWAY \
{ 0.4287f, 1.0000f, 0.3162f, 0.0100f, 1.0000f, 0.3000f, 0.1000f, 1.0000f, 0.1215f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 0.1531f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_HALLWAY \
{ 0.3645f, 1.0000f, 0.3162f, 0.7079f, 1.0000f, 1.4900f, 0.5900f, 1.0000f, 0.2458f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.6615f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_STONECORRIDOR \
{ 1.0000f, 1.0000f, 0.3162f, 0.7612f, 1.0000f, 2.7000f, 0.7900f, 1.0000f, 0.2472f, 0.0130f, { 0.0000f, 0.0000f, 0.0000f }, 1.5758f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_ALLEY \
{ 1.0000f, 0.3000f, 0.3162f, 0.7328f, 1.0000f, 1.4900f, 0.8600f, 1.0000f, 0.2500f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.9954f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 0.9500f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_FOREST \
{ 1.0000f, 0.3000f, 0.3162f, 0.0224f, 1.0000f, 1.4900f, 0.5400f, 1.0000f, 0.0525f, 0.1620f, { 0.0000f, 0.0000f, 0.0000f }, 0.7682f, 0.0880f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_CITY \
{ 1.0000f, 0.5000f, 0.3162f, 0.3981f, 1.0000f, 1.4900f, 0.6700f, 1.0000f, 0.0730f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.1427f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_MOUNTAINS \
{ 1.0000f, 0.2700f, 0.3162f, 0.0562f, 1.0000f, 1.4900f, 0.2100f, 1.0000f, 0.0407f, 0.3000f, { 0.0000f, 0.0000f, 0.0000f }, 0.1919f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_QUARRY \
{ 1.0000f, 1.0000f, 0.3162f, 0.3162f, 1.0000f, 1.4900f, 0.8300f, 1.0000f, 0.0000f, 0.0610f, { 0.0000f, 0.0000f, 0.0000f }, 1.7783f, 0.0250f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 0.7000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_PLAIN \
{ 1.0000f, 0.2100f, 0.3162f, 0.1000f, 1.0000f, 1.4900f, 0.5000f, 1.0000f, 0.0585f, 0.1790f, { 0.0000f, 0.0000f, 0.0000f }, 0.1089f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_PARKINGLOT \
{ 1.0000f, 1.0000f, 0.3162f, 1.0000f, 1.0000f, 1.6500f, 1.5000f, 1.0000f, 0.2082f, 0.0080f, { 0.0000f, 0.0000f, 0.0000f }, 0.2652f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_SEWERPIPE \
{ 0.3071f, 0.8000f, 0.3162f, 0.3162f, 1.0000f, 2.8100f, 0.1400f, 1.0000f, 1.6387f, 0.0140f, { 0.0000f, 0.0000f, 0.0000f }, 3.2471f, 0.0210f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_UNDERWATER \
{ 0.3645f, 1.0000f, 0.3162f, 0.0100f, 1.0000f, 1.4900f, 0.1000f, 1.0000f, 0.5963f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 7.0795f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 1.1800f, 0.3480f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_DRUGGED \
{ 0.4287f, 0.5000f, 0.3162f, 1.0000f, 1.0000f, 8.3900f, 1.3900f, 1.0000f, 0.8760f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 3.1081f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 1.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_DIZZY \
{ 0.3645f, 0.6000f, 0.3162f, 0.6310f, 1.0000f, 17.2300f, 0.5600f, 1.0000f, 0.1392f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.4937f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.8100f, 0.3100f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_PSYCHOTIC \
{ 0.0625f, 0.5000f, 0.3162f, 0.8404f, 1.0000f, 7.5600f, 0.9100f, 1.0000f, 0.4864f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 2.4378f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 4.0000f, 1.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
/* Castle Presets */
#define EFX_REVERB_PRESET_CASTLE_SMALLROOM \
{ 1.0000f, 0.8900f, 0.3162f, 0.3981f, 0.1000f, 1.2200f, 0.8300f, 0.3100f, 0.8913f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_CASTLE_SHORTPASSAGE \
{ 1.0000f, 0.8900f, 0.3162f, 0.3162f, 0.1000f, 2.3200f, 0.8300f, 0.3100f, 0.8913f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_CASTLE_MEDIUMROOM \
{ 1.0000f, 0.9300f, 0.3162f, 0.2818f, 0.1000f, 2.0400f, 0.8300f, 0.4600f, 0.6310f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 1.5849f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1550f, 0.0300f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_CASTLE_LARGEROOM \
{ 1.0000f, 0.8200f, 0.3162f, 0.2818f, 0.1259f, 2.5300f, 0.8300f, 0.5000f, 0.4467f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.1850f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_CASTLE_LONGPASSAGE \
{ 1.0000f, 0.8900f, 0.3162f, 0.3981f, 0.1000f, 3.4200f, 0.8300f, 0.3100f, 0.8913f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_CASTLE_HALL \
{ 1.0000f, 0.8100f, 0.3162f, 0.2818f, 0.1778f, 3.1400f, 0.7900f, 0.6200f, 0.1778f, 0.0560f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_CASTLE_CUPBOARD \
{ 1.0000f, 0.8900f, 0.3162f, 0.2818f, 0.1000f, 0.6700f, 0.8700f, 0.3100f, 1.4125f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 3.5481f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_CASTLE_COURTYARD \
{ 1.0000f, 0.4200f, 0.3162f, 0.4467f, 0.1995f, 2.1300f, 0.6100f, 0.2300f, 0.2239f, 0.1600f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0360f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.3700f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_CASTLE_ALCOVE \
{ 1.0000f, 0.8900f, 0.3162f, 0.5012f, 0.1000f, 1.6400f, 0.8700f, 0.3100f, 1.0000f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 }
/* Factory Presets */
#define EFX_REVERB_PRESET_FACTORY_SMALLROOM \
{ 0.3645f, 0.8200f, 0.3162f, 0.7943f, 0.5012f, 1.7200f, 0.6500f, 1.3100f, 0.7079f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.7783f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.1190f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_FACTORY_SHORTPASSAGE \
{ 0.3645f, 0.6400f, 0.2512f, 0.7943f, 0.5012f, 2.5300f, 0.6500f, 1.3100f, 1.0000f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.1350f, 0.2300f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_FACTORY_MEDIUMROOM \
{ 0.4287f, 0.8200f, 0.2512f, 0.7943f, 0.5012f, 2.7600f, 0.6500f, 1.3100f, 0.2818f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1740f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_FACTORY_LARGEROOM \
{ 0.4287f, 0.7500f, 0.2512f, 0.7079f, 0.6310f, 4.2400f, 0.5100f, 1.3100f, 0.1778f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.2310f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_FACTORY_LONGPASSAGE \
{ 0.3645f, 0.6400f, 0.2512f, 0.7943f, 0.5012f, 4.0600f, 0.6500f, 1.3100f, 1.0000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0370f, { 0.0000f, 0.0000f, 0.0000f }, 0.1350f, 0.2300f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_FACTORY_HALL \
{ 0.4287f, 0.7500f, 0.3162f, 0.7079f, 0.6310f, 7.4300f, 0.5100f, 1.3100f, 0.0631f, 0.0730f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0270f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_FACTORY_CUPBOARD \
{ 0.3071f, 0.6300f, 0.2512f, 0.7943f, 0.5012f, 0.4900f, 0.6500f, 1.3100f, 1.2589f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.1070f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_FACTORY_COURTYARD \
{ 0.3071f, 0.5700f, 0.3162f, 0.3162f, 0.6310f, 2.3200f, 0.2900f, 0.5600f, 0.2239f, 0.1400f, { 0.0000f, 0.0000f, 0.0000f }, 0.3981f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2900f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_FACTORY_ALCOVE \
{ 0.3645f, 0.5900f, 0.2512f, 0.7943f, 0.5012f, 3.1400f, 0.6500f, 1.3100f, 1.4125f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.1140f, 0.1000f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 }
/* Ice Palace Presets */
#define EFX_REVERB_PRESET_ICEPALACE_SMALLROOM \
{ 1.0000f, 0.8400f, 0.3162f, 0.5623f, 0.2818f, 1.5100f, 1.5300f, 0.2700f, 0.8913f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1640f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_ICEPALACE_SHORTPASSAGE \
{ 1.0000f, 0.7500f, 0.3162f, 0.5623f, 0.2818f, 1.7900f, 1.4600f, 0.2800f, 0.5012f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0190f, { 0.0000f, 0.0000f, 0.0000f }, 0.1770f, 0.0900f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_ICEPALACE_MEDIUMROOM \
{ 1.0000f, 0.8700f, 0.3162f, 0.5623f, 0.4467f, 2.2200f, 1.5300f, 0.3200f, 0.3981f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0270f, { 0.0000f, 0.0000f, 0.0000f }, 0.1860f, 0.1200f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_ICEPALACE_LARGEROOM \
{ 1.0000f, 0.8100f, 0.3162f, 0.5623f, 0.4467f, 3.1400f, 1.5300f, 0.3200f, 0.2512f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0270f, { 0.0000f, 0.0000f, 0.0000f }, 0.2140f, 0.1100f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_ICEPALACE_LONGPASSAGE \
{ 1.0000f, 0.7700f, 0.3162f, 0.5623f, 0.3981f, 3.0100f, 1.4600f, 0.2800f, 0.7943f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0250f, { 0.0000f, 0.0000f, 0.0000f }, 0.1860f, 0.0400f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_ICEPALACE_HALL \
{ 1.0000f, 0.7600f, 0.3162f, 0.4467f, 0.5623f, 5.4900f, 1.5300f, 0.3800f, 0.1122f, 0.0540f, { 0.0000f, 0.0000f, 0.0000f }, 0.6310f, 0.0520f, { 0.0000f, 0.0000f, 0.0000f }, 0.2260f, 0.1100f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_ICEPALACE_CUPBOARD \
{ 1.0000f, 0.8300f, 0.3162f, 0.5012f, 0.2239f, 0.7600f, 1.5300f, 0.2600f, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.1430f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_ICEPALACE_COURTYARD \
{ 1.0000f, 0.5900f, 0.3162f, 0.2818f, 0.3162f, 2.0400f, 1.2000f, 0.3800f, 0.3162f, 0.1730f, { 0.0000f, 0.0000f, 0.0000f }, 0.3162f, 0.0430f, { 0.0000f, 0.0000f, 0.0000f }, 0.2350f, 0.4800f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_ICEPALACE_ALCOVE \
{ 1.0000f, 0.8400f, 0.3162f, 0.5623f, 0.2818f, 2.7600f, 1.4600f, 0.2800f, 1.1220f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1610f, 0.0900f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 }
/* Space Station Presets */
#define EFX_REVERB_PRESET_SPACESTATION_SMALLROOM \
{ 0.2109f, 0.7000f, 0.3162f, 0.7079f, 0.8913f, 1.7200f, 0.8200f, 0.5500f, 0.7943f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0130f, { 0.0000f, 0.0000f, 0.0000f }, 0.1880f, 0.2600f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_SPACESTATION_SHORTPASSAGE \
{ 0.2109f, 0.8700f, 0.3162f, 0.6310f, 0.8913f, 3.5700f, 0.5000f, 0.5500f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.1720f, 0.2000f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_SPACESTATION_MEDIUMROOM \
{ 0.2109f, 0.7500f, 0.3162f, 0.6310f, 0.8913f, 3.0100f, 0.5000f, 0.5500f, 0.3981f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0350f, { 0.0000f, 0.0000f, 0.0000f }, 0.2090f, 0.3100f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_SPACESTATION_LARGEROOM \
{ 0.3645f, 0.8100f, 0.3162f, 0.6310f, 0.8913f, 3.8900f, 0.3800f, 0.6100f, 0.3162f, 0.0560f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0350f, { 0.0000f, 0.0000f, 0.0000f }, 0.2330f, 0.2800f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_SPACESTATION_LONGPASSAGE \
{ 0.4287f, 0.8200f, 0.3162f, 0.6310f, 0.8913f, 4.6200f, 0.6200f, 0.5500f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0310f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2300f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_SPACESTATION_HALL \
{ 0.4287f, 0.8700f, 0.3162f, 0.6310f, 0.8913f, 7.1100f, 0.3800f, 0.6100f, 0.1778f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.6310f, 0.0470f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2500f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_SPACESTATION_CUPBOARD \
{ 0.1715f, 0.5600f, 0.3162f, 0.7079f, 0.8913f, 0.7900f, 0.8100f, 0.5500f, 1.4125f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.7783f, 0.0180f, { 0.0000f, 0.0000f, 0.0000f }, 0.1810f, 0.3100f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_SPACESTATION_ALCOVE \
{ 0.2109f, 0.7800f, 0.3162f, 0.7079f, 0.8913f, 1.1600f, 0.8100f, 0.5500f, 1.4125f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0180f, { 0.0000f, 0.0000f, 0.0000f }, 0.1920f, 0.2100f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 }
/* Wooden Galleon Presets */
#define EFX_REVERB_PRESET_WOODEN_SMALLROOM \
{ 1.0000f, 1.0000f, 0.3162f, 0.1122f, 0.3162f, 0.7900f, 0.3200f, 0.8700f, 1.0000f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_WOODEN_SHORTPASSAGE \
{ 1.0000f, 1.0000f, 0.3162f, 0.1259f, 0.3162f, 1.7500f, 0.5000f, 0.8700f, 0.8913f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.6310f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_WOODEN_MEDIUMROOM \
{ 1.0000f, 1.0000f, 0.3162f, 0.1000f, 0.2818f, 1.4700f, 0.4200f, 0.8200f, 0.8913f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_WOODEN_LARGEROOM \
{ 1.0000f, 1.0000f, 0.3162f, 0.0891f, 0.2818f, 2.6500f, 0.3300f, 0.8200f, 0.8913f, 0.0660f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_WOODEN_LONGPASSAGE \
{ 1.0000f, 1.0000f, 0.3162f, 0.1000f, 0.3162f, 1.9900f, 0.4000f, 0.7900f, 1.0000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.4467f, 0.0360f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_WOODEN_HALL \
{ 1.0000f, 1.0000f, 0.3162f, 0.0794f, 0.2818f, 3.4500f, 0.3000f, 0.8200f, 0.8913f, 0.0880f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0630f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_WOODEN_CUPBOARD \
{ 1.0000f, 1.0000f, 0.3162f, 0.1413f, 0.3162f, 0.5600f, 0.4600f, 0.9100f, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0280f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_WOODEN_COURTYARD \
{ 1.0000f, 0.6500f, 0.3162f, 0.0794f, 0.3162f, 1.7900f, 0.3500f, 0.7900f, 0.5623f, 0.1230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1000f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_WOODEN_ALCOVE \
{ 1.0000f, 1.0000f, 0.3162f, 0.1259f, 0.3162f, 1.2200f, 0.6200f, 0.9100f, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 }
/* Sports Presets */
#define EFX_REVERB_PRESET_SPORT_EMPTYSTADIUM \
{ 1.0000f, 1.0000f, 0.3162f, 0.4467f, 0.7943f, 6.2600f, 0.5100f, 1.1000f, 0.0631f, 0.1830f, { 0.0000f, 0.0000f, 0.0000f }, 0.3981f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_SPORT_SQUASHCOURT \
{ 1.0000f, 0.7500f, 0.3162f, 0.3162f, 0.7943f, 2.2200f, 0.9100f, 1.1600f, 0.4467f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1260f, 0.1900f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_SPORT_SMALLSWIMMINGPOOL \
{ 1.0000f, 0.7000f, 0.3162f, 0.7943f, 0.8913f, 2.7600f, 1.2500f, 1.1400f, 0.6310f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1790f, 0.1500f, 0.8950f, 0.1900f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_SPORT_LARGESWIMMINGPOOL \
{ 1.0000f, 0.8200f, 0.3162f, 0.7943f, 1.0000f, 5.4900f, 1.3100f, 1.1400f, 0.4467f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 0.5012f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2220f, 0.5500f, 1.1590f, 0.2100f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_SPORT_GYMNASIUM \
{ 1.0000f, 0.8100f, 0.3162f, 0.4467f, 0.8913f, 3.1400f, 1.0600f, 1.3500f, 0.3981f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.5623f, 0.0450f, { 0.0000f, 0.0000f, 0.0000f }, 0.1460f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_SPORT_FULLSTADIUM \
{ 1.0000f, 1.0000f, 0.3162f, 0.0708f, 0.7943f, 5.2500f, 0.1700f, 0.8000f, 0.1000f, 0.1880f, { 0.0000f, 0.0000f, 0.0000f }, 0.2818f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_SPORT_STADIUMTANNOY \
{ 1.0000f, 0.7800f, 0.3162f, 0.5623f, 0.5012f, 2.5300f, 0.8800f, 0.6800f, 0.2818f, 0.2300f, { 0.0000f, 0.0000f, 0.0000f }, 0.5012f, 0.0630f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
/* Prefab Presets */
#define EFX_REVERB_PRESET_PREFAB_WORKSHOP \
{ 0.4287f, 1.0000f, 0.3162f, 0.1413f, 0.3981f, 0.7600f, 1.0000f, 1.0000f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_PREFAB_SCHOOLROOM \
{ 0.4022f, 0.6900f, 0.3162f, 0.6310f, 0.5012f, 0.9800f, 0.4500f, 0.1800f, 1.4125f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.0950f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_PREFAB_PRACTISEROOM \
{ 0.4022f, 0.8700f, 0.3162f, 0.3981f, 0.5012f, 1.1200f, 0.5600f, 0.1800f, 1.2589f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.0950f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_PREFAB_OUTHOUSE \
{ 1.0000f, 0.8200f, 0.3162f, 0.1122f, 0.1585f, 1.3800f, 0.3800f, 0.3500f, 0.8913f, 0.0240f, { 0.0000f, 0.0000f, -0.0000f }, 0.6310f, 0.0440f, { 0.0000f, 0.0000f, 0.0000f }, 0.1210f, 0.1700f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_PREFAB_CARAVAN \
{ 1.0000f, 1.0000f, 0.3162f, 0.0891f, 0.1259f, 0.4300f, 1.5000f, 1.0000f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
/* Dome and Pipe Presets */
#define EFX_REVERB_PRESET_DOME_TOMB \
{ 1.0000f, 0.7900f, 0.3162f, 0.3548f, 0.2239f, 4.1800f, 0.2100f, 0.1000f, 0.3868f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 1.6788f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.1770f, 0.1900f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_PIPE_SMALL \
{ 1.0000f, 1.0000f, 0.3162f, 0.3548f, 0.2239f, 5.0400f, 0.1000f, 0.1000f, 0.5012f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 2.5119f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_DOME_SAINTPAULS \
{ 1.0000f, 0.8700f, 0.3162f, 0.3548f, 0.2239f, 10.4800f, 0.1900f, 0.1000f, 0.1778f, 0.0900f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0420f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.1200f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_PIPE_LONGTHIN \
{ 0.2560f, 0.9100f, 0.3162f, 0.4467f, 0.2818f, 9.2100f, 0.1800f, 0.1000f, 0.7079f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_PIPE_LARGE \
{ 1.0000f, 1.0000f, 0.3162f, 0.3548f, 0.2239f, 8.4500f, 0.1000f, 0.1000f, 0.3981f, 0.0460f, { 0.0000f, 0.0000f, 0.0000f }, 1.5849f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_PIPE_RESONANT \
{ 0.1373f, 0.9100f, 0.3162f, 0.4467f, 0.2818f, 6.8100f, 0.1800f, 0.1000f, 0.7079f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x0 }
/* Outdoors Presets */
#define EFX_REVERB_PRESET_OUTDOORS_BACKYARD \
{ 1.0000f, 0.4500f, 0.3162f, 0.2512f, 0.5012f, 1.1200f, 0.3400f, 0.4600f, 0.4467f, 0.0690f, { 0.0000f, 0.0000f, -0.0000f }, 0.7079f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.2180f, 0.3400f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_OUTDOORS_ROLLINGPLAINS \
{ 1.0000f, 0.0000f, 0.3162f, 0.0112f, 0.6310f, 2.1300f, 0.2100f, 0.4600f, 0.1778f, 0.3000f, { 0.0000f, 0.0000f, -0.0000f }, 0.4467f, 0.0190f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_OUTDOORS_DEEPCANYON \
{ 1.0000f, 0.7400f, 0.3162f, 0.1778f, 0.6310f, 3.8900f, 0.2100f, 0.4600f, 0.3162f, 0.2230f, { 0.0000f, 0.0000f, -0.0000f }, 0.3548f, 0.0190f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_OUTDOORS_CREEK \
{ 1.0000f, 0.3500f, 0.3162f, 0.1778f, 0.5012f, 2.1300f, 0.2100f, 0.4600f, 0.3981f, 0.1150f, { 0.0000f, 0.0000f, -0.0000f }, 0.1995f, 0.0310f, { 0.0000f, 0.0000f, 0.0000f }, 0.2180f, 0.3400f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_OUTDOORS_VALLEY \
{ 1.0000f, 0.2800f, 0.3162f, 0.0282f, 0.1585f, 2.8800f, 0.2600f, 0.3500f, 0.1413f, 0.2630f, { 0.0000f, 0.0000f, -0.0000f }, 0.3981f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.3400f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 }
/* Mood Presets */
#define EFX_REVERB_PRESET_MOOD_HEAVEN \
{ 1.0000f, 0.9400f, 0.3162f, 0.7943f, 0.4467f, 5.0400f, 1.1200f, 0.5600f, 0.2427f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0800f, 2.7420f, 0.0500f, 0.9977f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_MOOD_HELL \
{ 1.0000f, 0.5700f, 0.3162f, 0.3548f, 0.4467f, 3.5700f, 0.4900f, 2.0000f, 0.0000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1100f, 0.0400f, 2.1090f, 0.5200f, 0.9943f, 5000.0000f, 139.5000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_MOOD_MEMORY \
{ 1.0000f, 0.8500f, 0.3162f, 0.6310f, 0.3548f, 4.0600f, 0.8200f, 0.5600f, 0.0398f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.4740f, 0.4500f, 0.9886f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
/* Driving Presets */
#define EFX_REVERB_PRESET_DRIVING_COMMENTATOR \
{ 1.0000f, 0.0000f, 3.1623f, 0.5623f, 0.5012f, 2.4200f, 0.8800f, 0.6800f, 0.1995f, 0.0930f, { 0.0000f, 0.0000f, 0.0000f }, 0.2512f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9886f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_DRIVING_PITGARAGE \
{ 0.4287f, 0.5900f, 0.3162f, 0.7079f, 0.5623f, 1.7200f, 0.9300f, 0.8700f, 0.5623f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.1100f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_DRIVING_INCAR_RACER \
{ 0.0832f, 0.8000f, 0.3162f, 1.0000f, 0.7943f, 0.1700f, 2.0000f, 0.4100f, 1.7783f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10268.2002f, 251.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_DRIVING_INCAR_SPORTS \
{ 0.0832f, 0.8000f, 0.3162f, 0.6310f, 1.0000f, 0.1700f, 0.7500f, 0.4100f, 1.0000f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.5623f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10268.2002f, 251.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_DRIVING_INCAR_LUXURY \
{ 0.2560f, 1.0000f, 0.3162f, 0.1000f, 0.5012f, 0.1300f, 0.4100f, 0.4600f, 0.7943f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.5849f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10268.2002f, 251.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_DRIVING_FULLGRANDSTAND \
{ 1.0000f, 1.0000f, 0.3162f, 0.2818f, 0.6310f, 3.0100f, 1.3700f, 1.2800f, 0.3548f, 0.0900f, { 0.0000f, 0.0000f, 0.0000f }, 0.1778f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10420.2002f, 250.0000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_DRIVING_EMPTYGRANDSTAND \
{ 1.0000f, 1.0000f, 0.3162f, 1.0000f, 0.7943f, 4.6200f, 1.7500f, 1.4000f, 0.2082f, 0.0900f, { 0.0000f, 0.0000f, 0.0000f }, 0.2512f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10420.2002f, 250.0000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_DRIVING_TUNNEL \
{ 1.0000f, 0.8100f, 0.3162f, 0.3981f, 0.8913f, 3.4200f, 0.9400f, 1.3100f, 0.7079f, 0.0510f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0470f, { 0.0000f, 0.0000f, 0.0000f }, 0.2140f, 0.0500f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 155.3000f, 0.0000f, 0x1 }
/* City Presets */
#define EFX_REVERB_PRESET_CITY_STREETS \
{ 1.0000f, 0.7800f, 0.3162f, 0.7079f, 0.8913f, 1.7900f, 1.1200f, 0.9100f, 0.2818f, 0.0460f, { 0.0000f, 0.0000f, 0.0000f }, 0.1995f, 0.0280f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_CITY_SUBWAY \
{ 1.0000f, 0.7400f, 0.3162f, 0.7079f, 0.8913f, 3.0100f, 1.2300f, 0.9100f, 0.7079f, 0.0460f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0280f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 0.2100f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_CITY_MUSEUM \
{ 1.0000f, 0.8200f, 0.3162f, 0.1778f, 0.1778f, 3.2800f, 1.4000f, 0.5700f, 0.2512f, 0.0390f, { 0.0000f, 0.0000f, -0.0000f }, 0.8913f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 0.1300f, 0.1700f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_CITY_LIBRARY \
{ 1.0000f, 0.8200f, 0.3162f, 0.2818f, 0.0891f, 2.7600f, 0.8900f, 0.4100f, 0.3548f, 0.0290f, { 0.0000f, 0.0000f, -0.0000f }, 0.8913f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.1300f, 0.1700f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_CITY_UNDERPASS \
{ 1.0000f, 0.8200f, 0.3162f, 0.4467f, 0.8913f, 3.5700f, 1.1200f, 0.9100f, 0.3981f, 0.0590f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0370f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.1400f, 0.2500f, 0.0000f, 0.9920f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_CITY_ABANDONED \
{ 1.0000f, 0.6900f, 0.3162f, 0.7943f, 0.8913f, 3.2800f, 1.1700f, 0.9100f, 0.4467f, 0.0440f, { 0.0000f, 0.0000f, 0.0000f }, 0.2818f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2000f, 0.2500f, 0.0000f, 0.9966f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
/* Misc. Presets */
#define EFX_REVERB_PRESET_DUSTYROOM \
{ 0.3645f, 0.5600f, 0.3162f, 0.7943f, 0.7079f, 1.7900f, 0.3800f, 0.2100f, 0.5012f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0060f, { 0.0000f, 0.0000f, 0.0000f }, 0.2020f, 0.0500f, 0.2500f, 0.0000f, 0.9886f, 13046.0000f, 163.3000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_CHAPEL \
{ 1.0000f, 0.8400f, 0.3162f, 0.5623f, 1.0000f, 4.6200f, 0.6400f, 1.2300f, 0.4467f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.1100f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_SMALLWATERROOM \
{ 1.0000f, 0.7000f, 0.3162f, 0.4477f, 1.0000f, 1.5100f, 1.2500f, 1.1400f, 0.8913f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1790f, 0.1500f, 0.8950f, 0.1900f, 0.9920f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
#endif /* EFX_PRESETS_H */

View File

@ -1,761 +0,0 @@
#ifndef AL_EFX_H
#define AL_EFX_H
#include "alc.h"
#include "al.h"
#ifdef __cplusplus
extern "C" {
#endif
#define ALC_EXT_EFX_NAME "ALC_EXT_EFX"
#define ALC_EFX_MAJOR_VERSION 0x20001
#define ALC_EFX_MINOR_VERSION 0x20002
#define ALC_MAX_AUXILIARY_SENDS 0x20003
/* Listener properties. */
#define AL_METERS_PER_UNIT 0x20004
/* Source properties. */
#define AL_DIRECT_FILTER 0x20005
#define AL_AUXILIARY_SEND_FILTER 0x20006
#define AL_AIR_ABSORPTION_FACTOR 0x20007
#define AL_ROOM_ROLLOFF_FACTOR 0x20008
#define AL_CONE_OUTER_GAINHF 0x20009
#define AL_DIRECT_FILTER_GAINHF_AUTO 0x2000A
#define AL_AUXILIARY_SEND_FILTER_GAIN_AUTO 0x2000B
#define AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO 0x2000C
/* Effect properties. */
/* Reverb effect parameters */
#define AL_REVERB_DENSITY 0x0001
#define AL_REVERB_DIFFUSION 0x0002
#define AL_REVERB_GAIN 0x0003
#define AL_REVERB_GAINHF 0x0004
#define AL_REVERB_DECAY_TIME 0x0005
#define AL_REVERB_DECAY_HFRATIO 0x0006
#define AL_REVERB_REFLECTIONS_GAIN 0x0007
#define AL_REVERB_REFLECTIONS_DELAY 0x0008
#define AL_REVERB_LATE_REVERB_GAIN 0x0009
#define AL_REVERB_LATE_REVERB_DELAY 0x000A
#define AL_REVERB_AIR_ABSORPTION_GAINHF 0x000B
#define AL_REVERB_ROOM_ROLLOFF_FACTOR 0x000C
#define AL_REVERB_DECAY_HFLIMIT 0x000D
/* EAX Reverb effect parameters */
#define AL_EAXREVERB_DENSITY 0x0001
#define AL_EAXREVERB_DIFFUSION 0x0002
#define AL_EAXREVERB_GAIN 0x0003
#define AL_EAXREVERB_GAINHF 0x0004
#define AL_EAXREVERB_GAINLF 0x0005
#define AL_EAXREVERB_DECAY_TIME 0x0006
#define AL_EAXREVERB_DECAY_HFRATIO 0x0007
#define AL_EAXREVERB_DECAY_LFRATIO 0x0008
#define AL_EAXREVERB_REFLECTIONS_GAIN 0x0009
#define AL_EAXREVERB_REFLECTIONS_DELAY 0x000A
#define AL_EAXREVERB_REFLECTIONS_PAN 0x000B
#define AL_EAXREVERB_LATE_REVERB_GAIN 0x000C
#define AL_EAXREVERB_LATE_REVERB_DELAY 0x000D
#define AL_EAXREVERB_LATE_REVERB_PAN 0x000E
#define AL_EAXREVERB_ECHO_TIME 0x000F
#define AL_EAXREVERB_ECHO_DEPTH 0x0010
#define AL_EAXREVERB_MODULATION_TIME 0x0011
#define AL_EAXREVERB_MODULATION_DEPTH 0x0012
#define AL_EAXREVERB_AIR_ABSORPTION_GAINHF 0x0013
#define AL_EAXREVERB_HFREFERENCE 0x0014
#define AL_EAXREVERB_LFREFERENCE 0x0015
#define AL_EAXREVERB_ROOM_ROLLOFF_FACTOR 0x0016
#define AL_EAXREVERB_DECAY_HFLIMIT 0x0017
/* Chorus effect parameters */
#define AL_CHORUS_WAVEFORM 0x0001
#define AL_CHORUS_PHASE 0x0002
#define AL_CHORUS_RATE 0x0003
#define AL_CHORUS_DEPTH 0x0004
#define AL_CHORUS_FEEDBACK 0x0005
#define AL_CHORUS_DELAY 0x0006
/* Distortion effect parameters */
#define AL_DISTORTION_EDGE 0x0001
#define AL_DISTORTION_GAIN 0x0002
#define AL_DISTORTION_LOWPASS_CUTOFF 0x0003
#define AL_DISTORTION_EQCENTER 0x0004
#define AL_DISTORTION_EQBANDWIDTH 0x0005
/* Echo effect parameters */
#define AL_ECHO_DELAY 0x0001
#define AL_ECHO_LRDELAY 0x0002
#define AL_ECHO_DAMPING 0x0003
#define AL_ECHO_FEEDBACK 0x0004
#define AL_ECHO_SPREAD 0x0005
/* Flanger effect parameters */
#define AL_FLANGER_WAVEFORM 0x0001
#define AL_FLANGER_PHASE 0x0002
#define AL_FLANGER_RATE 0x0003
#define AL_FLANGER_DEPTH 0x0004
#define AL_FLANGER_FEEDBACK 0x0005
#define AL_FLANGER_DELAY 0x0006
/* Frequency shifter effect parameters */
#define AL_FREQUENCY_SHIFTER_FREQUENCY 0x0001
#define AL_FREQUENCY_SHIFTER_LEFT_DIRECTION 0x0002
#define AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION 0x0003
/* Vocal morpher effect parameters */
#define AL_VOCAL_MORPHER_PHONEMEA 0x0001
#define AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING 0x0002
#define AL_VOCAL_MORPHER_PHONEMEB 0x0003
#define AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING 0x0004
#define AL_VOCAL_MORPHER_WAVEFORM 0x0005
#define AL_VOCAL_MORPHER_RATE 0x0006
/* Pitchshifter effect parameters */
#define AL_PITCH_SHIFTER_COARSE_TUNE 0x0001
#define AL_PITCH_SHIFTER_FINE_TUNE 0x0002
/* Ringmodulator effect parameters */
#define AL_RING_MODULATOR_FREQUENCY 0x0001
#define AL_RING_MODULATOR_HIGHPASS_CUTOFF 0x0002
#define AL_RING_MODULATOR_WAVEFORM 0x0003
/* Autowah effect parameters */
#define AL_AUTOWAH_ATTACK_TIME 0x0001
#define AL_AUTOWAH_RELEASE_TIME 0x0002
#define AL_AUTOWAH_RESONANCE 0x0003
#define AL_AUTOWAH_PEAK_GAIN 0x0004
/* Compressor effect parameters */
#define AL_COMPRESSOR_ONOFF 0x0001
/* Equalizer effect parameters */
#define AL_EQUALIZER_LOW_GAIN 0x0001
#define AL_EQUALIZER_LOW_CUTOFF 0x0002
#define AL_EQUALIZER_MID1_GAIN 0x0003
#define AL_EQUALIZER_MID1_CENTER 0x0004
#define AL_EQUALIZER_MID1_WIDTH 0x0005
#define AL_EQUALIZER_MID2_GAIN 0x0006
#define AL_EQUALIZER_MID2_CENTER 0x0007
#define AL_EQUALIZER_MID2_WIDTH 0x0008
#define AL_EQUALIZER_HIGH_GAIN 0x0009
#define AL_EQUALIZER_HIGH_CUTOFF 0x000A
/* Effect type */
#define AL_EFFECT_FIRST_PARAMETER 0x0000
#define AL_EFFECT_LAST_PARAMETER 0x8000
#define AL_EFFECT_TYPE 0x8001
/* Effect types, used with the AL_EFFECT_TYPE property */
#define AL_EFFECT_NULL 0x0000
#define AL_EFFECT_REVERB 0x0001
#define AL_EFFECT_CHORUS 0x0002
#define AL_EFFECT_DISTORTION 0x0003
#define AL_EFFECT_ECHO 0x0004
#define AL_EFFECT_FLANGER 0x0005
#define AL_EFFECT_FREQUENCY_SHIFTER 0x0006
#define AL_EFFECT_VOCAL_MORPHER 0x0007
#define AL_EFFECT_PITCH_SHIFTER 0x0008
#define AL_EFFECT_RING_MODULATOR 0x0009
#define AL_EFFECT_AUTOWAH 0x000A
#define AL_EFFECT_COMPRESSOR 0x000B
#define AL_EFFECT_EQUALIZER 0x000C
#define AL_EFFECT_EAXREVERB 0x8000
/* Auxiliary Effect Slot properties. */
#define AL_EFFECTSLOT_EFFECT 0x0001
#define AL_EFFECTSLOT_GAIN 0x0002
#define AL_EFFECTSLOT_AUXILIARY_SEND_AUTO 0x0003
/* NULL Auxiliary Slot ID to disable a source send. */
#define AL_EFFECTSLOT_NULL 0x0000
/* Filter properties. */
/* Lowpass filter parameters */
#define AL_LOWPASS_GAIN 0x0001
#define AL_LOWPASS_GAINHF 0x0002
/* Highpass filter parameters */
#define AL_HIGHPASS_GAIN 0x0001
#define AL_HIGHPASS_GAINLF 0x0002
/* Bandpass filter parameters */
#define AL_BANDPASS_GAIN 0x0001
#define AL_BANDPASS_GAINLF 0x0002
#define AL_BANDPASS_GAINHF 0x0003
/* Filter type */
#define AL_FILTER_FIRST_PARAMETER 0x0000
#define AL_FILTER_LAST_PARAMETER 0x8000
#define AL_FILTER_TYPE 0x8001
/* Filter types, used with the AL_FILTER_TYPE property */
#define AL_FILTER_NULL 0x0000
#define AL_FILTER_LOWPASS 0x0001
#define AL_FILTER_HIGHPASS 0x0002
#define AL_FILTER_BANDPASS 0x0003
/* Effect object function types. */
typedef void (AL_APIENTRY *LPALGENEFFECTS)(ALsizei, ALuint*);
typedef void (AL_APIENTRY *LPALDELETEEFFECTS)(ALsizei, const ALuint*);
typedef ALboolean (AL_APIENTRY *LPALISEFFECT)(ALuint);
typedef void (AL_APIENTRY *LPALEFFECTI)(ALuint, ALenum, ALint);
typedef void (AL_APIENTRY *LPALEFFECTIV)(ALuint, ALenum, const ALint*);
typedef void (AL_APIENTRY *LPALEFFECTF)(ALuint, ALenum, ALfloat);
typedef void (AL_APIENTRY *LPALEFFECTFV)(ALuint, ALenum, const ALfloat*);
typedef void (AL_APIENTRY *LPALGETEFFECTI)(ALuint, ALenum, ALint*);
typedef void (AL_APIENTRY *LPALGETEFFECTIV)(ALuint, ALenum, ALint*);
typedef void (AL_APIENTRY *LPALGETEFFECTF)(ALuint, ALenum, ALfloat*);
typedef void (AL_APIENTRY *LPALGETEFFECTFV)(ALuint, ALenum, ALfloat*);
/* Filter object function types. */
typedef void (AL_APIENTRY *LPALGENFILTERS)(ALsizei, ALuint*);
typedef void (AL_APIENTRY *LPALDELETEFILTERS)(ALsizei, const ALuint*);
typedef ALboolean (AL_APIENTRY *LPALISFILTER)(ALuint);
typedef void (AL_APIENTRY *LPALFILTERI)(ALuint, ALenum, ALint);
typedef void (AL_APIENTRY *LPALFILTERIV)(ALuint, ALenum, const ALint*);
typedef void (AL_APIENTRY *LPALFILTERF)(ALuint, ALenum, ALfloat);
typedef void (AL_APIENTRY *LPALFILTERFV)(ALuint, ALenum, const ALfloat*);
typedef void (AL_APIENTRY *LPALGETFILTERI)(ALuint, ALenum, ALint*);
typedef void (AL_APIENTRY *LPALGETFILTERIV)(ALuint, ALenum, ALint*);
typedef void (AL_APIENTRY *LPALGETFILTERF)(ALuint, ALenum, ALfloat*);
typedef void (AL_APIENTRY *LPALGETFILTERFV)(ALuint, ALenum, ALfloat*);
/* Auxiliary Effect Slot object function types. */
typedef void (AL_APIENTRY *LPALGENAUXILIARYEFFECTSLOTS)(ALsizei, ALuint*);
typedef void (AL_APIENTRY *LPALDELETEAUXILIARYEFFECTSLOTS)(ALsizei, const ALuint*);
typedef ALboolean (AL_APIENTRY *LPALISAUXILIARYEFFECTSLOT)(ALuint);
typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTI)(ALuint, ALenum, ALint);
typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTIV)(ALuint, ALenum, const ALint*);
typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTF)(ALuint, ALenum, ALfloat);
typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, const ALfloat*);
typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTI)(ALuint, ALenum, ALint*);
typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTIV)(ALuint, ALenum, ALint*);
typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTF)(ALuint, ALenum, ALfloat*);
typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, ALfloat*);
#ifdef AL_ALEXT_PROTOTYPES
AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects);
AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects);
AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect);
AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint iValue);
AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *piValues);
AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat flValue);
AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat *pflValues);
AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *piValue);
AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *piValues);
AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *pflValue);
AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *pflValues);
AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters);
AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters);
AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter);
AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint iValue);
AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *piValues);
AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat flValue);
AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat *pflValues);
AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *piValue);
AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *piValues);
AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *pflValue);
AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *pflValues);
AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots);
AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots);
AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot);
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint iValue);
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *piValues);
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue);
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *pflValues);
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue);
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues);
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue);
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues);
#endif
/* Filter ranges and defaults. */
/* Lowpass filter */
#define AL_LOWPASS_MIN_GAIN (0.0f)
#define AL_LOWPASS_MAX_GAIN (1.0f)
#define AL_LOWPASS_DEFAULT_GAIN (1.0f)
#define AL_LOWPASS_MIN_GAINHF (0.0f)
#define AL_LOWPASS_MAX_GAINHF (1.0f)
#define AL_LOWPASS_DEFAULT_GAINHF (1.0f)
/* Highpass filter */
#define AL_HIGHPASS_MIN_GAIN (0.0f)
#define AL_HIGHPASS_MAX_GAIN (1.0f)
#define AL_HIGHPASS_DEFAULT_GAIN (1.0f)
#define AL_HIGHPASS_MIN_GAINLF (0.0f)
#define AL_HIGHPASS_MAX_GAINLF (1.0f)
#define AL_HIGHPASS_DEFAULT_GAINLF (1.0f)
/* Bandpass filter */
#define AL_BANDPASS_MIN_GAIN (0.0f)
#define AL_BANDPASS_MAX_GAIN (1.0f)
#define AL_BANDPASS_DEFAULT_GAIN (1.0f)
#define AL_BANDPASS_MIN_GAINHF (0.0f)
#define AL_BANDPASS_MAX_GAINHF (1.0f)
#define AL_BANDPASS_DEFAULT_GAINHF (1.0f)
#define AL_BANDPASS_MIN_GAINLF (0.0f)
#define AL_BANDPASS_MAX_GAINLF (1.0f)
#define AL_BANDPASS_DEFAULT_GAINLF (1.0f)
/* Effect parameter ranges and defaults. */
/* Standard reverb effect */
#define AL_REVERB_MIN_DENSITY (0.0f)
#define AL_REVERB_MAX_DENSITY (1.0f)
#define AL_REVERB_DEFAULT_DENSITY (1.0f)
#define AL_REVERB_MIN_DIFFUSION (0.0f)
#define AL_REVERB_MAX_DIFFUSION (1.0f)
#define AL_REVERB_DEFAULT_DIFFUSION (1.0f)
#define AL_REVERB_MIN_GAIN (0.0f)
#define AL_REVERB_MAX_GAIN (1.0f)
#define AL_REVERB_DEFAULT_GAIN (0.32f)
#define AL_REVERB_MIN_GAINHF (0.0f)
#define AL_REVERB_MAX_GAINHF (1.0f)
#define AL_REVERB_DEFAULT_GAINHF (0.89f)
#define AL_REVERB_MIN_DECAY_TIME (0.1f)
#define AL_REVERB_MAX_DECAY_TIME (20.0f)
#define AL_REVERB_DEFAULT_DECAY_TIME (1.49f)
#define AL_REVERB_MIN_DECAY_HFRATIO (0.1f)
#define AL_REVERB_MAX_DECAY_HFRATIO (2.0f)
#define AL_REVERB_DEFAULT_DECAY_HFRATIO (0.83f)
#define AL_REVERB_MIN_REFLECTIONS_GAIN (0.0f)
#define AL_REVERB_MAX_REFLECTIONS_GAIN (3.16f)
#define AL_REVERB_DEFAULT_REFLECTIONS_GAIN (0.05f)
#define AL_REVERB_MIN_REFLECTIONS_DELAY (0.0f)
#define AL_REVERB_MAX_REFLECTIONS_DELAY (0.3f)
#define AL_REVERB_DEFAULT_REFLECTIONS_DELAY (0.007f)
#define AL_REVERB_MIN_LATE_REVERB_GAIN (0.0f)
#define AL_REVERB_MAX_LATE_REVERB_GAIN (10.0f)
#define AL_REVERB_DEFAULT_LATE_REVERB_GAIN (1.26f)
#define AL_REVERB_MIN_LATE_REVERB_DELAY (0.0f)
#define AL_REVERB_MAX_LATE_REVERB_DELAY (0.1f)
#define AL_REVERB_DEFAULT_LATE_REVERB_DELAY (0.011f)
#define AL_REVERB_MIN_AIR_ABSORPTION_GAINHF (0.892f)
#define AL_REVERB_MAX_AIR_ABSORPTION_GAINHF (1.0f)
#define AL_REVERB_DEFAULT_AIR_ABSORPTION_GAINHF (0.994f)
#define AL_REVERB_MIN_ROOM_ROLLOFF_FACTOR (0.0f)
#define AL_REVERB_MAX_ROOM_ROLLOFF_FACTOR (10.0f)
#define AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f)
#define AL_REVERB_MIN_DECAY_HFLIMIT AL_FALSE
#define AL_REVERB_MAX_DECAY_HFLIMIT AL_TRUE
#define AL_REVERB_DEFAULT_DECAY_HFLIMIT AL_TRUE
/* EAX reverb effect */
#define AL_EAXREVERB_MIN_DENSITY (0.0f)
#define AL_EAXREVERB_MAX_DENSITY (1.0f)
#define AL_EAXREVERB_DEFAULT_DENSITY (1.0f)
#define AL_EAXREVERB_MIN_DIFFUSION (0.0f)
#define AL_EAXREVERB_MAX_DIFFUSION (1.0f)
#define AL_EAXREVERB_DEFAULT_DIFFUSION (1.0f)
#define AL_EAXREVERB_MIN_GAIN (0.0f)
#define AL_EAXREVERB_MAX_GAIN (1.0f)
#define AL_EAXREVERB_DEFAULT_GAIN (0.32f)
#define AL_EAXREVERB_MIN_GAINHF (0.0f)
#define AL_EAXREVERB_MAX_GAINHF (1.0f)
#define AL_EAXREVERB_DEFAULT_GAINHF (0.89f)
#define AL_EAXREVERB_MIN_GAINLF (0.0f)
#define AL_EAXREVERB_MAX_GAINLF (1.0f)
#define AL_EAXREVERB_DEFAULT_GAINLF (1.0f)
#define AL_EAXREVERB_MIN_DECAY_TIME (0.1f)
#define AL_EAXREVERB_MAX_DECAY_TIME (20.0f)
#define AL_EAXREVERB_DEFAULT_DECAY_TIME (1.49f)
#define AL_EAXREVERB_MIN_DECAY_HFRATIO (0.1f)
#define AL_EAXREVERB_MAX_DECAY_HFRATIO (2.0f)
#define AL_EAXREVERB_DEFAULT_DECAY_HFRATIO (0.83f)
#define AL_EAXREVERB_MIN_DECAY_LFRATIO (0.1f)
#define AL_EAXREVERB_MAX_DECAY_LFRATIO (2.0f)
#define AL_EAXREVERB_DEFAULT_DECAY_LFRATIO (1.0f)
#define AL_EAXREVERB_MIN_REFLECTIONS_GAIN (0.0f)
#define AL_EAXREVERB_MAX_REFLECTIONS_GAIN (3.16f)
#define AL_EAXREVERB_DEFAULT_REFLECTIONS_GAIN (0.05f)
#define AL_EAXREVERB_MIN_REFLECTIONS_DELAY (0.0f)
#define AL_EAXREVERB_MAX_REFLECTIONS_DELAY (0.3f)
#define AL_EAXREVERB_DEFAULT_REFLECTIONS_DELAY (0.007f)
#define AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ (0.0f)
#define AL_EAXREVERB_MIN_LATE_REVERB_GAIN (0.0f)
#define AL_EAXREVERB_MAX_LATE_REVERB_GAIN (10.0f)
#define AL_EAXREVERB_DEFAULT_LATE_REVERB_GAIN (1.26f)
#define AL_EAXREVERB_MIN_LATE_REVERB_DELAY (0.0f)
#define AL_EAXREVERB_MAX_LATE_REVERB_DELAY (0.1f)
#define AL_EAXREVERB_DEFAULT_LATE_REVERB_DELAY (0.011f)
#define AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ (0.0f)
#define AL_EAXREVERB_MIN_ECHO_TIME (0.075f)
#define AL_EAXREVERB_MAX_ECHO_TIME (0.25f)
#define AL_EAXREVERB_DEFAULT_ECHO_TIME (0.25f)
#define AL_EAXREVERB_MIN_ECHO_DEPTH (0.0f)
#define AL_EAXREVERB_MAX_ECHO_DEPTH (1.0f)
#define AL_EAXREVERB_DEFAULT_ECHO_DEPTH (0.0f)
#define AL_EAXREVERB_MIN_MODULATION_TIME (0.04f)
#define AL_EAXREVERB_MAX_MODULATION_TIME (4.0f)
#define AL_EAXREVERB_DEFAULT_MODULATION_TIME (0.25f)
#define AL_EAXREVERB_MIN_MODULATION_DEPTH (0.0f)
#define AL_EAXREVERB_MAX_MODULATION_DEPTH (1.0f)
#define AL_EAXREVERB_DEFAULT_MODULATION_DEPTH (0.0f)
#define AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF (0.892f)
#define AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF (1.0f)
#define AL_EAXREVERB_DEFAULT_AIR_ABSORPTION_GAINHF (0.994f)
#define AL_EAXREVERB_MIN_HFREFERENCE (1000.0f)
#define AL_EAXREVERB_MAX_HFREFERENCE (20000.0f)
#define AL_EAXREVERB_DEFAULT_HFREFERENCE (5000.0f)
#define AL_EAXREVERB_MIN_LFREFERENCE (20.0f)
#define AL_EAXREVERB_MAX_LFREFERENCE (1000.0f)
#define AL_EAXREVERB_DEFAULT_LFREFERENCE (250.0f)
#define AL_EAXREVERB_MIN_ROOM_ROLLOFF_FACTOR (0.0f)
#define AL_EAXREVERB_MAX_ROOM_ROLLOFF_FACTOR (10.0f)
#define AL_EAXREVERB_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f)
#define AL_EAXREVERB_MIN_DECAY_HFLIMIT AL_FALSE
#define AL_EAXREVERB_MAX_DECAY_HFLIMIT AL_TRUE
#define AL_EAXREVERB_DEFAULT_DECAY_HFLIMIT AL_TRUE
/* Chorus effect */
#define AL_CHORUS_WAVEFORM_SINUSOID (0)
#define AL_CHORUS_WAVEFORM_TRIANGLE (1)
#define AL_CHORUS_MIN_WAVEFORM (0)
#define AL_CHORUS_MAX_WAVEFORM (1)
#define AL_CHORUS_DEFAULT_WAVEFORM (1)
#define AL_CHORUS_MIN_PHASE (-180)
#define AL_CHORUS_MAX_PHASE (180)
#define AL_CHORUS_DEFAULT_PHASE (90)
#define AL_CHORUS_MIN_RATE (0.0f)
#define AL_CHORUS_MAX_RATE (10.0f)
#define AL_CHORUS_DEFAULT_RATE (1.1f)
#define AL_CHORUS_MIN_DEPTH (0.0f)
#define AL_CHORUS_MAX_DEPTH (1.0f)
#define AL_CHORUS_DEFAULT_DEPTH (0.1f)
#define AL_CHORUS_MIN_FEEDBACK (-1.0f)
#define AL_CHORUS_MAX_FEEDBACK (1.0f)
#define AL_CHORUS_DEFAULT_FEEDBACK (0.25f)
#define AL_CHORUS_MIN_DELAY (0.0f)
#define AL_CHORUS_MAX_DELAY (0.016f)
#define AL_CHORUS_DEFAULT_DELAY (0.016f)
/* Distortion effect */
#define AL_DISTORTION_MIN_EDGE (0.0f)
#define AL_DISTORTION_MAX_EDGE (1.0f)
#define AL_DISTORTION_DEFAULT_EDGE (0.2f)
#define AL_DISTORTION_MIN_GAIN (0.01f)
#define AL_DISTORTION_MAX_GAIN (1.0f)
#define AL_DISTORTION_DEFAULT_GAIN (0.05f)
#define AL_DISTORTION_MIN_LOWPASS_CUTOFF (80.0f)
#define AL_DISTORTION_MAX_LOWPASS_CUTOFF (24000.0f)
#define AL_DISTORTION_DEFAULT_LOWPASS_CUTOFF (8000.0f)
#define AL_DISTORTION_MIN_EQCENTER (80.0f)
#define AL_DISTORTION_MAX_EQCENTER (24000.0f)
#define AL_DISTORTION_DEFAULT_EQCENTER (3600.0f)
#define AL_DISTORTION_MIN_EQBANDWIDTH (80.0f)
#define AL_DISTORTION_MAX_EQBANDWIDTH (24000.0f)
#define AL_DISTORTION_DEFAULT_EQBANDWIDTH (3600.0f)
/* Echo effect */
#define AL_ECHO_MIN_DELAY (0.0f)
#define AL_ECHO_MAX_DELAY (0.207f)
#define AL_ECHO_DEFAULT_DELAY (0.1f)
#define AL_ECHO_MIN_LRDELAY (0.0f)
#define AL_ECHO_MAX_LRDELAY (0.404f)
#define AL_ECHO_DEFAULT_LRDELAY (0.1f)
#define AL_ECHO_MIN_DAMPING (0.0f)
#define AL_ECHO_MAX_DAMPING (0.99f)
#define AL_ECHO_DEFAULT_DAMPING (0.5f)
#define AL_ECHO_MIN_FEEDBACK (0.0f)
#define AL_ECHO_MAX_FEEDBACK (1.0f)
#define AL_ECHO_DEFAULT_FEEDBACK (0.5f)
#define AL_ECHO_MIN_SPREAD (-1.0f)
#define AL_ECHO_MAX_SPREAD (1.0f)
#define AL_ECHO_DEFAULT_SPREAD (-1.0f)
/* Flanger effect */
#define AL_FLANGER_WAVEFORM_SINUSOID (0)
#define AL_FLANGER_WAVEFORM_TRIANGLE (1)
#define AL_FLANGER_MIN_WAVEFORM (0)
#define AL_FLANGER_MAX_WAVEFORM (1)
#define AL_FLANGER_DEFAULT_WAVEFORM (1)
#define AL_FLANGER_MIN_PHASE (-180)
#define AL_FLANGER_MAX_PHASE (180)
#define AL_FLANGER_DEFAULT_PHASE (0)
#define AL_FLANGER_MIN_RATE (0.0f)
#define AL_FLANGER_MAX_RATE (10.0f)
#define AL_FLANGER_DEFAULT_RATE (0.27f)
#define AL_FLANGER_MIN_DEPTH (0.0f)
#define AL_FLANGER_MAX_DEPTH (1.0f)
#define AL_FLANGER_DEFAULT_DEPTH (1.0f)
#define AL_FLANGER_MIN_FEEDBACK (-1.0f)
#define AL_FLANGER_MAX_FEEDBACK (1.0f)
#define AL_FLANGER_DEFAULT_FEEDBACK (-0.5f)
#define AL_FLANGER_MIN_DELAY (0.0f)
#define AL_FLANGER_MAX_DELAY (0.004f)
#define AL_FLANGER_DEFAULT_DELAY (0.002f)
/* Frequency shifter effect */
#define AL_FREQUENCY_SHIFTER_MIN_FREQUENCY (0.0f)
#define AL_FREQUENCY_SHIFTER_MAX_FREQUENCY (24000.0f)
#define AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY (0.0f)
#define AL_FREQUENCY_SHIFTER_MIN_LEFT_DIRECTION (0)
#define AL_FREQUENCY_SHIFTER_MAX_LEFT_DIRECTION (2)
#define AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION (0)
#define AL_FREQUENCY_SHIFTER_DIRECTION_DOWN (0)
#define AL_FREQUENCY_SHIFTER_DIRECTION_UP (1)
#define AL_FREQUENCY_SHIFTER_DIRECTION_OFF (2)
#define AL_FREQUENCY_SHIFTER_MIN_RIGHT_DIRECTION (0)
#define AL_FREQUENCY_SHIFTER_MAX_RIGHT_DIRECTION (2)
#define AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION (0)
/* Vocal morpher effect */
#define AL_VOCAL_MORPHER_MIN_PHONEMEA (0)
#define AL_VOCAL_MORPHER_MAX_PHONEMEA (29)
#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEA (0)
#define AL_VOCAL_MORPHER_MIN_PHONEMEA_COARSE_TUNING (-24)
#define AL_VOCAL_MORPHER_MAX_PHONEMEA_COARSE_TUNING (24)
#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEA_COARSE_TUNING (0)
#define AL_VOCAL_MORPHER_MIN_PHONEMEB (0)
#define AL_VOCAL_MORPHER_MAX_PHONEMEB (29)
#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEB (10)
#define AL_VOCAL_MORPHER_MIN_PHONEMEB_COARSE_TUNING (-24)
#define AL_VOCAL_MORPHER_MAX_PHONEMEB_COARSE_TUNING (24)
#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEB_COARSE_TUNING (0)
#define AL_VOCAL_MORPHER_PHONEME_A (0)
#define AL_VOCAL_MORPHER_PHONEME_E (1)
#define AL_VOCAL_MORPHER_PHONEME_I (2)
#define AL_VOCAL_MORPHER_PHONEME_O (3)
#define AL_VOCAL_MORPHER_PHONEME_U (4)
#define AL_VOCAL_MORPHER_PHONEME_AA (5)
#define AL_VOCAL_MORPHER_PHONEME_AE (6)
#define AL_VOCAL_MORPHER_PHONEME_AH (7)
#define AL_VOCAL_MORPHER_PHONEME_AO (8)
#define AL_VOCAL_MORPHER_PHONEME_EH (9)
#define AL_VOCAL_MORPHER_PHONEME_ER (10)
#define AL_VOCAL_MORPHER_PHONEME_IH (11)
#define AL_VOCAL_MORPHER_PHONEME_IY (12)
#define AL_VOCAL_MORPHER_PHONEME_UH (13)
#define AL_VOCAL_MORPHER_PHONEME_UW (14)
#define AL_VOCAL_MORPHER_PHONEME_B (15)
#define AL_VOCAL_MORPHER_PHONEME_D (16)
#define AL_VOCAL_MORPHER_PHONEME_F (17)
#define AL_VOCAL_MORPHER_PHONEME_G (18)
#define AL_VOCAL_MORPHER_PHONEME_J (19)
#define AL_VOCAL_MORPHER_PHONEME_K (20)
#define AL_VOCAL_MORPHER_PHONEME_L (21)
#define AL_VOCAL_MORPHER_PHONEME_M (22)
#define AL_VOCAL_MORPHER_PHONEME_N (23)
#define AL_VOCAL_MORPHER_PHONEME_P (24)
#define AL_VOCAL_MORPHER_PHONEME_R (25)
#define AL_VOCAL_MORPHER_PHONEME_S (26)
#define AL_VOCAL_MORPHER_PHONEME_T (27)
#define AL_VOCAL_MORPHER_PHONEME_V (28)
#define AL_VOCAL_MORPHER_PHONEME_Z (29)
#define AL_VOCAL_MORPHER_WAVEFORM_SINUSOID (0)
#define AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE (1)
#define AL_VOCAL_MORPHER_WAVEFORM_SAWTOOTH (2)
#define AL_VOCAL_MORPHER_MIN_WAVEFORM (0)
#define AL_VOCAL_MORPHER_MAX_WAVEFORM (2)
#define AL_VOCAL_MORPHER_DEFAULT_WAVEFORM (0)
#define AL_VOCAL_MORPHER_MIN_RATE (0.0f)
#define AL_VOCAL_MORPHER_MAX_RATE (10.0f)
#define AL_VOCAL_MORPHER_DEFAULT_RATE (1.41f)
/* Pitch shifter effect */
#define AL_PITCH_SHIFTER_MIN_COARSE_TUNE (-12)
#define AL_PITCH_SHIFTER_MAX_COARSE_TUNE (12)
#define AL_PITCH_SHIFTER_DEFAULT_COARSE_TUNE (12)
#define AL_PITCH_SHIFTER_MIN_FINE_TUNE (-50)
#define AL_PITCH_SHIFTER_MAX_FINE_TUNE (50)
#define AL_PITCH_SHIFTER_DEFAULT_FINE_TUNE (0)
/* Ring modulator effect */
#define AL_RING_MODULATOR_MIN_FREQUENCY (0.0f)
#define AL_RING_MODULATOR_MAX_FREQUENCY (8000.0f)
#define AL_RING_MODULATOR_DEFAULT_FREQUENCY (440.0f)
#define AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF (0.0f)
#define AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF (24000.0f)
#define AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF (800.0f)
#define AL_RING_MODULATOR_SINUSOID (0)
#define AL_RING_MODULATOR_SAWTOOTH (1)
#define AL_RING_MODULATOR_SQUARE (2)
#define AL_RING_MODULATOR_MIN_WAVEFORM (0)
#define AL_RING_MODULATOR_MAX_WAVEFORM (2)
#define AL_RING_MODULATOR_DEFAULT_WAVEFORM (0)
/* Autowah effect */
#define AL_AUTOWAH_MIN_ATTACK_TIME (0.0001f)
#define AL_AUTOWAH_MAX_ATTACK_TIME (1.0f)
#define AL_AUTOWAH_DEFAULT_ATTACK_TIME (0.06f)
#define AL_AUTOWAH_MIN_RELEASE_TIME (0.0001f)
#define AL_AUTOWAH_MAX_RELEASE_TIME (1.0f)
#define AL_AUTOWAH_DEFAULT_RELEASE_TIME (0.06f)
#define AL_AUTOWAH_MIN_RESONANCE (2.0f)
#define AL_AUTOWAH_MAX_RESONANCE (1000.0f)
#define AL_AUTOWAH_DEFAULT_RESONANCE (1000.0f)
#define AL_AUTOWAH_MIN_PEAK_GAIN (0.00003f)
#define AL_AUTOWAH_MAX_PEAK_GAIN (31621.0f)
#define AL_AUTOWAH_DEFAULT_PEAK_GAIN (11.22f)
/* Compressor effect */
#define AL_COMPRESSOR_MIN_ONOFF (0)
#define AL_COMPRESSOR_MAX_ONOFF (1)
#define AL_COMPRESSOR_DEFAULT_ONOFF (1)
/* Equalizer effect */
#define AL_EQUALIZER_MIN_LOW_GAIN (0.126f)
#define AL_EQUALIZER_MAX_LOW_GAIN (7.943f)
#define AL_EQUALIZER_DEFAULT_LOW_GAIN (1.0f)
#define AL_EQUALIZER_MIN_LOW_CUTOFF (50.0f)
#define AL_EQUALIZER_MAX_LOW_CUTOFF (800.0f)
#define AL_EQUALIZER_DEFAULT_LOW_CUTOFF (200.0f)
#define AL_EQUALIZER_MIN_MID1_GAIN (0.126f)
#define AL_EQUALIZER_MAX_MID1_GAIN (7.943f)
#define AL_EQUALIZER_DEFAULT_MID1_GAIN (1.0f)
#define AL_EQUALIZER_MIN_MID1_CENTER (200.0f)
#define AL_EQUALIZER_MAX_MID1_CENTER (3000.0f)
#define AL_EQUALIZER_DEFAULT_MID1_CENTER (500.0f)
#define AL_EQUALIZER_MIN_MID1_WIDTH (0.01f)
#define AL_EQUALIZER_MAX_MID1_WIDTH (1.0f)
#define AL_EQUALIZER_DEFAULT_MID1_WIDTH (1.0f)
#define AL_EQUALIZER_MIN_MID2_GAIN (0.126f)
#define AL_EQUALIZER_MAX_MID2_GAIN (7.943f)
#define AL_EQUALIZER_DEFAULT_MID2_GAIN (1.0f)
#define AL_EQUALIZER_MIN_MID2_CENTER (1000.0f)
#define AL_EQUALIZER_MAX_MID2_CENTER (8000.0f)
#define AL_EQUALIZER_DEFAULT_MID2_CENTER (3000.0f)
#define AL_EQUALIZER_MIN_MID2_WIDTH (0.01f)
#define AL_EQUALIZER_MAX_MID2_WIDTH (1.0f)
#define AL_EQUALIZER_DEFAULT_MID2_WIDTH (1.0f)
#define AL_EQUALIZER_MIN_HIGH_GAIN (0.126f)
#define AL_EQUALIZER_MAX_HIGH_GAIN (7.943f)
#define AL_EQUALIZER_DEFAULT_HIGH_GAIN (1.0f)
#define AL_EQUALIZER_MIN_HIGH_CUTOFF (4000.0f)
#define AL_EQUALIZER_MAX_HIGH_CUTOFF (16000.0f)
#define AL_EQUALIZER_DEFAULT_HIGH_CUTOFF (6000.0f)
/* Source parameter value ranges and defaults. */
#define AL_MIN_AIR_ABSORPTION_FACTOR (0.0f)
#define AL_MAX_AIR_ABSORPTION_FACTOR (10.0f)
#define AL_DEFAULT_AIR_ABSORPTION_FACTOR (0.0f)
#define AL_MIN_ROOM_ROLLOFF_FACTOR (0.0f)
#define AL_MAX_ROOM_ROLLOFF_FACTOR (10.0f)
#define AL_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f)
#define AL_MIN_CONE_OUTER_GAINHF (0.0f)
#define AL_MAX_CONE_OUTER_GAINHF (1.0f)
#define AL_DEFAULT_CONE_OUTER_GAINHF (1.0f)
#define AL_MIN_DIRECT_FILTER_GAINHF_AUTO AL_FALSE
#define AL_MAX_DIRECT_FILTER_GAINHF_AUTO AL_TRUE
#define AL_DEFAULT_DIRECT_FILTER_GAINHF_AUTO AL_TRUE
#define AL_MIN_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_FALSE
#define AL_MAX_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_TRUE
#define AL_DEFAULT_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_TRUE
#define AL_MIN_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_FALSE
#define AL_MAX_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_TRUE
#define AL_DEFAULT_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_TRUE
/* Listener parameter value ranges and defaults. */
#define AL_MIN_METERS_PER_UNIT FLT_MIN
#define AL_MAX_METERS_PER_UNIT FLT_MAX
#define AL_DEFAULT_METERS_PER_UNIT (1.0f)
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* AL_EFX_H */

92621
extlibs/headers/miniaudio/miniaudio.h vendored Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1 +0,0 @@
Versions/Current/OpenAL

View File

@ -1 +0,0 @@
Versions/Current/Resources

View File

@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>OpenAL</string>
<key>CFBundleIdentifier</key>
<string>org.sfml-dev.OpenAL</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
</dict>
</plist>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -29,27 +29,29 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Audio/Export.hpp> #include <SFML/Audio/Export.hpp>
#include <memory>
namespace sf namespace sf
{ {
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Base class for classes that require an OpenAL context /// \brief Base class for classes that require an audio device
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
class SFML_AUDIO_API AlResource class SFML_AUDIO_API AudioResource
{ {
protected: protected:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Default constructor /// \brief Default constructor
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
AlResource(); AudioResource();
private:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Destructor // Member data
///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
~AlResource(); const std::shared_ptr<void> m_device; //!< Sound device
}; };
} // namespace sf } // namespace sf
@ -60,7 +62,7 @@ protected:
/// \ingroup audio /// \ingroup audio
/// ///
/// This class is for internal use only, it must be the base /// This class is for internal use only, it must be the base
/// of every class that requires a valid OpenAL context in /// of every class that requires a valid audio device in
/// order to work. /// order to work.
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -33,6 +33,7 @@
#include <filesystem> #include <filesystem>
#include <memory> #include <memory>
#include <vector>
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
@ -119,6 +120,19 @@ public:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
unsigned int getSampleRate() const; unsigned int getSampleRate() const;
////////////////////////////////////////////////////////////
/// \brief Get the map of position in sample frame to sound channel
///
/// This is used to map a sample in the sample stream to a
/// position during spatialisation.
///
/// \return Map of position in sample frame to sound channel
///
/// \see getSampleRate, getChannelCount, getDuration
///
////////////////////////////////////////////////////////////
const std::vector<SoundChannel>& getChannelMap() const;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Get the total duration of the sound file /// \brief Get the total duration of the sound file
/// ///
@ -221,8 +235,8 @@ private:
std::unique_ptr<InputStream, StreamDeleter> m_stream{nullptr, false}; //!< Input stream used to access the file's data std::unique_ptr<InputStream, StreamDeleter> m_stream{nullptr, false}; //!< Input stream used to access the file's data
std::uint64_t m_sampleOffset{}; //!< Sample Read Position std::uint64_t m_sampleOffset{}; //!< Sample Read Position
std::uint64_t m_sampleCount{}; //!< Total number of samples in the file std::uint64_t m_sampleCount{}; //!< Total number of samples in the file
unsigned int m_channelCount{}; //!< Number of channels of the sound
unsigned int m_sampleRate{}; //!< Number of samples per second unsigned int m_sampleRate{}; //!< Number of samples per second
std::vector<SoundChannel> m_channelMap; //!< The map of position in sample frame to sound channel
}; };
} // namespace sf } // namespace sf

View File

@ -29,6 +29,7 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Audio/Export.hpp> #include <SFML/Audio/Export.hpp>
#include <SFML/System/Angle.hpp>
#include <SFML/System/Vector3.hpp> #include <SFML/System/Vector3.hpp>
@ -39,6 +40,24 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
namespace sf::Listener namespace sf::Listener
{ {
////////////////////////////////////////////////////////////
/// \brief Structure defining the properties of a directional cone
///
/// Sounds will play at gain 1 when they are positioned
/// within the inner angle of the cone. Sounds will play
/// at outerGain when they are positioned outside the
/// outer angle of the cone. The gain declines linearly
/// from 1 to outerGain as the sound moves from the inner
/// angle to the outer angle.
///
////////////////////////////////////////////////////////////
struct Cone
{
Angle innerAngle; //!< Inner angle
Angle outerAngle; //!< Outer angle
float outerGain{}; //!< Outer gain
};
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Change the global volume of all the sounds and musics /// \brief Change the global volume of all the sounds and musics
/// ///
@ -112,6 +131,51 @@ SFML_AUDIO_API void setDirection(const Vector3f& direction);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
SFML_AUDIO_API Vector3f getDirection(); SFML_AUDIO_API Vector3f getDirection();
////////////////////////////////////////////////////////////
/// \brief Set the velocity of the listener in the scene
///
/// The default listener's velocity is (0, 0, -1).
///
/// \param velocity New listener's velocity
///
/// \see getVelocity, getDirection, setUpVector, setPosition
///
////////////////////////////////////////////////////////////
SFML_AUDIO_API void setVelocity(const Vector3f& velocity);
////////////////////////////////////////////////////////////
/// \brief Get the current forward vector of the listener in the scene
///
/// \return Listener's velocity
///
/// \see setVelocity
///
////////////////////////////////////////////////////////////
SFML_AUDIO_API Vector3f getVelocity();
////////////////////////////////////////////////////////////
/// \brief Set the cone properties of the listener in the audio scene
///
/// The cone defines how directional attenuation is applied.
/// The default cone of a sound is {2 * PI, 2 * PI, 1}.
///
/// \param cone Cone properties of the listener in the scene
///
/// \see getCone
///
////////////////////////////////////////////////////////////
SFML_AUDIO_API void setCone(const Listener::Cone& cone);
////////////////////////////////////////////////////////////
/// \brief Get the cone properties of the listener in the audio scene
///
/// \return Cone properties of the listener
///
/// \see setCone
///
////////////////////////////////////////////////////////////
SFML_AUDIO_API Listener::Cone getCone();
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Set the upward vector of the listener in the scene /// \brief Set the upward vector of the listener in the scene
/// ///

View File

@ -29,10 +29,12 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Audio/Export.hpp> #include <SFML/Audio/Export.hpp>
#include <SFML/Audio/SoundChannel.hpp>
#include <SFML/Audio/SoundFileWriter.hpp> #include <SFML/Audio/SoundFileWriter.hpp>
#include <filesystem> #include <filesystem>
#include <memory> #include <memory>
#include <vector>
#include <cstdint> #include <cstdint>
@ -54,11 +56,15 @@ public:
/// \param filename Path of the sound file to write /// \param filename Path of the sound file to write
/// \param sampleRate Sample rate of the sound /// \param sampleRate Sample rate of the sound
/// \param channelCount Number of channels in the sound /// \param channelCount Number of channels in the sound
/// \param channelMap Map of position in sample frame to sound channel
/// ///
/// \return True if the file was successfully opened /// \return True if the file was successfully opened
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
[[nodiscard]] bool openFromFile(const std::filesystem::path& filename, unsigned int sampleRate, unsigned int channelCount); [[nodiscard]] bool openFromFile(const std::filesystem::path& filename,
unsigned int sampleRate,
unsigned int channelCount,
const std::vector<SoundChannel>& channelMap);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Write audio samples to the file /// \brief Write audio samples to the file

View File

@ -31,6 +31,9 @@
#include <SFML/Audio/SoundSource.hpp> #include <SFML/Audio/SoundSource.hpp>
#include <memory>
#include <cstdlib>
namespace sf namespace sf
{ {
@ -218,18 +221,18 @@ private:
void detachBuffer(); void detachBuffer();
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Re-attach sound to its internal buffer /// \brief Get the sound object
/// ///
/// This allows the sound buffer to attach back the sounds /// \return The sound object
/// that use it after the sound buffer has been updated.
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void reattachBuffer(); void* getSound() const override;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Member data // Member data
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
const SoundBuffer* m_buffer{}; //!< Sound buffer bound to the source struct Impl;
const std::unique_ptr<Impl> m_impl; //!< Implementation details
}; };
} // namespace sf } // namespace sf

View File

@ -29,7 +29,7 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Audio/Export.hpp> #include <SFML/Audio/Export.hpp>
#include <SFML/Audio/AlResource.hpp> #include <SFML/Audio/SoundChannel.hpp>
#include <SFML/System/Time.hpp> #include <SFML/System/Time.hpp>
@ -51,14 +51,14 @@ class InputStream;
/// \brief Storage for audio samples defining a sound /// \brief Storage for audio samples defining a sound
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
class SFML_AUDIO_API SoundBuffer : AlResource class SFML_AUDIO_API SoundBuffer
{ {
public: public:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Default constructor /// \brief Default constructor
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
SoundBuffer(); SoundBuffer() = default;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Copy constructor /// \brief Copy constructor
@ -129,6 +129,7 @@ public:
/// \param sampleCount Number of samples in the array /// \param sampleCount Number of samples in the array
/// \param channelCount Number of channels (1 = mono, 2 = stereo, ...) /// \param channelCount Number of channels (1 = mono, 2 = stereo, ...)
/// \param sampleRate Sample rate (number of samples to play per second) /// \param sampleRate Sample rate (number of samples to play per second)
/// \param channelMap Map of position in sample frame to sound channel
/// ///
/// \return True if loading succeeded, false if it failed /// \return True if loading succeeded, false if it failed
/// ///
@ -138,7 +139,8 @@ public:
[[nodiscard]] bool loadFromSamples(const std::int16_t* samples, [[nodiscard]] bool loadFromSamples(const std::int16_t* samples,
std::uint64_t sampleCount, std::uint64_t sampleCount,
unsigned int channelCount, unsigned int channelCount,
unsigned int sampleRate); unsigned int sampleRate,
const std::vector<SoundChannel>& channelMap);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Save the sound buffer to an audio file /// \brief Save the sound buffer to an audio file
@ -191,7 +193,7 @@ public:
/// ///
/// \return Sample rate (number of samples per second) /// \return Sample rate (number of samples per second)
/// ///
/// \see getChannelCount, getDuration /// \see getChannelCount, getChannelmap, getDuration
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
unsigned int getSampleRate() const; unsigned int getSampleRate() const;
@ -204,17 +206,30 @@ public:
/// ///
/// \return Number of channels /// \return Number of channels
/// ///
/// \see getSampleRate, getDuration /// \see getSampleRate, getChannelmap, getDuration
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
unsigned int getChannelCount() const; unsigned int getChannelCount() const;
////////////////////////////////////////////////////////////
/// \brief Get the map of position in sample frame to sound channel
///
/// This is used to map a sample in the sample stream to a
/// position during spatialisation.
///
/// \return Map of position in sample frame to sound channel
///
/// \see getSampleRate, getChannelCount, getDuration
///
////////////////////////////////////////////////////////////
std::vector<SoundChannel> getChannelMap() const;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Get the total duration of the sound /// \brief Get the total duration of the sound
/// ///
/// \return Sound duration /// \return Sound duration
/// ///
/// \see getSampleRate, getChannelCount /// \see getSampleRate, getChannelCount, getChannelmap
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
Time getDuration() const; Time getDuration() const;
@ -247,11 +262,12 @@ private:
/// ///
/// \param channelCount Number of channels /// \param channelCount Number of channels
/// \param sampleRate Sample rate (number of samples per second) /// \param sampleRate Sample rate (number of samples per second)
/// \param channelMap Map of position in sample frame to sound channel
/// ///
/// \return True on success, false if any error happened /// \return True on success, false if any error happened
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
[[nodiscard]] bool update(unsigned int channelCount, unsigned int sampleRate); [[nodiscard]] bool update(unsigned int channelCount, unsigned int sampleRate, const std::vector<SoundChannel>& channelMap);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Add a sound to the list of sounds that use this buffer /// \brief Add a sound to the list of sounds that use this buffer
@ -277,8 +293,9 @@ private:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Member data // Member data
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
unsigned int m_buffer{}; //!< OpenAL buffer identifier
std::vector<std::int16_t> m_samples; //!< Samples buffer std::vector<std::int16_t> m_samples; //!< Samples buffer
unsigned int m_sampleRate{44100}; //!< Number of samples per second
std::vector<SoundChannel> m_channelMap{SoundChannel::Mono}; //!< The map of position in sample frame to sound channel
Time m_duration; //!< Sound duration Time m_duration; //!< Sound duration
mutable SoundList m_sounds; //!< List of sounds that are using this buffer mutable SoundList m_sounds; //!< List of sounds that are using this buffer
}; };

View File

@ -0,0 +1,65 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2024 Laurent Gomila (laurent@sfml-dev.org)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
#pragma once
namespace sf
{
////////////////////////////////////////////////////////////
/// \ingroup audio
/// \brief Types of sound channels that can be read/written from sound buffers/files
///
/// In multi-channel audio, each sound channel can be
/// assigned a position. The position of the channel is
/// used to determine where to place a sound when it
/// is spatialised. Assigning an incorrect sound channel
/// will result in multi-channel audio being positioned
/// incorrectly when using spatialisation.
///
////////////////////////////////////////////////////////////
enum class SoundChannel
{
Unspecified,
Mono,
FrontLeft,
FrontRight,
FrontCenter,
FrontLeftOfCenter,
FrontRightOfCenter,
LowFrequencyEffects,
BackLeft,
BackRight,
BackCenter,
SideLeft,
SideRight,
TopCenter,
TopFrontLeft,
TopFrontRight,
TopFrontCenter,
TopBackLeft,
TopBackRight,
TopBackCenter
};
} // namespace sf

View File

@ -29,7 +29,6 @@
#include <memory> #include <memory>
namespace sf namespace sf
{ {
namespace priv namespace priv

View File

@ -29,7 +29,10 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Audio/Export.hpp> #include <SFML/Audio/Export.hpp>
#include <SFML/Audio/SoundChannel.hpp>
#include <optional> #include <optional>
#include <vector>
#include <cstdint> #include <cstdint>
@ -54,6 +57,7 @@ public:
std::uint64_t sampleCount{}; //!< Total number of samples in the file std::uint64_t sampleCount{}; //!< Total number of samples in the file
unsigned int channelCount{}; //!< Number of channels of the sound unsigned int channelCount{}; //!< Number of channels of the sound
unsigned int sampleRate{}; //!< Samples rate of the sound, in samples per second unsigned int sampleRate{}; //!< Samples rate of the sound, in samples per second
std::vector<SoundChannel> channelMap; //!< Map of position in sample frame to sound channel
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -29,7 +29,12 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Audio/Export.hpp> #include <SFML/Audio/Export.hpp>
#include <SFML/Audio/SoundChannel.hpp>
#include <filesystem> #include <filesystem>
#include <vector>
#include <cstdint>
namespace sf namespace sf
@ -53,13 +58,15 @@ public:
/// \param filename Path of the file to open /// \param filename Path of the file to open
/// \param sampleRate Sample rate of the sound /// \param sampleRate Sample rate of the sound
/// \param channelCount Number of channels of the sound /// \param channelCount Number of channels of the sound
/// \param channelMap Map of position in sample frame to sound channel
/// ///
/// \return True if the file was successfully opened /// \return True if the file was successfully opened
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
[[nodiscard]] virtual bool open(const std::filesystem::path& filename, [[nodiscard]] virtual bool open(const std::filesystem::path& filename,
unsigned int sampleRate, unsigned int sampleRate,
unsigned int channelCount) = 0; unsigned int channelCount,
const std::vector<SoundChannel>& channelMap) = 0;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Write audio samples to the open file /// \brief Write audio samples to the open file
@ -101,7 +108,7 @@ public:
/// // return true if the writer can handle the format /// // return true if the writer can handle the format
/// } /// }
/// ///
/// [[nodiscard]] bool open(const std::filesystem::path& filename, unsigned int sampleRate, unsigned int channelCount) override /// [[nodiscard]] bool open(const std::filesystem::path& filename, unsigned int sampleRate, unsigned int channelCount, const std::vector<SoundChannel>& channelMap) override
/// { /// {
/// // open the file 'filename' for writing, /// // open the file 'filename' for writing,
/// // write the given sample rate and channel count to the file header /// // write the given sample rate and channel count to the file header

View File

@ -29,12 +29,10 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Audio/Export.hpp> #include <SFML/Audio/Export.hpp>
#include <SFML/Audio/AlResource.hpp> #include <SFML/Audio/SoundChannel.hpp>
#include <SFML/System/Time.hpp>
#include <memory>
#include <string> #include <string>
#include <thread>
#include <vector> #include <vector>
#include <cstddef> #include <cstddef>
@ -47,7 +45,7 @@ namespace sf
/// \brief Abstract base class for capturing sound data /// \brief Abstract base class for capturing sound data
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
class SFML_AUDIO_API SoundRecorder : AlResource class SFML_AUDIO_API SoundRecorder
{ {
public: public:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -176,6 +174,17 @@ public:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
unsigned int getChannelCount() const; unsigned int getChannelCount() const;
////////////////////////////////////////////////////////////
/// \brief Get the map of position in sample frame to sound channel
///
/// This is used to map a sample in the sample stream to a
/// position during spatialisation.
///
/// \return Map of position in sample frame to sound channel
///
////////////////////////////////////////////////////////////
const std::vector<SoundChannel>& getChannelMap() const;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Check if the system supports audio capture /// \brief Check if the system supports audio capture
/// ///
@ -196,25 +205,7 @@ protected:
/// This constructor is only meant to be called by derived classes. /// This constructor is only meant to be called by derived classes.
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
SoundRecorder() = default; SoundRecorder();
////////////////////////////////////////////////////////////
/// \brief Set the processing interval
///
/// The processing interval controls the period
/// between calls to the onProcessSamples function. You may
/// want to use a small interval if you want to process the
/// recorded data in real time, for example.
///
/// Note: this is only a hint, the actual period may vary.
/// So don't rely on this parameter to implement precise timing.
///
/// The default processing interval is 100 ms.
///
/// \param interval Processing interval
///
////////////////////////////////////////////////////////////
void setProcessingInterval(Time interval);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Start capturing audio data /// \brief Start capturing audio data
@ -257,61 +248,11 @@ protected:
virtual void onStop(); virtual void onStop();
private: private:
////////////////////////////////////////////////////////////
/// \brief Function called as the entry point of the thread
///
/// This function starts the recording loop, and returns
/// only when the capture is stopped.
///
////////////////////////////////////////////////////////////
void record();
////////////////////////////////////////////////////////////
/// \brief Get the new available audio samples and process them
///
/// This function is called continuously during the
/// capture loop. It retrieves the captured samples and
/// forwards them to the derived class.
///
////////////////////////////////////////////////////////////
void processCapturedSamples();
////////////////////////////////////////////////////////////
/// \brief Clean up the recorder's internal resources
///
/// This function is called when the capture stops.
///
////////////////////////////////////////////////////////////
void cleanup();
////////////////////////////////////////////////////////////
/// \brief Launch a new capture thread running 'record'
///
/// This function is called when the capture is started or
/// when the device is changed.
///
////////////////////////////////////////////////////////////
void launchCapturingThread();
////////////////////////////////////////////////////////////
/// \brief Stop capturing and wait for 'm_thread' to join
///
/// This function is called when the capture is stopped or
/// when the device is changed.
///
////////////////////////////////////////////////////////////
void awaitCapturingThread();
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Member data // Member data
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
std::thread m_thread; //!< Thread running the background recording task struct Impl;
std::vector<std::int16_t> m_samples; //!< Buffer to store captured samples const std::unique_ptr<Impl> m_impl; //!< Implementation details
unsigned int m_sampleRate{}; //!< Sample rate
Time m_processingInterval{milliseconds(100)}; //!< Time period between calls to onProcessSamples
bool m_isCapturing{}; //!< Capturing state
std::string m_deviceName{getDefaultDevice()}; //!< Name of the audio capture device
unsigned int m_channelCount{1}; //!< Number of recording channels
}; };
} // namespace sf } // namespace sf

View File

@ -29,8 +29,9 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Audio/Export.hpp> #include <SFML/Audio/Export.hpp>
#include <SFML/Audio/AlResource.hpp> #include <SFML/Audio/AudioResource.hpp>
#include <SFML/System/Angle.hpp>
#include <SFML/System/Vector3.hpp> #include <SFML/System/Vector3.hpp>
@ -41,7 +42,7 @@ namespace sf
/// \brief Base class defining a sound's properties /// \brief Base class defining a sound's properties
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
class SFML_AUDIO_API SoundSource : AlResource class SFML_AUDIO_API SoundSource : protected AudioResource
{ {
public: public:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -55,19 +56,37 @@ public:
Playing //!< Sound is playing Playing //!< Sound is playing
}; };
////////////////////////////////////////////////////////////
/// \brief Structure defining the properties of a directional cone
///
/// Sounds will play at gain 1 when the listener
/// is positioned within the inner angle of the cone.
/// Sounds will play at outerGain when the listener is
/// positioned outside the outer angle of the cone.
/// The gain declines linearly from 1 to outerGain as the
/// listener moves from the inner angle to the outer angle.
///
////////////////////////////////////////////////////////////
struct Cone
{
Angle innerAngle; //!< Inner angle
Angle outerAngle; //!< Outer angle
float outerGain{}; //!< Outer gain
};
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Copy constructor /// \brief Copy constructor
/// ///
/// \param copy Instance to copy /// \param copy Instance to copy
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
SoundSource(const SoundSource& copy); SoundSource(const SoundSource& copy) = default;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Destructor /// \brief Destructor
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
virtual ~SoundSource(); virtual ~SoundSource() = default;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Set the pitch of the sound /// \brief Set the pitch of the sound
@ -85,6 +104,21 @@ public:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void setPitch(float pitch); void setPitch(float pitch);
////////////////////////////////////////////////////////////
/// \brief Set the pan of the sound
///
/// Using panning, a mono sound can be panned between
/// stereo channels. When the pan is set to -1, the sound
/// is played only on the left channel, when the pan is set
/// to +1, the sound is played only on the right channel.
///
/// \param pan New pan to apply to the sound [-1, +1]
///
/// \see getPan
///
////////////////////////////////////////////////////////////
void setPan(float pan);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Set the volume of the sound /// \brief Set the volume of the sound
/// ///
@ -98,6 +132,21 @@ public:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void setVolume(float volume); void setVolume(float volume);
////////////////////////////////////////////////////////////
/// \brief Set whether spatialization of the sound is enabled
///
/// Spatialization is the application of various effects to
/// simulate a sound being emitted at a virtual position in
/// 3D space and exhibiting various physical phenomena such as
/// directional attenuation and doppler shift.
///
/// \param enabled True to enable spatialization, false to disable
///
/// \see isSpatializationEnabled
///
////////////////////////////////////////////////////////////
void setSpatializationEnabled(bool enabled);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Set the 3D position of the sound in the audio scene /// \brief Set the 3D position of the sound in the audio scene
/// ///
@ -112,6 +161,79 @@ public:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void setPosition(const Vector3f& position); void setPosition(const Vector3f& position);
////////////////////////////////////////////////////////////
/// \brief Set the 3D direction of the sound in the audio scene
///
/// The direction defines where the sound source is facing
/// in 3D space. It will affect how the sound is attenuated
/// if facing away from the listener.
/// The default direction of a sound is (0, 0, -1).
///
/// \param direction Direction of the sound in the scene
///
/// \see getDirection
///
////////////////////////////////////////////////////////////
void setDirection(const Vector3f& direction);
////////////////////////////////////////////////////////////
/// \brief Set the cone properties of the sound in the audio scene
///
/// The cone defines how directional attenuation is applied.
/// The default cone of a sound is {2 * PI, 2 * PI, 1}.
///
/// \param cone Cone properties of the sound in the scene
///
/// \see getCone
///
////////////////////////////////////////////////////////////
void setCone(const Cone& cone);
////////////////////////////////////////////////////////////
/// \brief Set the 3D velocity of the sound in the audio scene
///
/// The velocity is used to determine how to doppler shift
/// the sound. Sounds moving towards the listener will be
/// perceived to have a higher pitch and sounds moving away
/// from the listener will be perceived to have a lower pitch.
///
/// \param velocity Velocity of the sound in the scene
///
/// \see getVelocity
///
////////////////////////////////////////////////////////////
void setVelocity(const Vector3f& velocity);
////////////////////////////////////////////////////////////
/// \brief Set the doppler factor of the sound
///
/// The doppler factor determines how strong the doppler
/// shift will be.
///
/// \param factor New doppler factor to apply to the sound
///
/// \see getDopplerFactor
///
////////////////////////////////////////////////////////////
void setDopplerFactor(float factor);
////////////////////////////////////////////////////////////
/// \brief Set the directional attenuation factor of the sound
///
/// Depending on the virtual position of an output channel
/// relative to the listener (such as in surround sound
/// setups), sounds will be attenuated when emitting them
/// from certain channels. This factor determines how strong
/// the attenuation based on output channel position
/// relative to the listener is.
///
/// \param factor New directional attenuation factor to apply to the sound
///
/// \see getDirectionalAttenuationFactor
///
////////////////////////////////////////////////////////////
void setDirectionalAttenuationFactor(float factor);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Make the sound's position relative to the listener or absolute /// \brief Make the sound's position relative to the listener or absolute
/// ///
@ -145,6 +267,51 @@ public:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void setMinDistance(float distance); void setMinDistance(float distance);
////////////////////////////////////////////////////////////
/// \brief Set the maximum distance of the sound
///
/// The "maximum distance" of a sound is the minimum
/// distance at which it is heard at its minimum volume. Closer
/// than the maximum distance, it will start to fade in according
/// to its attenuation factor.
/// The default value of the maximum distance is the maximum
/// value a float can represent.
///
/// \param distance New maximum distance of the sound
///
/// \see getMaxDistance, setAttenuation
///
////////////////////////////////////////////////////////////
void setMaxDistance(float distance);
////////////////////////////////////////////////////////////
/// \brief Set the minimum gain of the sound
///
/// When the sound is further away from the listener than
/// the "maximum distance" the attenuated gain is clamped
/// so it cannot go below the minimum gain value.
///
/// \param gain New minimum gain of the sound
///
/// \see getMinGain, setAttenuation
///
////////////////////////////////////////////////////////////
void setMinGain(float gain);
////////////////////////////////////////////////////////////
/// \brief Set the maximum gain of the sound
///
/// When the sound is closer from the listener than
/// the "minimum distance" the attenuated gain is clamped
/// so it cannot go above the maximum gain value.
///
/// \param gain New maximum gain of the sound
///
/// \see getMaxGain, setAttenuation
///
////////////////////////////////////////////////////////////
void setMaxGain(float gain);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Set the attenuation factor of the sound /// \brief Set the attenuation factor of the sound
/// ///
@ -174,6 +341,16 @@ public:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
float getPitch() const; float getPitch() const;
////////////////////////////////////////////////////////////
/// \brief Get the pan of the sound
///
/// \return Pan of the sound
///
/// \see setPan
///
////////////////////////////////////////////////////////////
float getPan() const;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Get the volume of the sound /// \brief Get the volume of the sound
/// ///
@ -184,6 +361,16 @@ public:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
float getVolume() const; float getVolume() const;
////////////////////////////////////////////////////////////
/// \brief Tell whether spatialization of the sound is enabled
///
/// \return True if spatialization is enabled, false if it's disabled
///
/// \see setSpatializationEnabled
///
////////////////////////////////////////////////////////////
bool isSpatializationEnabled() const;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Get the 3D position of the sound in the audio scene /// \brief Get the 3D position of the sound in the audio scene
/// ///
@ -194,6 +381,56 @@ public:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
Vector3f getPosition() const; Vector3f getPosition() const;
////////////////////////////////////////////////////////////
/// \brief Get the 3D direction of the sound in the audio scene
///
/// \return Direction of the sound
///
/// \see setDirection
///
////////////////////////////////////////////////////////////
Vector3f getDirection() const;
////////////////////////////////////////////////////////////
/// \brief Get the cone properties of the sound in the audio scene
///
/// \return Cone properties of the sound
///
/// \see setCone
///
////////////////////////////////////////////////////////////
Cone getCone() const;
////////////////////////////////////////////////////////////
/// \brief Get the 3D velocity of the sound in the audio scene
///
/// \return Velocity of the sound
///
/// \see setVelocity
///
////////////////////////////////////////////////////////////
Vector3f getVelocity() const;
////////////////////////////////////////////////////////////
/// \brief Get the doppler factor of the sound
///
/// \return Doppler factor of the sound
///
/// \see setDopplerFactor
///
////////////////////////////////////////////////////////////
float getDopplerFactor() const;
////////////////////////////////////////////////////////////
/// \brief Get the directional attenuation factor of the sound
///
/// \return Directional attenuation factor of the sound
///
/// \see setDirectionalAttenuationFactor
///
////////////////////////////////////////////////////////////
float getDirectionalAttenuationFactor() const;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Tell whether the sound's position is relative to the /// \brief Tell whether the sound's position is relative to the
/// listener or is absolute /// listener or is absolute
@ -215,6 +452,36 @@ public:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
float getMinDistance() const; float getMinDistance() const;
////////////////////////////////////////////////////////////
/// \brief Get the maximum distance of the sound
///
/// \return Maximum distance of the sound
///
/// \see setMaxDistance, getAttenuation
///
////////////////////////////////////////////////////////////
float getMaxDistance() const;
////////////////////////////////////////////////////////////
/// \brief Get the minimum gain of the sound
///
/// \return Minimum gain of the sound
///
/// \see setMinGain, getAttenuation
///
////////////////////////////////////////////////////////////
float getMinGain() const;
////////////////////////////////////////////////////////////
/// \brief Get the maximum gain of the sound
///
/// \return Maximum gain of the sound
///
/// \see setMaxGain, getAttenuation
///
////////////////////////////////////////////////////////////
float getMaxGain() const;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Get the attenuation factor of the sound /// \brief Get the attenuation factor of the sound
/// ///
@ -276,7 +543,7 @@ public:
/// \return Current status of the sound /// \return Current status of the sound
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
virtual Status getStatus() const; virtual Status getStatus() const = 0;
protected: protected:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -285,12 +552,16 @@ protected:
/// This constructor is meant to be called by derived classes only. /// This constructor is meant to be called by derived classes only.
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
SoundSource(); SoundSource() = default;
private:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Member data /// \brief Get the sound object
///
/// \return The sound object
///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
unsigned int m_source{}; //!< OpenAL source identifier virtual void* getSound() const = 0;
}; };
// NOLINTEND(readability-make-member-function-const) // NOLINTEND(readability-make-member-function-const)

View File

@ -29,12 +29,13 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Audio/Export.hpp> #include <SFML/Audio/Export.hpp>
#include <SFML/Audio/SoundChannel.hpp>
#include <SFML/Audio/SoundSource.hpp> #include <SFML/Audio/SoundSource.hpp>
#include <SFML/System/Time.hpp> #include <SFML/System/Time.hpp>
#include <mutex> #include <memory>
#include <thread> #include <vector>
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
@ -123,6 +124,17 @@ public:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
unsigned int getSampleRate() const; unsigned int getSampleRate() const;
////////////////////////////////////////////////////////////
/// \brief Get the map of position in sample frame to sound channel
///
/// This is used to map a sample in the sample stream to a
/// position during spatialisation.
///
/// \return Map of position in sample frame to sound channel
///
////////////////////////////////////////////////////////////
std::vector<SoundChannel> getChannelMap() const;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Get the current status of the stream (stopped, paused, playing) /// \brief Get the current status of the stream (stopped, paused, playing)
/// ///
@ -193,7 +205,7 @@ protected:
/// This constructor is only meant to be called by derived classes. /// This constructor is only meant to be called by derived classes.
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
SoundStream() = default; SoundStream();
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Define the audio stream parameters /// \brief Define the audio stream parameters
@ -207,9 +219,10 @@ protected:
/// ///
/// \param channelCount Number of channels of the stream /// \param channelCount Number of channels of the stream
/// \param sampleRate Sample rate, in samples per second /// \param sampleRate Sample rate, in samples per second
/// \param channelMap Map of position in sample frame to sound channel
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void initialize(unsigned int channelCount, unsigned int sampleRate); void initialize(unsigned int channelCount, unsigned int sampleRate, const std::vector<SoundChannel>& channelMap);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Request a new chunk of audio samples from the stream source /// \brief Request a new chunk of audio samples from the stream source
@ -253,103 +266,20 @@ protected:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
virtual std::int64_t onLoop(); virtual std::int64_t onLoop();
////////////////////////////////////////////////////////////
/// \brief Set the processing interval
///
/// The processing interval controls the period at which the
/// audio buffers are filled by calls to onGetData. A smaller
/// interval may be useful for low-latency streams. Note that
/// the given period is only a hint and the actual period may
/// vary. The default processing interval is 10 ms.
///
/// \param interval Processing interval
///
////////////////////////////////////////////////////////////
void setProcessingInterval(Time interval);
private: private:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Function called as the entry point of the thread /// \brief Get the sound object
/// ///
/// This function starts the streaming loop, and returns /// \return The sound object
/// only when the sound is stopped.
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void streamData(); void* getSound() const override;
////////////////////////////////////////////////////////////
/// \brief Fill a new buffer with audio samples, and append
/// it to the playing queue
///
/// This function is called as soon as a buffer has been fully
/// consumed; it fills it again and inserts it back into the
/// playing queue.
///
/// \param bufferNum Number of the buffer to fill (in [0, BufferCount])
/// \param immediateLoop Treat empty buffers as spent, and act on loops immediately
///
/// \return True if the stream source has requested to stop, false otherwise
///
////////////////////////////////////////////////////////////
[[nodiscard]] bool fillAndPushBuffer(unsigned int bufferNum, bool immediateLoop = false);
////////////////////////////////////////////////////////////
/// \brief Fill the audio buffers and put them all into the playing queue
///
/// This function is called when playing starts and the
/// playing queue is empty.
///
/// \return True if the derived class has requested to stop, false otherwise
///
////////////////////////////////////////////////////////////
[[nodiscard]] bool fillQueue();
////////////////////////////////////////////////////////////
/// \brief Clear all the audio buffers and empty the playing queue
///
/// This function is called when the stream is stopped.
///
////////////////////////////////////////////////////////////
void clearQueue();
////////////////////////////////////////////////////////////
/// \brief Launch a new stream thread running 'streamData'
///
/// This function is called when the stream is played or
/// when the playing offset is changed.
///
////////////////////////////////////////////////////////////
void launchStreamingThread(Status threadStartState);
////////////////////////////////////////////////////////////
/// \brief Stop streaming and wait for 'm_thread' to join
///
/// This function is called when the playback is stopped or
/// when the sound stream is destroyed.
///
////////////////////////////////////////////////////////////
void awaitStreamingThread();
// NOLINTBEGIN(readability-identifier-naming)
static constexpr unsigned int BufferCount{3}; //!< Number of audio buffers used by the streaming loop
static constexpr unsigned int BufferRetries{2}; //!< Number of retries (excluding initial try) for onGetData()
// NOLINTEND(readability-identifier-naming)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Member data // Member data
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
std::thread m_thread; //!< Thread running the background tasks struct Impl;
mutable std::recursive_mutex m_threadMutex; //!< Thread mutex const std::unique_ptr<Impl> m_impl; //!< Implementation details
Status m_threadStartState{Stopped}; //!< State the thread starts in (Playing, Paused, Stopped)
bool m_isStreaming{}; //!< Streaming state (true = playing, false = stopped)
unsigned int m_buffers[BufferCount]{}; //!< Sound buffers used to store temporary audio data
unsigned int m_channelCount{}; //!< Number of channels (1 = mono, 2 = stereo, ...)
unsigned int m_sampleRate{}; //!< Frequency (samples / second)
std::int32_t m_format{}; //!< Format of the internal sound buffers
bool m_loop{}; //!< Loop flag (true to loop, false to play once)
std::uint64_t m_samplesProcessed{}; //!< Number of samples processed since beginning of the stream
std::int64_t m_bufferSeeks[BufferCount]{}; //!< If buffer is an "end buffer", holds next seek position, else NoLoop. For play offset calculation.
Time m_processingInterval{milliseconds(10)}; //!< Interval for checking and filling the internal sound buffers.
}; };
} // namespace sf } // namespace sf

View File

@ -70,10 +70,10 @@ In short, SFML is free for any use (commercial or personal, proprietary or open-
## External libraries used by SFML ## External libraries used by SFML
- [_OpenAL-Soft_](https://github.com/kcat/openal-soft) is under the [LGPL license](https://github.com/kcat/openal-soft/blob/master/COPYING)
- [_stb_image_ and _stb_image_write_](https://github.com/nothings/stb) are [public domain](https://github.com/nothings/stb/blob/master/LICENSE) - [_stb_image_ and _stb_image_write_](https://github.com/nothings/stb) are [public domain](https://github.com/nothings/stb/blob/master/LICENSE)
- [_freetype_](https://gitlab.freedesktop.org/freetype/freetype) is under the [FreeType license or the GPL license](https://gitlab.freedesktop.org/freetype/freetype/-/blob/master/LICENSE.TXT) - [_freetype_](https://gitlab.freedesktop.org/freetype/freetype) is under the [FreeType license or the GPL license](https://gitlab.freedesktop.org/freetype/freetype/-/blob/master/LICENSE.TXT)
- [_libogg_](https://gitlab.xiph.org/xiph/ogg) is under the [BSD license](https://gitlab.xiph.org/xiph/ogg/-/blob/master/COPYING) - [_libogg_](https://gitlab.xiph.org/xiph/ogg) is under the [BSD license](https://gitlab.xiph.org/xiph/ogg/-/blob/master/COPYING)
- [_libvorbis_](https://gitlab.xiph.org/xiph/vorbis) is under the [BSD license](https://gitlab.xiph.org/xiph/vorbis/-/blob/master/COPYING) - [_libvorbis_](https://gitlab.xiph.org/xiph/vorbis) is under the [BSD license](https://gitlab.xiph.org/xiph/vorbis/-/blob/master/COPYING)
- [_libflac_](https://gitlab.xiph.org/xiph/flac) is under the [BSD license](https://gitlab.xiph.org/xiph/flac/-/blob/master/COPYING.Xiph) - [_libflac_](https://gitlab.xiph.org/xiph/flac) is under the [BSD license](https://gitlab.xiph.org/xiph/flac/-/blob/master/COPYING.Xiph)
- [_minimp3_](https://github.com/lieff/minimp3) is under the [CC0 license](https://github.com/lieff/minimp3/blob/master/LICENSE) - [_minimp3_](https://github.com/lieff/minimp3) is under the [CC0 license](https://github.com/lieff/minimp3/blob/master/LICENSE)
- [_miniaudio_](https://github.com/mackron/miniaudio) is [public domain or under the MIT No Attribution license](https://github.com/mackron/miniaudio/blob/master/LICENSE)

View File

@ -1,117 +0,0 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2024 Laurent Gomila (laurent@sfml-dev.org)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Audio/ALCheck.hpp>
#include <SFML/System/Err.hpp>
#include <ostream>
#include <string>
#include <utility>
#if defined(__APPLE__)
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
namespace
{
// A nested named namespace is used here to allow unity builds of SFML.
namespace AlCheckImpl
{
thread_local ALenum lastError(AL_NO_ERROR);
} // namespace AlCheckImpl
} // namespace
namespace sf::priv
{
////////////////////////////////////////////////////////////
void alCheckError(const std::filesystem::path& file, unsigned int line, std::string_view expression)
{
// Get the last error
const ALenum errorCode = alGetError();
if (errorCode != AL_NO_ERROR)
{
AlCheckImpl::lastError = errorCode;
std::string error = "Unknown error";
std::string description = "No description";
// Decode the error code
switch (errorCode)
{
case AL_INVALID_NAME:
{
error = "AL_INVALID_NAME";
description = "A bad name (ID) has been specified.";
break;
}
case AL_INVALID_ENUM:
{
error = "AL_INVALID_ENUM";
description = "An unacceptable value has been specified for an enumerated argument.";
break;
}
case AL_INVALID_VALUE:
{
error = "AL_INVALID_VALUE";
description = "A numeric argument is out of range.";
break;
}
case AL_INVALID_OPERATION:
{
error = "AL_INVALID_OPERATION";
description = "The specified operation is not allowed in the current state.";
break;
}
case AL_OUT_OF_MEMORY:
{
error = "AL_OUT_OF_MEMORY";
description = "There is not enough memory left to execute the command.";
break;
}
}
// Log the error
err() << "An internal OpenAL call failed in " << file.filename() << "(" << line << ")."
<< "\nExpression:\n " << expression << "\nError description:\n " << error << "\n " << description << '\n'
<< std::endl;
}
}
////////////////////////////////////////////////////////////
ALenum alGetLastErrorImpl()
{
return std::exchange(AlCheckImpl::lastError, AL_NO_ERROR);
}
} // namespace sf::priv

View File

@ -1,93 +0,0 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2024 Laurent Gomila (laurent@sfml-dev.org)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
#pragma once
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Config.hpp>
#include <filesystem>
#include <string_view>
#if defined(__APPLE__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
#include <al.h>
#include <alc.h>
namespace sf::priv
{
////////////////////////////////////////////////////////////
/// Let's define a macro to quickly check every OpenAL API call
////////////////////////////////////////////////////////////
#ifdef SFML_DEBUG
// If in debug mode, perform a test on every call
// The do-while loop is needed so that alCheck can be used as a single statement in if/else branches
#define alCheck(expr) \
do \
{ \
expr; \
sf::priv::alCheckError(__FILE__, __LINE__, #expr); \
} while (false)
#define alGetLastError sf::priv::alGetLastErrorImpl
#else
// Else, we don't add any overhead
#define alCheck(expr) (expr)
#define alGetLastError alGetError
#endif
////////////////////////////////////////////////////////////
/// Check the last OpenAL error
///
/// \param file Source file where the call is located
/// \param line Line number of the source file where the call is located
/// \param expression The evaluated expression as a string
///
////////////////////////////////////////////////////////////
void alCheckError(const std::filesystem::path& file, unsigned int line, std::string_view expression);
////////////////////////////////////////////////////////////
/// Get the last OpenAL error on this thread
///
/// \return The last OpenAL error on this thread
///
////////////////////////////////////////////////////////////
ALenum alGetLastErrorImpl();
} // namespace sf::priv
#if defined(__APPLE__)
#pragma GCC diagnostic pop
#endif

View File

@ -25,211 +25,331 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Headers // Headers
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Audio/ALCheck.hpp>
#include <SFML/Audio/AudioDevice.hpp> #include <SFML/Audio/AudioDevice.hpp>
#include <SFML/Audio/Listener.hpp>
#include <SFML/System/Err.hpp> #include <SFML/System/Err.hpp>
#include <optional> #include <algorithm>
#include <ostream> #include <ostream>
#if defined(__APPLE__)
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
namespace
{
ALCdevice* audioDevice = nullptr;
ALCcontext* audioContext = nullptr;
float listenerVolume = 100.f;
sf::Vector3f listenerPosition(0.f, 0.f, 0.f);
sf::Vector3f listenerDirection(0.f, 0.f, -1.f);
sf::Vector3f listenerUpVector(0.f, 1.f, 0.f);
} // namespace
namespace sf::priv namespace sf::priv
{ {
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
AudioDevice::AudioDevice() AudioDevice::AudioDevice()
{ {
// Create the device // Ensure we only ever have a single AudioDevice instance
audioDevice = alcOpenDevice(nullptr); assert(getInstance() == nullptr);
getInstance() = this;
if (audioDevice) // Create the log
m_log.emplace();
if (auto result = ma_log_init(nullptr, &*m_log); result != MA_SUCCESS)
{ {
m_log.reset();
err() << "Failed to initialize the audio log: " << ma_result_description(result) << std::endl;
return;
}
// Register our logging callback to output any warning/error messages
if (auto result = ma_log_register_callback(&*m_log,
ma_log_callback_init(
[](void*, ma_uint32 level, const char* message)
{
if (level <= MA_LOG_LEVEL_WARNING)
err() << "miniaudio " << ma_log_level_to_string(level)
<< ": " << message << std::flush;
},
nullptr));
result != MA_SUCCESS)
err() << "Failed to register audio log callback: " << ma_result_description(result) << std::endl;
// Create the context // Create the context
audioContext = alcCreateContext(audioDevice, nullptr); m_context.emplace();
if (audioContext) auto contextConfig = ma_context_config_init();
{ contextConfig.pLog = &*m_log;
// Set the context as the current one (we'll only need one)
alcMakeContextCurrent(audioContext);
// Apply the listener properties the user might have set if (auto result = ma_context_init(nullptr, 0, &contextConfig, &*m_context); result != MA_SUCCESS)
float orientation[] = {listenerDirection.x,
listenerDirection.y,
listenerDirection.z,
listenerUpVector.x,
listenerUpVector.y,
listenerUpVector.z};
alCheck(alListenerf(AL_GAIN, listenerVolume * 0.01f));
alCheck(alListener3f(AL_POSITION, listenerPosition.x, listenerPosition.y, listenerPosition.z));
alCheck(alListenerfv(AL_ORIENTATION, orientation));
}
else
{ {
err() << "Failed to create the audio context" << std::endl; m_context.reset();
err() << "Failed to initialize the audio context: " << ma_result_description(result) << std::endl;
return;
} }
}
else // Count the playback devices
ma_uint32 deviceCount;
if (auto result = ma_context_get_devices(&*m_context, nullptr, &deviceCount, nullptr, nullptr); result != MA_SUCCESS)
{ {
err() << "Failed to open the audio device" << std::endl; err() << "Failed to get audio playback devices: " << ma_result_description(result) << std::endl;
return;
} }
// Check if there are audio playback devices available on the system
if (deviceCount == 0)
{
err() << "No audio playback devices available on the system" << std::endl;
return;
}
// Create the playback device
m_playbackDevice.emplace();
auto playbackDeviceConfig = ma_device_config_init(ma_device_type_playback);
playbackDeviceConfig.dataCallback = [](ma_device* device, void* output, const void*, ma_uint32 frameCount)
{
auto& audioDevice = *static_cast<AudioDevice*>(device->pUserData);
if (audioDevice.m_engine)
{
if (auto result = ma_engine_read_pcm_frames(&*audioDevice.m_engine, output, frameCount, nullptr);
result != MA_SUCCESS)
err() << "Failed to read PCM frames from audio engine: " << ma_result_description(result) << std::endl;
}
};
playbackDeviceConfig.pUserData = this;
playbackDeviceConfig.playback.format = ma_format_f32;
if (auto result = ma_device_init(&*m_context, &playbackDeviceConfig, &*m_playbackDevice); result != MA_SUCCESS)
{
m_playbackDevice.reset();
err() << "Failed to initialize the audio playback device: " << ma_result_description(result) << std::endl;
return;
}
// Create the engine
auto engineConfig = ma_engine_config_init();
engineConfig.pContext = &*m_context;
engineConfig.pDevice = &*m_playbackDevice;
engineConfig.listenerCount = 1;
m_engine.emplace();
if (auto result = ma_engine_init(&engineConfig, &*m_engine); result != MA_SUCCESS)
{
m_engine.reset();
err() << "Failed to initialize the audio engine: " << ma_result_description(result) << std::endl;
return;
}
// Set master volume, position, velocity, cone and world up vector
if (auto result = ma_device_set_master_volume(ma_engine_get_device(&*m_engine), getListenerProperties().volume * 0.01f);
result != MA_SUCCESS)
err() << "Failed to set audio device master volume: " << ma_result_description(result) << std::endl;
ma_engine_listener_set_position(&*m_engine,
0,
getListenerProperties().position.x,
getListenerProperties().position.y,
getListenerProperties().position.z);
ma_engine_listener_set_velocity(&*m_engine,
0,
getListenerProperties().velocity.x,
getListenerProperties().velocity.y,
getListenerProperties().velocity.z);
ma_engine_listener_set_cone(&*m_engine,
0,
getListenerProperties().cone.innerAngle.asRadians(),
getListenerProperties().cone.outerAngle.asRadians(),
getListenerProperties().cone.outerGain);
ma_engine_listener_set_world_up(&*m_engine,
0,
getListenerProperties().upVector.x,
getListenerProperties().upVector.y,
getListenerProperties().upVector.z);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
AudioDevice::~AudioDevice() AudioDevice::~AudioDevice()
{ {
// Destroy the engine
if (m_engine)
ma_engine_uninit(&*m_engine);
// Destroy the playback device
if (m_playbackDevice)
ma_device_uninit(&*m_playbackDevice);
// Destroy the context // Destroy the context
alcMakeContextCurrent(nullptr); if (m_context)
if (audioContext) ma_context_uninit(&*m_context);
alcDestroyContext(audioContext);
// Destroy the device // Destroy the log
if (audioDevice) if (m_log)
alcCloseDevice(audioDevice); ma_log_uninit(&*m_log);
// Ensure we only ever have a single AudioDevice instance
assert(getInstance() != nullptr);
getInstance() = nullptr;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool AudioDevice::isExtensionSupported(const std::string& extension) ma_engine* AudioDevice::getEngine()
{ {
// Create a temporary audio device in case none exists yet. auto* instance = getInstance();
// This device will not be used in this function and merely
// makes sure there is a valid OpenAL device for extension
// queries if none has been created yet.
std::optional<AudioDevice> device;
if (!audioDevice)
device.emplace();
if ((extension.length() > 2) && (extension.substr(0, 3) == "ALC")) if (instance && instance->m_engine)
return alcIsExtensionPresent(audioDevice, extension.c_str()) != AL_FALSE; return &*instance->m_engine;
else
return alIsExtensionPresent(extension.c_str()) != AL_FALSE;
}
return nullptr;
////////////////////////////////////////////////////////////
int AudioDevice::getFormatFromChannelCount(unsigned int channelCount)
{
// Create a temporary audio device in case none exists yet.
// This device will not be used in this function and merely
// makes sure there is a valid OpenAL device for format
// queries if none has been created yet.
std::optional<AudioDevice> device;
if (!audioDevice)
device.emplace();
// Find the good format according to the number of channels
int format = 0;
// clang-format off
switch (channelCount)
{
case 1: format = AL_FORMAT_MONO16; break;
case 2: format = AL_FORMAT_STEREO16; break;
case 4: format = alGetEnumValue("AL_FORMAT_QUAD16"); break;
case 6: format = alGetEnumValue("AL_FORMAT_51CHN16"); break;
case 7: format = alGetEnumValue("AL_FORMAT_61CHN16"); break;
case 8: format = alGetEnumValue("AL_FORMAT_71CHN16"); break;
default: format = 0; break;
}
// clang-format on
// Fixes a bug on OS X
if (format == -1)
format = 0;
return format;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void AudioDevice::setGlobalVolume(float volume) void AudioDevice::setGlobalVolume(float volume)
{ {
if (audioContext) // Store the volume in case no audio device exists yet
alCheck(alListenerf(AL_GAIN, volume * 0.01f)); getListenerProperties().volume = volume;
listenerVolume = volume; auto* instance = getInstance();
if (!instance || !instance->m_engine)
return;
if (auto result = ma_device_set_master_volume(ma_engine_get_device(&*instance->m_engine), volume * 0.01f);
result != MA_SUCCESS)
err() << "Failed to set audio device master volume: " << ma_result_description(result) << std::endl;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
float AudioDevice::getGlobalVolume() float AudioDevice::getGlobalVolume()
{ {
return listenerVolume; return getListenerProperties().volume;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void AudioDevice::setPosition(const Vector3f& position) void AudioDevice::setPosition(const Vector3f& position)
{ {
if (audioContext) // Store the position in case no audio device exists yet
alCheck(alListener3f(AL_POSITION, position.x, position.y, position.z)); getListenerProperties().position = position;
listenerPosition = position; auto* instance = getInstance();
if (!instance || !instance->m_engine)
return;
ma_engine_listener_set_position(&*instance->m_engine, 0, position.x, position.y, position.z);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
Vector3f AudioDevice::getPosition() Vector3f AudioDevice::getPosition()
{ {
return listenerPosition; return getListenerProperties().position;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void AudioDevice::setDirection(const Vector3f& direction) void AudioDevice::setDirection(const Vector3f& direction)
{ {
if (audioContext) // Store the direction in case no audio device exists yet
{ getListenerProperties().direction = direction;
float orientation[] =
{direction.x, direction.y, direction.z, listenerUpVector.x, listenerUpVector.y, listenerUpVector.z};
alCheck(alListenerfv(AL_ORIENTATION, orientation));
}
listenerDirection = direction; auto* instance = getInstance();
if (!instance || !instance->m_engine)
return;
ma_engine_listener_set_direction(&*instance->m_engine, 0, direction.x, direction.y, direction.z);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
Vector3f AudioDevice::getDirection() Vector3f AudioDevice::getDirection()
{ {
return listenerDirection; return getListenerProperties().direction;
}
////////////////////////////////////////////////////////////
void AudioDevice::setVelocity(const Vector3f& velocity)
{
// Store the velocity in case no audio device exists yet
getListenerProperties().velocity = velocity;
auto* instance = getInstance();
if (!instance || !instance->m_engine)
return;
ma_engine_listener_set_velocity(&*instance->m_engine, 0, velocity.x, velocity.y, velocity.z);
}
////////////////////////////////////////////////////////////
Vector3f AudioDevice::getVelocity()
{
return getListenerProperties().velocity;
}
////////////////////////////////////////////////////////////
void AudioDevice::setCone(const Listener::Cone& cone)
{
// Store the cone in case no audio device exists yet
getListenerProperties().cone = cone;
auto* instance = getInstance();
if (!instance || !instance->m_engine)
return;
ma_engine_listener_set_cone(&*instance->m_engine,
0,
std::clamp(cone.innerAngle.asRadians(), 0.f, sf::degrees(360).asRadians()),
std::clamp(cone.outerAngle.asRadians(), 0.f, sf::degrees(360).asRadians()),
cone.outerGain);
}
////////////////////////////////////////////////////////////
Listener::Cone AudioDevice::getCone()
{
return getListenerProperties().cone;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void AudioDevice::setUpVector(const Vector3f& upVector) void AudioDevice::setUpVector(const Vector3f& upVector)
{ {
if (audioContext) // Store the up vector in case no audio device exists yet
{ getListenerProperties().upVector = upVector;
float orientation[] =
{listenerDirection.x, listenerDirection.y, listenerDirection.z, upVector.x, upVector.y, upVector.z};
alCheck(alListenerfv(AL_ORIENTATION, orientation));
}
listenerUpVector = upVector; auto* instance = getInstance();
if (!instance || !instance->m_engine)
return;
ma_engine_listener_set_world_up(&*instance->m_engine, 0, upVector.x, upVector.y, upVector.z);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
Vector3f AudioDevice::getUpVector() Vector3f AudioDevice::getUpVector()
{ {
return listenerUpVector; return getListenerProperties().upVector;
}
////////////////////////////////////////////////////////////
AudioDevice*& AudioDevice::getInstance()
{
static AudioDevice* instance{};
return instance;
}
////////////////////////////////////////////////////////////
AudioDevice::ListenerProperties& AudioDevice::getListenerProperties()
{
static ListenerProperties properties;
return properties;
} }
} // namespace sf::priv } // namespace sf::priv

View File

@ -27,9 +27,13 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Headers // Headers
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Audio/Listener.hpp>
#include <SFML/System/Vector3.hpp> #include <SFML/System/Vector3.hpp>
#include <string> #include <miniaudio.h>
#include <optional>
namespace sf::priv namespace sf::priv
@ -56,28 +60,16 @@ public:
~AudioDevice(); ~AudioDevice();
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Check if an OpenAL extension is supported /// \brief Get the audio engine
/// ///
/// This functions automatically finds whether it /// There should only be a single instance of AudioDevice.
/// is an AL or ALC extension, and calls the corresponding /// As long as an AudioResource exists, this function should
/// function. /// always return a valid pointer to the audio engine.
/// ///
/// \param extension Name of the extension to test /// \return The audio engine
///
/// \return True if the extension is supported, false if not
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
static bool isExtensionSupported(const std::string& extension); static ma_engine* getEngine();
////////////////////////////////////////////////////////////
/// \brief Get the OpenAL format that matches the given number of channels
///
/// \param channelCount Number of channels
///
/// \return Corresponding format
///
////////////////////////////////////////////////////////////
static int getFormatFromChannelCount(unsigned int channelCount);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Change the global volume of all the sounds and musics /// \brief Change the global volume of all the sounds and musics
@ -152,6 +144,51 @@ public:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
static Vector3f getDirection(); static Vector3f getDirection();
////////////////////////////////////////////////////////////
/// \brief Set the velocity of the listener in the scene
///
/// The default listener's velocity is (0, 0, -1).
///
/// \param velocity New listener's velocity
///
/// \see getVelocity, getDirection, setUpVector, setPosition
///
////////////////////////////////////////////////////////////
static void setVelocity(const Vector3f& velocity);
////////////////////////////////////////////////////////////
/// \brief Get the current forward vector of the listener in the scene
///
/// \return Listener's velocity
///
/// \see setVelocity
///
////////////////////////////////////////////////////////////
static Vector3f getVelocity();
////////////////////////////////////////////////////////////
/// \brief Set the cone properties of the listener in the audio scene
///
/// The cone defines how directional attenuation is applied.
/// The default cone of a sound is {2 * PI, 2 * PI, 1}.
///
/// \param cone Cone properties of the listener in the scene
///
/// \see getCone
///
////////////////////////////////////////////////////////////
static void setCone(const Listener::Cone& cone);
////////////////////////////////////////////////////////////
/// \brief Get the cone properties of the listener in the audio scene
///
/// \return Cone properties of the listener
///
/// \see setCone
///
////////////////////////////////////////////////////////////
static Listener::Cone getCone();
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Set the upward vector of the listener in the scene /// \brief Set the upward vector of the listener in the scene
/// ///
@ -178,6 +215,41 @@ public:
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
static Vector3f getUpVector(); static Vector3f getUpVector();
private:
////////////////////////////////////////////////////////////
/// \brief This function makes sure the instance pointer is initialized before using it
///
/// \return The instance pointer
///
////////////////////////////////////////////////////////////
static AudioDevice*& getInstance();
struct ListenerProperties
{
float volume{100.f};
sf::Vector3f position{0, 0, 0};
sf::Vector3f direction{0, 0, -1};
sf::Vector3f velocity{0, 0, 0};
Listener::Cone cone{sf::degrees(360), sf::degrees(360), 1};
sf::Vector3f upVector{0, 1, 0};
};
////////////////////////////////////////////////////////////
/// \brief Get the listener properties
///
/// \return The listener properties
///
////////////////////////////////////////////////////////////
static ListenerProperties& getListenerProperties();
////////////////////////////////////////////////////////////
// Member data
////////////////////////////////////////////////////////////
std::optional<ma_log> m_log; //!< The miniaudio log
std::optional<ma_context> m_context; //!< The miniaudio context
std::optional<ma_device> m_playbackDevice; //!< The miniaudio playback device
std::optional<ma_engine> m_engine; //!< The miniaudio engine (used for effects and spatialisation)
}; };
} // namespace sf::priv } // namespace sf::priv

View File

@ -25,55 +25,38 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Headers // Headers
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Audio/AlResource.hpp>
#include <SFML/Audio/AudioDevice.hpp> #include <SFML/Audio/AudioDevice.hpp>
#include <SFML/Audio/AudioResource.hpp>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
namespace
{
// OpenAL resources counter and its mutex
unsigned int count = 0;
std::recursive_mutex mutex;
// The audio device is instantiated on demand rather than at global startup,
// which solves a lot of weird crashes and errors.
// It is destroyed when it is no longer needed.
std::unique_ptr<sf::priv::AudioDevice> globalDevice;
} // namespace
namespace sf namespace sf
{ {
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
AlResource::AlResource() AudioResource::AudioResource() :
{ m_device(
// Protect from concurrent access []()
{
// Ensure we only ever create a single instance of an
// AudioDevice that is shared between all AudioResources
static std::mutex mutex;
static std::weak_ptr<sf::priv::AudioDevice> weakAudioDevice;
const std::lock_guard lock(mutex); const std::lock_guard lock(mutex);
// If this is the very first resource, trigger the global device initialization auto audioDevice = weakAudioDevice.lock();
if (count == 0)
globalDevice = std::make_unique<priv::AudioDevice>();
// Increment the resources counter if (audioDevice == nullptr)
++count; {
} audioDevice = std::make_shared<priv::AudioDevice>();
weakAudioDevice = audioDevice;
}
return audioDevice;
//////////////////////////////////////////////////////////// }())
AlResource::~AlResource()
{ {
// Protect from concurrent access
const std::lock_guard lock(mutex);
// Decrement the resources counter
--count;
// If there's no more resource alive, we can destroy the device
if (count == 0)
globalDevice.reset();
} }
} // namespace sf } // namespace sf

View File

@ -3,15 +3,16 @@ set(SRCROOT ${PROJECT_SOURCE_DIR}/src/SFML/Audio)
# all source files # all source files
set(SRC set(SRC
${SRCROOT}/ALCheck.cpp ${SRCROOT}/AudioResource.cpp
${SRCROOT}/ALCheck.hpp ${INCROOT}/AudioResource.hpp
${SRCROOT}/AlResource.cpp
${INCROOT}/AlResource.hpp
${SRCROOT}/AudioDevice.cpp ${SRCROOT}/AudioDevice.cpp
${SRCROOT}/AudioDevice.hpp ${SRCROOT}/AudioDevice.hpp
${INCROOT}/Export.hpp ${INCROOT}/Export.hpp
${SRCROOT}/Listener.cpp ${SRCROOT}/Listener.cpp
${INCROOT}/Listener.hpp ${INCROOT}/Listener.hpp
${SRCROOT}/Miniaudio.cpp
${SRCROOT}/MiniaudioUtils.hpp
${SRCROOT}/MiniaudioUtils.cpp
${SRCROOT}/Music.cpp ${SRCROOT}/Music.cpp
${INCROOT}/Music.hpp ${INCROOT}/Music.hpp
${SRCROOT}/Sound.cpp ${SRCROOT}/Sound.cpp
@ -20,6 +21,7 @@ set(SRC
${INCROOT}/SoundBuffer.hpp ${INCROOT}/SoundBuffer.hpp
${SRCROOT}/SoundBufferRecorder.cpp ${SRCROOT}/SoundBufferRecorder.cpp
${INCROOT}/SoundBufferRecorder.hpp ${INCROOT}/SoundBufferRecorder.hpp
${INCROOT}/SoundChannel.hpp
${SRCROOT}/InputSoundFile.cpp ${SRCROOT}/InputSoundFile.cpp
${INCROOT}/InputSoundFile.hpp ${INCROOT}/InputSoundFile.hpp
${SRCROOT}/OutputSoundFile.cpp ${SRCROOT}/OutputSoundFile.cpp
@ -56,18 +58,21 @@ set(CODECS_SRC
) )
source_group("codecs" FILES ${CODECS_SRC}) source_group("codecs" FILES ${CODECS_SRC})
# let CMake know about our additional audio libraries paths (on Windows and macOS) # Ensure certain files are compiled as Objective-C++
if(SFML_OS_WINDOWS) # See: https://miniaud.io/docs/manual/index.html#Building
list(APPEND CMAKE_INCLUDE_PATH "${PROJECT_SOURCE_DIR}/extlibs/headers/AL") if(SFML_OS_IOS)
elseif(SFML_OS_MACOS) enable_language(OBJCXX)
set_source_files_properties(${SRCROOT}/Miniaudio.cpp PROPERTIES LANGUAGE OBJCXX)
endif()
# let CMake know about our additional audio libraries paths (on Android and macOS)
if(SFML_OS_MACOS)
list(APPEND CMAKE_LIBRARY_PATH "${PROJECT_SOURCE_DIR}/extlibs/libs-macos/Frameworks") list(APPEND CMAKE_LIBRARY_PATH "${PROJECT_SOURCE_DIR}/extlibs/libs-macos/Frameworks")
elseif(SFML_OS_ANDROID) elseif(SFML_OS_ANDROID)
list(APPEND CMAKE_INCLUDE_PATH "${PROJECT_SOURCE_DIR}/extlibs/headers/AL")
list(APPEND CMAKE_INCLUDE_PATH "${PROJECT_SOURCE_DIR}/extlibs/android") list(APPEND CMAKE_INCLUDE_PATH "${PROJECT_SOURCE_DIR}/extlibs/android")
endif() endif()
# find external libraries # find external libraries
find_package(OpenAL REQUIRED)
find_package(Vorbis REQUIRED) find_package(Vorbis REQUIRED)
find_package(FLAC REQUIRED) find_package(FLAC REQUIRED)
@ -78,17 +83,29 @@ sfml_add_library(Audio
# avoids warnings in vorbisfile.h # avoids warnings in vorbisfile.h
target_compile_definitions(sfml-audio PRIVATE OV_EXCLUDE_STATIC_CALLBACKS FLAC__NO_DLL) target_compile_definitions(sfml-audio PRIVATE OV_EXCLUDE_STATIC_CALLBACKS FLAC__NO_DLL)
# disable miniaudio features we do not use
target_compile_definitions(sfml-audio PRIVATE MA_NO_DECODING MA_NO_ENCODING MA_NO_RESOURCE_MANAGER MA_NO_GENERATION)
# setup dependencies # setup dependencies
target_link_libraries(sfml-audio target_link_libraries(sfml-audio
PUBLIC SFML::System PUBLIC SFML::System
PRIVATE OpenAL::OpenAL Vorbis::vorbis FLAC::FLAC) PRIVATE Vorbis::vorbis FLAC::FLAC)
if(NOT SFML_OS_IOS) if(SFML_OS_IOS)
target_link_libraries(sfml-audio PRIVATE "-framework Foundation" "-framework CoreFoundation" "-framework CoreAudio" "-framework AudioToolbox" "-framework AVFoundation")
else()
target_link_libraries(sfml-audio PRIVATE Vorbis::vorbisfile Vorbis::vorbisenc) target_link_libraries(sfml-audio PRIVATE Vorbis::vorbisfile Vorbis::vorbisenc)
endif() endif()
# miniaudio sources
target_include_directories(sfml-audio SYSTEM PRIVATE "${PROJECT_SOURCE_DIR}/extlibs/headers/miniaudio")
# minimp3 sources # minimp3 sources
target_include_directories(sfml-audio SYSTEM PRIVATE "${PROJECT_SOURCE_DIR}/extlibs/headers/minimp3") target_include_directories(sfml-audio SYSTEM PRIVATE "${PROJECT_SOURCE_DIR}/extlibs/headers/minimp3")
if(SFML_OS_ANDROID) if(SFML_OS_ANDROID)
target_link_libraries(sfml-audio PRIVATE android OpenSLES) target_link_libraries(sfml-audio PRIVATE android OpenSLES)
endif() endif()
if(SFML_OS_LINUX)
target_link_libraries(sfml-audio PRIVATE dl)
endif()

View File

@ -35,10 +35,11 @@
#include <SFML/System/MemoryInputStream.hpp> #include <SFML/System/MemoryInputStream.hpp>
#include <SFML/System/Time.hpp> #include <SFML/System/Time.hpp>
#include <algorithm>
#include <ostream> #include <ostream>
#include <utility> #include <utility>
#include <cstdint>
namespace sf namespace sf
{ {
@ -92,8 +93,8 @@ bool InputSoundFile::openFromFile(const std::filesystem::path& filename)
// Retrieve the attributes of the open sound file // Retrieve the attributes of the open sound file
m_sampleCount = info->sampleCount; m_sampleCount = info->sampleCount;
m_channelCount = info->channelCount;
m_sampleRate = info->sampleRate; m_sampleRate = info->sampleRate;
m_channelMap = info->channelMap;
return true; return true;
} }
@ -127,8 +128,8 @@ bool InputSoundFile::openFromMemory(const void* data, std::size_t sizeInBytes)
// Retrieve the attributes of the open sound file // Retrieve the attributes of the open sound file
m_sampleCount = info->sampleCount; m_sampleCount = info->sampleCount;
m_channelCount = info->channelCount;
m_sampleRate = info->sampleRate; m_sampleRate = info->sampleRate;
m_channelMap = info->channelMap;
return true; return true;
} }
@ -163,8 +164,8 @@ bool InputSoundFile::openFromStream(InputStream& stream)
// Retrieve the attributes of the open sound file // Retrieve the attributes of the open sound file
m_sampleCount = info->sampleCount; m_sampleCount = info->sampleCount;
m_channelCount = info->channelCount;
m_sampleRate = info->sampleRate; m_sampleRate = info->sampleRate;
m_channelMap = info->channelMap;
return true; return true;
} }
@ -180,7 +181,7 @@ std::uint64_t InputSoundFile::getSampleCount() const
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
unsigned int InputSoundFile::getChannelCount() const unsigned int InputSoundFile::getChannelCount() const
{ {
return m_channelCount; return static_cast<unsigned int>(m_channelMap.size());
} }
@ -191,15 +192,22 @@ unsigned int InputSoundFile::getSampleRate() const
} }
////////////////////////////////////////////////////////////
const std::vector<SoundChannel>& InputSoundFile::getChannelMap() const
{
return m_channelMap;
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
Time InputSoundFile::getDuration() const Time InputSoundFile::getDuration() const
{ {
// Make sure we don't divide by 0 // Make sure we don't divide by 0
if (m_channelCount == 0 || m_sampleRate == 0) if (m_channelMap.empty() || m_sampleRate == 0)
return Time::Zero; return Time::Zero;
return seconds( return seconds(
static_cast<float>(m_sampleCount) / static_cast<float>(m_channelCount) / static_cast<float>(m_sampleRate)); static_cast<float>(m_sampleCount) / static_cast<float>(m_channelMap.size()) / static_cast<float>(m_sampleRate));
} }
@ -207,11 +215,11 @@ Time InputSoundFile::getDuration() const
Time InputSoundFile::getTimeOffset() const Time InputSoundFile::getTimeOffset() const
{ {
// Make sure we don't divide by 0 // Make sure we don't divide by 0
if (m_channelCount == 0 || m_sampleRate == 0) if (m_channelMap.empty() || m_sampleRate == 0)
return Time::Zero; return Time::Zero;
return seconds( return seconds(
static_cast<float>(m_sampleOffset) / static_cast<float>(m_channelCount) / static_cast<float>(m_sampleRate)); static_cast<float>(m_sampleOffset) / static_cast<float>(m_channelMap.size()) / static_cast<float>(m_sampleRate));
} }
@ -225,11 +233,11 @@ std::uint64_t InputSoundFile::getSampleOffset() const
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void InputSoundFile::seek(std::uint64_t sampleOffset) void InputSoundFile::seek(std::uint64_t sampleOffset)
{ {
if (m_reader && m_channelCount != 0) if (m_reader && !m_channelMap.empty())
{ {
// The reader handles an overrun gracefully, but we // The reader handles an overrun gracefully, but we
// pre-check to keep our known position consistent // pre-check to keep our known position consistent
m_sampleOffset = std::min(sampleOffset / m_channelCount * m_channelCount, m_sampleCount); m_sampleOffset = std::min(sampleOffset / m_channelMap.size() * m_channelMap.size(), m_sampleCount);
m_reader->seek(m_sampleOffset); m_reader->seek(m_sampleOffset);
} }
} }
@ -238,7 +246,7 @@ void InputSoundFile::seek(std::uint64_t sampleOffset)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void InputSoundFile::seek(Time timeOffset) void InputSoundFile::seek(Time timeOffset)
{ {
seek(static_cast<std::uint64_t>(timeOffset.asSeconds() * static_cast<float>(m_sampleRate)) * m_channelCount); seek(static_cast<std::uint64_t>(timeOffset.asSeconds() * static_cast<float>(m_sampleRate)) * m_channelMap.size());
} }
@ -257,6 +265,7 @@ std::uint64_t InputSoundFile::read(std::int16_t* samples, std::uint64_t maxCount
void InputSoundFile::close() void InputSoundFile::close()
{ {
*this = {}; *this = {};
m_channelMap.clear();
} }
} // namespace sf } // namespace sf

View File

@ -73,6 +73,34 @@ Vector3f Listener::getDirection()
} }
////////////////////////////////////////////////////////////
void Listener::setVelocity(const Vector3f& velocity)
{
priv::AudioDevice::setVelocity(velocity);
}
////////////////////////////////////////////////////////////
Vector3f Listener::getVelocity()
{
return priv::AudioDevice::getVelocity();
}
////////////////////////////////////////////////////////////
void Listener::setCone(const Listener::Cone& cone)
{
priv::AudioDevice::setCone(cone);
}
////////////////////////////////////////////////////////////
Listener::Cone Listener::getCone()
{
return priv::AudioDevice::getCone();
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void Listener::setUpVector(const Vector3f& upVector) void Listener::setUpVector(const Vector3f& upVector)
{ {

View File

@ -0,0 +1,33 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2024 Laurent Gomila (laurent@sfml-dev.org)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#if defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wnull-dereference" // Work around MinGW warning
#endif
// #define MA_DEBUG_OUTPUT // Uncomment to enable miniaudio debug output to console
#define MINIAUDIO_IMPLEMENTATION
#include <miniaudio.h>

View File

@ -0,0 +1,245 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2024 Laurent Gomila (laurent@sfml-dev.org)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Audio/MiniaudioUtils.hpp>
#include <SFML/Audio/SoundChannel.hpp>
#include <SFML/System/Angle.hpp>
#include <SFML/System/Err.hpp>
#include <SFML/System/Time.hpp>
#include <miniaudio.h>
#include <functional>
#include <limits>
#include <ostream>
#include <cassert>
namespace sf::priv
{
namespace
{
////////////////////////////////////////////////////////////
struct SavedSettings
{
float pitch{1.f};
float pan{0.f};
float volume{1.f};
ma_bool32 spatializationEnabled{MA_TRUE};
ma_vec3f position{0.f, 0.f, 0.f};
ma_vec3f direction{0.f, 0.f, -1.f};
float directionalAttenuationFactor{1.f};
ma_vec3f velocity{0.f, 0.f, 0.f};
float dopplerFactor{1.f};
ma_positioning positioning{ma_positioning_absolute};
float minDistance{1.f};
float maxDistance{std::numeric_limits<float>::max()};
float minGain{0.f};
float maxGain{1.f};
float rollOff{1.f};
float innerAngle{sf::degrees(360).asRadians()};
float outerAngle{sf::degrees(360).asRadians()};
float outerGain{0.f};
};
////////////////////////////////////////////////////////////
SavedSettings saveSettings(const ma_sound& sound)
{
float innerAngle;
float outerAngle;
float outerGain;
ma_sound_get_cone(&sound, &innerAngle, &outerAngle, &outerGain);
return SavedSettings{ma_sound_get_pitch(&sound),
ma_sound_get_pan(&sound),
ma_sound_get_volume(&sound),
ma_sound_is_spatialization_enabled(&sound),
ma_sound_get_position(&sound),
ma_sound_get_direction(&sound),
ma_sound_get_directional_attenuation_factor(&sound),
ma_sound_get_velocity(&sound),
ma_sound_get_doppler_factor(&sound),
ma_sound_get_positioning(&sound),
ma_sound_get_min_distance(&sound),
ma_sound_get_max_distance(&sound),
ma_sound_get_min_gain(&sound),
ma_sound_get_max_gain(&sound),
ma_sound_get_rolloff(&sound),
innerAngle,
outerAngle,
outerGain};
}
////////////////////////////////////////////////////////////
void applySettings(ma_sound& sound, const SavedSettings& savedSettings)
{
ma_sound_set_pitch(&sound, savedSettings.pitch);
ma_sound_set_pan(&sound, savedSettings.pan);
ma_sound_set_volume(&sound, savedSettings.volume);
ma_sound_set_spatialization_enabled(&sound, savedSettings.spatializationEnabled);
ma_sound_set_position(&sound, savedSettings.position.x, savedSettings.position.y, savedSettings.position.z);
ma_sound_set_direction(&sound, savedSettings.direction.x, savedSettings.direction.y, savedSettings.direction.z);
ma_sound_set_directional_attenuation_factor(&sound, savedSettings.directionalAttenuationFactor);
ma_sound_set_velocity(&sound, savedSettings.velocity.x, savedSettings.velocity.y, savedSettings.velocity.z);
ma_sound_set_doppler_factor(&sound, savedSettings.dopplerFactor);
ma_sound_set_positioning(&sound, savedSettings.positioning);
ma_sound_set_min_distance(&sound, savedSettings.minDistance);
ma_sound_set_max_distance(&sound, savedSettings.maxDistance);
ma_sound_set_min_gain(&sound, savedSettings.minGain);
ma_sound_set_max_gain(&sound, savedSettings.maxGain);
ma_sound_set_rolloff(&sound, savedSettings.rollOff);
ma_sound_set_cone(&sound, savedSettings.innerAngle, savedSettings.outerAngle, savedSettings.outerGain);
}
////////////////////////////////////////////////////////////
void initializeDataSource(ma_data_source_base& dataSourceBase, const ma_data_source_vtable& vtable)
{
// Set this object up as a miniaudio data source
ma_data_source_config config = ma_data_source_config_init();
config.vtable = &vtable;
if (const ma_result result = ma_data_source_init(&config, &dataSourceBase); result != MA_SUCCESS)
err() << "Failed to initialize audio data source: " << ma_result_description(result) << std::endl;
}
} // namespace
////////////////////////////////////////////////////////////
ma_channel MiniaudioUtils::soundChannelToMiniaudioChannel(sf::SoundChannel soundChannel)
{
switch (soundChannel)
{
case SoundChannel::Unspecified:
return MA_CHANNEL_NONE;
case SoundChannel::Mono:
return MA_CHANNEL_MONO;
case SoundChannel::FrontLeft:
return MA_CHANNEL_FRONT_LEFT;
case SoundChannel::FrontRight:
return MA_CHANNEL_FRONT_RIGHT;
case SoundChannel::FrontCenter:
return MA_CHANNEL_FRONT_CENTER;
case SoundChannel::FrontLeftOfCenter:
return MA_CHANNEL_FRONT_LEFT_CENTER;
case SoundChannel::FrontRightOfCenter:
return MA_CHANNEL_FRONT_RIGHT_CENTER;
case SoundChannel::LowFrequencyEffects:
return MA_CHANNEL_LFE;
case SoundChannel::BackLeft:
return MA_CHANNEL_BACK_LEFT;
case SoundChannel::BackRight:
return MA_CHANNEL_BACK_RIGHT;
case SoundChannel::BackCenter:
return MA_CHANNEL_BACK_CENTER;
case SoundChannel::SideLeft:
return MA_CHANNEL_SIDE_LEFT;
case SoundChannel::SideRight:
return MA_CHANNEL_SIDE_RIGHT;
case SoundChannel::TopCenter:
return MA_CHANNEL_TOP_CENTER;
case SoundChannel::TopFrontLeft:
return MA_CHANNEL_TOP_FRONT_LEFT;
case SoundChannel::TopFrontRight:
return MA_CHANNEL_TOP_FRONT_RIGHT;
case SoundChannel::TopFrontCenter:
return MA_CHANNEL_TOP_FRONT_CENTER;
case SoundChannel::TopBackLeft:
return MA_CHANNEL_TOP_BACK_LEFT;
case SoundChannel::TopBackRight:
return MA_CHANNEL_TOP_BACK_RIGHT;
default:
assert(soundChannel == SoundChannel::TopBackCenter);
return MA_CHANNEL_TOP_BACK_CENTER;
}
}
////////////////////////////////////////////////////////////
Time MiniaudioUtils::getPlayingOffset(ma_sound& sound)
{
float cursor = 0.f;
if (const ma_result result = ma_sound_get_cursor_in_seconds(&sound, &cursor); result != MA_SUCCESS)
{
err() << "Failed to get sound cursor: " << ma_result_description(result) << std::endl;
return {};
}
return seconds(cursor);
}
////////////////////////////////////////////////////////////
ma_uint64 MiniaudioUtils::getFrameIndex(ma_sound& sound, Time timeOffset)
{
ma_uint32 sampleRate{};
if (const ma_result result = ma_sound_get_data_format(&sound, nullptr, nullptr, &sampleRate, nullptr, 0);
result != MA_SUCCESS)
err() << "Failed to get sound data format: " << ma_result_description(result) << std::endl;
const auto frameIndex = static_cast<ma_uint64>(timeOffset.asSeconds() * static_cast<float>(sampleRate));
if (const ma_result result = ma_sound_seek_to_pcm_frame(&sound, frameIndex); result != MA_SUCCESS)
err() << "Failed to seek sound to pcm frame: " << ma_result_description(result) << std::endl;
return frameIndex;
}
////////////////////////////////////////////////////////////
void MiniaudioUtils::reinitializeSound(ma_sound& sound, const std::function<void()>& initializeFn)
{
const SavedSettings savedSettings = saveSettings(sound);
ma_sound_uninit(&sound);
initializeFn();
applySettings(sound, savedSettings);
}
////////////////////////////////////////////////////////////
void MiniaudioUtils::initializeSound(const ma_data_source_vtable& vtable,
ma_data_source_base& dataSourceBase,
ma_sound& sound,
const std::function<void()>& initializeFn)
{
initializeDataSource(dataSourceBase, vtable);
// Initialize sound structure and set default settings
initializeFn();
applySettings(sound, SavedSettings{});
}
} // namespace sf::priv

View File

@ -0,0 +1,57 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2024 Laurent Gomila (laurent@sfml-dev.org)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
#pragma once
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Audio/SoundChannel.hpp>
#include <miniaudio.h>
#include <functional>
////////////////////////////////////////////////////////////
// Forward declarations
////////////////////////////////////////////////////////////
namespace sf
{
class Time;
}
namespace sf::priv::MiniaudioUtils
{
[[nodiscard]] ma_channel soundChannelToMiniaudioChannel(sf::SoundChannel soundChannel);
[[nodiscard]] Time getPlayingOffset(ma_sound& sound);
[[nodiscard]] ma_uint64 getFrameIndex(ma_sound& sound, Time timeOffset);
void reinitializeSound(ma_sound& sound, const std::function<void()>& initializeFn);
void initializeSound(const ma_data_source_vtable& vtable,
ma_data_source_base& dataSourceBase,
ma_sound& sound,
const std::function<void()>& initializeFn);
} // namespace sf::priv::MiniaudioUtils

View File

@ -25,20 +25,15 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Headers // Headers
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Audio/ALCheck.hpp>
#include <SFML/Audio/Music.hpp> #include <SFML/Audio/Music.hpp>
#include <SFML/System/Err.hpp> #include <SFML/System/Err.hpp>
#include <SFML/System/Time.hpp> #include <SFML/System/Time.hpp>
#include <algorithm> #include <algorithm>
#include <fstream>
#include <mutex> #include <mutex>
#include <ostream> #include <ostream>
#if defined(__APPLE__)
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
namespace sf namespace sf
{ {
@ -242,7 +237,7 @@ void Music::initialize()
m_samples.resize(m_file.getSampleRate() * m_file.getChannelCount()); m_samples.resize(m_file.getSampleRate() * m_file.getChannelCount());
// Initialize the stream // Initialize the stream
SoundStream::initialize(m_file.getChannelCount(), m_file.getSampleRate()); SoundStream::initialize(m_file.getChannelCount(), m_file.getSampleRate(), m_file.getChannelMap());
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -33,7 +33,10 @@
namespace sf namespace sf
{ {
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool OutputSoundFile::openFromFile(const std::filesystem::path& filename, unsigned int sampleRate, unsigned int channelCount) bool OutputSoundFile::openFromFile(const std::filesystem::path& filename,
unsigned int sampleRate,
unsigned int channelCount,
const std::vector<SoundChannel>& channelMap)
{ {
// If the file is already open, first close it // If the file is already open, first close it
close(); close();
@ -44,7 +47,7 @@ bool OutputSoundFile::openFromFile(const std::filesystem::path& filename, unsign
return false; return false;
// Pass the stream to the reader // Pass the stream to the reader
if (!m_writer->open(filename, sampleRate, channelCount)) if (!m_writer->open(filename, sampleRate, channelCount, channelMap))
{ {
close(); close();
return false; return false;

View File

@ -25,29 +25,214 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Headers // Headers
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Audio/ALCheck.hpp> #include <SFML/Audio/AudioDevice.hpp>
#include <SFML/Audio/MiniaudioUtils.hpp>
#include <SFML/Audio/Sound.hpp> #include <SFML/Audio/Sound.hpp>
#include <SFML/Audio/SoundBuffer.hpp> #include <SFML/Audio/SoundBuffer.hpp>
#if defined(__APPLE__) #include <SFML/System/Err.hpp>
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif #include <miniaudio.h>
#include <algorithm>
#include <ostream>
#include <vector>
#include <cassert>
#include <cstring>
namespace sf namespace sf
{ {
//////////////////////////////////////////////////////////// struct Sound::Impl
Sound::Sound(const SoundBuffer& buffer) : m_buffer(&buffer)
{ {
m_buffer->attachSound(this); Impl()
alCheck(alSourcei(m_source, AL_BUFFER, static_cast<ALint>(m_buffer->m_buffer))); {
static constexpr ma_data_source_vtable vtable{read, seek, getFormat, getCursor, getLength, setLooping, 0};
priv::MiniaudioUtils::initializeSound(vtable, dataSourceBase, sound, [this] { initialize(); });
}
~Impl()
{
ma_sound_uninit(&sound);
ma_data_source_uninit(&dataSourceBase);
}
void initialize()
{
// Initialize the sound
auto* engine = priv::AudioDevice::getEngine();
if (engine == nullptr)
{
err() << "Failed to initialize sound: No engine available" << std::endl;
return;
}
ma_sound_config soundConfig;
soundConfig = ma_sound_config_init();
soundConfig.pDataSource = this;
soundConfig.pEndCallbackUserData = this;
soundConfig.endCallback = [](void* userData, ma_sound* soundPtr)
{
auto& impl = *static_cast<Impl*>(userData);
impl.status = Stopped;
// Seek back to the start of the sound when it finishes playing
if (const ma_result result = ma_sound_seek_to_pcm_frame(soundPtr, 0); result != MA_SUCCESS)
err() << "Failed to seek sound to frame 0: " << ma_result_description(result) << std::endl;
};
if (const ma_result result = ma_sound_init_ex(engine, &soundConfig, &sound); result != MA_SUCCESS)
{
err() << "Failed to initialize sound: " << ma_result_description(result) << std::endl;
return;
}
// Because we are providing a custom data source, we have to provide the channel map ourselves
if (buffer && !buffer->getChannelMap().empty())
{
soundChannelMap.clear();
for (const SoundChannel channel : buffer->getChannelMap())
{
soundChannelMap.push_back(priv::MiniaudioUtils::soundChannelToMiniaudioChannel(channel));
}
sound.engineNode.spatializer.pChannelMapIn = soundChannelMap.data();
}
else
{
sound.engineNode.spatializer.pChannelMapIn = nullptr;
}
}
void reinitialize()
{
priv::MiniaudioUtils::reinitializeSound(sound, [this] { initialize(); });
}
static ma_result read(ma_data_source* dataSource, void* framesOut, ma_uint64 frameCount, ma_uint64* framesRead)
{
auto& impl = *static_cast<Impl*>(dataSource);
const auto* buffer = impl.buffer;
if (buffer == nullptr)
return MA_NO_DATA_AVAILABLE;
// Determine how many frames we can read
*framesRead = std::min<ma_uint64>(frameCount, (buffer->getSampleCount() - impl.cursor) / buffer->getChannelCount());
// Copy the samples to the output
const auto sampleCount = *framesRead * buffer->getChannelCount();
std::memcpy(framesOut,
buffer->getSamples() + impl.cursor,
static_cast<std::size_t>(sampleCount) * sizeof(buffer->getSamples()[0]));
impl.cursor += static_cast<std::size_t>(sampleCount);
// If we are looping and at the end of the sound, set the cursor back to the start
if (impl.looping && (impl.cursor >= buffer->getSampleCount()))
impl.cursor = 0;
return MA_SUCCESS;
}
static ma_result seek(ma_data_source* dataSource, ma_uint64 frameIndex)
{
auto& impl = *static_cast<Impl*>(dataSource);
const auto* buffer = impl.buffer;
if (buffer == nullptr)
return MA_NO_DATA_AVAILABLE;
impl.cursor = static_cast<std::size_t>(frameIndex * buffer->getChannelCount());
return MA_SUCCESS;
}
static ma_result getFormat(ma_data_source* dataSource,
ma_format* format,
ma_uint32* channels,
ma_uint32* sampleRate,
ma_channel*,
size_t)
{
const auto& impl = *static_cast<const Impl*>(dataSource);
const auto* buffer = impl.buffer;
// If we don't have valid values yet, initialize with defaults so sound creation doesn't fail
*format = ma_format_s16;
*channels = buffer && buffer->getChannelCount() ? buffer->getChannelCount() : 1;
*sampleRate = buffer && buffer->getSampleRate() ? buffer->getSampleRate() : 44100;
return MA_SUCCESS;
}
static ma_result getCursor(ma_data_source* dataSource, ma_uint64* cursor)
{
const auto& impl = *static_cast<const Impl*>(dataSource);
const auto* buffer = impl.buffer;
if (buffer == nullptr)
return MA_NO_DATA_AVAILABLE;
*cursor = impl.cursor / buffer->getChannelCount();
return MA_SUCCESS;
}
static ma_result getLength(ma_data_source* dataSource, ma_uint64* length)
{
const auto& impl = *static_cast<const Impl*>(dataSource);
const auto* buffer = impl.buffer;
if (buffer == nullptr)
return MA_NO_DATA_AVAILABLE;
*length = buffer->getSampleCount() / buffer->getChannelCount();
return MA_SUCCESS;
}
static ma_result setLooping(ma_data_source* dataSource, ma_bool32 looping)
{
auto& impl = *static_cast<Impl*>(dataSource);
impl.looping = (looping == MA_TRUE);
return MA_SUCCESS;
}
////////////////////////////////////////////////////////////
// Member data
////////////////////////////////////////////////////////////
ma_data_source_base dataSourceBase{}; //!< The struct that makes this object a miniaudio data source (must be first member)
std::vector<ma_channel> soundChannelMap; //!< The map of position in sample frame to sound channel (miniaudio channels)
ma_sound sound{}; //!< The sound
std::size_t cursor{}; //!< The current playing position
bool looping{}; //!< True if we are looping the sound
const SoundBuffer* buffer{}; //!< Sound buffer bound to the source
Status status{Stopped}; //!< The status
};
////////////////////////////////////////////////////////////
Sound::Sound(const SoundBuffer& buffer) : m_impl(std::make_unique<Impl>())
{
setBuffer(buffer);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
Sound::Sound(const Sound& copy) : SoundSource(copy), m_buffer(copy.m_buffer) // NOLINTNEXTLINE(readability-redundant-member-init)
Sound::Sound(const Sound& copy) : SoundSource(copy), m_impl(std::make_unique<Impl>())
{ {
m_buffer->attachSound(this); SoundSource::operator=(copy);
alCheck(alSourcei(m_source, AL_BUFFER, static_cast<ALint>(m_buffer->m_buffer)));
if (copy.m_impl->buffer)
setBuffer(*copy.m_impl->buffer);
setLoop(copy.getLoop()); setLoop(copy.getLoop());
} }
@ -56,28 +241,55 @@ Sound::Sound(const Sound& copy) : SoundSource(copy), m_buffer(copy.m_buffer)
Sound::~Sound() Sound::~Sound()
{ {
stop(); stop();
m_buffer->detachSound(this); if (m_impl->buffer)
m_impl->buffer->detachSound(this);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void Sound::play() void Sound::play()
{ {
alCheck(alSourcePlay(m_source)); if (m_impl->status == Playing)
setPlayingOffset(Time::Zero);
if (const ma_result result = ma_sound_start(&m_impl->sound); result != MA_SUCCESS)
{
err() << "Failed to start playing sound: " << ma_result_description(result) << std::endl;
}
else
{
m_impl->status = Playing;
}
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void Sound::pause() void Sound::pause()
{ {
alCheck(alSourcePause(m_source)); if (const ma_result result = ma_sound_stop(&m_impl->sound); result != MA_SUCCESS)
{
err() << "Failed to stop playing sound: " << ma_result_description(result) << std::endl;
}
else
{
if (m_impl->status == Playing)
m_impl->status = Paused;
}
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void Sound::stop() void Sound::stop()
{ {
alCheck(alSourceStop(m_source)); if (const ma_result result = ma_sound_stop(&m_impl->sound); result != MA_SUCCESS)
{
err() << "Failed to stop playing sound: " << ma_result_description(result) << std::endl;
}
else
{
setPlayingOffset(Time::Zero);
m_impl->status = Stopped;
}
} }
@ -85,61 +297,72 @@ void Sound::stop()
void Sound::setBuffer(const SoundBuffer& buffer) void Sound::setBuffer(const SoundBuffer& buffer)
{ {
// First detach from the previous buffer // First detach from the previous buffer
if (m_impl->buffer)
{
stop(); stop();
m_buffer->detachSound(this);
// Reset cursor
m_impl->cursor = 0;
m_impl->buffer->detachSound(this);
}
// Assign and use the new buffer // Assign and use the new buffer
m_buffer = &buffer; m_impl->buffer = &buffer;
m_buffer->attachSound(this); m_impl->buffer->attachSound(this);
alCheck(alSourcei(m_source, AL_BUFFER, static_cast<ALint>(m_buffer->m_buffer)));
m_impl->reinitialize();
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void Sound::setLoop(bool loop) void Sound::setLoop(bool loop)
{ {
alCheck(alSourcei(m_source, AL_LOOPING, loop)); ma_sound_set_looping(&m_impl->sound, loop ? MA_TRUE : MA_FALSE);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void Sound::setPlayingOffset(Time timeOffset) void Sound::setPlayingOffset(Time timeOffset)
{ {
alCheck(alSourcef(m_source, AL_SEC_OFFSET, timeOffset.asSeconds())); if (m_impl->sound.pDataSource == nullptr || m_impl->sound.engineNode.pEngine == nullptr)
return;
const auto frameIndex = priv::MiniaudioUtils::getFrameIndex(m_impl->sound, timeOffset);
if (m_impl->buffer)
m_impl->cursor = static_cast<std::size_t>(frameIndex * m_impl->buffer->getChannelCount());
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
const SoundBuffer& Sound::getBuffer() const const SoundBuffer& Sound::getBuffer() const
{ {
return *m_buffer; assert(m_impl && "Sound::getBuffer() Cannot access unset buffer");
return *m_impl->buffer;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool Sound::getLoop() const bool Sound::getLoop() const
{ {
ALint loop; return ma_sound_is_looping(&m_impl->sound) == MA_TRUE;
alCheck(alGetSourcei(m_source, AL_LOOPING, &loop));
return loop != 0;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
Time Sound::getPlayingOffset() const Time Sound::getPlayingOffset() const
{ {
ALfloat secs = 0.f; if (!m_impl->buffer || m_impl->buffer->getChannelCount() == 0 || m_impl->buffer->getSampleRate() == 0)
alCheck(alGetSourcef(m_source, AL_SEC_OFFSET, &secs)); return {};
return seconds(secs); return priv::MiniaudioUtils::getPlayingOffset(m_impl->sound);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
Sound::Status Sound::getStatus() const Sound::Status Sound::getStatus() const
{ {
return SoundSource::getStatus(); return m_impl->status;
} }
@ -147,8 +370,7 @@ Sound::Status Sound::getStatus() const
Sound& Sound::operator=(const Sound& right) Sound& Sound::operator=(const Sound& right)
{ {
// Here we don't use the copy-and-swap idiom, because it would mess up // Here we don't use the copy-and-swap idiom, because it would mess up
// the list of sound instances contained in the buffers and unnecessarily // the list of sound instances contained in the buffers
// destroy/create OpenAL sound sources
// Handle self-assignment here, as no copy-and-swap idiom is being used // Handle self-assignment here, as no copy-and-swap idiom is being used
if (this == &right) if (this == &right)
@ -157,8 +379,17 @@ Sound& Sound::operator=(const Sound& right)
// Delegate to base class, which copies all the sound attributes // Delegate to base class, which copies all the sound attributes
SoundSource::operator=(right); SoundSource::operator=(right);
// Detach the sound instance from the previous buffer (if any)
if (m_impl->buffer)
{
stop();
m_impl->buffer->detachSound(this);
m_impl->buffer = nullptr;
}
// Copy the remaining sound attributes // Copy the remaining sound attributes
setBuffer(*right.m_buffer); if (right.m_impl->buffer)
setBuffer(*right.m_impl->buffer);
setLoop(right.getLoop()); setLoop(right.getLoop());
return *this; return *this;
@ -172,14 +403,18 @@ void Sound::detachBuffer()
stop(); stop();
// Detach the buffer // Detach the buffer
alCheck(alSourcei(m_source, AL_BUFFER, 0)); if (m_impl->buffer)
{
m_impl->buffer->detachSound(this);
m_impl->buffer = nullptr;
}
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void Sound::reattachBuffer() void* Sound::getSound() const
{ {
alCheck(alSourcei(m_source, AL_BUFFER, static_cast<ALint>(m_buffer->m_buffer))); return &m_impl->sound;
} }
} // namespace sf } // namespace sf

View File

@ -25,43 +25,29 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Headers // Headers
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Audio/ALCheck.hpp>
#include <SFML/Audio/AudioDevice.hpp>
#include <SFML/Audio/InputSoundFile.hpp> #include <SFML/Audio/InputSoundFile.hpp>
#include <SFML/Audio/OutputSoundFile.hpp> #include <SFML/Audio/OutputSoundFile.hpp>
#include <SFML/Audio/Sound.hpp> #include <SFML/Audio/Sound.hpp>
#include <SFML/Audio/SoundBuffer.hpp> #include <SFML/Audio/SoundBuffer.hpp>
#include <SFML/System/Err.hpp> #include <SFML/System/Err.hpp>
#include <SFML/System/Time.hpp>
#include <exception> #include <exception>
#include <ostream> #include <ostream>
#include <utility> #include <utility>
#if defined(__APPLE__)
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
namespace sf namespace sf
{ {
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
SoundBuffer::SoundBuffer() SoundBuffer::SoundBuffer(const SoundBuffer& copy)
{ {
// Create the buffer // don't copy the attached sounds
alCheck(alGenBuffers(1, &m_buffer)); m_samples = copy.m_samples;
} m_duration = copy.m_duration;
////////////////////////////////////////////////////////////
SoundBuffer::SoundBuffer(const SoundBuffer& copy) : m_samples(copy.m_samples), m_duration(copy.m_duration)
// don't copy the attached sounds
{
// Create the buffer
alCheck(alGenBuffers(1, &m_buffer));
// Update the internal buffer with the new samples // Update the internal buffer with the new samples
if (!update(copy.getChannelCount(), copy.getSampleRate())) if (!update(copy.getChannelCount(), copy.getSampleRate(), copy.getChannelMap()))
err() << "Failed to update copy-constructed sound buffer" << std::endl; err() << "Failed to update copy-constructed sound buffer" << std::endl;
} }
@ -69,16 +55,15 @@ SoundBuffer::SoundBuffer(const SoundBuffer& copy) : m_samples(copy.m_samples), m
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
SoundBuffer::~SoundBuffer() SoundBuffer::~SoundBuffer()
{ {
// Make sure no sound is attached to this buffer // To prevent the iterator from becoming invalid, move the entire buffer to another
if (!m_sounds.empty()) // container. Otherwise calling resetBuffer would result in detachSound being
{ // called which removes the sound from the internal list.
err() << "Failed to destruct sound buffer because it is used by " << m_sounds.size() << " sound(s)" << std::endl; SoundList sounds;
std::terminate(); sounds.swap(m_sounds);
}
// Destroy the buffer // Detach the buffer from the sounds that use it
if (m_buffer) for (Sound* soundPtr : sounds)
alCheck(alDeleteBuffers(1, &m_buffer)); soundPtr->detachBuffer();
} }
@ -119,15 +104,16 @@ bool SoundBuffer::loadFromStream(InputStream& stream)
bool SoundBuffer::loadFromSamples(const std::int16_t* samples, bool SoundBuffer::loadFromSamples(const std::int16_t* samples,
std::uint64_t sampleCount, std::uint64_t sampleCount,
unsigned int channelCount, unsigned int channelCount,
unsigned int sampleRate) unsigned int sampleRate,
const std::vector<SoundChannel>& channelMap)
{ {
if (samples && sampleCount && channelCount && sampleRate) if (samples && sampleCount && channelCount && sampleRate && !channelMap.empty())
{ {
// Copy the new audio samples // Copy the new audio samples
m_samples.assign(samples, samples + sampleCount); m_samples.assign(samples, samples + sampleCount);
// Update the internal buffer with the new samples // Update the internal buffer with the new samples
return update(channelCount, sampleRate); return update(channelCount, sampleRate, channelMap);
} }
else else
{ {
@ -148,7 +134,7 @@ bool SoundBuffer::saveToFile(const std::filesystem::path& filename) const
{ {
// Create the sound file in write mode // Create the sound file in write mode
OutputSoundFile file; OutputSoundFile file;
if (file.openFromFile(filename, getSampleRate(), getChannelCount())) if (file.openFromFile(filename, getSampleRate(), getChannelCount(), getChannelMap()))
{ {
// Write the samples to the opened file // Write the samples to the opened file
file.write(m_samples.data(), m_samples.size()); file.write(m_samples.data(), m_samples.size());
@ -179,20 +165,21 @@ std::uint64_t SoundBuffer::getSampleCount() const
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
unsigned int SoundBuffer::getSampleRate() const unsigned int SoundBuffer::getSampleRate() const
{ {
ALint sampleRate; return m_sampleRate;
alCheck(alGetBufferi(m_buffer, AL_FREQUENCY, &sampleRate));
return static_cast<unsigned int>(sampleRate);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
unsigned int SoundBuffer::getChannelCount() const unsigned int SoundBuffer::getChannelCount() const
{ {
ALint channelCount; return static_cast<unsigned int>(m_channelMap.size());
alCheck(alGetBufferi(m_buffer, AL_CHANNELS, &channelCount)); }
return static_cast<unsigned int>(channelCount);
////////////////////////////////////////////////////////////
std::vector<SoundChannel> SoundBuffer::getChannelMap() const
{
return m_channelMap;
} }
@ -209,15 +196,10 @@ SoundBuffer& SoundBuffer::operator=(const SoundBuffer& right)
SoundBuffer temp(right); SoundBuffer temp(right);
std::swap(m_samples, temp.m_samples); std::swap(m_samples, temp.m_samples);
std::swap(m_buffer, temp.m_buffer); std::swap(m_sampleRate, temp.m_sampleRate);
std::swap(m_channelMap, temp.m_channelMap);
std::swap(m_duration, temp.m_duration); std::swap(m_duration, temp.m_duration);
std::swap(m_sounds, temp.m_sounds); // swap sounds too, so that they are detached when temp is destroyed
// Reattach sounds that use this buffer so they get bound to the new OpenAL buffer
for (Sound* soundPtr : m_sounds)
{
soundPtr->stop();
soundPtr->reattachBuffer();
}
return *this; return *this;
} }
@ -228,15 +210,13 @@ bool SoundBuffer::initialize(InputSoundFile& file)
{ {
// Retrieve the sound parameters // Retrieve the sound parameters
const std::uint64_t sampleCount = file.getSampleCount(); const std::uint64_t sampleCount = file.getSampleCount();
const unsigned int channelCount = file.getChannelCount();
const unsigned int sampleRate = file.getSampleRate();
// Read the samples from the provided file // Read the samples from the provided file
m_samples.resize(static_cast<std::size_t>(sampleCount)); m_samples.resize(static_cast<std::size_t>(sampleCount));
if (file.read(m_samples.data(), sampleCount) == sampleCount) if (file.read(m_samples.data(), sampleCount) == sampleCount)
{ {
// Update the internal buffer with the new samples // Update the internal buffer with the new samples
return update(channelCount, sampleRate); return update(file.getChannelCount(), file.getSampleRate(), file.getChannelMap());
} }
else else
{ {
@ -246,37 +226,29 @@ bool SoundBuffer::initialize(InputSoundFile& file)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool SoundBuffer::update(unsigned int channelCount, unsigned int sampleRate) bool SoundBuffer::update(unsigned int channelCount, unsigned int sampleRate, const std::vector<SoundChannel>& channelMap)
{ {
// Check parameters // Check parameters
if (!channelCount || !sampleRate || m_samples.empty()) if (!channelCount || !sampleRate || (channelMap.size() != channelCount))
return false; return false;
// Find the good format according to the number of channels m_sampleRate = sampleRate;
const ALenum format = priv::AudioDevice::getFormatFromChannelCount(channelCount); m_channelMap = channelMap;
// Check if the format is valid // First make a copy of the list of sounds so we can reattach later
if (format == 0) const SoundList sounds(m_sounds);
{
err() << "Failed to load sound buffer (unsupported number of channels: " << channelCount << ")" << std::endl;
return false;
}
// Detach the buffer from the sounds that use it (to avoid OpenAL errors) // Detach the buffer from the sounds that use it
for (Sound* soundPtr : m_sounds) for (Sound* soundPtr : sounds)
soundPtr->detachBuffer(); soundPtr->detachBuffer();
// Fill the buffer
const auto size = static_cast<ALsizei>(m_samples.size() * sizeof(std::int16_t));
alCheck(alBufferData(m_buffer, format, m_samples.data(), size, static_cast<ALsizei>(sampleRate)));
// Compute the duration // Compute the duration
m_duration = seconds( m_duration = seconds(
static_cast<float>(m_samples.size()) / static_cast<float>(sampleRate) / static_cast<float>(channelCount)); static_cast<float>(m_samples.size()) / static_cast<float>(sampleRate) / static_cast<float>(channelCount));
// Now reattach the buffer to the sounds that use it // Now reattach the buffer to the sounds that use it
for (Sound* soundPtr : m_sounds) for (Sound* soundPtr : sounds)
soundPtr->reattachBuffer(); soundPtr->setBuffer(*this);
return true; return true;
} }

View File

@ -69,7 +69,7 @@ void SoundBufferRecorder::onStop()
if (m_samples.empty()) if (m_samples.empty())
return; return;
if (!m_buffer.loadFromSamples(m_samples.data(), m_samples.size(), getChannelCount(), getSampleRate())) if (!m_buffer.loadFromSamples(m_samples.data(), m_samples.size(), getChannelCount(), getSampleRate(), getChannelMap()))
err() << "Failed to stop capturing audio data" << std::endl; err() << "Failed to stop capturing audio data" << std::endl;
} }

View File

@ -175,6 +175,69 @@ void streamMetadata(const FLAC__StreamDecoder*, const FLAC__StreamMetadata* meta
data->info.sampleCount = meta->data.stream_info.total_samples * meta->data.stream_info.channels; data->info.sampleCount = meta->data.stream_info.total_samples * meta->data.stream_info.channels;
data->info.sampleRate = meta->data.stream_info.sample_rate; data->info.sampleRate = meta->data.stream_info.sample_rate;
data->info.channelCount = meta->data.stream_info.channels; data->info.channelCount = meta->data.stream_info.channels;
// For FLAC channel mapping refer to: https://xiph.org/flac/format.html#frame_header
switch (data->info.channelCount)
{
case 0:
sf::err() << "No channels in FLAC file" << std::endl;
break;
case 1:
data->info.channelMap = {sf::SoundChannel::Mono};
break;
case 2:
data->info.channelMap = {sf::SoundChannel::FrontLeft, sf::SoundChannel::FrontRight};
break;
case 3:
data->info.channelMap = {sf::SoundChannel::FrontLeft,
sf::SoundChannel::FrontRight,
sf::SoundChannel::FrontCenter};
break;
case 4:
data->info.channelMap = {sf::SoundChannel::FrontLeft,
sf::SoundChannel::FrontRight,
sf::SoundChannel::BackLeft,
sf::SoundChannel::BackRight};
break;
case 5:
data->info.channelMap = {sf::SoundChannel::FrontLeft,
sf::SoundChannel::FrontRight,
sf::SoundChannel::FrontCenter,
sf::SoundChannel::BackLeft,
sf::SoundChannel::BackRight};
break;
case 6:
data->info.channelMap = {sf::SoundChannel::FrontLeft,
sf::SoundChannel::FrontRight,
sf::SoundChannel::FrontCenter,
sf::SoundChannel::LowFrequencyEffects,
sf::SoundChannel::BackLeft,
sf::SoundChannel::BackRight};
break;
case 7:
data->info.channelMap = {sf::SoundChannel::FrontLeft,
sf::SoundChannel::FrontRight,
sf::SoundChannel::FrontCenter,
sf::SoundChannel::LowFrequencyEffects,
sf::SoundChannel::BackCenter,
sf::SoundChannel::SideLeft,
sf::SoundChannel::SideRight};
break;
case 8:
data->info.channelMap = {sf::SoundChannel::FrontLeft,
sf::SoundChannel::FrontRight,
sf::SoundChannel::FrontCenter,
sf::SoundChannel::LowFrequencyEffects,
sf::SoundChannel::BackLeft,
sf::SoundChannel::BackRight,
sf::SoundChannel::SideLeft,
sf::SoundChannel::SideRight};
break;
default:
sf::err() << "FLAC files with more than 8 channels not supported" << std::endl;
assert(false);
break;
}
} }
} }

View File

@ -52,10 +52,13 @@
#include <SFML/Audio/SoundFileReaderMp3.hpp> #include <SFML/Audio/SoundFileReaderMp3.hpp>
#include <SFML/System/Err.hpp>
#include <SFML/System/InputStream.hpp> #include <SFML/System/InputStream.hpp>
#include <algorithm> #include <algorithm>
#include <ostream>
#include <cassert>
#include <cstdint> #include <cstdint>
#include <cstring> #include <cstring>
@ -135,6 +138,24 @@ std::optional<SoundFileReader::Info> SoundFileReaderMp3::open(InputStream& strea
info.sampleRate = static_cast<unsigned int>(m_decoder.info.hz); info.sampleRate = static_cast<unsigned int>(m_decoder.info.hz);
info.sampleCount = m_decoder.samples; info.sampleCount = m_decoder.samples;
// MP3 only supports mono/stereo channels
switch (info.channelCount)
{
case 0:
sf::err() << "No channels in MP3 file" << std::endl;
break;
case 1:
info.channelMap = {sf::SoundChannel::Mono};
break;
case 2:
info.channelMap = {sf::SoundChannel::SideLeft, sf::SoundChannel::SideRight};
break;
default:
sf::err() << "MP3 files with more than 2 channels not supported" << std::endl;
assert(false);
break;
}
m_numSamples = info.sampleCount; m_numSamples = info.sampleCount;
return info; return info;
} }

View File

@ -112,6 +112,64 @@ std::optional<SoundFileReader::Info> SoundFileReaderOgg::open(InputStream& strea
info.sampleRate = static_cast<unsigned int>(vorbisInfo->rate); info.sampleRate = static_cast<unsigned int>(vorbisInfo->rate);
info.sampleCount = static_cast<std::size_t>(ov_pcm_total(&m_vorbis, -1) * vorbisInfo->channels); info.sampleCount = static_cast<std::size_t>(ov_pcm_total(&m_vorbis, -1) * vorbisInfo->channels);
// For Vorbis channel mapping refer to: https://xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-810004.3.9
switch (info.channelCount)
{
case 0:
err() << "No channels in Vorbis file" << std::endl;
break;
case 1:
info.channelMap = {SoundChannel::Mono};
break;
case 2:
info.channelMap = {SoundChannel::FrontLeft, SoundChannel::FrontRight};
break;
case 3:
info.channelMap = {SoundChannel::FrontLeft, SoundChannel::FrontCenter, SoundChannel::FrontRight};
break;
case 4:
info.channelMap = {SoundChannel::FrontLeft, SoundChannel::FrontRight, SoundChannel::BackLeft, SoundChannel::BackRight};
break;
case 5:
info.channelMap = {SoundChannel::FrontLeft,
SoundChannel::FrontCenter,
SoundChannel::FrontRight,
SoundChannel::BackLeft,
SoundChannel::BackRight};
break;
case 6:
info.channelMap = {SoundChannel::FrontLeft,
SoundChannel::FrontCenter,
SoundChannel::FrontRight,
SoundChannel::BackLeft,
SoundChannel::BackRight,
SoundChannel::LowFrequencyEffects};
break;
case 7:
info.channelMap = {SoundChannel::FrontLeft,
SoundChannel::FrontCenter,
SoundChannel::FrontRight,
SoundChannel::SideLeft,
SoundChannel::SideRight,
SoundChannel::BackCenter,
SoundChannel::LowFrequencyEffects};
break;
case 8:
info.channelMap = {SoundChannel::FrontLeft,
SoundChannel::FrontCenter,
SoundChannel::FrontRight,
SoundChannel::SideLeft,
SoundChannel::SideRight,
SoundChannel::BackLeft,
SoundChannel::BackRight,
SoundChannel::LowFrequencyEffects};
break;
default:
err() << "Vorbis files with more than 8 channels not supported" << std::endl;
assert(false);
break;
}
// We must keep the channel count for the seek function // We must keep the channel count for the seek function
m_channelCount = info.channelCount; m_channelCount = info.channelCount;

View File

@ -122,7 +122,7 @@ std::optional<SoundFileReader::Info> SoundFileReaderWav::open(InputStream& strea
{ {
m_stream = &stream; m_stream = &stream;
const auto info = parseHeader(); auto info = parseHeader();
if (!info) if (!info)
err() << "Failed to open WAV sound file (invalid or unsupported file)" << std::endl; err() << "Failed to open WAV sound file (invalid or unsupported file)" << std::endl;
@ -300,6 +300,63 @@ std::optional<SoundFileReader::Info> SoundFileReaderWav::parseHeader()
if (!decode(*m_stream, channelMask)) if (!decode(*m_stream, channelMask))
return std::nullopt; return std::nullopt;
// NOLINTBEGIN(readability-identifier-naming)
// For WAVE channel mapping refer to: https://learn.microsoft.com/en-us/previous-versions/windows/hardware/design/dn653308(v=vs.85)#default-channel-ordering
static constexpr auto SPEAKER_FRONT_LEFT = 0x1u;
static constexpr auto SPEAKER_FRONT_RIGHT = 0x2u;
static constexpr auto SPEAKER_FRONT_CENTER = 0x4u;
static constexpr auto SPEAKER_LOW_FREQUENCY = 0x8u;
static constexpr auto SPEAKER_BACK_LEFT = 0x10u;
static constexpr auto SPEAKER_BACK_RIGHT = 0x20u;
static constexpr auto SPEAKER_FRONT_LEFT_OF_CENTER = 0x40u;
static constexpr auto SPEAKER_FRONT_RIGHT_OF_CENTER = 0x80u;
static constexpr auto SPEAKER_BACK_CENTER = 0x100u;
static constexpr auto SPEAKER_SIDE_LEFT = 0x200u;
static constexpr auto SPEAKER_SIDE_RIGHT = 0x400u;
static constexpr auto SPEAKER_TOP_CENTER = 0x800u;
static constexpr auto SPEAKER_TOP_FRONT_LEFT = 0x1000u;
static constexpr auto SPEAKER_TOP_FRONT_CENTER = 0x2000u;
static constexpr auto SPEAKER_TOP_FRONT_RIGHT = 0x4000u;
static constexpr auto SPEAKER_TOP_BACK_LEFT = 0x8000u;
static constexpr auto SPEAKER_TOP_BACK_CENTER = 0x10000u;
static constexpr auto SPEAKER_TOP_BACK_RIGHT = 0x20000u;
// NOLINTEND(readability-identifier-naming)
info.channelMap.clear();
const auto checkChannel = [channelMask, &info](auto bit, auto soundChannel)
{
if ((channelMask & bit) != 0)
info.channelMap.push_back(soundChannel);
};
checkChannel(SPEAKER_FRONT_LEFT, SoundChannel::FrontLeft);
checkChannel(SPEAKER_FRONT_RIGHT, SoundChannel::FrontRight);
checkChannel(SPEAKER_FRONT_CENTER, SoundChannel::FrontCenter);
checkChannel(SPEAKER_LOW_FREQUENCY, SoundChannel::LowFrequencyEffects);
checkChannel(SPEAKER_BACK_LEFT, SoundChannel::BackLeft);
checkChannel(SPEAKER_BACK_RIGHT, SoundChannel::BackRight);
checkChannel(SPEAKER_FRONT_LEFT_OF_CENTER, SoundChannel::FrontLeftOfCenter);
checkChannel(SPEAKER_FRONT_RIGHT_OF_CENTER, SoundChannel::FrontRightOfCenter);
checkChannel(SPEAKER_BACK_CENTER, SoundChannel::BackCenter);
checkChannel(SPEAKER_SIDE_LEFT, SoundChannel::SideLeft);
checkChannel(SPEAKER_SIDE_RIGHT, SoundChannel::SideRight);
checkChannel(SPEAKER_TOP_CENTER, SoundChannel::TopCenter);
checkChannel(SPEAKER_TOP_FRONT_LEFT, SoundChannel::TopFrontLeft);
checkChannel(SPEAKER_TOP_FRONT_CENTER, SoundChannel::TopFrontCenter);
checkChannel(SPEAKER_TOP_FRONT_RIGHT, SoundChannel::TopFrontRight);
checkChannel(SPEAKER_TOP_BACK_LEFT, SoundChannel::TopBackLeft);
checkChannel(SPEAKER_TOP_BACK_CENTER, SoundChannel::TopBackCenter);
checkChannel(SPEAKER_TOP_BACK_RIGHT, SoundChannel::TopBackRight);
assert(info.channelCount == info.channelMap.size());
if (info.channelCount != info.channelMap.size())
{
err() << "WAV sound file channel count does not match number of set bits in channel mask" << std::endl;
return std::nullopt;
}
// Subformat // Subformat
char subformat[16]; char subformat[16];
if (static_cast<std::size_t>(m_stream->read(subformat, static_cast<std::int64_t>(sizeof(subformat)))) != if (static_cast<std::size_t>(m_stream->read(subformat, static_cast<std::int64_t>(sizeof(subformat)))) !=
@ -321,6 +378,34 @@ std::optional<SoundFileReader::Info> SoundFileReaderWav::parseHeader()
return std::nullopt; return std::nullopt;
} }
} }
else
{
// If we don't have a waveFormatExtensible header, fill the channel map based on a best guess for mono/stereo
info.channelMap.clear();
if (info.channelCount == 0)
{
err() << "WAV sound file channel count 0" << std::endl;
return std::nullopt;
}
else if (info.channelCount == 1)
{
info.channelMap.push_back(SoundChannel::Mono);
}
else if (info.channelCount == 2)
{
info.channelMap.push_back(SoundChannel::FrontLeft);
info.channelMap.push_back(SoundChannel::FrontRight);
}
else
{
info.channelMap.push_back(SoundChannel::FrontLeft);
info.channelMap.push_back(SoundChannel::FrontRight);
for (auto i = 2u; i < info.channelCount; ++i)
info.channelMap.push_back(SoundChannel::Unspecified);
}
}
// Skip potential extra information // Skip potential extra information
if (m_stream->seek(subChunkStart + subChunkSize) == -1) if (m_stream->seek(subChunkStart + subChunkSize) == -1)

View File

@ -52,8 +52,82 @@ bool SoundFileWriterFlac::check(const std::filesystem::path& filename)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool SoundFileWriterFlac::open(const std::filesystem::path& filename, unsigned int sampleRate, unsigned int channelCount) bool SoundFileWriterFlac::open(const std::filesystem::path& filename,
unsigned int sampleRate,
unsigned int channelCount,
const std::vector<SoundChannel>& channelMap)
{ {
std::vector<SoundChannel> targetChannelMap;
// For FLAC channel mapping refer to: https://xiph.org/flac/format.html#frame_header
switch (channelCount)
{
case 0:
err() << "No channels to write to FLAC file" << std::endl;
return false;
case 1:
targetChannelMap = {SoundChannel::Mono};
break;
case 2:
targetChannelMap = {SoundChannel::FrontLeft, SoundChannel::FrontRight};
break;
case 3:
targetChannelMap = {SoundChannel::FrontLeft, SoundChannel::FrontRight, SoundChannel::FrontCenter};
break;
case 4:
targetChannelMap = {SoundChannel::FrontLeft, SoundChannel::FrontRight, SoundChannel::BackLeft, SoundChannel::BackRight};
break;
case 5:
targetChannelMap = {SoundChannel::FrontLeft,
SoundChannel::FrontRight,
SoundChannel::FrontCenter,
SoundChannel::BackLeft,
SoundChannel::BackRight};
break;
case 6:
targetChannelMap = {SoundChannel::FrontLeft,
SoundChannel::FrontRight,
SoundChannel::FrontCenter,
SoundChannel::LowFrequencyEffects,
SoundChannel::BackLeft,
SoundChannel::BackRight};
break;
case 7:
targetChannelMap = {SoundChannel::FrontLeft,
SoundChannel::FrontRight,
SoundChannel::FrontCenter,
SoundChannel::LowFrequencyEffects,
SoundChannel::BackCenter,
SoundChannel::SideLeft,
SoundChannel::SideRight};
break;
case 8:
targetChannelMap = {SoundChannel::FrontLeft,
SoundChannel::FrontRight,
SoundChannel::FrontCenter,
SoundChannel::LowFrequencyEffects,
SoundChannel::BackLeft,
SoundChannel::BackRight,
SoundChannel::SideLeft,
SoundChannel::SideRight};
break;
default:
err() << "FLAC files with more than 8 channels not supported" << std::endl;
return false;
}
// Check if the channel map contains channels that we cannot remap to a mapping supported by FLAC
if (!std::is_permutation(channelMap.begin(), channelMap.end(), targetChannelMap.begin()))
{
err() << "Provided channel map cannot be reordered to a channel map supported by FLAC" << std::endl;
return false;
}
// Build the remap rable
for (auto i = 0u; i < channelCount; ++i)
m_remapTable[i] = static_cast<std::size_t>(
std::find(channelMap.begin(), channelMap.end(), targetChannelMap[i]) - channelMap.begin());
// Create the encoder // Create the encoder
m_encoder.reset(FLAC__stream_encoder_new()); m_encoder.reset(FLAC__stream_encoder_new());
if (!m_encoder) if (!m_encoder)
@ -92,8 +166,15 @@ void SoundFileWriterFlac::write(const std::int16_t* samples, std::uint64_t count
// Make sure that we don't process too many samples at once // Make sure that we don't process too many samples at once
const unsigned int frames = std::min(static_cast<unsigned int>(count / m_channelCount), 10000u); const unsigned int frames = std::min(static_cast<unsigned int>(count / m_channelCount), 10000u);
// Convert the samples to 32-bits // Convert the samples to 32-bits and remap the channels
m_samples32.assign(samples, samples + frames * m_channelCount); m_samples32.clear();
m_samples32.reserve(frames * m_channelCount);
for (auto frame = 0u; frame < frames; ++frame)
{
for (auto channel = 0u; channel < m_channelCount; ++channel)
m_samples32.push_back(samples[frame * m_channelCount + m_remapTable[channel]]);
}
// Write them to the FLAC stream // Write them to the FLAC stream
FLAC__stream_encoder_process_interleaved(m_encoder.get(), m_samples32.data(), frames); FLAC__stream_encoder_process_interleaved(m_encoder.get(), m_samples32.data(), frames);

View File

@ -62,11 +62,15 @@ public:
/// \param filename Path of the file to open /// \param filename Path of the file to open
/// \param sampleRate Sample rate of the sound /// \param sampleRate Sample rate of the sound
/// \param channelCount Number of channels of the sound /// \param channelCount Number of channels of the sound
/// \param channelMap Map of position in sample frame to sound channel
/// ///
/// \return True if the file was successfully opened /// \return True if the file was successfully opened
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
[[nodiscard]] bool open(const std::filesystem::path& filename, unsigned int sampleRate, unsigned int channelCount) override; [[nodiscard]] bool open(const std::filesystem::path& filename,
unsigned int sampleRate,
unsigned int channelCount,
const std::vector<SoundChannel>& channelMap) override;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Write audio samples to the open file /// \brief Write audio samples to the open file
@ -87,6 +91,7 @@ private:
}; };
std::unique_ptr<FLAC__StreamEncoder, FlacStreamEncoderDeleter> m_encoder; //!< FLAC stream encoder std::unique_ptr<FLAC__StreamEncoder, FlacStreamEncoderDeleter> m_encoder; //!< FLAC stream encoder
unsigned int m_channelCount{}; //!< Number of channels unsigned int m_channelCount{}; //!< Number of channels
std::size_t m_remapTable[8]{}; //!< Table we use to remap source to target channel order
std::vector<std::int32_t> m_samples32; //!< Conversion buffer std::vector<std::int32_t> m_samples32; //!< Conversion buffer
}; };

View File

@ -54,8 +54,82 @@ SoundFileWriterOgg::~SoundFileWriterOgg()
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool SoundFileWriterOgg::open(const std::filesystem::path& filename, unsigned int sampleRate, unsigned int channelCount) bool SoundFileWriterOgg::open(const std::filesystem::path& filename,
unsigned int sampleRate,
unsigned int channelCount,
const std::vector<SoundChannel>& channelMap)
{ {
std::vector<SoundChannel> targetChannelMap;
// For Vorbis channel mapping refer to: https://xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-810004.3.9
switch (channelCount)
{
case 0:
err() << "No channels to write to Vorbis file" << std::endl;
return false;
case 1:
targetChannelMap = {SoundChannel::Mono};
break;
case 2:
targetChannelMap = {SoundChannel::FrontLeft, SoundChannel::FrontRight};
break;
case 3:
targetChannelMap = {SoundChannel::FrontLeft, SoundChannel::FrontCenter, SoundChannel::FrontRight};
break;
case 4:
targetChannelMap = {SoundChannel::FrontLeft, SoundChannel::FrontRight, SoundChannel::BackLeft, SoundChannel::BackRight};
break;
case 5:
targetChannelMap = {SoundChannel::FrontLeft,
SoundChannel::FrontCenter,
SoundChannel::FrontRight,
SoundChannel::BackLeft,
SoundChannel::BackRight};
break;
case 6:
targetChannelMap = {SoundChannel::FrontLeft,
SoundChannel::FrontCenter,
SoundChannel::FrontRight,
SoundChannel::BackLeft,
SoundChannel::BackRight,
SoundChannel::LowFrequencyEffects};
break;
case 7:
targetChannelMap = {SoundChannel::FrontLeft,
SoundChannel::FrontCenter,
SoundChannel::FrontRight,
SoundChannel::SideLeft,
SoundChannel::SideRight,
SoundChannel::BackCenter,
SoundChannel::LowFrequencyEffects};
break;
case 8:
targetChannelMap = {SoundChannel::FrontLeft,
SoundChannel::FrontCenter,
SoundChannel::FrontRight,
SoundChannel::SideLeft,
SoundChannel::SideRight,
SoundChannel::BackLeft,
SoundChannel::BackRight,
SoundChannel::LowFrequencyEffects};
break;
default:
err() << "Vorbis files with more than 8 channels not supported" << std::endl;
return false;
}
// Check if the channel map contains channels that we cannot remap to a mapping supported by FLAC
if (!std::is_permutation(channelMap.begin(), channelMap.end(), targetChannelMap.begin()))
{
err() << "Provided channel map cannot be reordered to a channel map supported by Vorbis" << std::endl;
return false;
}
// Build the remap table
for (auto i = 0u; i < channelCount; ++i)
m_remapTable[i] = static_cast<std::size_t>(
std::find(channelMap.begin(), channelMap.end(), targetChannelMap[i]) - channelMap.begin());
// Save the channel count // Save the channel count
m_channelCount = channelCount; m_channelCount = channelCount;
@ -135,10 +209,14 @@ void SoundFileWriterOgg::write(const std::int16_t* samples, std::uint64_t count)
float** buffer = vorbis_analysis_buffer(&m_state, bufferSize); float** buffer = vorbis_analysis_buffer(&m_state, bufferSize);
assert(buffer && "Vorbis buffer failed to allocate"); assert(buffer && "Vorbis buffer failed to allocate");
// Write the samples to the buffer, converted to float // Write the samples to the buffer, converted to float and remapped to target channels
for (int i = 0; i < std::min(frameCount, bufferSize); ++i) for (int i = 0; i < std::min(frameCount, bufferSize); ++i)
{
for (unsigned int j = 0; j < m_channelCount; ++j) for (unsigned int j = 0; j < m_channelCount; ++j)
buffer[j][i] = *samples++ / 32767.0f; buffer[j][i] = samples[m_remapTable[j]] / 32767.0f;
samples += m_channelCount;
}
// Tell the library how many samples we've written // Tell the library how many samples we've written
vorbis_analysis_wrote(&m_state, std::min(frameCount, bufferSize)); vorbis_analysis_wrote(&m_state, std::min(frameCount, bufferSize));

View File

@ -68,11 +68,15 @@ public:
/// \param filename Path of the file to open /// \param filename Path of the file to open
/// \param sampleRate Sample rate of the sound /// \param sampleRate Sample rate of the sound
/// \param channelCount Number of channels of the sound /// \param channelCount Number of channels of the sound
/// \param channelMap Map of position in sample frame to sound channel
/// ///
/// \return True if the file was successfully opened /// \return True if the file was successfully opened
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
[[nodiscard]] bool open(const std::filesystem::path& filename, unsigned int sampleRate, unsigned int channelCount) override; [[nodiscard]] bool open(const std::filesystem::path& filename,
unsigned int sampleRate,
unsigned int channelCount,
const std::vector<SoundChannel>& channelMap) override;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Write audio samples to the open file /// \brief Write audio samples to the open file
@ -99,11 +103,12 @@ private:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Member data // Member data
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
unsigned int m_channelCount{}; // channel count of the sound being written unsigned int m_channelCount{}; //!< Channel count of the sound being written
std::ofstream m_file; // output file std::size_t m_remapTable[8]{}; //!< Table we use to remap source to target channel order
ogg_stream_state m_ogg{}; // ogg stream std::ofstream m_file; //!< Output file
vorbis_info m_vorbis{}; // vorbis handle ogg_stream_state m_ogg{}; //!< OGG stream
vorbis_dsp_state m_state{}; // current encoding state vorbis_info m_vorbis{}; //!< Vorbis handle
vorbis_dsp_state m_state{}; //!< Current encoding state
}; };
} // namespace sf::priv } // namespace sf::priv

View File

@ -30,10 +30,12 @@
#include <SFML/System/Err.hpp> #include <SFML/System/Err.hpp>
#include <SFML/System/Utils.hpp> #include <SFML/System/Utils.hpp>
#include <algorithm>
#include <ostream> #include <ostream>
#include <cassert> #include <cassert>
#include <cstddef> #include <cstddef>
#include <cstdint>
namespace namespace
@ -82,8 +84,128 @@ SoundFileWriterWav::~SoundFileWriterWav()
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool SoundFileWriterWav::open(const std::filesystem::path& filename, unsigned int sampleRate, unsigned int channelCount) bool SoundFileWriterWav::open(const std::filesystem::path& filename,
unsigned int sampleRate,
unsigned int channelCount,
const std::vector<SoundChannel>& channelMap)
{ {
auto channelMask = 0u;
if (channelCount == 0)
{
err() << "WAV sound file channel count 0" << std::endl;
return false;
}
else if (channelCount == 1)
{
m_remapTable[0] = 0;
}
else if (channelCount == 2)
{
m_remapTable[0] = 0;
m_remapTable[1] = 1;
}
else
{
// NOLINTBEGIN(readability-identifier-naming)
// For WAVE channel mapping refer to: https://learn.microsoft.com/en-us/previous-versions/windows/hardware/design/dn653308(v=vs.85)#default-channel-ordering
static constexpr auto SPEAKER_FRONT_LEFT = 0x1u;
static constexpr auto SPEAKER_FRONT_RIGHT = 0x2u;
static constexpr auto SPEAKER_FRONT_CENTER = 0x4u;
static constexpr auto SPEAKER_LOW_FREQUENCY = 0x8u;
static constexpr auto SPEAKER_BACK_LEFT = 0x10u;
static constexpr auto SPEAKER_BACK_RIGHT = 0x20u;
static constexpr auto SPEAKER_FRONT_LEFT_OF_CENTER = 0x40u;
static constexpr auto SPEAKER_FRONT_RIGHT_OF_CENTER = 0x80u;
static constexpr auto SPEAKER_BACK_CENTER = 0x100u;
static constexpr auto SPEAKER_SIDE_LEFT = 0x200u;
static constexpr auto SPEAKER_SIDE_RIGHT = 0x400u;
static constexpr auto SPEAKER_TOP_CENTER = 0x800u;
static constexpr auto SPEAKER_TOP_FRONT_LEFT = 0x1000u;
static constexpr auto SPEAKER_TOP_FRONT_CENTER = 0x2000u;
static constexpr auto SPEAKER_TOP_FRONT_RIGHT = 0x4000u;
static constexpr auto SPEAKER_TOP_BACK_LEFT = 0x8000u;
static constexpr auto SPEAKER_TOP_BACK_CENTER = 0x10000u;
static constexpr auto SPEAKER_TOP_BACK_RIGHT = 0x20000u;
// NOLINTEND(readability-identifier-naming)
struct SupportedChannel
{
std::uint32_t bit;
SoundChannel channel;
};
std::vector<SupportedChannel>
targetChannelMap{{SPEAKER_FRONT_LEFT, SoundChannel::FrontLeft},
{SPEAKER_FRONT_RIGHT, SoundChannel::FrontRight},
{SPEAKER_FRONT_CENTER, SoundChannel::FrontCenter},
{SPEAKER_LOW_FREQUENCY, SoundChannel::LowFrequencyEffects},
{SPEAKER_BACK_LEFT, SoundChannel::BackLeft},
{SPEAKER_BACK_RIGHT, SoundChannel::BackRight},
{SPEAKER_FRONT_LEFT_OF_CENTER, SoundChannel::FrontLeftOfCenter},
{SPEAKER_FRONT_RIGHT_OF_CENTER, SoundChannel::FrontRightOfCenter},
{SPEAKER_BACK_CENTER, SoundChannel::BackCenter},
{SPEAKER_SIDE_LEFT, SoundChannel::SideLeft},
{SPEAKER_SIDE_RIGHT, SoundChannel::SideRight},
{SPEAKER_TOP_CENTER, SoundChannel::TopCenter},
{SPEAKER_TOP_FRONT_LEFT, SoundChannel::TopFrontLeft},
{SPEAKER_TOP_FRONT_CENTER, SoundChannel::TopFrontCenter},
{SPEAKER_TOP_FRONT_RIGHT, SoundChannel::TopFrontRight},
{SPEAKER_TOP_BACK_LEFT, SoundChannel::TopBackLeft},
{SPEAKER_TOP_BACK_CENTER, SoundChannel::TopBackCenter},
{SPEAKER_TOP_BACK_RIGHT, SoundChannel::TopBackRight}};
// Check for duplicate channel entries
{
auto sortedChannelMap = channelMap;
std::sort(sortedChannelMap.begin(), sortedChannelMap.end());
if (std::adjacent_find(sortedChannelMap.begin(), sortedChannelMap.end()) != sortedChannelMap.end())
{
err() << "Duplicate channels in channel map" << std::endl;
return false;
}
}
// Construct the target channel map by removing unused channels
for (auto iter = targetChannelMap.begin(); iter != targetChannelMap.end();)
{
if (std::find(channelMap.begin(), channelMap.end(), iter->channel) == channelMap.end())
{
iter = targetChannelMap.erase(iter);
}
else
{
++iter;
}
}
// Verify that all the input channels exist in the target channel map
for (const SoundChannel channel : channelMap)
{
if (std::find_if(targetChannelMap.begin(),
targetChannelMap.end(),
[channel](const SupportedChannel& c) { return c.channel == channel; }) ==
targetChannelMap.end())
{
err() << "Could not map all input channels to a channel supported by WAV" << std::endl;
return false;
}
}
// Build the remap table
for (auto i = 0u; i < channelCount; ++i)
m_remapTable[i] = static_cast<std::size_t>(
std::find(channelMap.begin(), channelMap.end(), targetChannelMap[i].channel) - channelMap.begin());
// Generate the channel mask
for (const auto& channel : targetChannelMap)
channelMask |= channel.bit;
}
// Save the channel count
m_channelCount = channelCount;
// Open the file // Open the file
m_file.open(filename, std::ios::binary); m_file.open(filename, std::ios::binary);
if (!m_file) if (!m_file)
@ -93,7 +215,7 @@ bool SoundFileWriterWav::open(const std::filesystem::path& filename, unsigned in
} }
// Write the header // Write the header
writeHeader(sampleRate, channelCount); writeHeader(sampleRate, channelCount, channelMask);
return true; return true;
} }
@ -103,14 +225,24 @@ bool SoundFileWriterWav::open(const std::filesystem::path& filename, unsigned in
void SoundFileWriterWav::write(const std::int16_t* samples, std::uint64_t count) void SoundFileWriterWav::write(const std::int16_t* samples, std::uint64_t count)
{ {
assert(m_file.good() && "Most recent I/O operation failed"); assert(m_file.good() && "Most recent I/O operation failed");
assert(count % m_channelCount == 0);
while (count--) if (count % m_channelCount != 0)
encode(m_file, *samples++); err() << "Writing samples to WAV sound file requires writing full frames at a time" << std::endl;
while (count >= m_channelCount)
{
for (auto i = 0u; i < m_channelCount; ++i)
encode(m_file, samples[m_remapTable[i]]);
samples += m_channelCount;
count -= m_channelCount;
}
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void SoundFileWriterWav::writeHeader(unsigned int sampleRate, unsigned int channelCount) void SoundFileWriterWav::writeHeader(unsigned int sampleRate, unsigned int channelCount, unsigned int channelMask)
{ {
assert(m_file.good() && "Most recent I/O operation failed"); assert(m_file.good() && "Most recent I/O operation failed");
@ -126,12 +258,25 @@ void SoundFileWriterWav::writeHeader(unsigned int sampleRate, unsigned int chann
// Write the sub-chunk 1 ("format") id and size // Write the sub-chunk 1 ("format") id and size
char fmtChunkId[4] = {'f', 'm', 't', ' '}; char fmtChunkId[4] = {'f', 'm', 't', ' '};
m_file.write(fmtChunkId, sizeof(fmtChunkId)); m_file.write(fmtChunkId, sizeof(fmtChunkId));
if (channelCount > 2)
{
const std::uint32_t fmtChunkSize = 40;
encode(m_file, fmtChunkSize);
// Write the format (Extensible)
const std::uint16_t format = 65534;
encode(m_file, format);
}
else
{
const std::uint32_t fmtChunkSize = 16; const std::uint32_t fmtChunkSize = 16;
encode(m_file, fmtChunkSize); encode(m_file, fmtChunkSize);
// Write the format (PCM) // Write the format (PCM)
const std::uint16_t format = 1; const std::uint16_t format = 1;
encode(m_file, format); encode(m_file, format);
}
// Write the sound attributes // Write the sound attributes
encode(m_file, static_cast<std::uint16_t>(channelCount)); encode(m_file, static_cast<std::uint16_t>(channelCount));
@ -143,6 +288,18 @@ void SoundFileWriterWav::writeHeader(unsigned int sampleRate, unsigned int chann
const std::uint16_t bitsPerSample = 16; const std::uint16_t bitsPerSample = 16;
encode(m_file, bitsPerSample); encode(m_file, bitsPerSample);
if (channelCount > 2)
{
const std::uint16_t extensionSize = 16;
encode(m_file, extensionSize);
encode(m_file, bitsPerSample);
encode(m_file, channelMask);
// Write the subformat (PCM)
char subformat[16] =
{'\x01', '\x00', '\x00', '\x00', '\x00', '\x00', '\x10', '\x00', '\x80', '\x00', '\x00', '\xAA', '\x00', '\x38', '\x9B', '\x71'};
m_file.write(subformat, sizeof(subformat));
}
// Write the sub-chunk 2 ("data") id and size // Write the sub-chunk 2 ("data") id and size
char dataChunkId[4] = {'d', 'a', 't', 'a'}; char dataChunkId[4] = {'d', 'a', 't', 'a'};
m_file.write(dataChunkId, sizeof(dataChunkId)); m_file.write(dataChunkId, sizeof(dataChunkId));

View File

@ -66,11 +66,15 @@ public:
/// \param filename Path of the file to open /// \param filename Path of the file to open
/// \param sampleRate Sample rate of the sound /// \param sampleRate Sample rate of the sound
/// \param channelCount Number of channels of the sound /// \param channelCount Number of channels of the sound
/// \param channelMap Map of position in sample frame to sound channel
/// ///
/// \return True if the file was successfully opened /// \return True if the file was successfully opened
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
[[nodiscard]] bool open(const std::filesystem::path& filename, unsigned int sampleRate, unsigned int channelCount) override; [[nodiscard]] bool open(const std::filesystem::path& filename,
unsigned int sampleRate,
unsigned int channelCount,
const std::vector<SoundChannel>& channelMap) override;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Write audio samples to the open file /// \brief Write audio samples to the open file
@ -87,9 +91,10 @@ private:
/// ///
/// \param sampleRate Sample rate of the sound /// \param sampleRate Sample rate of the sound
/// \param channelCount Number of channels of the sound /// \param channelCount Number of channels of the sound
/// \param channelMask Channel mask bits if we are writing extensible header
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void writeHeader(unsigned int sampleRate, unsigned int channelCount); void writeHeader(unsigned int sampleRate, unsigned int channelCount, unsigned int channelMask);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Close the file /// \brief Close the file
@ -101,6 +106,8 @@ private:
// Member data // Member data
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
std::ofstream m_file; //!< File stream to write to std::ofstream m_file; //!< File stream to write to
unsigned int m_channelCount{}; //!< Channel count of the sound being written
std::size_t m_remapTable[18]{}; //!< Table we use to remap source to target channel order
}; };
} // namespace sf::priv } // namespace sf::priv

View File

@ -25,44 +25,206 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Headers // Headers
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Audio/ALCheck.hpp>
#include <SFML/Audio/AudioDevice.hpp>
#include <SFML/Audio/SoundRecorder.hpp> #include <SFML/Audio/SoundRecorder.hpp>
#include <SFML/System/Err.hpp> #include <SFML/System/Err.hpp>
#include <SFML/System/Sleep.hpp> #include <SFML/System/Sleep.hpp>
#include <miniaudio.h>
#include <algorithm>
#include <optional>
#include <ostream> #include <ostream>
#include <cassert> #include <cassert>
#include <cstring> #include <cstring>
#ifdef _MSC_VER
#pragma warning(disable : 4355) // 'this' used in base member initializer list
#endif
#if defined(__APPLE__)
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
namespace
{
ALCdevice* captureDevice = nullptr;
}
namespace sf namespace sf
{ {
struct SoundRecorder::Impl
{
Impl(SoundRecorder* ownerPtr) : owner(ownerPtr)
{
}
bool initialize()
{
if (!context)
return false;
// Find the device by its name
auto devices = getAvailableDevices();
auto iter = std::find_if(devices.begin(),
devices.end(),
[this](const ma_device_info& info) { return info.name == deviceName; });
if (iter == devices.end())
return false;
// (Re-)create the capture device
if (captureDevice)
{
ma_device_uninit(&*captureDevice);
}
else
{
captureDevice.emplace();
}
auto captureDeviceConfig = ma_device_config_init(ma_device_type_capture);
captureDeviceConfig.capture.pDeviceID = &iter->id;
captureDeviceConfig.capture.channels = channelCount;
captureDeviceConfig.capture.format = ma_format_s16;
captureDeviceConfig.sampleRate = sampleRate;
captureDeviceConfig.pUserData = this;
captureDeviceConfig.dataCallback = [](ma_device* device, void*, const void* input, ma_uint32 frameCount)
{
auto& impl = *static_cast<Impl*>(device->pUserData);
// Copy the new samples into our temporary buffer
impl.samples.resize(frameCount * impl.channelCount);
std::memcpy(impl.samples.data(), input, frameCount * impl.channelCount * sizeof(std::int16_t));
// Notify the derived class of the availability of new samples
if (!impl.owner->onProcessSamples(impl.samples.data(), impl.samples.size()))
{
// If the derived class wants to stop, stop the capture
if (auto result = ma_device_stop(device); result != MA_SUCCESS)
{
err() << "Failed to stop audio capture device: " << ma_result_description(result) << std::endl;
return;
}
}
};
if (auto result = ma_device_init(&*context, &captureDeviceConfig, &*captureDevice); result != MA_SUCCESS)
{
captureDevice.reset();
err() << "Failed to initialize the audio capture device: " << ma_result_description(result) << std::endl;
return false;
}
return true;
}
static std::vector<ma_device_info> getAvailableDevices()
{
std::vector<ma_device_info> deviceList;
// Create the context
ma_context context;
auto contextConfig = ma_context_config_init();
if (auto result = ma_context_init(nullptr, 0, &contextConfig, &context); result != MA_SUCCESS)
{
err() << "Failed to initialize the audio context: " << ma_result_description(result) << std::endl;
return deviceList;
}
// Enumerate the capture devices
ma_device_info* deviceInfos;
ma_uint32 deviceCount;
if (auto result = ma_context_get_devices(&context, nullptr, nullptr, &deviceInfos, &deviceCount);
result != MA_SUCCESS)
{
err() << "Failed to get audio capture devices: " << ma_result_description(result) << std::endl;
ma_context_uninit(&context);
return deviceList;
}
for (auto i = 0u; i < deviceCount; ++i)
deviceList.push_back(deviceInfos[i]);
ma_context_uninit(&context);
return deviceList;
}
////////////////////////////////////////////////////////////
// Member data
////////////////////////////////////////////////////////////
SoundRecorder* const owner; //!< Owning SoundRecorder object
std::optional<ma_log> log; //!< The miniaudio log
std::optional<ma_context> context; //!< The miniaudio context
std::optional<ma_device> captureDevice; //!< The miniaudio capture device
std::string deviceName{getDefaultDevice()}; //!< Name of the audio capture device
unsigned int channelCount{1}; //!< Number of recording channels
unsigned int sampleRate{44100}; //!< Sample rate
std::vector<std::int16_t> samples; //!< Buffer to store captured samples
std::vector<SoundChannel> channelMap{SoundChannel::Mono}; //!< The map of position in sample frame to sound channel
};
////////////////////////////////////////////////////////////
SoundRecorder::SoundRecorder() : m_impl(std::make_unique<Impl>(this))
{
// Create the log
m_impl->log.emplace();
if (auto result = ma_log_init(nullptr, &*m_impl->log); result != MA_SUCCESS)
{
m_impl->log.reset();
err() << "Failed to initialize the audio log: " << ma_result_description(result) << std::endl;
return;
}
// Register our logging callback to output any warning/error messages
if (auto result = ma_log_register_callback(&*m_impl->log,
ma_log_callback_init(
[](void*, ma_uint32 level, const char* message)
{
if (level <= MA_LOG_LEVEL_WARNING)
err() << "miniaudio " << ma_log_level_to_string(level)
<< ": " << message << std::flush;
},
nullptr));
result != MA_SUCCESS)
err() << "Failed to register audio log callback: " << ma_result_description(result) << std::endl;
// Create the context
m_impl->context.emplace();
auto contextConfig = ma_context_config_init();
contextConfig.pLog = &*m_impl->log;
if (auto result = ma_context_init(nullptr, 0, &contextConfig, &*m_impl->context); result != MA_SUCCESS)
{
m_impl->context.reset();
err() << "Failed to initialize the audio context: " << ma_result_description(result) << std::endl;
return;
}
// Create the capture device
m_impl->initialize();
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
SoundRecorder::~SoundRecorder() SoundRecorder::~SoundRecorder()
{ {
// This assertion is triggered if the recording is still running while // This assertion is triggered if the recording is still running while
// the object is destroyed. It ensures that stop() is called in the // the object is destroyed. It ensures that stop() is called in the
// destructor of the derived class, which makes sure that the recording // destructor of the derived class, which makes sure that the capture
// thread finishes before the derived object is destroyed. Otherwise a // device is stopped before the derived object is destroyed. Otherwise a
// "pure virtual method called" exception is triggered. // "pure virtual method called" exception is triggered.
assert(!m_isCapturing && assert(!(m_impl->captureDevice && ma_device_is_started(&*m_impl->captureDevice)) &&
"You must call stop() in the destructor of your derived class, so that the recording thread finishes before " "You must call stop() in the destructor of your derived class, so that the "
"your object is destroyed."); "capture device is stopped before your object is destroyed.");
// Destroy the capture device
if (m_impl->captureDevice)
ma_device_uninit(&*m_impl->captureDevice);
// Destroy the context
if (m_impl->context)
ma_context_uninit(&*m_impl->context);
// Destroy the log
if (m_impl->log)
ma_log_uninit(&*m_impl->log);
} }
@ -78,38 +240,41 @@ bool SoundRecorder::start(unsigned int sampleRate)
return false; return false;
} }
// Store the sample rate and re-initialize if necessary
if (m_impl->sampleRate != sampleRate)
{
m_impl->sampleRate = sampleRate;
if (!m_impl->initialize())
{
err() << "Failed to set audio capture device sample rate to " << sampleRate << std::endl;
return false;
}
}
// Ensure we have a capture device
if (!m_impl->captureDevice)
{
err() << "Trying to start audio capture, but no device available" << std::endl;
return false;
}
// Check that another capture is not already running // Check that another capture is not already running
if (captureDevice) if (ma_device_is_started(&*m_impl->captureDevice))
{ {
err() << "Trying to start audio capture, but another capture is already running" << std::endl; err() << "Trying to start audio capture, but another capture is already running" << std::endl;
return false; return false;
} }
// Determine the recording format
const ALCenum format = (m_channelCount == 1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
// Open the capture device for capturing 16 bits samples
captureDevice = alcCaptureOpenDevice(m_deviceName.c_str(), sampleRate, format, static_cast<ALCsizei>(sampleRate));
if (!captureDevice)
{
err() << "Failed to open the audio capture device with the name: " << m_deviceName << std::endl;
return false;
}
// Clear the array of samples
m_samples.clear();
// Store the sample rate
m_sampleRate = sampleRate;
// Notify derived class // Notify derived class
if (onStart()) if (onStart())
{ {
// Start the capture // Start the capture
alcCaptureStart(captureDevice); if (auto result = ma_device_start(&*m_impl->captureDevice); result != MA_SUCCESS)
{
// Start the capture in a new thread, to avoid blocking the main thread err() << "Failed to start audio capture device: " << ma_result_description(result) << std::endl;
launchCapturingThread(); return false;
}
return true; return true;
} }
@ -121,10 +286,15 @@ bool SoundRecorder::start(unsigned int sampleRate)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void SoundRecorder::stop() void SoundRecorder::stop()
{ {
// Stop the capturing thread if there is one // Stop the capturing device if one is started
if (m_isCapturing) if (m_impl->captureDevice && ma_device_is_started(&*m_impl->captureDevice))
{ {
awaitCapturingThread(); // Stop the capture
if (auto result = ma_device_stop(&*m_impl->captureDevice); result != MA_SUCCESS)
{
err() << "Failed to stop audio capture device: " << ma_result_description(result) << std::endl;
return;
}
// Notify derived class // Notify derived class
onStop(); onStop();
@ -135,24 +305,20 @@ void SoundRecorder::stop()
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
unsigned int SoundRecorder::getSampleRate() const unsigned int SoundRecorder::getSampleRate() const
{ {
return m_sampleRate; return m_impl->sampleRate;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
std::vector<std::string> SoundRecorder::getAvailableDevices() std::vector<std::string> SoundRecorder::getAvailableDevices()
{ {
// Convert the internal miniaudio device list into a name-only list
const auto devices = Impl::getAvailableDevices();
std::vector<std::string> deviceNameList; std::vector<std::string> deviceNameList;
deviceNameList.reserve(devices.size());
const ALchar* deviceList = alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER); for (const auto& device : devices)
if (deviceList) deviceNameList.emplace_back(device.name);
{
while (*deviceList)
{
deviceNameList.emplace_back(deviceList);
deviceList += std::strlen(deviceList) + 1;
}
}
return deviceNameList; return deviceNameList;
} }
@ -161,45 +327,30 @@ std::vector<std::string> SoundRecorder::getAvailableDevices()
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
std::string SoundRecorder::getDefaultDevice() std::string SoundRecorder::getDefaultDevice()
{ {
return alcGetString(nullptr, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER); const auto devices = Impl::getAvailableDevices();
for (const auto& device : devices)
{
if (device.isDefault)
return device.name;
}
return "";
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool SoundRecorder::setDevice(const std::string& name) bool SoundRecorder::setDevice(const std::string& name)
{ {
// Store the device name // Store the device name and re-initialize if necessary
if (name.empty()) if (m_impl->deviceName != name)
m_deviceName = getDefaultDevice();
else
m_deviceName = name;
if (m_isCapturing)
{ {
// Stop the capturing thread m_impl->deviceName = name;
awaitCapturingThread();
// Determine the recording format if (!m_impl->initialize())
const ALCenum format = (m_channelCount == 1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
// Open the requested capture device for capturing 16 bits samples
captureDevice = alcCaptureOpenDevice(m_deviceName.c_str(), m_sampleRate, format, static_cast<ALCsizei>(m_sampleRate));
if (!captureDevice)
{
// Notify derived class
onStop();
err() << "Failed to open the audio capture device with the name: " << m_deviceName << std::endl;
return false; return false;
} }
// Start the capture
alcCaptureStart(captureDevice);
// Start the capture in a new thread, to avoid blocking the main thread
launchCapturingThread();
}
return true; return true;
} }
@ -207,19 +358,14 @@ bool SoundRecorder::setDevice(const std::string& name)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
const std::string& SoundRecorder::getDevice() const const std::string& SoundRecorder::getDevice() const
{ {
return m_deviceName; return m_impl->deviceName;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void SoundRecorder::setChannelCount(unsigned int channelCount) void SoundRecorder::setChannelCount(unsigned int channelCount)
{ {
if (m_isCapturing) // We only bother supporting mono/stereo recording for now
{
err() << "It's not possible to change the channels while recording." << std::endl;
return;
}
if (channelCount < 1 || channelCount > 2) if (channelCount < 1 || channelCount > 2)
{ {
err() << "Unsupported channel count: " << channelCount err() << "Unsupported channel count: " << channelCount
@ -227,29 +373,52 @@ void SoundRecorder::setChannelCount(unsigned int channelCount)
return; return;
} }
m_channelCount = channelCount; // Store the channel count and re-initialize if necessary
if (m_impl->channelCount != channelCount)
{
m_impl->channelCount = channelCount;
m_impl->initialize();
// We only bother supporting mono/stereo recording for now
if (channelCount == 1)
{
m_impl->channelMap = {SoundChannel::Mono};
}
else if (channelCount == 2)
{
m_impl->channelMap = {SoundChannel::FrontLeft, SoundChannel::FrontRight};
}
}
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
unsigned int SoundRecorder::getChannelCount() const unsigned int SoundRecorder::getChannelCount() const
{ {
return m_channelCount; return m_impl->channelCount;
}
////////////////////////////////////////////////////////////
const std::vector<SoundChannel>& SoundRecorder::getChannelMap() const
{
return m_impl->channelMap;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool SoundRecorder::isAvailable() bool SoundRecorder::isAvailable()
{ {
return (priv::AudioDevice::isExtensionSupported("ALC_EXT_CAPTURE") != AL_FALSE) || // Try to open a device for capture to see if recording is available
(priv::AudioDevice::isExtensionSupported("ALC_EXT_capture") != AL_FALSE); // "bug" in macOS 10.5 and 10.6 auto config = ma_device_config_init(ma_device_type_capture);
} ma_device device;
if (ma_device_init(nullptr, &config, &device) != MA_SUCCESS)
return false;
//////////////////////////////////////////////////////////// ma_device_uninit(&device);
void SoundRecorder::setProcessingInterval(Time interval)
{ return true;
m_processingInterval = interval;
} }
@ -267,79 +436,4 @@ void SoundRecorder::onStop()
// Nothing to do // Nothing to do
} }
////////////////////////////////////////////////////////////
void SoundRecorder::record()
{
while (m_isCapturing)
{
// Process available samples
processCapturedSamples();
// Don't bother the CPU while waiting for more captured data
sleep(m_processingInterval);
}
// Capture is finished: clean up everything
cleanup();
}
////////////////////////////////////////////////////////////
void SoundRecorder::processCapturedSamples()
{
// Get the number of samples available
ALCint samplesAvailable;
alcGetIntegerv(captureDevice, ALC_CAPTURE_SAMPLES, 1, &samplesAvailable);
if (samplesAvailable > 0)
{
// Get the recorded samples
m_samples.resize(static_cast<std::size_t>(samplesAvailable) * getChannelCount());
alcCaptureSamples(captureDevice, m_samples.data(), samplesAvailable);
// Forward them to the derived class
if (!onProcessSamples(m_samples.data(), m_samples.size()))
{
// The user wants to stop the capture
m_isCapturing = false;
}
}
}
////////////////////////////////////////////////////////////
void SoundRecorder::cleanup()
{
// Stop the capture
alcCaptureStop(captureDevice);
// Get the samples left in the buffer
processCapturedSamples();
// Close the device
alcCaptureCloseDevice(captureDevice);
captureDevice = nullptr;
}
////////////////////////////////////////////////////////////
void SoundRecorder::launchCapturingThread()
{
m_isCapturing = true;
assert(!m_thread.joinable() && "Capture thread is already running");
m_thread = std::thread(&SoundRecorder::record, this);
}
////////////////////////////////////////////////////////////
void SoundRecorder::awaitCapturingThread()
{
m_isCapturing = false;
if (m_thread.joinable())
m_thread.join();
}
} // namespace sf } // namespace sf

View File

@ -25,186 +25,346 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Headers // Headers
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Audio/ALCheck.hpp>
#include <SFML/Audio/SoundSource.hpp> #include <SFML/Audio/SoundSource.hpp>
#if defined(__APPLE__) #include <miniaudio.h>
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif #include <algorithm>
namespace sf namespace sf
{ {
// NOLINTBEGIN(readability-make-member-function-const) // NOLINTBEGIN(readability-make-member-function-const)
////////////////////////////////////////////////////////////
SoundSource::SoundSource()
{
alCheck(alGenSources(1, &m_source));
alCheck(alSourcei(m_source, AL_BUFFER, 0));
}
////////////////////////////////////////////////////////////
SoundSource::SoundSource(const SoundSource& copy)
{
alCheck(alGenSources(1, &m_source));
alCheck(alSourcei(m_source, AL_BUFFER, 0));
setPitch(copy.getPitch());
setVolume(copy.getVolume());
setPosition(copy.getPosition());
setRelativeToListener(copy.isRelativeToListener());
setMinDistance(copy.getMinDistance());
setAttenuation(copy.getAttenuation());
}
////////////////////////////////////////////////////////////
SoundSource::~SoundSource()
{
alCheck(alSourcei(m_source, AL_BUFFER, 0));
alCheck(alDeleteSources(1, &m_source));
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void SoundSource::setPitch(float pitch) void SoundSource::setPitch(float pitch)
{ {
alCheck(alSourcef(m_source, AL_PITCH, pitch)); if (auto* sound = static_cast<ma_sound*>(getSound()))
ma_sound_set_pitch(sound, pitch);
}
////////////////////////////////////////////////////////////
void SoundSource::setPan(float pan)
{
if (auto* sound = static_cast<ma_sound*>(getSound()))
ma_sound_set_pan(sound, pan);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void SoundSource::setVolume(float volume) void SoundSource::setVolume(float volume)
{ {
alCheck(alSourcef(m_source, AL_GAIN, volume * 0.01f)); if (auto* sound = static_cast<ma_sound*>(getSound()))
ma_sound_set_volume(sound, volume * 0.01f);
}
////////////////////////////////////////////////////////////
void SoundSource::setSpatializationEnabled(bool enabled)
{
if (auto* sound = static_cast<ma_sound*>(getSound()))
ma_sound_set_spatialization_enabled(sound, enabled ? MA_TRUE : MA_FALSE);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void SoundSource::setPosition(const Vector3f& position) void SoundSource::setPosition(const Vector3f& position)
{ {
alCheck(alSource3f(m_source, AL_POSITION, position.x, position.y, position.z)); if (auto* sound = static_cast<ma_sound*>(getSound()))
ma_sound_set_position(sound, position.x, position.y, position.z);
}
////////////////////////////////////////////////////////////
void SoundSource::setDirection(const Vector3f& direction)
{
if (auto* sound = static_cast<ma_sound*>(getSound()))
ma_sound_set_direction(sound, direction.x, direction.y, direction.z);
}
////////////////////////////////////////////////////////////
void SoundSource::setCone(const Cone& cone)
{
if (auto* sound = static_cast<ma_sound*>(getSound()))
ma_sound_set_cone(sound,
std::clamp(cone.innerAngle, sf::degrees(0), sf::degrees(360)).asRadians(),
std::clamp(cone.outerAngle, sf::degrees(0), sf::degrees(360)).asRadians(),
cone.outerGain);
}
////////////////////////////////////////////////////////////
void SoundSource::setVelocity(const Vector3f& velocity)
{
if (auto* sound = static_cast<ma_sound*>(getSound()))
ma_sound_set_velocity(sound, velocity.x, velocity.y, velocity.z);
}
////////////////////////////////////////////////////////////
void SoundSource::setDopplerFactor(float factor)
{
if (auto* sound = static_cast<ma_sound*>(getSound()))
ma_sound_set_doppler_factor(sound, factor);
}
////////////////////////////////////////////////////////////
void SoundSource::setDirectionalAttenuationFactor(float factor)
{
if (auto* sound = static_cast<ma_sound*>(getSound()))
ma_sound_set_directional_attenuation_factor(sound, factor);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void SoundSource::setRelativeToListener(bool relative) void SoundSource::setRelativeToListener(bool relative)
{ {
alCheck(alSourcei(m_source, AL_SOURCE_RELATIVE, relative)); if (auto* sound = static_cast<ma_sound*>(getSound()))
ma_sound_set_positioning(sound, relative ? ma_positioning_relative : ma_positioning_absolute);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void SoundSource::setMinDistance(float distance) void SoundSource::setMinDistance(float distance)
{ {
alCheck(alSourcef(m_source, AL_REFERENCE_DISTANCE, distance)); if (auto* sound = static_cast<ma_sound*>(getSound()))
ma_sound_set_min_distance(sound, distance);
}
////////////////////////////////////////////////////////////
void SoundSource::setMaxDistance(float distance)
{
if (auto* sound = static_cast<ma_sound*>(getSound()))
ma_sound_set_max_distance(sound, distance);
}
////////////////////////////////////////////////////////////
void SoundSource::setMinGain(float gain)
{
if (auto* sound = static_cast<ma_sound*>(getSound()))
ma_sound_set_min_gain(sound, gain);
}
////////////////////////////////////////////////////////////
void SoundSource::setMaxGain(float gain)
{
if (auto* sound = static_cast<ma_sound*>(getSound()))
ma_sound_set_max_gain(sound, gain);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void SoundSource::setAttenuation(float attenuation) void SoundSource::setAttenuation(float attenuation)
{ {
alCheck(alSourcef(m_source, AL_ROLLOFF_FACTOR, attenuation)); if (auto* sound = static_cast<ma_sound*>(getSound()))
ma_sound_set_rolloff(sound, attenuation);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
float SoundSource::getPitch() const float SoundSource::getPitch() const
{ {
ALfloat pitch; if (const auto* sound = static_cast<const ma_sound*>(getSound()))
alCheck(alGetSourcef(m_source, AL_PITCH, &pitch)); return ma_sound_get_pitch(sound);
return pitch; return 0.f;
}
////////////////////////////////////////////////////////////
float SoundSource::getPan() const
{
if (const auto* sound = static_cast<const ma_sound*>(getSound()))
return ma_sound_get_pan(sound);
return 0.f;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
float SoundSource::getVolume() const float SoundSource::getVolume() const
{ {
ALfloat gain; if (const auto* sound = static_cast<const ma_sound*>(getSound()))
alCheck(alGetSourcef(m_source, AL_GAIN, &gain)); return ma_sound_get_volume(sound) * 100.f;
return gain * 100.f; return 0.f;
}
////////////////////////////////////////////////////////////
bool SoundSource::isSpatializationEnabled() const
{
if (const auto* sound = static_cast<const ma_sound*>(getSound()))
return ma_sound_is_spatialization_enabled(sound) == MA_TRUE;
return false;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
Vector3f SoundSource::getPosition() const Vector3f SoundSource::getPosition() const
{ {
Vector3f position; if (const auto* sound = static_cast<const ma_sound*>(getSound()))
alCheck(alGetSource3f(m_source, AL_POSITION, &position.x, &position.y, &position.z)); {
auto position = ma_sound_get_position(sound);
return {position.x, position.y, position.z};
}
return position; return {};
}
////////////////////////////////////////////////////////////
Vector3f SoundSource::getDirection() const
{
if (const auto* sound = static_cast<const ma_sound*>(getSound()))
{
auto direction = ma_sound_get_direction(sound);
return {direction.x, direction.y, direction.z};
}
return {};
}
////////////////////////////////////////////////////////////
SoundSource::Cone SoundSource::getCone() const
{
if (const auto* sound = static_cast<const ma_sound*>(getSound()))
{
float innerAngle = 0.f;
float outerAngle = 0.f;
Cone cone;
ma_sound_get_cone(sound, &innerAngle, &outerAngle, &cone.outerGain);
cone.innerAngle = sf::radians(innerAngle);
cone.outerAngle = sf::radians(outerAngle);
return cone;
}
return Cone{sf::radians(0), sf::radians(0), 0.f};
}
////////////////////////////////////////////////////////////
Vector3f SoundSource::getVelocity() const
{
if (const auto* sound = static_cast<const ma_sound*>(getSound()))
{
auto velocity = ma_sound_get_velocity(sound);
return {velocity.x, velocity.y, velocity.z};
}
return {};
}
////////////////////////////////////////////////////////////
float SoundSource::getDopplerFactor() const
{
if (const auto* sound = static_cast<const ma_sound*>(getSound()))
return ma_sound_get_doppler_factor(sound);
return 0.f;
}
////////////////////////////////////////////////////////////
float SoundSource::getDirectionalAttenuationFactor() const
{
if (const auto* sound = static_cast<const ma_sound*>(getSound()))
return ma_sound_get_directional_attenuation_factor(sound);
return 0.f;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool SoundSource::isRelativeToListener() const bool SoundSource::isRelativeToListener() const
{ {
ALint relative; if (const auto* sound = static_cast<const ma_sound*>(getSound()))
alCheck(alGetSourcei(m_source, AL_SOURCE_RELATIVE, &relative)); return ma_sound_get_positioning(sound) == ma_positioning_relative;
return relative != 0; return false;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
float SoundSource::getMinDistance() const float SoundSource::getMinDistance() const
{ {
ALfloat distance; if (const auto* sound = static_cast<const ma_sound*>(getSound()))
alCheck(alGetSourcef(m_source, AL_REFERENCE_DISTANCE, &distance)); return ma_sound_get_min_distance(sound);
return distance; return 0.f;
}
////////////////////////////////////////////////////////////
float SoundSource::getMaxDistance() const
{
if (const auto* sound = static_cast<const ma_sound*>(getSound()))
return ma_sound_get_max_distance(sound);
return 0.f;
}
////////////////////////////////////////////////////////////
float SoundSource::getMinGain() const
{
if (const auto* sound = static_cast<const ma_sound*>(getSound()))
return ma_sound_get_min_gain(sound);
return 0.f;
}
////////////////////////////////////////////////////////////
float SoundSource::getMaxGain() const
{
if (const auto* sound = static_cast<const ma_sound*>(getSound()))
return ma_sound_get_max_gain(sound);
return 0.f;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
float SoundSource::getAttenuation() const float SoundSource::getAttenuation() const
{ {
ALfloat attenuation; if (const auto* sound = static_cast<const ma_sound*>(getSound()))
alCheck(alGetSourcef(m_source, AL_ROLLOFF_FACTOR, &attenuation)); return ma_sound_get_rolloff(sound);
return attenuation; return 0.f;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
SoundSource& SoundSource::operator=(const SoundSource& right) SoundSource& SoundSource::operator=(const SoundSource& right)
{ {
// Leave m_source untouched -- it's not necessary to destroy and
// recreate the OpenAL sound source, hence no copy-and-swap idiom
// Assign the sound attributes // Assign the sound attributes
setPitch(right.getPitch()); setPitch(right.getPitch());
setPan(right.getPan());
setVolume(right.getVolume()); setVolume(right.getVolume());
setSpatializationEnabled(right.isSpatializationEnabled());
setPosition(right.getPosition()); setPosition(right.getPosition());
setDirection(right.getDirection());
setCone(right.getCone());
setVelocity(right.getVelocity());
setDopplerFactor(right.getDopplerFactor());
setRelativeToListener(right.isRelativeToListener()); setRelativeToListener(right.isRelativeToListener());
setMinDistance(right.getMinDistance()); setMinDistance(right.getMinDistance());
setMaxDistance(right.getMaxDistance());
setMinGain(right.getMinGain());
setMaxGain(right.getMaxGain());
setAttenuation(right.getAttenuation()); setAttenuation(right.getAttenuation());
return *this; return *this;
} }
////////////////////////////////////////////////////////////
SoundSource::Status SoundSource::getStatus() const
{
ALint status;
alCheck(alGetSourcei(m_source, AL_SOURCE_STATE, &status));
switch (status)
{
case AL_INITIAL:
case AL_STOPPED:
return Stopped;
case AL_PAUSED:
return Paused;
case AL_PLAYING:
return Playing;
}
return Stopped;
}
// NOLINTEND(readability-make-member-function-const) // NOLINTEND(readability-make-member-function-const)
} // namespace sf } // namespace sf

View File

@ -25,222 +25,373 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Headers // Headers
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Audio/ALCheck.hpp>
#include <SFML/Audio/AudioDevice.hpp> #include <SFML/Audio/AudioDevice.hpp>
#include <SFML/Audio/MiniaudioUtils.hpp>
#include <SFML/Audio/SoundStream.hpp> #include <SFML/Audio/SoundStream.hpp>
#include <SFML/System/Err.hpp> #include <SFML/System/Err.hpp>
#include <SFML/System/Sleep.hpp> #include <SFML/System/Sleep.hpp>
#include <mutex> #include <miniaudio.h>
#include <algorithm>
#include <ostream> #include <ostream>
#include <vector>
#include <cassert> #include <cassert>
#include <cstring>
#ifdef _MSC_VER
#pragma warning(disable : 4355) // 'this' used in base member initializer list
#endif
#if defined(__APPLE__)
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
namespace sf namespace sf
{ {
//////////////////////////////////////////////////////////// struct SoundStream::Impl
SoundStream::~SoundStream()
{ {
// Stop the sound if it was playing Impl(SoundStream* ownerPtr) : owner(ownerPtr)
{
static constexpr ma_data_source_vtable vtable{read, seek, getFormat, getCursor, getLength, setLooping, /* flags */ 0};
priv::MiniaudioUtils::initializeSound(vtable, dataSourceBase, sound, [this] { initialize(); });
}
// Wait for the thread to join ~Impl()
awaitStreamingThread(); {
ma_sound_uninit(&sound);
ma_data_source_uninit(&dataSourceBase);
}
void initialize()
{
// Initialize the sound
auto* engine = priv::AudioDevice::getEngine();
if (engine == nullptr)
{
err() << "Failed to initialize sound: No engine available" << std::endl;
return;
}
ma_sound_config soundConfig;
soundConfig = ma_sound_config_init();
soundConfig.pDataSource = this;
soundConfig.pEndCallbackUserData = this;
soundConfig.endCallback = [](void* userData, ma_sound* soundPtr)
{
// Seek back to the start of the sound when it finishes playing
auto& impl = *static_cast<Impl*>(userData);
impl.streaming = true;
impl.status = Stopped;
if (const ma_result result = ma_sound_seek_to_pcm_frame(soundPtr, 0); result != MA_SUCCESS)
err() << "Failed to seek sound to frame 0: " << ma_result_description(result) << std::endl;
};
if (const ma_result result = ma_sound_init_ex(engine, &soundConfig, &sound); result != MA_SUCCESS)
{
err() << "Failed to initialize sound: " << ma_result_description(result) << std::endl;
return;
}
// Because we are providing a custom data source, we have to provide the channel map ourselves
if (!channelMap.empty())
{
soundChannelMap.clear();
for (const SoundChannel channel : channelMap)
{
soundChannelMap.push_back(priv::MiniaudioUtils::soundChannelToMiniaudioChannel(channel));
}
sound.engineNode.spatializer.pChannelMapIn = soundChannelMap.data();
}
else
{
sound.engineNode.spatializer.pChannelMapIn = nullptr;
}
}
void reinitialize()
{
priv::MiniaudioUtils::reinitializeSound(sound, [this] { initialize(); });
}
static ma_result read(ma_data_source* dataSource, void* framesOut, ma_uint64 frameCount, ma_uint64* framesRead)
{
auto& impl = *static_cast<Impl*>(dataSource);
auto* owner = impl.owner;
// Try to fill our buffer with new samples if the source is still willing to stream data
if (impl.sampleBuffer.empty() && impl.streaming)
{
Chunk chunk;
impl.streaming = owner->onGetData(chunk);
if (chunk.samples && chunk.sampleCount)
{
impl.sampleBuffer.assign(chunk.samples, chunk.samples + chunk.sampleCount);
impl.sampleBufferCursor = 0;
}
}
// Push the samples to miniaudio
if (!impl.sampleBuffer.empty())
{
// Determine how many frames we can read
*framesRead = std::min<ma_uint64>(frameCount,
(impl.sampleBuffer.size() - impl.sampleBufferCursor) / impl.channelCount);
const auto sampleCount = *framesRead * impl.channelCount;
// Copy the samples to the output
std::memcpy(framesOut,
impl.sampleBuffer.data() + impl.sampleBufferCursor,
static_cast<std::size_t>(sampleCount) * sizeof(impl.sampleBuffer[0]));
impl.sampleBufferCursor += static_cast<std::size_t>(sampleCount);
impl.samplesProcessed += sampleCount;
if (impl.sampleBufferCursor >= impl.sampleBuffer.size())
{
impl.sampleBuffer.clear();
impl.sampleBufferCursor = 0;
// If we are looping and at the end of the loop, set the cursor back to the beginning of the loop
if (!impl.streaming && impl.loop)
{
if (auto seekPositionAfterLoop = owner->onLoop(); seekPositionAfterLoop != NoLoop)
{
impl.streaming = true;
impl.samplesProcessed = static_cast<std::uint64_t>(seekPositionAfterLoop);
}
}
}
}
else
{
*framesRead = 0;
}
return MA_SUCCESS;
}
static ma_result seek(ma_data_source* dataSource, ma_uint64 frameIndex)
{
auto& impl = *static_cast<Impl*>(dataSource);
auto* owner = impl.owner;
impl.streaming = true;
impl.sampleBuffer.clear();
impl.sampleBufferCursor = 0;
impl.samplesProcessed = frameIndex * impl.channelCount;
if (impl.sampleRate != 0)
{
owner->onSeek(seconds(static_cast<float>(frameIndex / impl.sampleRate)));
}
else
{
owner->onSeek(Time::Zero);
}
return MA_SUCCESS;
}
static ma_result getFormat(ma_data_source* dataSource,
ma_format* format,
ma_uint32* channels,
ma_uint32* sampleRate,
ma_channel*,
size_t)
{
const auto& impl = *static_cast<const Impl*>(dataSource);
// If we don't have valid values yet, initialize with defaults so sound creation doesn't fail
*format = ma_format_s16;
*channels = impl.channelCount ? impl.channelCount : 1;
*sampleRate = impl.sampleRate ? impl.sampleRate : 44100;
return MA_SUCCESS;
}
static ma_result getCursor(ma_data_source* dataSource, ma_uint64* cursor)
{
auto& impl = *static_cast<Impl*>(dataSource);
*cursor = impl.channelCount ? impl.samplesProcessed / impl.channelCount : 0;
return MA_SUCCESS;
}
static ma_result getLength(ma_data_source*, ma_uint64* length)
{
*length = 0;
return MA_NOT_IMPLEMENTED;
}
static ma_result setLooping(ma_data_source* dataSource, ma_bool32 looping)
{
static_cast<Impl*>(dataSource)->loop = (looping == MA_TRUE);
return MA_SUCCESS;
}
////////////////////////////////////////////////////////////
// Member data
////////////////////////////////////////////////////////////
ma_data_source_base dataSourceBase{}; //!< The struct that makes this object a miniaudio data source (must be first member)
SoundStream* const owner; //!< Owning SoundStream object
std::vector<ma_channel> soundChannelMap; //!< The map of position in sample frame to sound channel (miniaudio channels)
ma_sound sound{}; //!< The sound
std::vector<std::int16_t> sampleBuffer; //!< Our temporary sample buffer
std::size_t sampleBufferCursor{}; //!< The current read position in the temporary sample buffer
std::uint64_t samplesProcessed{}; //!< Number of samples processed since beginning of the stream
unsigned int channelCount{}; //!< Number of channels (1 = mono, 2 = stereo, ...)
unsigned int sampleRate{}; //!< Frequency (samples / second)
std::vector<SoundChannel> channelMap{}; //!< The map of position in sample frame to sound channel
bool loop{}; //!< Loop flag (true to loop, false to play once)
bool streaming{true}; //!< True if we are still streaming samples from the source
Status status{Stopped}; //!< The status
};
////////////////////////////////////////////////////////////
SoundStream::SoundStream() : m_impl(std::make_unique<Impl>(this))
{
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void SoundStream::initialize(unsigned int channelCount, unsigned int sampleRate) SoundStream::~SoundStream() = default;
////////////////////////////////////////////////////////////
void SoundStream::initialize(unsigned int channelCount, unsigned int sampleRate, const std::vector<SoundChannel>& channelMap)
{ {
m_channelCount = channelCount; m_impl->channelCount = channelCount;
m_sampleRate = sampleRate; m_impl->sampleRate = sampleRate;
m_samplesProcessed = 0; m_impl->channelMap = channelMap;
m_impl->samplesProcessed = 0;
{ m_impl->reinitialize();
const std::lock_guard lock(m_threadMutex);
m_isStreaming = false;
}
// Deduce the format from the number of channels
m_format = priv::AudioDevice::getFormatFromChannelCount(channelCount);
// Check if the format is valid
if (m_format == 0)
{
m_channelCount = 0;
m_sampleRate = 0;
err() << "Unsupported number of channels (" << m_channelCount << ")" << std::endl;
}
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void SoundStream::play() void SoundStream::play()
{ {
// Check if the sound parameters have been set if (m_impl->status == Playing)
if (m_format == 0) setPlayingOffset(Time::Zero);
if (const ma_result result = ma_sound_start(&m_impl->sound); result != MA_SUCCESS)
{ {
err() << "Failed to play audio stream: sound parameters have not been initialized (call initialize() first)" err() << "Failed to start playing sound: " << ma_result_description(result) << std::endl;
<< std::endl;
return;
} }
else
bool isStreaming = false;
Status threadStartState = Stopped;
{ {
const std::lock_guard lock(m_threadMutex); m_impl->status = Playing;
isStreaming = m_isStreaming;
threadStartState = m_threadStartState;
} }
if (isStreaming && (threadStartState == Paused))
{
// If the sound is paused, resume it
const std::lock_guard lock(m_threadMutex);
m_threadStartState = Playing;
alCheck(alSourcePlay(m_source));
return;
}
else if (isStreaming && (threadStartState == Playing))
{
// If the sound is playing, stop it and continue as if it was stopped
stop();
}
else if (!isStreaming && m_thread.joinable())
{
// If the streaming thread reached its end, let it join so it can be restarted.
// Also reset the playing offset at the beginning.
stop();
}
// Start updating the stream in a separate thread to avoid blocking the application
launchStreamingThread(Playing);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void SoundStream::pause() void SoundStream::pause()
{ {
// Handle pause() being called before the thread has started if (const ma_result result = ma_sound_stop(&m_impl->sound); result != MA_SUCCESS)
{ {
const std::lock_guard lock(m_threadMutex); err() << "Failed to stop playing sound: " << ma_result_description(result) << std::endl;
}
if (!m_isStreaming) else
return; {
if (m_impl->status == Playing)
m_threadStartState = Paused; m_impl->status = Paused;
} }
alCheck(alSourcePause(m_source));
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void SoundStream::stop() void SoundStream::stop()
{ {
// Wait for the thread to join if (const ma_result result = ma_sound_stop(&m_impl->sound); result != MA_SUCCESS)
awaitStreamingThread(); {
err() << "Failed to stop playing sound: " << ma_result_description(result) << std::endl;
// Move to the beginning }
onSeek(Time::Zero); else
{
setPlayingOffset(Time::Zero);
m_impl->status = Stopped;
}
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
unsigned int SoundStream::getChannelCount() const unsigned int SoundStream::getChannelCount() const
{ {
return m_channelCount; return m_impl->channelCount;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
unsigned int SoundStream::getSampleRate() const unsigned int SoundStream::getSampleRate() const
{ {
return m_sampleRate; return m_impl->sampleRate;
}
////////////////////////////////////////////////////////////
std::vector<SoundChannel> SoundStream::getChannelMap() const
{
return m_impl->channelMap;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
SoundStream::Status SoundStream::getStatus() const SoundStream::Status SoundStream::getStatus() const
{ {
Status status = SoundSource::getStatus(); return m_impl->status;
// To compensate for the lag between play() and alSourceplay()
if (status == Stopped)
{
const std::lock_guard lock(m_threadMutex);
if (m_isStreaming)
status = m_threadStartState;
}
return status;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void SoundStream::setPlayingOffset(Time timeOffset) void SoundStream::setPlayingOffset(Time timeOffset)
{ {
// Get old playing status if (m_impl->sampleRate == 0)
const Status oldStatus = getStatus();
// Stop the stream
stop();
// Let the derived class update the current position
onSeek(timeOffset);
// Restart streaming
m_samplesProcessed = static_cast<std::uint64_t>(timeOffset.asSeconds() * static_cast<float>(m_sampleRate)) *
m_channelCount;
if (oldStatus == Stopped)
return; return;
launchStreamingThread(oldStatus); if (m_impl->sound.pDataSource == nullptr || m_impl->sound.engineNode.pEngine == nullptr)
return;
const auto frameIndex = priv::MiniaudioUtils::getFrameIndex(m_impl->sound, timeOffset);
m_impl->streaming = true;
m_impl->sampleBuffer.clear();
m_impl->sampleBufferCursor = 0;
m_impl->samplesProcessed = frameIndex * m_impl->channelCount;
onSeek(seconds(static_cast<float>(frameIndex / m_impl->sampleRate)));
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
Time SoundStream::getPlayingOffset() const Time SoundStream::getPlayingOffset() const
{ {
if (m_sampleRate && m_channelCount) if (m_impl->channelCount == 0 || m_impl->sampleRate == 0)
{ return {};
ALfloat secs = 0.f;
alCheck(alGetSourcef(m_source, AL_SEC_OFFSET, &secs));
return seconds(secs + static_cast<float>(m_samplesProcessed) / static_cast<float>(m_sampleRate) / return priv::MiniaudioUtils::getPlayingOffset(m_impl->sound);
static_cast<float>(m_channelCount));
}
else
{
return Time::Zero;
}
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void SoundStream::setLoop(bool loop) void SoundStream::setLoop(bool loop)
{ {
m_loop = loop; ma_sound_set_looping(&m_impl->sound, loop ? MA_TRUE : MA_FALSE);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool SoundStream::getLoop() const bool SoundStream::getLoop() const
{ {
return m_loop; return ma_sound_is_looping(&m_impl->sound) == MA_TRUE;
} }
@ -251,275 +402,11 @@ std::int64_t SoundStream::onLoop()
return 0; return 0;
} }
////////////////////////////////////////////////////////////
void SoundStream::setProcessingInterval(Time interval)
{
m_processingInterval = interval;
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void SoundStream::streamData() void* SoundStream::getSound() const
{ {
bool requestStop = false; return &m_impl->sound;
{
const std::lock_guard lock(m_threadMutex);
// Check if the thread was launched Stopped
if (m_threadStartState == Stopped)
{
m_isStreaming = false;
return;
}
}
// Create the buffers
alCheck(alGenBuffers(BufferCount, m_buffers));
for (std::int64_t& bufferSeek : m_bufferSeeks)
bufferSeek = NoLoop;
// Fill the queue
requestStop = fillQueue();
// Play the sound
alCheck(alSourcePlay(m_source));
{
const std::lock_guard lock(m_threadMutex);
// Check if the thread was launched Paused
if (m_threadStartState == Paused)
alCheck(alSourcePause(m_source));
}
for (;;)
{
{
const std::lock_guard lock(m_threadMutex);
if (!m_isStreaming)
break;
}
// The stream has been interrupted!
if (SoundSource::getStatus() == Stopped)
{
if (!requestStop)
{
// Just continue
alCheck(alSourcePlay(m_source));
}
else
{
// End streaming
const std::lock_guard lock(m_threadMutex);
m_isStreaming = false;
}
}
// Get the number of buffers that have been processed (i.e. ready for reuse)
ALint nbProcessed = 0;
alCheck(alGetSourcei(m_source, AL_BUFFERS_PROCESSED, &nbProcessed));
while (nbProcessed--)
{
// Pop the first unused buffer from the queue
ALuint buffer;
alCheck(alSourceUnqueueBuffers(m_source, 1, &buffer));
// Find its number
unsigned int bufferNum = 0;
for (unsigned int i = 0; i < BufferCount; ++i)
if (m_buffers[i] == buffer)
{
bufferNum = i;
break;
}
// Retrieve its size and add it to the samples count
if (m_bufferSeeks[bufferNum] != NoLoop)
{
// This was the last buffer before EOF or Loop End: reset the sample count
m_samplesProcessed = static_cast<std::uint64_t>(m_bufferSeeks[bufferNum]);
m_bufferSeeks[bufferNum] = NoLoop;
}
else
{
ALint size;
ALint bits;
alCheck(alGetBufferi(buffer, AL_SIZE, &size));
alCheck(alGetBufferi(buffer, AL_BITS, &bits));
// Bits can be 0 if the format or parameters are corrupt, avoid division by zero
if (bits == 0)
{
err() << "Bits in sound stream are 0: make sure that the audio format is not corrupt "
<< "and initialize() has been called correctly" << std::endl;
// Abort streaming (exit main loop)
const std::lock_guard lock(m_threadMutex);
m_isStreaming = false;
requestStop = true;
break;
}
else
{
m_samplesProcessed += static_cast<std::uint64_t>(size / (bits / 8));
}
}
// Fill it and push it back into the playing queue
if (!requestStop)
{
if (fillAndPushBuffer(bufferNum))
requestStop = true;
}
}
// Check if any error has occurred
if (alGetLastError() != AL_NO_ERROR)
{
// Abort streaming (exit main loop)
const std::lock_guard lock(m_threadMutex);
m_isStreaming = false;
break;
}
// Leave some time for the other threads if the stream is still playing
if (SoundSource::getStatus() != Stopped)
sleep(m_processingInterval);
}
// Stop the playback
alCheck(alSourceStop(m_source));
// Dequeue any buffer left in the queue
clearQueue();
// Reset the playing position
m_samplesProcessed = 0;
// Delete the buffers
alCheck(alSourcei(m_source, AL_BUFFER, 0));
alCheck(alDeleteBuffers(BufferCount, m_buffers));
}
////////////////////////////////////////////////////////////
bool SoundStream::fillAndPushBuffer(unsigned int bufferNum, bool immediateLoop)
{
bool requestStop = false;
// Acquire audio data, also address EOF and error cases if they occur
Chunk data = {nullptr, 0};
for (std::uint32_t retryCount = 0; !onGetData(data) && (retryCount < BufferRetries); ++retryCount)
{
// Check if the stream must loop or stop
if (!m_loop)
{
// Not looping: Mark this buffer as ending with 0 and request stop
if (data.samples != nullptr && data.sampleCount != 0)
m_bufferSeeks[bufferNum] = 0;
requestStop = true;
break;
}
// Return to the beginning or loop-start of the stream source using onLoop(), and store the result in the buffer seek array
// This marks the buffer as the "last" one (so that we know where to reset the playing position)
m_bufferSeeks[bufferNum] = onLoop();
// If we got data, break and process it, else try to fill the buffer once again
if (data.samples != nullptr && data.sampleCount != 0)
break;
// If immediateLoop is specified, we have to immediately adjust the sample count
if (immediateLoop && (m_bufferSeeks[bufferNum] != NoLoop))
{
// We just tried to begin preloading at EOF or Loop End: reset the sample count
m_samplesProcessed = static_cast<std::uint64_t>(m_bufferSeeks[bufferNum]);
m_bufferSeeks[bufferNum] = NoLoop;
}
// We're a looping sound that got no data, so we retry onGetData()
}
// Fill the buffer if some data was returned
if (data.samples && data.sampleCount)
{
const unsigned int buffer = m_buffers[bufferNum];
// Fill the buffer
const auto size = static_cast<ALsizei>(data.sampleCount * sizeof(std::int16_t));
alCheck(alBufferData(buffer, m_format, data.samples, size, static_cast<ALsizei>(m_sampleRate)));
// Push it into the sound queue
alCheck(alSourceQueueBuffers(m_source, 1, &buffer));
}
else
{
// If we get here, we most likely ran out of retries
requestStop = true;
}
return requestStop;
}
////////////////////////////////////////////////////////////
bool SoundStream::fillQueue()
{
// Fill and enqueue all the available buffers
bool requestStop = false;
for (unsigned int i = 0; (i < BufferCount) && !requestStop; ++i)
{
// Since no sound has been loaded yet, we can't schedule loop seeks preemptively,
// So if we start on EOF or Loop End, we let fillAndPushBuffer() adjust the sample count
if (fillAndPushBuffer(i, (i == 0)))
requestStop = true;
}
return requestStop;
}
////////////////////////////////////////////////////////////
void SoundStream::clearQueue()
{
// Get the number of buffers still in the queue
ALint nbQueued;
alCheck(alGetSourcei(m_source, AL_BUFFERS_QUEUED, &nbQueued));
// Dequeue them all
ALuint buffer;
for (ALint i = 0; i < nbQueued; ++i)
alCheck(alSourceUnqueueBuffers(m_source, 1, &buffer));
}
////////////////////////////////////////////////////////////
void SoundStream::launchStreamingThread(Status threadStartState)
{
{
const std::lock_guard lock(m_threadMutex);
m_isStreaming = true;
m_threadStartState = threadStartState;
}
assert(!m_thread.joinable() && "Background thread is still running");
m_thread = std::thread(&SoundStream::streamData, this);
}
////////////////////////////////////////////////////////////
void SoundStream::awaitStreamingThread()
{
// Request the thread to join
{
const std::lock_guard lock(m_threadMutex);
m_isStreaming = false;
}
if (m_thread.joinable())
m_thread.join();
} }
} // namespace sf } // namespace sf

View File

@ -7,10 +7,8 @@ if(SFML_OS_WINDOWS)
if(SFML_COMPILER_GCC OR (SFML_COMPILER_CLANG AND MINGW)) if(SFML_COMPILER_GCC OR (SFML_COMPILER_CLANG AND MINGW))
if(ARCH_32BITS) if(ARCH_32BITS)
list(APPEND CMAKE_LIBRARY_PATH "${PROJECT_SOURCE_DIR}/extlibs/libs-mingw/x86") list(APPEND CMAKE_LIBRARY_PATH "${PROJECT_SOURCE_DIR}/extlibs/libs-mingw/x86")
list(APPEND CMAKE_LIBRARY_PATH "${PROJECT_SOURCE_DIR}/extlibs/bin/x86")
elseif(ARCH_64BITS) elseif(ARCH_64BITS)
list(APPEND CMAKE_LIBRARY_PATH "${PROJECT_SOURCE_DIR}/extlibs/libs-mingw/x64") list(APPEND CMAKE_LIBRARY_PATH "${PROJECT_SOURCE_DIR}/extlibs/libs-mingw/x64")
list(APPEND CMAKE_LIBRARY_PATH "${PROJECT_SOURCE_DIR}/extlibs/bin/x64")
endif() endif()
elseif(SFML_COMPILER_MSVC OR (SFML_COMPILER_CLANG AND NOT MINGW)) elseif(SFML_COMPILER_MSVC OR (SFML_COMPILER_CLANG AND NOT MINGW))
if(ARCH_32BITS) if(ARCH_32BITS)

View File

@ -1,9 +0,0 @@
#include <SFML/Audio/AlResource.hpp>
#include <type_traits>
static_assert(!std::is_constructible_v<sf::AlResource>);
static_assert(!std::is_copy_constructible_v<sf::AlResource>);
static_assert(std::is_copy_assignable_v<sf::AlResource>);
static_assert(!std::is_nothrow_move_constructible_v<sf::AlResource>);
static_assert(std::is_nothrow_move_assignable_v<sf::AlResource>);

View File

@ -0,0 +1,9 @@
#include <SFML/Audio/AudioResource.hpp>
#include <type_traits>
static_assert(!std::is_constructible_v<sf::AudioResource>);
static_assert(std::is_copy_constructible_v<sf::AudioResource>);
static_assert(!std::is_copy_assignable_v<sf::AudioResource>);
static_assert(std::is_nothrow_move_constructible_v<sf::AudioResource>);
static_assert(!std::is_nothrow_move_assignable_v<sf::AudioResource>);

View File

@ -1,6 +1,7 @@
#include <SFML/Audio/SoundFileFactory.hpp> #include <SFML/Audio/SoundFileFactory.hpp>
// Other 1st party headers // Other 1st party headers
#include <SFML/Audio/SoundChannel.hpp>
#include <SFML/Audio/SoundFileReader.hpp> #include <SFML/Audio/SoundFileReader.hpp>
#include <SFML/Audio/SoundFileWriter.hpp> #include <SFML/Audio/SoundFileWriter.hpp>
@ -47,7 +48,7 @@ struct NoopSoundFileWriter : sf::SoundFileWriter
return false; return false;
} }
bool open(const std::filesystem::path&, unsigned int, unsigned int) override bool open(const std::filesystem::path&, unsigned int, unsigned int, const std::vector<sf::SoundChannel>&) override
{ {
return false; return false;
} }

View File

@ -130,7 +130,7 @@ set(NETWORK_SRC
sfml_add_test(test-sfml-network "${NETWORK_SRC}" SFML::Network) sfml_add_test(test-sfml-network "${NETWORK_SRC}" SFML::Network)
set(AUDIO_SRC set(AUDIO_SRC
Audio/AlResource.test.cpp Audio/AudioResource.test.cpp
Audio/InputSoundFile.test.cpp Audio/InputSoundFile.test.cpp
Audio/Music.test.cpp Audio/Music.test.cpp
Audio/OutputSoundFile.test.cpp Audio/OutputSoundFile.test.cpp
@ -146,14 +146,6 @@ set(AUDIO_SRC
) )
sfml_add_test(test-sfml-audio "${AUDIO_SRC}" SFML::Audio) sfml_add_test(test-sfml-audio "${AUDIO_SRC}" SFML::Audio)
if(SFML_OS_WINDOWS AND NOT SFML_USE_SYSTEM_DEPS)
add_custom_command(
TARGET test-sfml-audio
COMMENT "Copy OpenAL DLL"
PRE_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/extlibs/bin/$<IF:$<BOOL:${ARCH_64BITS}>,x64,x86>/openal32.dll $<TARGET_FILE_DIR:test-sfml-audio>
VERBATIM)
endif()
if(SFML_ENABLE_COVERAGE AND SFML_OS_WINDOWS AND NOT SFML_COMPILER_GCC) if(SFML_ENABLE_COVERAGE AND SFML_OS_WINDOWS AND NOT SFML_COMPILER_GCC)
# Try to find and use OpenCppCoverage for coverage reporting when building with MSVC # Try to find and use OpenCppCoverage for coverage reporting when building with MSVC
find_program(OpenCppCoverage_BINARY "OpenCppCoverage.exe") find_program(OpenCppCoverage_BINARY "OpenCppCoverage.exe")

View File

@ -51,7 +51,4 @@ rm $DESTDIR/$1/usr/lib/libvorbis*.so*
# Compile freetype # Compile freetype
cd $LOCALDIR/build/freetype-* && sed -i 's/-version-info/-avoid-version/g' builds/unix/unix-cc.in && ./configure $HOST $PREFIX && make && make install cd $LOCALDIR/build/freetype-* && sed -i 's/-version-info/-avoid-version/g' builds/unix/unix-cc.in && ./configure $HOST $PREFIX && make && make install
# Compile OpenAL-Soft
cd $LOCALDIR/build/openal-soft-android-master && cd build && cmake -DCMAKE_TOOLCHAIN_FILE=$ANDROID_CMAKE_TOOLCHAIN -DANDROID_ABI=$ANDROID_ABI -DANDROID_NATIVE_API_LEVEL=android-9 -DANDROID_USE_STLPORT=1 .. && make openal && mv libopenal.so $DESTDIR/$1/usr/lib
export PATH=$OPATH export PATH=$OPATH

View File

@ -39,11 +39,3 @@ if [ ! -d "$PWD/tmp/$FREETYPE" ]
then then
tar -C build -xf src/$FREETYPE.tar.gz tar -C build -xf src/$FREETYPE.tar.gz
fi fi
wget -nc -P src https://github.com/AerialX/openal-soft-android/archive/master.tar.gz
if [ ! -d "$PWD/tmp/openal-soft-android-master" ]
then
tar -C build -xf src/master.tar.gz
fi
patch build/openal-soft-android-master/CMakeLists.txt patches/remove-so-version-suffix.diff

View File

@ -1,13 +0,0 @@
--- CMakeLists.txt.orig 2013-09-21 15:23:49.305453804 +0200
+++ CMakeLists.txt 2013-09-21 15:24:08.621454210 +0200
@@ -717,9 +717,7 @@
# Build a library
ADD_LIBRARY(${LIBNAME} ${LIBTYPE} ${OPENAL_OBJS} ${ALC_OBJS})
SET_TARGET_PROPERTIES(${LIBNAME} PROPERTIES DEFINE_SYMBOL AL_BUILD_LIBRARY
- COMPILE_FLAGS -DAL_ALEXT_PROTOTYPES
- VERSION ${LIB_VERSION}.0
- SOVERSION ${LIB_MAJOR_VERSION})
+ COMPILE_FLAGS -DAL_ALEXT_PROTOTYPES)
IF(WIN32 AND NOT LIBTYPE STREQUAL "STATIC")
SET_TARGET_PROPERTIES(${LIBNAME} PROPERTIES PREFIX "")
ENDIF()

View File

@ -8,8 +8,6 @@ Description: The Simple and Fast Multimedia Library, audio module.
URL: http://www.sfml-dev.org URL: http://www.sfml-dev.org
Version: @PROJECT_VERSION@ Version: @PROJECT_VERSION@
Requires: sfml-system Requires: sfml-system
Requires.private: openal, vorbisenc, vorbisfile, vorbis, ogg, flac Requires.private: vorbisenc, vorbisfile, vorbis, ogg, flac
Libs: -L${libdir} -lsfml-audio Libs: -L${libdir} -lsfml-audio
# openal may be a system framework
Libs.private: @OPENAL_LIBRARY@
Cflags: -I${includedir} Cflags: -I${includedir}

View File

@ -229,8 +229,8 @@ require () # $1 is a SFML module like 'system' or 'audio'
# copy extra dependencies # copy extra dependencies
if [ "$1" = "audio" ] if [ "$1" = "audio" ]
then then
# copy "FLAC" "ogg" "vorbis" "vorbisenc" "vorbisfile" "OpenAL" frameworks too # copy "FLAC" "ogg" "vorbis" "vorbisenc" "vorbisfile" frameworks too
for f in "FLAC" "ogg" "vorbis" "vorbisenc" "vorbisfile" "OpenAL" for f in "FLAC" "ogg" "vorbis" "vorbisenc" "vorbisfile"
do do
copy "$SFML_DEPENDENCIES_INSTALL_PREFIX/$f.framework" "$dest/$f.framework" copy "$SFML_DEPENDENCIES_INSTALL_PREFIX/$f.framework" "$dest/$f.framework"
done done