Merge 3aad099f6d
into 854ee12d9d
This commit is contained in:
commit
e80b71fa5d
|
@ -47,7 +47,6 @@ jobs:
|
|||
mv ./bin/${{matrix.platform}}/${{matrix.buildtype}}/re3.pdb ./gamefiles/
|
||||
- name: Move dynamic dependencies to gamefiles
|
||||
run: |
|
||||
mv ./vendor/mpg123/dist/Win64/libmpg123-0.dll ./gamefiles/
|
||||
mv ./vendor/openal-soft/dist/Win64/OpenAL32.dll ./gamefiles/
|
||||
- name: Upload artifact to actions
|
||||
uses: actions/upload-artifact@v2
|
||||
|
|
|
@ -48,7 +48,6 @@ jobs:
|
|||
- if: contains(matrix.platform, 'oal')
|
||||
name: Move dynamic dependencies to gamefiles
|
||||
run: |
|
||||
mv ./vendor/mpg123/dist/Win32/libmpg123-0.dll ./gamefiles/
|
||||
mv ./vendor/openal-soft/dist/Win32/OpenAL32.dll ./gamefiles/
|
||||
- name: Upload artifact to actions
|
||||
uses: actions/upload-artifact@v2
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
# - Find Miles SDK
|
||||
# Find the Miles SDK header + import library
|
||||
#
|
||||
# MilesSDK_INCLUDE_DIR - Where to find mss.h
|
||||
# MilesSDK_LIBRARIES - List of libraries when using MilesSDK.
|
||||
# MilesSDK_FOUND - True if Miles SDK found.
|
||||
# MilesSDK::MilesSDK - Imported library of Miles SDK
|
||||
|
||||
find_path(MilesSDK_INCLUDE_DIR mss.h
|
||||
PATHS "${MilesSDK_DIR}"
|
||||
PATH_SUFFIXES include
|
||||
)
|
||||
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(_miles_sdk_libname mss64)
|
||||
else()
|
||||
set(_miles_sdk_libname mss32)
|
||||
endif()
|
||||
|
||||
find_library(MilesSDK_LIBRARIES NAMES ${_miles_sdk_libname}
|
||||
PATHS "${MilesSDK_DIR}"
|
||||
PATH_SUFFIXES lib
|
||||
)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(MilesSDK DEFAULT_MSG MilesSDK_LIBRARIES MilesSDK_INCLUDE_DIR)
|
||||
|
||||
if(NOT TARGET MilesSDK::MilesSDK)
|
||||
add_library(MilesSDK::MilesSDK UNKNOWN IMPORTED)
|
||||
set_target_properties(MilesSDK::MilesSDK PROPERTIES
|
||||
IMPORTED_LOCATION "${MilesSDK_LIBRARIES}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${MilesSDK_INCLUDE_DIR}"
|
||||
)
|
||||
endif()
|
|
@ -1,38 +0,0 @@
|
|||
# - Find mpg123
|
||||
# Find the native mpg123 includes and library
|
||||
#
|
||||
# mpg123_INCLUDE_DIR - Where to find mpg123.h
|
||||
# mpg123_LIBRARIES - List of libraries when using mpg123.
|
||||
# mpg123_CFLAGS - Compile options to use mpg123
|
||||
# mpg123_FOUND - True if mpg123 found.
|
||||
# MPG123::libmpg123 - Imported library of libmpg123
|
||||
|
||||
find_package(PkgConfig QUIET)
|
||||
if(PKG_CONFIG_FOUND)
|
||||
pkg_search_module(PKG_MPG123 mpg123)
|
||||
endif()
|
||||
|
||||
find_path(mpg123_INCLUDE_DIR mpg123.h
|
||||
HINTS ${PKG_MPG123_INCLUDE_DIRS}
|
||||
PATHS "${mpg123_DIR}"
|
||||
PATH_SUFFIXES include
|
||||
)
|
||||
|
||||
find_library(mpg123_LIBRARIES NAMES mpg123 mpg123-0 libmpg123-0
|
||||
HINTS ${PKG_MPG123_LIBRARIES}
|
||||
PATHS "${mpg123_DIR}"
|
||||
PATH_SUFFIXES lib
|
||||
)
|
||||
|
||||
set(mpg123_CFLAGS "${PKG_MPG123_CFLAGS_OTHER}" CACHE STRING "CFLAGS of mpg123")
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(mpg123 DEFAULT_MSG mpg123_LIBRARIES mpg123_INCLUDE_DIR)
|
||||
|
||||
if(NOT TARGET MPG123::libmpg123)
|
||||
add_library(__libmpg123 INTERFACE)
|
||||
target_compile_options(__libmpg123 INTERFACE ${mpg123_CFLAGS})
|
||||
target_include_directories(__libmpg123 INTERFACE ${mpg123_INCLUDE_DIR})
|
||||
target_link_libraries(__libmpg123 INTERFACE ${mpg123_LIBRARIES})
|
||||
add_library(MPG123::libmpg123 ALIAS __libmpg123)
|
||||
endif()
|
|
@ -305,16 +305,6 @@
|
|||
<SETTING><NAME>FrameworkPath</NAME><VALUE>false</VALUE></SETTING>
|
||||
<SETTING><NAME>HostFlags</NAME><VALUE>All</VALUE></SETTING>
|
||||
</SETTING>
|
||||
<SETTING>
|
||||
<SETTING><NAME>SearchPath</NAME>
|
||||
<SETTING><NAME>Path</NAME><VALUE>..\src\extras</VALUE></SETTING>
|
||||
<SETTING><NAME>PathFormat</NAME><VALUE>Windows</VALUE></SETTING>
|
||||
<SETTING><NAME>PathRoot</NAME><VALUE>Project</VALUE></SETTING>
|
||||
</SETTING>
|
||||
<SETTING><NAME>Recursive</NAME><VALUE>true</VALUE></SETTING>
|
||||
<SETTING><NAME>FrameworkPath</NAME><VALUE>false</VALUE></SETTING>
|
||||
<SETTING><NAME>HostFlags</NAME><VALUE>All</VALUE></SETTING>
|
||||
</SETTING>
|
||||
</SETTING>
|
||||
<SETTING><NAME>SystemSearchPaths</NAME>
|
||||
<SETTING>
|
||||
|
@ -6554,16 +6544,6 @@
|
|||
<SETTING><NAME>FrameworkPath</NAME><VALUE>false</VALUE></SETTING>
|
||||
<SETTING><NAME>HostFlags</NAME><VALUE>All</VALUE></SETTING>
|
||||
</SETTING>
|
||||
<SETTING>
|
||||
<SETTING><NAME>SearchPath</NAME>
|
||||
<SETTING><NAME>Path</NAME><VALUE>..\src\extras</VALUE></SETTING>
|
||||
<SETTING><NAME>PathFormat</NAME><VALUE>Windows</VALUE></SETTING>
|
||||
<SETTING><NAME>PathRoot</NAME><VALUE>Project</VALUE></SETTING>
|
||||
</SETTING>
|
||||
<SETTING><NAME>Recursive</NAME><VALUE>true</VALUE></SETTING>
|
||||
<SETTING><NAME>FrameworkPath</NAME><VALUE>false</VALUE></SETTING>
|
||||
<SETTING><NAME>HostFlags</NAME><VALUE>All</VALUE></SETTING>
|
||||
</SETTING>
|
||||
</SETTING>
|
||||
<SETTING><NAME>SystemSearchPaths</NAME>
|
||||
<SETTING>
|
||||
|
@ -13869,8 +13849,6 @@
|
|||
<PATHFORMAT>Windows</PATHFORMAT>
|
||||
</FILEREF>
|
||||
</GROUP>
|
||||
<GROUP><NAME>extras</NAME>
|
||||
</GROUP>
|
||||
<GROUP><NAME>math</NAME>
|
||||
<FILEREF>
|
||||
<TARGETNAME>Debug</TARGETNAME>
|
||||
|
|
13
conanfile.py
13
conanfile.py
|
@ -21,15 +21,6 @@ class Re3Conan(ConanFile):
|
|||
"with_libsndfile": False,
|
||||
"with_opus": False,
|
||||
# "libsndfile:with_external_libs": False,
|
||||
# "mpg123:flexible_resampling": False,
|
||||
# "mpg123:network": False,
|
||||
# "mpg123:icy": False,
|
||||
# "mpg123:id3v2": False,
|
||||
# "mpg123:ieeefloat": False,
|
||||
# "mpg123:layer1": False,
|
||||
# "mpg123:layer2": False,
|
||||
# "mpg123:layer3": False,
|
||||
# "mpg123:moreinfo": False,
|
||||
# "sdl2:vulkan": False,
|
||||
# "sdl2:opengl": True,
|
||||
# "sdl2:sdl2main": True,
|
||||
|
@ -49,11 +40,9 @@ class Re3Conan(ConanFile):
|
|||
|
||||
def requirements(self):
|
||||
self.requires("librw/{}".format(self.version))
|
||||
self.requires("mpg123/1.26.4")
|
||||
if self.options.audio == "openal":
|
||||
self.requires("openal/1.21.0")
|
||||
elif self.options.audio == "miles":
|
||||
self.requires("miles-sdk/{}".format(self.version))
|
||||
|
||||
if self.options.with_libsndfile:
|
||||
self.requires("libsndfile/1.0.30")
|
||||
if self.options.with_opus:
|
||||
|
|
21
premake5.lua
21
premake5.lua
|
@ -257,6 +257,7 @@ project "re3"
|
|||
files { addSrcFiles("src/audio/oal") }
|
||||
files { addSrcFiles("src/buildings") }
|
||||
files { addSrcFiles("src/collision") }
|
||||
files { addSrcFiles("src/external") }
|
||||
files { addSrcFiles("src/control") }
|
||||
files { addSrcFiles("src/core") }
|
||||
files { addSrcFiles("src/entities") }
|
||||
|
@ -286,6 +287,7 @@ project "re3"
|
|||
includedirs { "src/audio/oal" }
|
||||
includedirs { "src/buildings" }
|
||||
includedirs { "src/collision" }
|
||||
includedirs { "src/external" }
|
||||
includedirs { "src/control" }
|
||||
includedirs { "src/core" }
|
||||
includedirs { "src/entities" }
|
||||
|
@ -318,8 +320,8 @@ project "re3"
|
|||
|
||||
filter "platforms:*mss"
|
||||
defines { "AUDIO_MSS" }
|
||||
includedirs { "vendor/milessdk/include" }
|
||||
libdirs { "vendor/milessdk/lib" }
|
||||
includedirs { "src/external/milessdk" }
|
||||
libdirs { "src/external/milessdk" }
|
||||
|
||||
if _OPTIONS["with-opus"] then
|
||||
filter "platforms:win*"
|
||||
|
@ -367,27 +369,24 @@ project "re3"
|
|||
|
||||
filter "platforms:win*oal"
|
||||
includedirs { "vendor/openal-soft/include" }
|
||||
includedirs { "vendor/libsndfile/include" }
|
||||
includedirs { "vendor/mpg123/include" }
|
||||
includedirs { "src/external/libsndfile/include" }
|
||||
|
||||
filter "platforms:win-x86*oal"
|
||||
libdirs { "vendor/mpg123/lib/Win32" }
|
||||
libdirs { "vendor/libsndfile/lib/Win32" }
|
||||
libdirs { "src/external/libsndfile/lib/Win32" }
|
||||
libdirs { "vendor/openal-soft/libs/Win32" }
|
||||
|
||||
filter "platforms:win-amd64*oal"
|
||||
libdirs { "vendor/mpg123/lib/Win64" }
|
||||
libdirs { "vendor/libsndfile/lib/Win64" }
|
||||
libdirs { "src/external/libsndfile/lib/Win64" }
|
||||
libdirs { "vendor/openal-soft/libs/Win64" }
|
||||
|
||||
filter "platforms:linux*oal"
|
||||
links { "openal", "mpg123", "sndfile", "pthread", "X11" }
|
||||
links { "openal", "sndfile", "pthread", "X11" }
|
||||
|
||||
filter "platforms:bsd*oal"
|
||||
links { "openal", "mpg123", "sndfile", "pthread", "X11" }
|
||||
links { "openal", "sndfile", "pthread", "X11" }
|
||||
|
||||
filter "platforms:macosx*oal"
|
||||
links { "openal", "mpg123", "sndfile", "pthread" }
|
||||
links { "openal", "sndfile", "pthread" }
|
||||
|
||||
filter "platforms:macosx-arm64-*oal"
|
||||
includedirs { "/opt/homebrew/opt/openal-soft/include" }
|
||||
|
|
|
@ -64,10 +64,6 @@ elseif(${PROJECT}_AUDIO STREQUAL "MSS")
|
|||
target_link_libraries(${EXECUTABLE} PRIVATE MilesSDK::MilesSDK)
|
||||
endif()
|
||||
|
||||
find_package(mpg123 REQUIRED)
|
||||
target_link_libraries(${EXECUTABLE} PRIVATE
|
||||
MPG123::libmpg123
|
||||
)
|
||||
if(${PROJECT}_WITH_OPUS)
|
||||
find_package(opusfile REQUIRED)
|
||||
target_link_libraries(${EXECUTABLE} PRIVATE
|
||||
|
|
|
@ -6,47 +6,46 @@
|
|||
#ifdef AUDIO_OAL_USE_SNDFILE
|
||||
#pragma comment( lib, "libsndfile-1.lib" )
|
||||
#endif
|
||||
#ifdef AUDIO_OAL_USE_MPG123
|
||||
#pragma comment( lib, "libmpg123-0.lib" )
|
||||
#endif
|
||||
#endif
|
||||
#ifdef AUDIO_OAL_USE_SNDFILE
|
||||
#include <sndfile.h>
|
||||
#endif
|
||||
#ifdef AUDIO_OAL_USE_MPG123
|
||||
#include <mpg123.h>
|
||||
#endif
|
||||
|
||||
#ifdef AUDIO_OAL_USE_OPUS
|
||||
#include <opusfile.h>
|
||||
#endif
|
||||
|
||||
#define MINIMP3_IMPLEMENTATION
|
||||
#include "minimp3_ex.h"
|
||||
|
||||
#include <queue>
|
||||
#include <utility>
|
||||
|
||||
#ifdef MULTITHREADED_AUDIO
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#define XPLAT_PTHREAD
|
||||
#include "crossplatform.h"
|
||||
#include "MusicManager.h"
|
||||
#include "stream.h"
|
||||
|
||||
std::thread gAudioThread;
|
||||
std::mutex gAudioThreadQueueMutex;
|
||||
std::condition_variable gAudioThreadCv;
|
||||
pthread_t gAudioThread;
|
||||
pthread_mutex_t gAudioThreadQueueMutex;
|
||||
pthread_cond_t gAudioThreadCv;
|
||||
bool gAudioThreadTerm = false;
|
||||
std::queue<CStream*> gStreamsToProcess; // values are not unique, we will handle that ourself
|
||||
std::queue<std::pair<IDecoder*, void*>> gStreamsToClose;
|
||||
#else
|
||||
#include "stream.h"
|
||||
#endif
|
||||
|
||||
#include "sampman.h"
|
||||
#else
|
||||
|
||||
#include "stream.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include "crossplatform.h"
|
||||
#endif
|
||||
|
||||
#endif // not MULTITHREADED_AUDIO
|
||||
|
||||
#include "sampman.h"
|
||||
|
||||
/*
|
||||
As we ran onto an issue of having different volume levels for mono streams
|
||||
and stereo streams we are now handling all the stereo panning ourselves.
|
||||
|
@ -61,7 +60,7 @@ class CSortStereoBuffer
|
|||
uint16* PcmBuf;
|
||||
size_t BufSize;
|
||||
//#ifdef MULTITHREADED_AUDIO
|
||||
// std::mutex Mutex;
|
||||
// pthread_mutex_t Mutex;
|
||||
//#endif
|
||||
|
||||
public:
|
||||
|
@ -91,12 +90,17 @@ public:
|
|||
void SortStereo(void* buf, size_t size)
|
||||
{
|
||||
//#ifdef MULTITHREADED_AUDIO
|
||||
// std::lock_guard<std::mutex> lock(Mutex);
|
||||
// pthread_mutex_lock(&Mutex);
|
||||
//#endif
|
||||
uint16* InBuf = (uint16*)buf;
|
||||
uint16* OutBuf = GetBuffer(size);
|
||||
|
||||
if (!OutBuf) return;
|
||||
if (!OutBuf) {
|
||||
//#ifdef MULTITHREADED_AUDIO
|
||||
// pthread_mutex_unlock(&Mutex);
|
||||
//#endif
|
||||
return;
|
||||
}
|
||||
|
||||
size_t rightStart = size / 4;
|
||||
for (size_t i = 0; i < size / 4; i++)
|
||||
|
@ -106,6 +110,9 @@ public:
|
|||
}
|
||||
|
||||
memcpy(InBuf, OutBuf, size);
|
||||
//#ifdef MULTITHREADED_AUDIO
|
||||
// pthread_mutex_unlock(&Mutex);
|
||||
//#endif
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -500,68 +507,35 @@ public:
|
|||
};
|
||||
#endif
|
||||
|
||||
#ifdef AUDIO_OAL_USE_MPG123
|
||||
|
||||
class CMP3File : public IDecoder
|
||||
{
|
||||
protected:
|
||||
mpg123_handle *m_pMH;
|
||||
mp3dec_ex_t m_handle;
|
||||
mp3dec_frame_info_t m_frameInfo;
|
||||
bool m_bOpened;
|
||||
uint32 m_nRate;
|
||||
uint32 m_nChannels;
|
||||
const char* m_pPath;
|
||||
bool m_bFileNotOpenedYet;
|
||||
public:
|
||||
CMP3File(const char *path) :
|
||||
m_pMH(nil),
|
||||
m_bOpened(false),
|
||||
m_nRate(0),
|
||||
m_nChannels(0),
|
||||
m_pPath(path),
|
||||
m_bFileNotOpenedYet(false)
|
||||
m_nChannels(0)
|
||||
{
|
||||
m_pMH = mpg123_new(nil, nil);
|
||||
if ( m_pMH )
|
||||
int res = mp3dec_ex_open(&m_handle, path, MP3D_SEEK_TO_SAMPLE);
|
||||
if (res == 0)
|
||||
{
|
||||
mpg123_param(m_pMH, MPG123_FLAGS, MPG123_SEEKBUFFER | MPG123_GAPLESS, 0.0);
|
||||
|
||||
m_bOpened = true;
|
||||
m_bFileNotOpenedYet = true;
|
||||
// It's possible to move this to audioFileOpsThread(), but effect isn't noticable + probably not compatible with our current cutscene audio handling
|
||||
#if 1
|
||||
FileOpen();
|
||||
#endif
|
||||
m_nRate = m_handle.info.hz;
|
||||
m_nChannels = m_handle.info.channels;
|
||||
}
|
||||
}
|
||||
|
||||
void FileOpen()
|
||||
{
|
||||
if(!m_bFileNotOpenedYet) return;
|
||||
|
||||
long rate = 0;
|
||||
int channels = 0;
|
||||
int encoding = 0;
|
||||
m_bOpened = mpg123_open(m_pMH, m_pPath) == MPG123_OK
|
||||
&& mpg123_getformat(m_pMH, &rate, &channels, &encoding) == MPG123_OK;
|
||||
|
||||
m_nRate = rate;
|
||||
m_nChannels = channels;
|
||||
|
||||
if(IsOpened()) {
|
||||
mpg123_format_none(m_pMH);
|
||||
mpg123_format(m_pMH, rate, channels, encoding);
|
||||
}
|
||||
m_bFileNotOpenedYet = false;
|
||||
}
|
||||
|
||||
~CMP3File()
|
||||
{
|
||||
if ( m_pMH )
|
||||
{
|
||||
mpg123_close(m_pMH);
|
||||
mpg123_delete(m_pMH);
|
||||
m_pMH = nil;
|
||||
}
|
||||
mp3dec_ex_close(&m_handle);
|
||||
}
|
||||
|
||||
bool IsOpened()
|
||||
|
@ -571,13 +545,13 @@ public:
|
|||
|
||||
uint32 GetSampleSize()
|
||||
{
|
||||
return sizeof(uint16);
|
||||
return sizeof(mp3d_sample_t); // uint16
|
||||
}
|
||||
|
||||
uint32 GetSampleCount()
|
||||
{
|
||||
if ( !IsOpened() || m_bFileNotOpenedYet ) return 0;
|
||||
return mpg123_length(m_pMH);
|
||||
if ( !IsOpened() ) return 0;
|
||||
return m_handle.samples;
|
||||
}
|
||||
|
||||
uint32 GetSampleRate()
|
||||
|
@ -592,33 +566,35 @@ public:
|
|||
|
||||
void Seek(uint32 milliseconds)
|
||||
{
|
||||
if ( !IsOpened() || m_bFileNotOpenedYet ) return;
|
||||
mpg123_seek(m_pMH, ms2samples(milliseconds), SEEK_SET);
|
||||
if ( !IsOpened() ) return;
|
||||
mp3dec_ex_seek(&m_handle, ms2samples(milliseconds));
|
||||
}
|
||||
|
||||
uint32 Tell()
|
||||
{
|
||||
if ( !IsOpened() || m_bFileNotOpenedYet ) return 0;
|
||||
return samples2ms(mpg123_tell(m_pMH));
|
||||
if ( !IsOpened() ) return 0;
|
||||
return samples2ms(m_handle.cur_sample);
|
||||
}
|
||||
|
||||
uint32 Decode(void *buffer)
|
||||
{
|
||||
if ( !IsOpened() || m_bFileNotOpenedYet ) return 0;
|
||||
|
||||
size_t size;
|
||||
int err = mpg123_read(m_pMH, (unsigned char *)buffer, GetBufferSize(), &size);
|
||||
if ( !IsOpened() ) return 0;
|
||||
|
||||
size_t read_samples = mp3dec_ex_read(&m_handle, (mp3d_sample_t*)buffer, GetBufferSamples());
|
||||
if (read_samples == 0)
|
||||
return 0;
|
||||
|
||||
size_t read_bytes = read_samples * GetSampleSize();
|
||||
|
||||
#if defined(__LP64__) || defined(_WIN64)
|
||||
assert("We can't handle audio files more then 2 GB yet :shrug:" && (size < UINT32_MAX));
|
||||
assert("We can't handle this big audio files yet :shrug:" && (read_bytes < UINT32_MAX));
|
||||
#endif
|
||||
if (err != MPG123_OK && err != MPG123_DONE) return 0;
|
||||
if (GetChannels() == 2)
|
||||
SortStereoBuffer.SortStereo(buffer, size);
|
||||
return (uint32)size;
|
||||
SortStereoBuffer.SortStereo(buffer, read_bytes);
|
||||
return (uint32)read_bytes;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
#define VAG_LINE_SIZE (0x10)
|
||||
#define VAG_SAMPLES_IN_LINE (28)
|
||||
|
||||
|
@ -1013,28 +989,33 @@ CStream::FlagAsToBeProcessed(bool close)
|
|||
if (!close && MusicManager.m_nMusicMode == MUSICMODE_CUTSCENE)
|
||||
return;
|
||||
|
||||
gAudioThreadQueueMutex.lock();
|
||||
pthread_mutex_lock(&gAudioThreadQueueMutex);
|
||||
if (close)
|
||||
gStreamsToClose.push(std::pair<IDecoder*, void*>(m_pSoundFile ? m_pSoundFile : nil, m_pBuffer ? m_pBuffer : nil));
|
||||
else
|
||||
gStreamsToProcess.push(this);
|
||||
|
||||
gAudioThreadQueueMutex.unlock();
|
||||
pthread_mutex_unlock(&gAudioThreadQueueMutex);
|
||||
|
||||
gAudioThreadCv.notify_one();
|
||||
pthread_cond_broadcast(&gAudioThreadCv);
|
||||
}
|
||||
|
||||
void audioFileOpsThread()
|
||||
void* audioFileOpsThread(void* arg)
|
||||
{
|
||||
do
|
||||
{
|
||||
CStream *stream;
|
||||
{
|
||||
// Just a semaphore
|
||||
std::unique_lock<std::mutex> queueMutex(gAudioThreadQueueMutex);
|
||||
gAudioThreadCv.wait(queueMutex, [] { return gStreamsToProcess.size() > 0 || gStreamsToClose.size() > 0 || gAudioThreadTerm; });
|
||||
if (gAudioThreadTerm)
|
||||
return;
|
||||
pthread_mutex_lock(&gAudioThreadQueueMutex);
|
||||
|
||||
while (gStreamsToProcess.size() == 0 && gStreamsToClose.size() == 0 && !gAudioThreadTerm)
|
||||
pthread_cond_wait(&gAudioThreadCv, &gAudioThreadQueueMutex);
|
||||
|
||||
if (gAudioThreadTerm) {
|
||||
pthread_mutex_unlock(&gAudioThreadQueueMutex);
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (!gStreamsToClose.empty()) {
|
||||
auto streamToClose = gStreamsToClose.front();
|
||||
|
@ -1051,19 +1032,22 @@ void audioFileOpsThread()
|
|||
if (!gStreamsToProcess.empty()) {
|
||||
stream = gStreamsToProcess.front();
|
||||
gStreamsToProcess.pop();
|
||||
} else
|
||||
} else {
|
||||
pthread_mutex_unlock(&gAudioThreadQueueMutex);
|
||||
continue;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&gAudioThreadQueueMutex);
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> lock(stream->m_mutex);
|
||||
pthread_mutex_lock(&stream->m_mutex);
|
||||
|
||||
std::pair<ALuint, ALuint> buffers, *lastBufAddr;
|
||||
bool insertBufsAfterCheck = false;
|
||||
|
||||
do {
|
||||
if (!stream->IsOpened()) {
|
||||
if (!stream->IsOpened())
|
||||
break;
|
||||
}
|
||||
|
||||
if (stream->m_bReset)
|
||||
break;
|
||||
|
@ -1082,9 +1066,9 @@ void audioFileOpsThread()
|
|||
if (stream->m_bDoSeek) {
|
||||
stream->m_bDoSeek = false;
|
||||
int pos = stream->m_SeekPos;
|
||||
lock.unlock();
|
||||
pthread_mutex_unlock(&stream->m_mutex);
|
||||
stream->m_pSoundFile->Seek(pos);
|
||||
lock.lock();
|
||||
pthread_mutex_lock(&stream->m_mutex);
|
||||
|
||||
continue; // let's do the checks again, make sure we didn't miss anything while Seeking
|
||||
}
|
||||
|
@ -1097,12 +1081,12 @@ void audioFileOpsThread()
|
|||
if (!stream->m_fillBuffers.empty()) {
|
||||
lastBufAddr = &stream->m_fillBuffers.front();
|
||||
buffers = *lastBufAddr;
|
||||
lock.unlock();
|
||||
pthread_mutex_unlock(&stream->m_mutex);
|
||||
|
||||
ALuint alBuffers[2] = {buffers.first, buffers.second}; // left - right
|
||||
bool filled = stream->FillBuffer(alBuffers);
|
||||
|
||||
lock.lock();
|
||||
pthread_mutex_lock(&stream->m_mutex);
|
||||
|
||||
// Make sure queue isn't touched after we released mutex
|
||||
if (!stream->m_fillBuffers.empty() && lastBufAddr == &stream->m_fillBuffers.front()) {
|
||||
|
@ -1115,32 +1099,33 @@ void audioFileOpsThread()
|
|||
|
||||
} while (true);
|
||||
|
||||
pthread_mutex_unlock(&stream->m_mutex);
|
||||
|
||||
} while(true);
|
||||
|
||||
return nil;
|
||||
}
|
||||
#endif
|
||||
|
||||
void CStream::Initialise()
|
||||
{
|
||||
#ifdef AUDIO_OAL_USE_MPG123
|
||||
mpg123_init();
|
||||
#endif
|
||||
#ifdef MULTITHREADED_AUDIO
|
||||
gAudioThread = std::thread(audioFileOpsThread);
|
||||
pthread_mutex_init(&gAudioThreadQueueMutex, NULL);
|
||||
pthread_cond_init(&gAudioThreadCv, NULL);
|
||||
pthread_create(&gAudioThread, NULL, &audioFileOpsThread, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CStream::Terminate()
|
||||
{
|
||||
#ifdef AUDIO_OAL_USE_MPG123
|
||||
mpg123_exit();
|
||||
#endif
|
||||
#ifdef MULTITHREADED_AUDIO
|
||||
gAudioThreadQueueMutex.lock();
|
||||
pthread_mutex_lock(&gAudioThreadQueueMutex);
|
||||
gAudioThreadTerm = true;
|
||||
gAudioThreadQueueMutex.unlock();
|
||||
pthread_mutex_unlock(&gAudioThreadQueueMutex);
|
||||
|
||||
gAudioThreadCv.notify_one();
|
||||
gAudioThread.join();
|
||||
pthread_cond_broadcast(&gAudioThreadCv);
|
||||
void *status;
|
||||
pthread_join(gAudioThread, &status);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1163,6 +1148,9 @@ CStream::CStream(ALuint *sources, ALuint (&buffers)[NUM_STREAMBUFFERS]) :
|
|||
m_nLoopCount(1)
|
||||
|
||||
{
|
||||
#ifdef MULTITHREADED_AUDIO
|
||||
pthread_mutex_init(&m_mutex, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CStream::Open(const char* filename, uint32 overrideSampleRate)
|
||||
|
@ -1170,7 +1158,7 @@ bool CStream::Open(const char* filename, uint32 overrideSampleRate)
|
|||
if (IsOpened()) return false;
|
||||
|
||||
#ifdef MULTITHREADED_AUDIO
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
|
||||
m_bDoSeek = false;
|
||||
m_SeekPos = 0;
|
||||
|
@ -1205,10 +1193,8 @@ bool CStream::Open(const char* filename, uint32 overrideSampleRate)
|
|||
#else
|
||||
m_pSoundFile = new CWavFile(m_aFilename);
|
||||
#endif
|
||||
#ifdef AUDIO_OAL_USE_MPG123
|
||||
else if (!strcasecmp(&m_aFilename[strlen(m_aFilename) - strlen(".mp3")], ".mp3"))
|
||||
m_pSoundFile = new CMP3File(m_aFilename);
|
||||
#endif
|
||||
else if (!strcasecmp(&m_aFilename[strlen(m_aFilename) - strlen(".vb")], ".VB"))
|
||||
m_pSoundFile = new CVbFile(m_aFilename, overrideSampleRate);
|
||||
#ifdef AUDIO_OAL_USE_OPUS
|
||||
|
@ -1235,9 +1221,13 @@ bool CStream::Open(const char* filename, uint32 overrideSampleRate)
|
|||
}
|
||||
#ifdef MULTITHREADED_AUDIO
|
||||
m_bIExist = true;
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
#ifdef MULTITHREADED_AUDIO
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1252,13 +1242,15 @@ void CStream::Close()
|
|||
|
||||
#ifdef MULTITHREADED_AUDIO
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
|
||||
Stop();
|
||||
ClearBuffers();
|
||||
m_bIExist = false;
|
||||
std::queue<std::pair<ALuint, ALuint>>().swap(m_fillBuffers);
|
||||
tsQueue<std::pair<ALuint, ALuint>>().swapNts(m_queueBuffers); // TSness not required, mutex is acquired
|
||||
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
}
|
||||
|
||||
FlagAsToBeProcessed(true);
|
||||
|
@ -1309,11 +1301,14 @@ bool CStream::IsPlaying()
|
|||
return true;
|
||||
|
||||
#ifdef MULTITHREADED_AUDIO
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
|
||||
// Streams are designed in such a way that m_fillBuffers and m_queueBuffers will be *always* filled if audio is playing, and mutex is acquired
|
||||
if (!m_fillBuffers.empty() || !m_queueBuffers.emptyNts())
|
||||
if (!m_fillBuffers.empty() || !m_queueBuffers.emptyNts()) {
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
return true;
|
||||
}
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1391,7 +1386,7 @@ void CStream::SetPosMS(uint32 nPos)
|
|||
if ( !IsOpened() ) return;
|
||||
|
||||
#ifdef MULTITHREADED_AUDIO
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
|
||||
std::queue<std::pair<ALuint, ALuint>>().swap(m_fillBuffers);
|
||||
tsQueue<std::pair<ALuint, ALuint>>().swapNts(m_queueBuffers); // TSness not required, second thread always access it when stream mutex acquired
|
||||
|
@ -1405,7 +1400,10 @@ void CStream::SetPosMS(uint32 nPos)
|
|||
m_pSoundFile->Seek(nPos);
|
||||
}
|
||||
ClearBuffers();
|
||||
|
||||
|
||||
#ifdef MULTITHREADED_AUDIO
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
#endif
|
||||
// adding to gStreamsToProcess not needed, someone always calls Start() / BuffersShouldBeFilled() after SetPosMS
|
||||
}
|
||||
|
||||
|
@ -1518,7 +1516,7 @@ bool CStream::Setup(bool imSureQueueIsEmpty, bool lock)
|
|||
{
|
||||
#ifdef MULTITHREADED_AUDIO
|
||||
if (lock)
|
||||
m_mutex.lock();
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
#endif
|
||||
|
||||
if (!imSureQueueIsEmpty) {
|
||||
|
@ -1534,7 +1532,7 @@ bool CStream::Setup(bool imSureQueueIsEmpty, bool lock)
|
|||
}
|
||||
|
||||
if (lock)
|
||||
m_mutex.unlock();
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
#else
|
||||
m_pSoundFile->Seek(0);
|
||||
#endif
|
||||
|
@ -1593,10 +1591,15 @@ void CStream::Start()
|
|||
if ( !HasSource() ) return;
|
||||
|
||||
#ifdef MULTITHREADED_AUDIO
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
tsQueue<std::pair<ALuint, ALuint>>().swapNts(m_queueBuffers); // TSness not required, second thread always access it when stream mutex acquired
|
||||
#endif
|
||||
|
||||
BuffersShouldBeFilled();
|
||||
|
||||
#ifdef MULTITHREADED_AUDIO
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CStream::Stop()
|
||||
|
@ -1658,7 +1661,7 @@ void CStream::Update()
|
|||
if (m_nLoopCount != 1 && m_bActive && totalBuffers[0] == 0)
|
||||
{
|
||||
#ifdef MULTITHREADED_AUDIO
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
|
||||
if (m_fillBuffers.empty() && m_queueBuffers.emptyNts()) // we already acquired stream mutex, which is enough for second thread. thus Nts variant
|
||||
#endif
|
||||
|
@ -1668,6 +1671,9 @@ void CStream::Update()
|
|||
if (m_nLoopCount != 0)
|
||||
m_nLoopCount--;
|
||||
}
|
||||
#ifdef MULTITHREADED_AUDIO
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1689,7 +1695,7 @@ void CStream::Update()
|
|||
if (m_bActive && buffersProcessed[1])
|
||||
{
|
||||
#ifdef MULTITHREADED_AUDIO
|
||||
m_mutex.lock();
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
#endif
|
||||
while (!tempFillBuffer.empty()) {
|
||||
auto elem = tempFillBuffer.front();
|
||||
|
@ -1697,7 +1703,7 @@ void CStream::Update()
|
|||
buffersQueuedButNotStarted = BufferShouldBeFilledAndQueued(&elem);
|
||||
}
|
||||
#ifdef MULTITHREADED_AUDIO
|
||||
m_mutex.unlock();
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
FlagAsToBeProcessed();
|
||||
#endif
|
||||
|
||||
|
@ -1721,7 +1727,7 @@ void CStream::ProviderInit()
|
|||
SetLoopCount(m_nLoopCount);
|
||||
SetPosMS(m_nPosBeforeReset);
|
||||
#ifdef MULTITHREADED_AUDIO
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
#endif
|
||||
if(m_bActive)
|
||||
BuffersShouldBeFilled();
|
||||
|
@ -1733,17 +1739,20 @@ void CStream::ProviderInit()
|
|||
|
||||
} else {
|
||||
#ifdef MULTITHREADED_AUDIO
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
#endif
|
||||
m_bReset = false;
|
||||
}
|
||||
#ifdef MULTITHREADED_AUDIO
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void CStream::ProviderTerm()
|
||||
{
|
||||
#ifdef MULTITHREADED_AUDIO
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
|
||||
// unlike Close() we will reuse this stream, so clearing queues are important.
|
||||
std::queue<std::pair<ALuint, ALuint>>().swap(m_fillBuffers);
|
||||
|
@ -1754,6 +1763,9 @@ void CStream::ProviderTerm()
|
|||
|
||||
Stop();
|
||||
ClearBuffers();
|
||||
#ifdef MULTITHREADED_AUDIO
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -59,26 +59,32 @@ public:
|
|||
template <typename T> class tsQueue
|
||||
{
|
||||
public:
|
||||
tsQueue() : count(0) { }
|
||||
tsQueue() : count(0) {
|
||||
pthread_mutex_init(&m_mutex, NULL);
|
||||
}
|
||||
|
||||
void push(const T &value)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
m_queue.push(value);
|
||||
count++;
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
}
|
||||
|
||||
bool peekPop(T *retVal)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
if (count == 0)
|
||||
return false;
|
||||
bool peekPop(T *retVal)
|
||||
{
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
if (count == 0) {
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
return false;
|
||||
}
|
||||
|
||||
*retVal = m_queue.front();
|
||||
m_queue.pop();
|
||||
count--;
|
||||
return true;
|
||||
}
|
||||
*retVal = m_queue.front();
|
||||
m_queue.pop();
|
||||
count--;
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
return true;
|
||||
}
|
||||
|
||||
void swapNts(tsQueue<T> &replaceWith)
|
||||
{
|
||||
|
@ -89,9 +95,11 @@ public:
|
|||
/*
|
||||
void swapTs(tsQueue<T> &replaceWith)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
std::lock_guard<std::mutex> lock2(replaceWith.m_mutex);
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
pthread_mutex_lock(&replaceWith.m_mutex);
|
||||
swapNts(replaceWith);
|
||||
pthread_mutex_unlock(&replaceWith.m_mutex);
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
}
|
||||
*/
|
||||
|
||||
|
@ -103,14 +111,16 @@ public:
|
|||
/*
|
||||
bool emptyTs()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
return emptyNts();
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
bool isEmpty = emptyNts();
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
return isEmpty;
|
||||
}
|
||||
*/
|
||||
|
||||
std::queue<T> m_queue;
|
||||
int count;
|
||||
mutable std::mutex m_mutex;
|
||||
pthread_mutex_t m_mutex;
|
||||
};
|
||||
#endif
|
||||
class CStream
|
||||
|
@ -124,10 +134,9 @@ class CStream
|
|||
|
||||
public:
|
||||
#ifdef MULTITHREADED_AUDIO
|
||||
std::mutex m_mutex;
|
||||
pthread_mutex_t m_mutex;
|
||||
std::queue<std::pair<ALuint, ALuint>> m_fillBuffers; // left and right buffer
|
||||
tsQueue<std::pair<ALuint, ALuint>> m_queueBuffers;
|
||||
// std::condition_variable m_closeCv;
|
||||
bool m_bDoSeek;
|
||||
uint32 m_SeekPos;
|
||||
bool m_bIExist;
|
||||
|
|
|
@ -27,6 +27,10 @@
|
|||
#endif
|
||||
|
||||
#include "common.h"
|
||||
#ifdef MULTITHREADED_AUDIO
|
||||
#define XPLAT_PTHREAD
|
||||
#include <queue>
|
||||
#endif
|
||||
#include "crossplatform.h"
|
||||
|
||||
#include "sampman.h"
|
||||
|
@ -36,11 +40,6 @@
|
|||
#include "oal/channel.h"
|
||||
|
||||
#include <utility>
|
||||
#ifdef MULTITHREADED_AUDIO
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <condition_variable>
|
||||
#endif
|
||||
#include "oal/stream.h"
|
||||
|
||||
#include "AudioManager.h"
|
||||
|
|
|
@ -428,9 +428,8 @@ enum Config {
|
|||
#define PS2_AUDIO_CHANNELS // increases the maximum number of audio channels to PS2 value of 44 (PC has 28 originally)
|
||||
#define PS2_AUDIO_PATHS // changes audio paths for cutscenes and radio to PS2 paths (needs vbdec on MSS builds)
|
||||
//#define AUDIO_OAL_USE_SNDFILE // use libsndfile to decode WAVs instead of our internal decoder
|
||||
#define AUDIO_OAL_USE_MPG123 // use mpg123 to support mp3 files
|
||||
#define PAUSE_RADIO_IN_FRONTEND // pause radio when game is paused
|
||||
#define MULTITHREADED_AUDIO // for streams. requires C++11 or later
|
||||
#define MULTITHREADED_AUDIO // for streams
|
||||
|
||||
#ifdef AUDIO_OPUS
|
||||
#define AUDIO_OAL_USE_OPUS // enable support of opus files
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -279,3 +279,129 @@ char* casepath(char const* path, bool checkPathFirst)
|
|||
return out;
|
||||
}
|
||||
#endif
|
||||
|
||||
// pthread wrapper for Windows
|
||||
#if defined _MSC_VER
|
||||
|
||||
#include <Windows.h>
|
||||
typedef CRITICAL_SECTION pthread_mutex_t;
|
||||
typedef void pthread_mutexattr_t;
|
||||
typedef void pthread_condattr_t;
|
||||
typedef void pthread_rwlockattr_t;
|
||||
typedef HANDLE pthread_t;
|
||||
typedef CONDITION_VARIABLE pthread_cond_t;
|
||||
|
||||
int pthread_create(pthread_t *thread, void *attr, void * (__cdecl *start_routine) (void *), void *arg)
|
||||
{
|
||||
if (thread == NULL || start_routine == NULL)
|
||||
return 1;
|
||||
|
||||
*thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) start_routine, arg, 0, NULL);
|
||||
if (*thread == NULL)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_join(pthread_t thread, void **value_ptr)
|
||||
{
|
||||
WaitForSingleObject(thread, INFINITE);
|
||||
CloseHandle(thread);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_detach(pthread_t thread)
|
||||
{
|
||||
return CloseHandle(thread) ? 0 : 1;
|
||||
}
|
||||
|
||||
int pthread_mutex_init(pthread_mutex_t *mutex, pthread_mutexattr_t *attr)
|
||||
{
|
||||
if (mutex == NULL)
|
||||
return 1;
|
||||
|
||||
InitializeCriticalSection(mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_mutex_destroy(pthread_mutex_t *mutex)
|
||||
{
|
||||
if (mutex == NULL)
|
||||
return 1;
|
||||
DeleteCriticalSection(mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_mutex_lock(pthread_mutex_t *mutex)
|
||||
{
|
||||
if (mutex == NULL)
|
||||
return 1;
|
||||
EnterCriticalSection(mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_mutex_unlock(pthread_mutex_t *mutex)
|
||||
{
|
||||
if (mutex == NULL)
|
||||
return 1;
|
||||
LeaveCriticalSection(mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *attr)
|
||||
{
|
||||
if (cond == NULL)
|
||||
return 1;
|
||||
InitializeConditionVariable(cond);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_cond_destroy(pthread_cond_t *cond)
|
||||
{
|
||||
/* Windows does not have a destroy for conditionals */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DWORD timespec_to_ms(const struct timespec *abstime)
|
||||
{
|
||||
DWORD t;
|
||||
|
||||
if (abstime == NULL)
|
||||
return INFINITE;
|
||||
|
||||
t = ((abstime->tv_sec - time(NULL)) * 1000) + (abstime->tv_nsec / 1000000);
|
||||
if (t < 0)
|
||||
t = 1;
|
||||
return t;
|
||||
}
|
||||
|
||||
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
|
||||
const struct timespec *abstime)
|
||||
{
|
||||
if (cond == NULL || mutex == NULL)
|
||||
return 1;
|
||||
if (!SleepConditionVariableCS(cond, mutex, timespec_to_ms(abstime)))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
|
||||
{
|
||||
return pthread_cond_timedwait(cond, mutex, NULL);
|
||||
}
|
||||
|
||||
int pthread_cond_signal(pthread_cond_t *cond)
|
||||
{
|
||||
if (cond == NULL)
|
||||
return 1;
|
||||
WakeConditionVariable(cond);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_cond_broadcast(pthread_cond_t *cond)
|
||||
{
|
||||
if (cond == NULL)
|
||||
return 1;
|
||||
WakeAllConditionVariable(cond);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
|
@ -30,7 +30,16 @@ enum eWinVersion
|
|||
extern DWORD _dwOperatingSystemVersion;
|
||||
#define fcaseopen fopen
|
||||
#define caserename rename
|
||||
#else
|
||||
|
||||
#if defined _MSC_VER && _MSC_VER < 1900
|
||||
struct timespec {
|
||||
time_t tv_sec;
|
||||
long tv_nsec;
|
||||
};
|
||||
#endif
|
||||
|
||||
#else // ifndef _WIN32
|
||||
|
||||
char *strupr(char *str);
|
||||
char *strlwr(char *str);
|
||||
|
||||
|
@ -157,3 +166,37 @@ bool FindNextFile(HANDLE, WIN32_FIND_DATA*);
|
|||
void FileTimeToSystemTime(time_t*, SYSTEMTIME*);
|
||||
void GetDateFormat(int, int, SYSTEMTIME*, int, char*, int);
|
||||
#endif
|
||||
|
||||
#ifdef XPLAT_PTHREAD
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// pthread wrapper for Windows
|
||||
#include <Windows.h>
|
||||
|
||||
typedef CRITICAL_SECTION pthread_mutex_t;
|
||||
typedef void pthread_mutexattr_t;
|
||||
typedef void pthread_condattr_t;
|
||||
typedef void pthread_rwlockattr_t;
|
||||
typedef HANDLE pthread_t;
|
||||
typedef CONDITION_VARIABLE pthread_cond_t;
|
||||
|
||||
int pthread_create(pthread_t *thread, void *attr, void *(*start_routine)(void *), void *arg);
|
||||
int pthread_join(pthread_t thread, void **value_ptr);
|
||||
int pthread_detach(pthread_t);
|
||||
|
||||
int pthread_mutex_init(pthread_mutex_t *mutex, pthread_mutexattr_t *attr);
|
||||
int pthread_mutex_destroy(pthread_mutex_t *mutex);
|
||||
int pthread_mutex_lock(pthread_mutex_t *mutex);
|
||||
int pthread_mutex_unlock(pthread_mutex_t *mutex);
|
||||
|
||||
int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *attr);
|
||||
int pthread_cond_destroy(pthread_cond_t *cond);
|
||||
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
|
||||
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime);
|
||||
int pthread_cond_signal(pthread_cond_t *cond);
|
||||
int pthread_cond_broadcast(pthread_cond_t *cond);
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -1,159 +0,0 @@
|
|||
/*
|
||||
libmpg123: MPEG Audio Decoder library
|
||||
|
||||
separate header just for audio format definitions not tied to
|
||||
library code
|
||||
|
||||
copyright 1995-2020 by the mpg123 project
|
||||
free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
*/
|
||||
|
||||
#ifndef MPG123_ENC_H
|
||||
#define MPG123_ENC_H
|
||||
|
||||
/** \file fmt123.h Audio format definitions. */
|
||||
|
||||
/** \defgroup mpg123_enc mpg123 PCM sample encodings
|
||||
* These are definitions for audio formats used by libmpg123 and
|
||||
* libout123.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** An enum over all sample types possibly known to mpg123.
|
||||
* The values are designed as bit flags to allow bitmasking for encoding
|
||||
* families.
|
||||
* This is also why the enum is not used as type for actual encoding variables,
|
||||
* plain integers (at least 16 bit, 15 bit being used) cover the possible
|
||||
* combinations of these flags.
|
||||
*
|
||||
* Note that (your build of) libmpg123 does not necessarily support all these.
|
||||
* Usually, you can expect the 8bit encodings and signed 16 bit.
|
||||
* Also 32bit float will be usual beginning with mpg123-1.7.0 .
|
||||
* What you should bear in mind is that (SSE, etc) optimized routines may be
|
||||
* absent for some formats. We do have SSE for 16, 32 bit and float, though.
|
||||
* 24 bit integer is done via postprocessing of 32 bit output -- just cutting
|
||||
* the last byte, no rounding, even. If you want better, do it yourself.
|
||||
*
|
||||
* All formats are in native byte order. If you need different endinaness, you
|
||||
* can simply postprocess the output buffers (libmpg123 wouldn't do anything
|
||||
* else). The macro MPG123_SAMPLESIZE() can be helpful there.
|
||||
*/
|
||||
enum mpg123_enc_enum
|
||||
{
|
||||
/* 0000 0000 0000 1111 Some 8 bit integer encoding. */
|
||||
MPG123_ENC_8 = 0x00f
|
||||
/* 0000 0000 0100 0000 Some 16 bit integer encoding. */
|
||||
, MPG123_ENC_16 = 0x040
|
||||
/* 0100 0000 0000 0000 Some 24 bit integer encoding. */
|
||||
, MPG123_ENC_24 = 0x4000
|
||||
/* 0000 0001 0000 0000 Some 32 bit integer encoding. */
|
||||
, MPG123_ENC_32 = 0x100
|
||||
/* 0000 0000 1000 0000 Some signed integer encoding. */
|
||||
, MPG123_ENC_SIGNED = 0x080
|
||||
/* 0000 1110 0000 0000 Some float encoding. */
|
||||
, MPG123_ENC_FLOAT = 0xe00
|
||||
/* 0000 0000 1101 0000 signed 16 bit */
|
||||
, MPG123_ENC_SIGNED_16 = (MPG123_ENC_16|MPG123_ENC_SIGNED|0x10)
|
||||
/* 0000 0000 0110 0000 unsigned 16 bit */
|
||||
, MPG123_ENC_UNSIGNED_16 = (MPG123_ENC_16|0x20)
|
||||
/* 0000 0000 0000 0001 unsigned 8 bit */
|
||||
, MPG123_ENC_UNSIGNED_8 = 0x01
|
||||
/* 0000 0000 1000 0010 signed 8 bit */
|
||||
, MPG123_ENC_SIGNED_8 = (MPG123_ENC_SIGNED|0x02)
|
||||
/* 0000 0000 0000 0100 ulaw 8 bit */
|
||||
, MPG123_ENC_ULAW_8 = 0x04
|
||||
/* 0000 0000 0000 1000 alaw 8 bit */
|
||||
, MPG123_ENC_ALAW_8 = 0x08
|
||||
/* 0001 0001 1000 0000 signed 32 bit */
|
||||
, MPG123_ENC_SIGNED_32 = MPG123_ENC_32|MPG123_ENC_SIGNED|0x1000
|
||||
/* 0010 0001 0000 0000 unsigned 32 bit */
|
||||
, MPG123_ENC_UNSIGNED_32 = MPG123_ENC_32|0x2000
|
||||
/* 0101 0000 1000 0000 signed 24 bit */
|
||||
, MPG123_ENC_SIGNED_24 = MPG123_ENC_24|MPG123_ENC_SIGNED|0x1000
|
||||
/* 0110 0000 0000 0000 unsigned 24 bit */
|
||||
, MPG123_ENC_UNSIGNED_24 = MPG123_ENC_24|0x2000
|
||||
/* 0000 0010 0000 0000 32bit float */
|
||||
, MPG123_ENC_FLOAT_32 = 0x200
|
||||
/* 0000 0100 0000 0000 64bit float */
|
||||
, MPG123_ENC_FLOAT_64 = 0x400
|
||||
/* Any possibly known encoding from the list above. */
|
||||
, MPG123_ENC_ANY = ( MPG123_ENC_SIGNED_16 | MPG123_ENC_UNSIGNED_16
|
||||
| MPG123_ENC_UNSIGNED_8 | MPG123_ENC_SIGNED_8
|
||||
| MPG123_ENC_ULAW_8 | MPG123_ENC_ALAW_8
|
||||
| MPG123_ENC_SIGNED_32 | MPG123_ENC_UNSIGNED_32
|
||||
| MPG123_ENC_SIGNED_24 | MPG123_ENC_UNSIGNED_24
|
||||
| MPG123_ENC_FLOAT_32 | MPG123_ENC_FLOAT_64 )
|
||||
};
|
||||
|
||||
/** Get size of one PCM sample with given encoding.
|
||||
* This is included both in libmpg123 and libout123. Both offer
|
||||
* an API function to provide the macro results from library
|
||||
* compile-time, not that of you application. This most likely
|
||||
* does not matter as I do not expect any fresh PCM sample
|
||||
* encoding to appear. But who knows? Perhaps the encoding type
|
||||
* will be abused for funny things in future, not even plain PCM.
|
||||
* And, by the way: Thomas really likes the ?: operator.
|
||||
* \param enc the encoding (mpg123_enc_enum value)
|
||||
* \return size of one sample in bytes
|
||||
*/
|
||||
#define MPG123_SAMPLESIZE(enc) ( \
|
||||
(enc) < 1 \
|
||||
? 0 \
|
||||
: ( (enc) & MPG123_ENC_8 \
|
||||
? 1 \
|
||||
: ( (enc) & MPG123_ENC_16 \
|
||||
? 2 \
|
||||
: ( (enc) & MPG123_ENC_24 \
|
||||
? 3 \
|
||||
: ( ( (enc) & MPG123_ENC_32 \
|
||||
|| (enc) == MPG123_ENC_FLOAT_32 ) \
|
||||
? 4 \
|
||||
: ( (enc) == MPG123_ENC_FLOAT_64 \
|
||||
? 8 \
|
||||
: 0 \
|
||||
) ) ) ) ) )
|
||||
|
||||
/** Representation of zero in differing encodings.
|
||||
* This exists to define proper silence in various encodings without
|
||||
* having to link to libsyn123 to do actual conversions at runtime.
|
||||
* You have to handle big/little endian order yourself, though.
|
||||
* This takes the shortcut that any signed encoding has a zero with
|
||||
* all-zero bits. Unsigned linear encodings just have the highest bit set
|
||||
* (2^(n-1) for n bits), while the nonlinear 8-bit ones are special.
|
||||
* \param enc the encoding (mpg123_enc_enum value)
|
||||
* \param siz bytes per sample (return value of MPG123_SAMPLESIZE(enc))
|
||||
* \param off byte (octet) offset counted from LSB
|
||||
* \return unsigned byte value for the designated octet
|
||||
*/
|
||||
#define MPG123_ZEROSAMPLE(enc, siz, off) ( \
|
||||
(enc) == MPG123_ENC_ULAW_8 \
|
||||
? (off == 0 ? 0xff : 0x00) \
|
||||
: ( (enc) == MPG123_ENC_ALAW_8 \
|
||||
? (off == 0 ? 0xd5 : 0x00) \
|
||||
: ( (((enc) & (MPG123_ENC_SIGNED|MPG123_ENC_FLOAT)) || (siz) != ((off)+1)) \
|
||||
? 0x00 \
|
||||
: 0x80 \
|
||||
) ) )
|
||||
|
||||
/** Structure defining an audio format.
|
||||
* Providing the members as individual function arguments to define a certain
|
||||
* output format is easy enough. This struct makes is more comfortable to deal
|
||||
* with a list of formats.
|
||||
* Negative values for the members might be used to communicate use of default
|
||||
* values.
|
||||
*/
|
||||
struct mpg123_fmt
|
||||
{
|
||||
long rate; /**< sampling rate in Hz */
|
||||
int channels; /**< channel count */
|
||||
/** encoding code, can be single value or bitwise or of members of
|
||||
* mpg123_enc_enum */
|
||||
int encoding;
|
||||
};
|
||||
|
||||
/* @} */
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue