mirror of
https://github.com/TerryCavanagh/VVVVVV.git
synced 2024-12-22 09:39:43 +01:00
Port to FAudio
This commit is contained in:
parent
a8feba029f
commit
f877eb3b56
7 changed files with 530 additions and 110 deletions
24
.github/workflows/ci.yml
vendored
24
.github/workflows/ci.yml
vendored
|
@ -22,7 +22,7 @@ jobs:
|
||||||
submodules: true
|
submodules: true
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: brew install ninja sdl2 sdl2_mixer
|
run: brew install ninja sdl2
|
||||||
|
|
||||||
- name: CMake configure (default version)
|
- name: CMake configure (default version)
|
||||||
run: |
|
run: |
|
||||||
|
@ -118,7 +118,6 @@ jobs:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
SDL_VERSION: 2.0.20
|
SDL_VERSION: 2.0.20
|
||||||
SDL_MIXER_VERSION: 2.0.4
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v1
|
||||||
|
@ -133,14 +132,6 @@ jobs:
|
||||||
path: C:\SDL
|
path: C:\SDL
|
||||||
key: ${{ runner.os }}-build-${{ env.cache-name }}
|
key: ${{ runner.os }}-build-${{ env.cache-name }}
|
||||||
|
|
||||||
- name: Cache SDL_mixer
|
|
||||||
uses: actions/cache@v2
|
|
||||||
env:
|
|
||||||
cache-name: cache-sdl-mixer
|
|
||||||
with:
|
|
||||||
path: C:\SDL_mixer
|
|
||||||
key: ${{ runner.os }}-build-${{ env.cache-name }}
|
|
||||||
|
|
||||||
- name: Download SDL if not cached
|
- name: Download SDL if not cached
|
||||||
run: |
|
run: |
|
||||||
if (-Not (Test-Path C:\SDL))
|
if (-Not (Test-Path C:\SDL))
|
||||||
|
@ -149,23 +140,14 @@ jobs:
|
||||||
Expand-Archive C:\SDL.zip -DestinationPath C:\
|
Expand-Archive C:\SDL.zip -DestinationPath C:\
|
||||||
}
|
}
|
||||||
|
|
||||||
- name: Download SDL_mixer if not cached
|
|
||||||
run: |
|
|
||||||
if (-Not (Test-Path C:\SDL_mixer))
|
|
||||||
{
|
|
||||||
Invoke-WebRequest "https://www.libsdl.org/projects/SDL_mixer/release/SDL2_mixer-devel-$env:SDL_MIXER_VERSION-VC.zip" -o C:\SDL_mixer.zip
|
|
||||||
Expand-Archive C:\SDL_mixer.zip -DestinationPath C:\
|
|
||||||
}
|
|
||||||
|
|
||||||
- name: CMake configure (default version)
|
- name: CMake configure (default version)
|
||||||
run: |
|
run: |
|
||||||
mkdir $env:SRC_DIR_PATH/build
|
mkdir $env:SRC_DIR_PATH/build
|
||||||
cd $env:SRC_DIR_PATH/build
|
cd $env:SRC_DIR_PATH/build
|
||||||
$env:LDFLAGS = "/LIBPATH:C:\SDL2-$env:SDL_VERSION\lib\x86 "
|
$env:LDFLAGS = "/LIBPATH:C:\SDL2-$env:SDL_VERSION\lib\x86 "
|
||||||
$env:LDFLAGS += "/LIBPATH:C:\SDL2_mixer-$env:SDL_MIXER_VERSION\lib\x86"
|
|
||||||
cmake -G "Visual Studio 17 2022" -A Win32 `
|
cmake -G "Visual Studio 17 2022" -A Win32 `
|
||||||
-DSDL2_INCLUDE_DIRS="C:\SDL2-$env:SDL_VERSION\include;C:\SDL2_mixer-$env:SDL_MIXER_VERSION\include" `
|
-DSDL2_INCLUDE_DIRS="C:\SDL2-$env:SDL_VERSION\include" `
|
||||||
-DSDL2_LIBRARIES="SDL2;SDL2main;SDL2_mixer" ..
|
-DSDL2_LIBRARIES="SDL2;SDL2main" ..
|
||||||
- name: Build (default version)
|
- name: Build (default version)
|
||||||
run: |
|
run: |
|
||||||
cd $env:SRC_DIR_PATH/build
|
cd $env:SRC_DIR_PATH/build
|
||||||
|
|
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -10,3 +10,6 @@
|
||||||
[submodule "third_party/utfcpp"]
|
[submodule "third_party/utfcpp"]
|
||||||
path = third_party/utfcpp
|
path = third_party/utfcpp
|
||||||
url = https://github.com/nemtrif/utfcpp
|
url = https://github.com/nemtrif/utfcpp
|
||||||
|
[submodule "third_party/FAudio"]
|
||||||
|
path = third_party/FAudio
|
||||||
|
url = https://github.com/FNA-XNA/FAudio
|
||||||
|
|
|
@ -135,6 +135,8 @@ if(BUNDLE_DEPENDENCIES)
|
||||||
../third_party/physfs/extras
|
../third_party/physfs/extras
|
||||||
../third_party/lodepng
|
../third_party/lodepng
|
||||||
../third_party/utfcpp/source
|
../third_party/utfcpp/source
|
||||||
|
../third_party/FAudio/include
|
||||||
|
../third_party/FAudio/src
|
||||||
)
|
)
|
||||||
else()
|
else()
|
||||||
target_include_directories(
|
target_include_directories(
|
||||||
|
@ -142,6 +144,7 @@ else()
|
||||||
src
|
src
|
||||||
../third_party/lodepng
|
../third_party/lodepng
|
||||||
../third_party/physfs/extras
|
../third_party/physfs/extras
|
||||||
|
../third_party/FAudio/src
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
@ -159,6 +162,13 @@ endif()
|
||||||
set(XML2_SRC
|
set(XML2_SRC
|
||||||
../third_party/tinyxml2/tinyxml2.cpp
|
../third_party/tinyxml2/tinyxml2.cpp
|
||||||
)
|
)
|
||||||
|
set(FAUDIO_SRC
|
||||||
|
../third_party/FAudio/src/FAudio.c
|
||||||
|
../third_party/FAudio/src/FAudio_internal.c
|
||||||
|
../third_party/FAudio/src/FAudio_internal_simd.c
|
||||||
|
../third_party/FAudio/src/FAudio_operationset.c
|
||||||
|
../third_party/FAudio/src/FAudio_platform_sdl2.c
|
||||||
|
)
|
||||||
set(PFS_SRC
|
set(PFS_SRC
|
||||||
../third_party/physfs/src/physfs.c
|
../third_party/physfs/src/physfs.c
|
||||||
../third_party/physfs/src/physfs_archiver_dir.c
|
../third_party/physfs/src/physfs_archiver_dir.c
|
||||||
|
@ -289,12 +299,17 @@ if(BUNDLE_DEPENDENCIES)
|
||||||
target_compile_definitions(physfs-static PRIVATE
|
target_compile_definitions(physfs-static PRIVATE
|
||||||
-DPHYSFS_SUPPORTS_DEFAULT=0 -DPHYSFS_SUPPORTS_ZIP=1
|
-DPHYSFS_SUPPORTS_DEFAULT=0 -DPHYSFS_SUPPORTS_ZIP=1
|
||||||
)
|
)
|
||||||
|
add_library(faudio-static STATIC ${FAUDIO_SRC})
|
||||||
|
target_include_directories(
|
||||||
|
faudio-static PRIVATE
|
||||||
|
../third_party/FAudio/include
|
||||||
|
)
|
||||||
|
|
||||||
target_link_libraries(VVVVVV physfs-static tinyxml2-static lodepng-static)
|
target_link_libraries(VVVVVV physfs-static tinyxml2-static lodepng-static faudio-static)
|
||||||
else()
|
else()
|
||||||
find_package(utf8cpp CONFIG)
|
find_package(utf8cpp CONFIG)
|
||||||
|
|
||||||
target_link_libraries(VVVVVV physfs tinyxml2 utf8cpp lodepng-static)
|
target_link_libraries(VVVVVV physfs tinyxml2 utf8cpp lodepng-static FAudio)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# SDL2 Dependency (Detection pulled from FAudio)
|
# SDL2 Dependency (Detection pulled from FAudio)
|
||||||
|
@ -302,24 +317,41 @@ if(DEFINED SDL2_INCLUDE_DIRS AND DEFINED SDL2_LIBRARIES)
|
||||||
message(STATUS "Using pre-defined SDL2 variables SDL2_INCLUDE_DIRS and SDL2_LIBRARIES")
|
message(STATUS "Using pre-defined SDL2 variables SDL2_INCLUDE_DIRS and SDL2_LIBRARIES")
|
||||||
target_include_directories(VVVVVV SYSTEM PRIVATE "$<BUILD_INTERFACE:${SDL2_INCLUDE_DIRS}>")
|
target_include_directories(VVVVVV SYSTEM PRIVATE "$<BUILD_INTERFACE:${SDL2_INCLUDE_DIRS}>")
|
||||||
target_link_libraries(VVVVVV ${SDL2_LIBRARIES})
|
target_link_libraries(VVVVVV ${SDL2_LIBRARIES})
|
||||||
|
if(BUNDLE_DEPENDENCIES)
|
||||||
|
target_include_directories(faudio-static SYSTEM PRIVATE "$<BUILD_INTERFACE:${SDL2_INCLUDE_DIRS}>")
|
||||||
|
target_link_libraries(faudio-static ${SDL2_LIBRARIES})
|
||||||
|
endif()
|
||||||
elseif (EMSCRIPTEN)
|
elseif (EMSCRIPTEN)
|
||||||
message(STATUS "Using Emscripten SDL2")
|
message(STATUS "Using Emscripten SDL2")
|
||||||
target_compile_options(VVVVVV PUBLIC -sUSE_SDL=2 -sUSE_SDL_MIXER=2)
|
target_compile_options(VVVVVV PUBLIC -sUSE_SDL=2)
|
||||||
target_link_libraries(VVVVVV -sUSE_SDL=2 -sUSE_SDL_MIXER=2)
|
target_link_libraries(VVVVVV -sUSE_SDL=2)
|
||||||
|
if(BUNDLE_DEPENDENCIES)
|
||||||
|
target_compile_options(faudio-static PUBLIC -sUSE_SDL=2)
|
||||||
|
target_link_libraries(faudio-static -sUSE_SDL=2)
|
||||||
|
endif()
|
||||||
else()
|
else()
|
||||||
# Only try to autodetect if both SDL2 variables aren't explicitly set
|
# Only try to autodetect if both SDL2 variables aren't explicitly set
|
||||||
find_package(SDL2 CONFIG)
|
find_package(SDL2 CONFIG)
|
||||||
if(TARGET SDL2::SDL2)
|
if(TARGET SDL2::SDL2)
|
||||||
message(STATUS "Using TARGET SDL2::SDL2")
|
message(STATUS "Using TARGET SDL2::SDL2")
|
||||||
target_link_libraries(VVVVVV SDL2::SDL2 SDL2_mixer)
|
target_link_libraries(VVVVVV SDL2::SDL2)
|
||||||
|
if(BUNDLE_DEPENDENCIES)
|
||||||
|
target_link_libraries(faudio-static SDL2::SDL2)
|
||||||
|
endif()
|
||||||
elseif(TARGET SDL2)
|
elseif(TARGET SDL2)
|
||||||
message(STATUS "Using TARGET SDL2")
|
message(STATUS "Using TARGET SDL2")
|
||||||
target_link_libraries(VVVVVV SDL2 SDL2_mixer)
|
target_link_libraries(VVVVVV SDL2)
|
||||||
|
if(BUNDLE_DEPENDENCIES)
|
||||||
|
target_link_libraries(faudio-static SDL2)
|
||||||
|
endif()
|
||||||
else()
|
else()
|
||||||
message(STATUS "No TARGET SDL2::SDL2, or SDL2, using variables")
|
message(STATUS "No TARGET SDL2::SDL2, or SDL2, using variables")
|
||||||
find_path(SDL2_MIXER_INCLUDE_DIRS NAMES SDL_mixer.h PATH_SUFFIXES SDL2)
|
target_include_directories(VVVVVV SYSTEM PRIVATE "$<BUILD_INTERFACE:${SDL2_INCLUDE_DIRS}>")
|
||||||
target_include_directories(VVVVVV SYSTEM PRIVATE "$<BUILD_INTERFACE:${SDL2_INCLUDE_DIRS}>" ${SDL2_MIXER_INCLUDE_DIRS})
|
target_link_libraries(VVVVVV ${SDL2_LIBRARIES})
|
||||||
target_link_libraries(VVVVVV ${SDL2_LIBRARIES} SDL2_mixer)
|
if(BUNDLE_DEPENDENCIES)
|
||||||
|
target_include_directories(faudio-static SYSTEM PRIVATE "$<BUILD_INTERFACE:${SDL2_INCLUDE_DIRS}>")
|
||||||
|
target_link_libraries(faudio-static ${SDL2_LIBRARIES})
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,6 @@ WORKDIR /tmp
|
||||||
RUN curl -O https://www.libsdl.org/release/SDL2-2.0.20.tar.gz
|
RUN curl -O https://www.libsdl.org/release/SDL2-2.0.20.tar.gz
|
||||||
RUN tar -xf SDL2-2.0.20.tar.gz
|
RUN tar -xf SDL2-2.0.20.tar.gz
|
||||||
RUN mkdir SDL2-2.0.20/build
|
RUN mkdir SDL2-2.0.20/build
|
||||||
RUN curl -O https://www.libsdl.org/projects/SDL_mixer/release/SDL2_mixer-2.0.4.tar.gz
|
|
||||||
RUN tar -xf SDL2_mixer-2.0.4.tar.gz
|
|
||||||
RUN mkdir SDL2_mixer-2.0.4/build
|
|
||||||
|
|
||||||
# add EPEL (for SDL2)
|
# add EPEL (for SDL2)
|
||||||
RUN yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
|
RUN yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
|
||||||
|
@ -30,12 +27,7 @@ RUN ../configure
|
||||||
RUN make -j $(nproc)
|
RUN make -j $(nproc)
|
||||||
RUN make install
|
RUN make install
|
||||||
|
|
||||||
WORKDIR /tmp/SDL2_mixer-2.0.4/build
|
|
||||||
RUN ../configure
|
|
||||||
RUN make -j $(nproc)
|
|
||||||
RUN make install
|
|
||||||
|
|
||||||
WORKDIR /tmp
|
WORKDIR /tmp
|
||||||
RUN rm -rf SDL2-2.0.20.tar.gz SDL2-2.0.20/ SDL2_mixer-2.0.4.tar.gz SDL2_mixer-2.0.4/
|
RUN rm -rf SDL2-2.0.20.tar.gz SDL2-2.0.20/
|
||||||
|
|
||||||
WORKDIR /
|
WORKDIR /
|
||||||
|
|
|
@ -6,8 +6,7 @@ VVVVVV's official desktop versions are built with the following environments:
|
||||||
- macOS: Xcode CLT, currently targeting 10.9 SDK
|
- macOS: Xcode CLT, currently targeting 10.9 SDK
|
||||||
- GNU/Linux: CentOS 7
|
- GNU/Linux: CentOS 7
|
||||||
|
|
||||||
The engine depends solely on [SDL2](https://libsdl.org/) 2.0.20+ and
|
The engine depends solely on [SDL2](https://libsdl.org/) 2.0.20+. All other dependencies
|
||||||
[SDL2_mixer](https://www.libsdl.org/projects/SDL_mixer/). All other dependencies
|
|
||||||
are statically linked into the engine. The development libraries for Windows can
|
are statically linked into the engine. The development libraries for Windows can
|
||||||
be downloaded from their respective websites, Linux developers can find the dev
|
be downloaded from their respective websites, Linux developers can find the dev
|
||||||
libraries from their respective repositories, and macOS developers should
|
libraries from their respective repositories, and macOS developers should
|
||||||
|
@ -22,14 +21,14 @@ current implementation has been tested with Steamworks SDK v1.46.
|
||||||
|
|
||||||
To generate the projects on Windows:
|
To generate the projects on Windows:
|
||||||
```
|
```
|
||||||
# Put your SDL2/SDL2_mixer folders somewhere nice!
|
# Put your SDL2 folders somewhere nice!
|
||||||
mkdir flibitBuild
|
mkdir flibitBuild
|
||||||
cd flibitBuild
|
cd flibitBuild
|
||||||
cmake -A Win32 -G "Visual Studio 10 2010" .. -DSDL2_INCLUDE_DIRS="C:\SDL2-2.0.20\include;C:\SDL2_mixer-2.0.4\include" -DSDL2_LIBRARIES="C:\SDL2-2.0.20\lib\x86\SDL2;C:\SDL2-2.0.20\lib\x86\SDL2main;C:\SDL2_mixer-2.0.4\lib\x86\SDL2_mixer"
|
cmake -A Win32 -G "Visual Studio 10 2010" .. -DSDL2_INCLUDE_DIRS="C:\SDL2-2.0.20\include" -DSDL2_LIBRARIES="C:\SDL2-2.0.20\lib\x86\SDL2;C:\SDL2-2.0.20\lib\x86\SDL2main"
|
||||||
```
|
```
|
||||||
|
|
||||||
Note that on some systems, the `SDL2_LIBRARIES` list on Windows may need
|
Note that on some systems, the `SDL2_LIBRARIES` list on Windows may need
|
||||||
SDL2/SDL2main/SDL2_mixer to have `.lib` at the end of them. The reason for this
|
SDL2/SDL2main to have `.lib` at the end of them. The reason for this
|
||||||
inconsistency is unknown.
|
inconsistency is unknown.
|
||||||
|
|
||||||
Also note that if you're using a Visual Studio later than 2010, you will need to
|
Also note that if you're using a Visual Studio later than 2010, you will need to
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "Music.h"
|
#include "Music.h"
|
||||||
|
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
|
#include <FAudio.h>
|
||||||
#include <physfsrwops.h>
|
#include <physfsrwops.h>
|
||||||
|
|
||||||
#include "BinaryBlob.h"
|
#include "BinaryBlob.h"
|
||||||
|
@ -10,168 +11,560 @@
|
||||||
#include "Graphics.h"
|
#include "Graphics.h"
|
||||||
#include "Map.h"
|
#include "Map.h"
|
||||||
#include "Script.h"
|
#include "Script.h"
|
||||||
|
#include "Unused.h"
|
||||||
#include "UtilityClass.h"
|
#include "UtilityClass.h"
|
||||||
#include "Vlogging.h"
|
#include "Vlogging.h"
|
||||||
|
|
||||||
/* Begin SDL_mixer wrapper */
|
|
||||||
|
|
||||||
#include <SDL_mixer.h>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#define VVV_MAX_VOLUME MIX_MAX_VOLUME
|
/* stb_vorbis */
|
||||||
|
|
||||||
|
#define malloc SDL_malloc
|
||||||
|
#define realloc SDL_realloc
|
||||||
|
#define free SDL_free
|
||||||
|
#ifdef memset /* Thanks, Apple! */
|
||||||
|
#undef memset
|
||||||
|
#endif
|
||||||
|
#define memset SDL_memset
|
||||||
|
#ifdef memcpy /* Thanks, Apple! */
|
||||||
|
#undef memcpy
|
||||||
|
#endif
|
||||||
|
#define memcpy SDL_memcpy
|
||||||
|
#define memcmp SDL_memcmp
|
||||||
|
|
||||||
|
#define pow SDL_pow
|
||||||
|
#define log(x) SDL_log(x)
|
||||||
|
#define sin(x) SDL_sin(x)
|
||||||
|
#define cos(x) SDL_cos(x)
|
||||||
|
#define floor SDL_floor
|
||||||
|
#define abs(x) SDL_abs(x)
|
||||||
|
#define ldexp(v, e) SDL_scalbn((v), (e))
|
||||||
|
#define exp(x) SDL_exp(x)
|
||||||
|
|
||||||
|
#define qsort SDL_qsort
|
||||||
|
|
||||||
|
#define assert SDL_assert
|
||||||
|
|
||||||
|
#define FILE SDL_RWops
|
||||||
|
#ifdef SEEK_SET
|
||||||
|
#undef SEEK_SET
|
||||||
|
#endif
|
||||||
|
#ifdef SEEK_CUR
|
||||||
|
#undef SEEK_CUR
|
||||||
|
#endif
|
||||||
|
#ifdef SEEK_END
|
||||||
|
#undef SEEK_END
|
||||||
|
#endif
|
||||||
|
#ifdef EOF
|
||||||
|
#undef EOF
|
||||||
|
#endif
|
||||||
|
#define SEEK_SET 0
|
||||||
|
#define SEEK_CUR 1
|
||||||
|
#define SEEK_END 2
|
||||||
|
#define EOF -1
|
||||||
|
#define fopen(path, mode) SDL_RWFromFile(path, mode)
|
||||||
|
#define fopen_s(io, path, mode) (!(*io = fopen(path, mode)))
|
||||||
|
#define fclose(io) SDL_RWclose(io)
|
||||||
|
#define fread(dst, size, count, io) SDL_RWread(io, dst, size, count)
|
||||||
|
#define fseek(io, offset, whence) SDL_RWseek(io, offset, whence)
|
||||||
|
#define ftell(io) SDL_RWtell(io)
|
||||||
|
|
||||||
|
#define FAudio_alloca(x) SDL_stack_alloc(uint8_t, x)
|
||||||
|
#define FAudio_dealloca(x) SDL_stack_free(x)
|
||||||
|
|
||||||
|
#define STB_VORBIS_NO_PUSHDATA_API 1
|
||||||
|
#define STB_VORBIS_NO_INTEGER_CONVERSION 1
|
||||||
|
#include <stb_vorbis.h>
|
||||||
|
|
||||||
|
/* End stb_vorbis include */
|
||||||
|
|
||||||
|
#define VVV_MAX_VOLUME 128
|
||||||
|
#define VVV_MAX_CHANNELS 8
|
||||||
|
|
||||||
|
class SoundTrack;
|
||||||
|
class MusicTrack;
|
||||||
|
static std::vector<SoundTrack> soundTracks;
|
||||||
|
static std::vector<MusicTrack> musicTracks;
|
||||||
|
|
||||||
|
static FAudio* faudioctx = NULL;
|
||||||
|
static FAudioMasteringVoice* masteringvoice = NULL;
|
||||||
|
|
||||||
class SoundTrack
|
class SoundTrack
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SoundTrack(const char* fileName)
|
SoundTrack(const char* fileName)
|
||||||
{
|
{
|
||||||
/* SDL_LoadWAV, convert spec to FAudioBuffer */
|
|
||||||
unsigned char *mem;
|
unsigned char *mem;
|
||||||
size_t length;
|
size_t length;
|
||||||
|
SDL_AudioSpec spec;
|
||||||
|
SDL_RWops *fileIn;
|
||||||
|
SDL_zerop(this);
|
||||||
FILESYSTEM_loadAssetToMemory(fileName, &mem, &length, false);
|
FILESYSTEM_loadAssetToMemory(fileName, &mem, &length, false);
|
||||||
if (mem == NULL)
|
if (mem == NULL)
|
||||||
{
|
{
|
||||||
m_sound = NULL;
|
|
||||||
vlog_error("Unable to load WAV file %s", fileName);
|
vlog_error("Unable to load WAV file %s", fileName);
|
||||||
SDL_assert(0 && "WAV file missing!");
|
SDL_assert(0 && "WAV file missing!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SDL_RWops *fileIn = SDL_RWFromConstMem(mem, length);
|
fileIn = SDL_RWFromConstMem(mem, length);
|
||||||
m_sound = Mix_LoadWAV_RW(fileIn, 1);
|
if (SDL_LoadWAV_RW(fileIn, 1, &spec, &wav_buffer, &wav_length) == NULL)
|
||||||
FILESYSTEM_freeMemory(&mem);
|
|
||||||
|
|
||||||
if (m_sound == NULL)
|
|
||||||
{
|
{
|
||||||
vlog_error("Unable to load WAV file: %s", Mix_GetError());
|
vlog_error("Unable to load WAV file %s", fileName);
|
||||||
|
goto end;
|
||||||
}
|
}
|
||||||
|
format.nChannels = spec.channels;
|
||||||
|
format.nSamplesPerSec = spec.freq;
|
||||||
|
format.wFormatTag = FAUDIO_FORMAT_PCM;
|
||||||
|
format.wBitsPerSample = 16;
|
||||||
|
format.nBlockAlign = format.nChannels * format.wBitsPerSample;
|
||||||
|
format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;
|
||||||
|
format.cbSize = 0;
|
||||||
|
valid = true;
|
||||||
|
end:
|
||||||
|
FILESYSTEM_freeMemory(&mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dispose()
|
void Dispose()
|
||||||
{
|
{
|
||||||
/* Destroy all track voices, SDL_free buffer from LoadWAV */
|
SDL_free(wav_buffer);
|
||||||
Mix_FreeChunk(m_sound);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Play()
|
void Play()
|
||||||
{
|
{
|
||||||
/* Fire-and-forget from a per-track FAudioSourceVoice pool */
|
if (!valid)
|
||||||
if (Mix_PlayChannel(-1, m_sound, 0) == -1)
|
|
||||||
{
|
{
|
||||||
vlog_error("Unable to play WAV file: %s", Mix_GetError());
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < VVV_MAX_CHANNELS; i++)
|
||||||
|
{
|
||||||
|
FAudioVoiceState voicestate;
|
||||||
|
FAudioSourceVoice_GetState(voices[i], &voicestate, 0);
|
||||||
|
if (voicestate.BuffersQueued == 0)
|
||||||
|
{
|
||||||
|
FAudioVoiceDetails details;
|
||||||
|
FAudioVoice_GetVoiceDetails(voices[i], &details);
|
||||||
|
if (details.InputChannels != format.nChannels)
|
||||||
|
{
|
||||||
|
FAudioVoice_DestroyVoice(voices[i]);
|
||||||
|
FAudio_CreateSourceVoice(faudioctx, &voices[i], &format, 0, 2.0f, NULL, NULL, NULL);
|
||||||
|
}
|
||||||
|
const FAudioBuffer faudio_buffer = {
|
||||||
|
FAUDIO_END_OF_STREAM, /* Flags */
|
||||||
|
wav_length * 8, /* AudioBytes */
|
||||||
|
wav_buffer, /* AudioData */
|
||||||
|
0, /* playbegin */
|
||||||
|
0, /* playlength */
|
||||||
|
0, /* LoopBegin */
|
||||||
|
0, /* LoopLength */
|
||||||
|
0, /* LoopCount */
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
if (FAudioSourceVoice_SubmitSourceBuffer(voices[i], &faudio_buffer, NULL))
|
||||||
|
{
|
||||||
|
vlog_error("Unable to queue sound buffer");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (FAudioSourceVoice_Start(voices[i], 0, FAUDIO_COMMIT_NOW))
|
||||||
|
{
|
||||||
|
vlog_error("Unable to start voice processing");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Init(int audio_rate, int audio_channels)
|
static void Init(int audio_rate, int audio_channels)
|
||||||
{
|
{
|
||||||
const Uint16 audio_format = AUDIO_S16SYS;
|
if (voices == NULL)
|
||||||
const int audio_buffers = 1024;
|
|
||||||
|
|
||||||
/* FAudioCreate, FAudio_CreateMasteringVoice */
|
|
||||||
if (Mix_OpenAudio(audio_rate, audio_format, audio_channels, audio_buffers) != 0)
|
|
||||||
{
|
{
|
||||||
vlog_error("Unable to initialize audio: %s", Mix_GetError());
|
voices = (FAudioSourceVoice**) SDL_malloc(sizeof(FAudioSourceVoice*) * VVV_MAX_CHANNELS);
|
||||||
SDL_assert(0 && "Unable to initialize audio!");
|
for (int i = 0; i < VVV_MAX_CHANNELS; i++)
|
||||||
|
{
|
||||||
|
FAudioWaveFormatEx format;
|
||||||
|
format.nChannels = 1; /* Assume 1 for SoundTracks. Will be recreated if mismatched during play */
|
||||||
|
format.nSamplesPerSec = audio_rate;
|
||||||
|
format.wFormatTag = FAUDIO_FORMAT_PCM;
|
||||||
|
format.wBitsPerSample = 16;
|
||||||
|
format.nBlockAlign = format.nChannels * format.wBitsPerSample;
|
||||||
|
format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;
|
||||||
|
format.cbSize = 0;
|
||||||
|
if (FAudio_CreateSourceVoice(faudioctx, &voices[i], &format, 0, 2.0f, NULL, NULL, NULL))
|
||||||
|
{
|
||||||
|
vlog_error("Unable to create source voice no. %i", i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Pause()
|
static void Pause()
|
||||||
{
|
{
|
||||||
/* FAudio_StopEngine */
|
for (size_t i = 0; i < VVV_MAX_CHANNELS; i++)
|
||||||
Mix_Pause(-1);
|
{
|
||||||
|
FAudioSourceVoice_Stop(voices[i], 0, FAUDIO_COMMIT_NOW);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Resume()
|
static void Resume()
|
||||||
{
|
{
|
||||||
/* FAudio_StartEngine */
|
for (size_t i = 0; i < VVV_MAX_CHANNELS; i++)
|
||||||
Mix_Resume(-1);
|
{
|
||||||
|
FAudioSourceVoice_Start(voices[i], 0, FAUDIO_COMMIT_NOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Destroy()
|
||||||
|
{
|
||||||
|
if (voices != NULL)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < VVV_MAX_CHANNELS; i++)
|
||||||
|
{
|
||||||
|
FAudioVoice_DestroyVoice(voices[i]);
|
||||||
|
}
|
||||||
|
SDL_free(voices);
|
||||||
|
voices = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SetVolume(int soundVolume)
|
static void SetVolume(int soundVolume)
|
||||||
{
|
{
|
||||||
/* FAudioVoice_SetVolume on all sounds. Yeah, all of them :/
|
float adj_vol = (float) soundVolume / VVV_MAX_VOLUME;
|
||||||
* If we get desperate we can use a submix and set volume on that, but
|
for (size_t i = 0; i < VVV_MAX_CHANNELS; i++)
|
||||||
* the submix is an extra mix stage so just loop all sounds manually...
|
{
|
||||||
*/
|
FAudioVoice_SetVolume(voices[i], adj_vol, FAUDIO_COMMIT_NOW);
|
||||||
Mix_Volume(-1, soundVolume);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
Uint8 *wav_buffer = NULL;
|
||||||
Mix_Chunk *m_sound;
|
Uint32 wav_length;
|
||||||
|
FAudioWaveFormatEx format;
|
||||||
|
bool valid;
|
||||||
|
|
||||||
|
static FAudioSourceVoice** voices;
|
||||||
};
|
};
|
||||||
|
FAudioSourceVoice** SoundTrack::voices = NULL;
|
||||||
|
|
||||||
class MusicTrack
|
class MusicTrack
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MusicTrack(SDL_RWops *rw)
|
MusicTrack(SDL_RWops *rw)
|
||||||
{
|
{
|
||||||
/* Open an stb_vorbis handle */
|
SDL_zerop(this);
|
||||||
m_music = Mix_LoadMUS_RW(rw, 1);
|
read_buf = (Uint8*) SDL_malloc(rw->size(rw));
|
||||||
if (m_music == NULL)
|
SDL_RWread(rw, read_buf, rw->size(rw), 1);
|
||||||
|
int err;
|
||||||
|
stb_vorbis_info vorbis_info;
|
||||||
|
stb_vorbis_comment vorbis_comment;
|
||||||
|
vorbis = stb_vorbis_open_memory(read_buf, rw->size(rw), &err, NULL);
|
||||||
|
if (vorbis == NULL)
|
||||||
{
|
{
|
||||||
vlog_error("Unable to load Magic Binary Music file: %s", Mix_GetError());
|
vlog_error("Unable to create Vorbis handle, error %d", err);
|
||||||
|
SDL_free(read_buf);
|
||||||
|
read_buf = NULL;
|
||||||
|
goto end;
|
||||||
}
|
}
|
||||||
|
vorbis_info = stb_vorbis_get_info(vorbis);
|
||||||
|
format.wFormatTag = FAUDIO_FORMAT_IEEE_FLOAT;
|
||||||
|
format.wBitsPerSample = sizeof(float) * 8;
|
||||||
|
format.nChannels = vorbis_info.channels;
|
||||||
|
format.nSamplesPerSec = vorbis_info.sample_rate;
|
||||||
|
format.nBlockAlign = format.nChannels * format.wBitsPerSample;
|
||||||
|
format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;
|
||||||
|
format.cbSize = 0;
|
||||||
|
|
||||||
|
channels = format.nChannels;
|
||||||
|
size = format.nAvgBytesPerSec / 20;
|
||||||
|
|
||||||
|
decoded_buf_playing = (Uint8*) SDL_malloc(size);
|
||||||
|
decoded_buf_reserve = (Uint8*) SDL_malloc(size);
|
||||||
|
|
||||||
|
loopbegin = 0;
|
||||||
|
looplength = 0;
|
||||||
|
vorbis_comment = stb_vorbis_get_comment(vorbis);
|
||||||
|
parseComments(this, vorbis_comment.comment_list, vorbis_comment.comment_list_length);
|
||||||
|
valid = true;
|
||||||
|
|
||||||
|
end:
|
||||||
|
SDL_RWclose(rw);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dispose()
|
void Dispose()
|
||||||
{
|
{
|
||||||
/* Free stb_vorbis */
|
stb_vorbis_close(vorbis);
|
||||||
Mix_FreeMusic(m_music);
|
SDL_free(read_buf);
|
||||||
|
SDL_free(decoded_buf_playing);
|
||||||
|
SDL_free(decoded_buf_reserve);
|
||||||
|
if (!IsHalted())
|
||||||
|
{
|
||||||
|
FAudioVoice_DestroyVoice(musicVoice);
|
||||||
|
musicVoice = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Play(bool loop)
|
bool Play(bool loop)
|
||||||
{
|
{
|
||||||
/* Create/Validate static FAudioSourceVoice, begin streaming */
|
if (!valid)
|
||||||
if (Mix_PlayMusic(m_music, loop ? -1 : 0) == -1)
|
|
||||||
{
|
{
|
||||||
vlog_error("Mix_PlayMusic: %s", Mix_GetError());
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shouldloop = loop;
|
||||||
|
sample_pos = 0;
|
||||||
|
stb_vorbis_seek_start(vorbis);
|
||||||
|
|
||||||
|
if (IsHalted())
|
||||||
|
{
|
||||||
|
SDL_zero(callbacks);
|
||||||
|
callbacks.OnBufferStart = &MusicTrack::refillReserve;
|
||||||
|
callbacks.OnBufferEnd = &MusicTrack::swapBuffers;
|
||||||
|
FAudio_CreateSourceVoice(faudioctx, &musicVoice, &format, 0, 2.0f, &callbacks, NULL, NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Pause();
|
||||||
|
FAudioSourceVoice_FlushSourceBuffers(musicVoice);
|
||||||
|
}
|
||||||
|
|
||||||
|
FAudioBuffer faudio_buffer;
|
||||||
|
SDL_zero(faudio_buffer);
|
||||||
|
if (looplength == 0)
|
||||||
|
{
|
||||||
|
faudio_buffer.PlayLength = stb_vorbis_get_samples_float_interleaved(vorbis, channels, (float*) decoded_buf_playing, size / sizeof(float));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int samples_read = stb_vorbis_get_samples_float_interleaved(vorbis, channels, (float*) decoded_buf_playing, size / sizeof(float));
|
||||||
|
faudio_buffer.PlayLength = SDL_min(samples_read, (loopbegin + looplength) - sample_pos);
|
||||||
|
}
|
||||||
|
faudio_buffer.AudioBytes = size;
|
||||||
|
faudio_buffer.pAudioData = decoded_buf_playing;
|
||||||
|
faudio_buffer.pContext = this;
|
||||||
|
sample_pos += faudio_buffer.PlayLength;
|
||||||
|
if (FAudioSourceVoice_SubmitSourceBuffer(musicVoice, &faudio_buffer, NULL))
|
||||||
|
{
|
||||||
|
vlog_error("Unable to queue sound buffer");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Resume();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Halt()
|
static void Halt()
|
||||||
{
|
{
|
||||||
/* FAudioVoice_Destroy */
|
if (!IsHalted())
|
||||||
Mix_HaltMusic();
|
{
|
||||||
|
FAudioSourceVoice_FlushSourceBuffers(musicVoice);
|
||||||
|
FAudioVoice_DestroyVoice(musicVoice);
|
||||||
|
musicVoice = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool IsHalted()
|
static bool IsHalted()
|
||||||
{
|
{
|
||||||
/* return musicVoice == NULL; */
|
return musicVoice == NULL;
|
||||||
return Mix_PausedMusic() == 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Pause()
|
static void Pause()
|
||||||
{
|
{
|
||||||
/* FAudioSourceVoice_Pause */
|
if (!IsHalted())
|
||||||
Mix_PauseMusic();
|
{
|
||||||
|
FAudioSourceVoice_Stop(musicVoice, 0, FAUDIO_COMMIT_NOW);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Resume()
|
static void Resume()
|
||||||
{
|
{
|
||||||
/* FAudioSourceVoice_Resume */
|
if (!IsHalted())
|
||||||
Mix_ResumeMusic();
|
{
|
||||||
|
FAudioSourceVoice_Start(musicVoice, 0, FAUDIO_COMMIT_NOW);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SetVolume(int musicVolume)
|
static void SetVolume(int musicVolume)
|
||||||
{
|
{
|
||||||
/* FAudioSourceVoice_SetVolume */
|
float adj_vol = (float) musicVolume / VVV_MAX_VOLUME;
|
||||||
Mix_VolumeMusic(musicVolume);
|
if (!IsHalted())
|
||||||
|
{
|
||||||
|
FAudioVoice_SetVolume(musicVoice, adj_vol, FAUDIO_COMMIT_NOW);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
stb_vorbis* vorbis;
|
||||||
Mix_Music *m_music;
|
int channels;
|
||||||
|
Uint32 size;
|
||||||
|
int loopbegin;
|
||||||
|
int looplength;
|
||||||
|
int sample_pos; //stb_vorbis offset not yet functional on pulldata API. TODO Replace when fixed
|
||||||
|
|
||||||
|
FAudioVoiceCallback callbacks;
|
||||||
|
FAudioWaveFormatEx format;
|
||||||
|
|
||||||
|
Uint8* decoded_buf_playing = NULL;
|
||||||
|
Uint8* decoded_buf_reserve = NULL;
|
||||||
|
Uint8* read_buf = NULL;
|
||||||
|
bool shouldloop;
|
||||||
|
bool valid;
|
||||||
|
|
||||||
|
static FAudioSourceVoice* musicVoice;
|
||||||
|
|
||||||
|
static void refillReserve(FAudioVoiceCallback* callback, void* ctx)
|
||||||
|
{
|
||||||
|
MusicTrack* t = (MusicTrack*) ctx;
|
||||||
|
FAudioBuffer faudio_buffer;
|
||||||
|
SDL_zero(faudio_buffer);
|
||||||
|
UNUSED(callback);
|
||||||
|
if (t->looplength == 0)
|
||||||
|
{
|
||||||
|
faudio_buffer.PlayLength = stb_vorbis_get_samples_float_interleaved(t->vorbis, t->channels, (float*) t->decoded_buf_reserve, t->size / sizeof(float));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int samples_read = stb_vorbis_get_samples_float_interleaved(t->vorbis, t->channels, (float*) t->decoded_buf_reserve, t->size / sizeof(float));
|
||||||
|
faudio_buffer.PlayLength = SDL_min(samples_read, (t->loopbegin + t->looplength) - t->sample_pos);
|
||||||
|
}
|
||||||
|
faudio_buffer.AudioBytes = t->size;
|
||||||
|
faudio_buffer.pAudioData = t->decoded_buf_reserve;
|
||||||
|
faudio_buffer.pContext = t;
|
||||||
|
if (faudio_buffer.PlayLength == 0)
|
||||||
|
{
|
||||||
|
if (t->shouldloop)
|
||||||
|
{
|
||||||
|
stb_vorbis_seek(t->vorbis, t->loopbegin);
|
||||||
|
t->sample_pos = t->loopbegin;
|
||||||
|
if (t->looplength != 0)
|
||||||
|
{
|
||||||
|
int samples_read = stb_vorbis_get_samples_float_interleaved(t->vorbis, t->channels, (float*) t->decoded_buf_reserve, t->size / sizeof(float));
|
||||||
|
faudio_buffer.PlayLength = SDL_min(samples_read, (t->loopbegin + t->looplength) - t->sample_pos);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
faudio_buffer.PlayLength = stb_vorbis_get_samples_float_interleaved(t->vorbis, t->channels, (float*) t->decoded_buf_reserve, t->size / sizeof(float));
|
||||||
|
}
|
||||||
|
if (faudio_buffer.PlayLength == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t->sample_pos += faudio_buffer.PlayLength;
|
||||||
|
FAudioSourceVoice_SubmitSourceBuffer(musicVoice, &faudio_buffer, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void swapBuffers(FAudioVoiceCallback* callback, void* ctx)
|
||||||
|
{
|
||||||
|
MusicTrack* t = (MusicTrack*) ctx;
|
||||||
|
Uint8* tmp = t->decoded_buf_playing;
|
||||||
|
UNUSED(callback);
|
||||||
|
t->decoded_buf_playing = t->decoded_buf_reserve;
|
||||||
|
t->decoded_buf_reserve = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lifted from SDL_mixer, we used it in 2.3 and previous */
|
||||||
|
static void parseComments(MusicTrack* t, char** comments, int comment_list_length)
|
||||||
|
{
|
||||||
|
int loopend = 0;
|
||||||
|
for (int i = 0; i < comment_list_length; i++)
|
||||||
|
{
|
||||||
|
char *param = SDL_strdup(comments[i]);
|
||||||
|
char *argument = param;
|
||||||
|
char *value = SDL_strchr(param, '=');
|
||||||
|
if (value == NULL)
|
||||||
|
{
|
||||||
|
value = param + SDL_strlen(param);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*(value++) = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Want to match LOOP-START, LOOP_START, etc. Remove - or _ from
|
||||||
|
* string if it is present at position 4. */
|
||||||
|
char buf[5];
|
||||||
|
SDL_strlcpy(buf, argument, sizeof(buf));
|
||||||
|
if (SDL_strcasecmp(buf, "LOOP") == 0 && ((argument[4] == '_') || (argument[4] == '-')))
|
||||||
|
{
|
||||||
|
SDL_memmove(argument + 4, argument + 5, SDL_strlen(argument) - 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SDL_strcasecmp(argument, "LOOPSTART") == 0)
|
||||||
|
{
|
||||||
|
t->loopbegin = _Mix_ParseTime(value, t->format.nSamplesPerSec);
|
||||||
|
}
|
||||||
|
else if (SDL_strcasecmp(argument, "LOOPLENGTH") == 0)
|
||||||
|
{
|
||||||
|
t->looplength = SDL_strtoll(value, NULL, 10);
|
||||||
|
}
|
||||||
|
else if (SDL_strcasecmp(argument, "LOOPEND") == 0)
|
||||||
|
{
|
||||||
|
loopend = _Mix_ParseTime(value, t->format.nSamplesPerSec);
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_free(param);
|
||||||
|
}
|
||||||
|
if (loopend != 0)
|
||||||
|
{
|
||||||
|
t->looplength = loopend - t->loopbegin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _Mix_ParseTime(char *time, long samplerate_hz)
|
||||||
|
{
|
||||||
|
char *num_start, *p;
|
||||||
|
Sint64 result;
|
||||||
|
char c;
|
||||||
|
int val;
|
||||||
|
|
||||||
|
/* Time is directly expressed as a sample position */
|
||||||
|
if (SDL_strchr(time, ':') == NULL)
|
||||||
|
{
|
||||||
|
return SDL_strtoll(time, NULL, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = 0;
|
||||||
|
num_start = time;
|
||||||
|
|
||||||
|
for (p = time; *p != '\0'; ++p)
|
||||||
|
{
|
||||||
|
if (*p == '.' || *p == ':')
|
||||||
|
{
|
||||||
|
c = *p; *p = '\0';
|
||||||
|
if ((val = SDL_atoi(num_start)) < 0)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
result = result * 60 + val;
|
||||||
|
num_start = p + 1;
|
||||||
|
*p = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*p == '.')
|
||||||
|
{
|
||||||
|
double val_f = SDL_atof(p);
|
||||||
|
if (val_f < 0)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return result * samplerate_hz + (Sint64) (val_f * samplerate_hz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((val = SDL_atoi(num_start)) < 0)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return (result * 60 + val) * samplerate_hz;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::vector<SoundTrack> soundTracks;
|
FAudioSourceVoice* MusicTrack::musicVoice = NULL;
|
||||||
static std::vector<MusicTrack> musicTracks;
|
|
||||||
|
|
||||||
/* End SDL_mixer wrapper */
|
|
||||||
|
|
||||||
musicclass::musicclass(void)
|
musicclass::musicclass(void)
|
||||||
{
|
{
|
||||||
SoundTrack::Init(44100, 2);
|
|
||||||
|
|
||||||
safeToProcessMusic= false;
|
safeToProcessMusic= false;
|
||||||
m_doFadeInVol = false;
|
m_doFadeInVol = false;
|
||||||
m_doFadeOutVol = false;
|
m_doFadeOutVol = false;
|
||||||
|
@ -190,6 +583,19 @@ musicclass::musicclass(void)
|
||||||
|
|
||||||
void musicclass::init(void)
|
void musicclass::init(void)
|
||||||
{
|
{
|
||||||
|
if (FAudioCreate(&faudioctx, 0, FAUDIO_DEFAULT_PROCESSOR))
|
||||||
|
{
|
||||||
|
vlog_error("Unable to initialize FAudio");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (FAudio_CreateMasteringVoice(faudioctx, &masteringvoice, 2, 44100, 0, 0, NULL))
|
||||||
|
{
|
||||||
|
vlog_error("Unable to create mastering voice");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SoundTrack::Init(44100, 2);
|
||||||
|
|
||||||
soundTracks.push_back(SoundTrack( "sounds/jump.wav" ));
|
soundTracks.push_back(SoundTrack( "sounds/jump.wav" ));
|
||||||
soundTracks.push_back(SoundTrack( "sounds/jump2.wav" ));
|
soundTracks.push_back(SoundTrack( "sounds/jump2.wav" ));
|
||||||
soundTracks.push_back(SoundTrack( "sounds/hurt.wav" ));
|
soundTracks.push_back(SoundTrack( "sounds/hurt.wav" ));
|
||||||
|
@ -341,10 +747,7 @@ void musicclass::destroy(void)
|
||||||
soundTracks[i].Dispose();
|
soundTracks[i].Dispose();
|
||||||
}
|
}
|
||||||
soundTracks.clear();
|
soundTracks.clear();
|
||||||
|
SoundTrack::Destroy();
|
||||||
// Before we free all the music: stop playing music, else SDL2_mixer
|
|
||||||
// will call SDL_Delay() if we are fading, resulting in no-draw frames
|
|
||||||
MusicTrack::Halt();
|
|
||||||
|
|
||||||
for (size_t i = 0; i < musicTracks.size(); ++i)
|
for (size_t i = 0; i < musicTracks.size(); ++i)
|
||||||
{
|
{
|
||||||
|
@ -354,6 +757,14 @@ void musicclass::destroy(void)
|
||||||
|
|
||||||
pppppp_blob.clear();
|
pppppp_blob.clear();
|
||||||
mmmmmm_blob.clear();
|
mmmmmm_blob.clear();
|
||||||
|
if (masteringvoice != NULL)
|
||||||
|
{
|
||||||
|
FAudioVoice_DestroyVoice(masteringvoice);
|
||||||
|
}
|
||||||
|
if (faudioctx != NULL)
|
||||||
|
{
|
||||||
|
FAudio_Release(faudioctx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void musicclass::play(int t)
|
void musicclass::play(int t)
|
||||||
|
|
1
third_party/FAudio
vendored
Submodule
1
third_party/FAudio
vendored
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 1d13854fb83ac9868e0a2e5b8d3e58522b5fa66f
|
Loading…
Reference in a new issue