This commit is contained in:
erorcun 2021-08-15 12:38:38 +01:00 committed by GitHub
commit e80b71fa5d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 3596 additions and 2127 deletions

View File

@ -47,7 +47,6 @@ jobs:
mv ./bin/${{matrix.platform}}/${{matrix.buildtype}}/re3.pdb ./gamefiles/ mv ./bin/${{matrix.platform}}/${{matrix.buildtype}}/re3.pdb ./gamefiles/
- name: Move dynamic dependencies to gamefiles - name: Move dynamic dependencies to gamefiles
run: | run: |
mv ./vendor/mpg123/dist/Win64/libmpg123-0.dll ./gamefiles/
mv ./vendor/openal-soft/dist/Win64/OpenAL32.dll ./gamefiles/ mv ./vendor/openal-soft/dist/Win64/OpenAL32.dll ./gamefiles/
- name: Upload artifact to actions - name: Upload artifact to actions
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v2

View File

@ -48,7 +48,6 @@ jobs:
- if: contains(matrix.platform, 'oal') - if: contains(matrix.platform, 'oal')
name: Move dynamic dependencies to gamefiles name: Move dynamic dependencies to gamefiles
run: | run: |
mv ./vendor/mpg123/dist/Win32/libmpg123-0.dll ./gamefiles/
mv ./vendor/openal-soft/dist/Win32/OpenAL32.dll ./gamefiles/ mv ./vendor/openal-soft/dist/Win32/OpenAL32.dll ./gamefiles/
- name: Upload artifact to actions - name: Upload artifact to actions
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v2

View File

@ -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()

View File

@ -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()

View File

@ -305,16 +305,6 @@
<SETTING><NAME>FrameworkPath</NAME><VALUE>false</VALUE></SETTING> <SETTING><NAME>FrameworkPath</NAME><VALUE>false</VALUE></SETTING>
<SETTING><NAME>HostFlags</NAME><VALUE>All</VALUE></SETTING> <SETTING><NAME>HostFlags</NAME><VALUE>All</VALUE></SETTING>
</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>
<SETTING><NAME>SystemSearchPaths</NAME> <SETTING><NAME>SystemSearchPaths</NAME>
<SETTING> <SETTING>
@ -6554,16 +6544,6 @@
<SETTING><NAME>FrameworkPath</NAME><VALUE>false</VALUE></SETTING> <SETTING><NAME>FrameworkPath</NAME><VALUE>false</VALUE></SETTING>
<SETTING><NAME>HostFlags</NAME><VALUE>All</VALUE></SETTING> <SETTING><NAME>HostFlags</NAME><VALUE>All</VALUE></SETTING>
</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>
<SETTING><NAME>SystemSearchPaths</NAME> <SETTING><NAME>SystemSearchPaths</NAME>
<SETTING> <SETTING>
@ -13869,8 +13849,6 @@
<PATHFORMAT>Windows</PATHFORMAT> <PATHFORMAT>Windows</PATHFORMAT>
</FILEREF> </FILEREF>
</GROUP> </GROUP>
<GROUP><NAME>extras</NAME>
</GROUP>
<GROUP><NAME>math</NAME> <GROUP><NAME>math</NAME>
<FILEREF> <FILEREF>
<TARGETNAME>Debug</TARGETNAME> <TARGETNAME>Debug</TARGETNAME>

View File

@ -21,15 +21,6 @@ class Re3Conan(ConanFile):
"with_libsndfile": False, "with_libsndfile": False,
"with_opus": False, "with_opus": False,
# "libsndfile:with_external_libs": 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:vulkan": False,
# "sdl2:opengl": True, # "sdl2:opengl": True,
# "sdl2:sdl2main": True, # "sdl2:sdl2main": True,
@ -49,11 +40,9 @@ class Re3Conan(ConanFile):
def requirements(self): def requirements(self):
self.requires("librw/{}".format(self.version)) self.requires("librw/{}".format(self.version))
self.requires("mpg123/1.26.4")
if self.options.audio == "openal": if self.options.audio == "openal":
self.requires("openal/1.21.0") self.requires("openal/1.21.0")
elif self.options.audio == "miles":
self.requires("miles-sdk/{}".format(self.version))
if self.options.with_libsndfile: if self.options.with_libsndfile:
self.requires("libsndfile/1.0.30") self.requires("libsndfile/1.0.30")
if self.options.with_opus: if self.options.with_opus:

View File

@ -257,6 +257,7 @@ project "re3"
files { addSrcFiles("src/audio/oal") } files { addSrcFiles("src/audio/oal") }
files { addSrcFiles("src/buildings") } files { addSrcFiles("src/buildings") }
files { addSrcFiles("src/collision") } files { addSrcFiles("src/collision") }
files { addSrcFiles("src/external") }
files { addSrcFiles("src/control") } files { addSrcFiles("src/control") }
files { addSrcFiles("src/core") } files { addSrcFiles("src/core") }
files { addSrcFiles("src/entities") } files { addSrcFiles("src/entities") }
@ -286,6 +287,7 @@ project "re3"
includedirs { "src/audio/oal" } includedirs { "src/audio/oal" }
includedirs { "src/buildings" } includedirs { "src/buildings" }
includedirs { "src/collision" } includedirs { "src/collision" }
includedirs { "src/external" }
includedirs { "src/control" } includedirs { "src/control" }
includedirs { "src/core" } includedirs { "src/core" }
includedirs { "src/entities" } includedirs { "src/entities" }
@ -318,8 +320,8 @@ project "re3"
filter "platforms:*mss" filter "platforms:*mss"
defines { "AUDIO_MSS" } defines { "AUDIO_MSS" }
includedirs { "vendor/milessdk/include" } includedirs { "src/external/milessdk" }
libdirs { "vendor/milessdk/lib" } libdirs { "src/external/milessdk" }
if _OPTIONS["with-opus"] then if _OPTIONS["with-opus"] then
filter "platforms:win*" filter "platforms:win*"
@ -367,27 +369,24 @@ project "re3"
filter "platforms:win*oal" filter "platforms:win*oal"
includedirs { "vendor/openal-soft/include" } includedirs { "vendor/openal-soft/include" }
includedirs { "vendor/libsndfile/include" } includedirs { "src/external/libsndfile/include" }
includedirs { "vendor/mpg123/include" }
filter "platforms:win-x86*oal" filter "platforms:win-x86*oal"
libdirs { "vendor/mpg123/lib/Win32" } libdirs { "src/external/libsndfile/lib/Win32" }
libdirs { "vendor/libsndfile/lib/Win32" }
libdirs { "vendor/openal-soft/libs/Win32" } libdirs { "vendor/openal-soft/libs/Win32" }
filter "platforms:win-amd64*oal" filter "platforms:win-amd64*oal"
libdirs { "vendor/mpg123/lib/Win64" } libdirs { "src/external/libsndfile/lib/Win64" }
libdirs { "vendor/libsndfile/lib/Win64" }
libdirs { "vendor/openal-soft/libs/Win64" } libdirs { "vendor/openal-soft/libs/Win64" }
filter "platforms:linux*oal" filter "platforms:linux*oal"
links { "openal", "mpg123", "sndfile", "pthread", "X11" } links { "openal", "sndfile", "pthread", "X11" }
filter "platforms:bsd*oal" filter "platforms:bsd*oal"
links { "openal", "mpg123", "sndfile", "pthread", "X11" } links { "openal", "sndfile", "pthread", "X11" }
filter "platforms:macosx*oal" filter "platforms:macosx*oal"
links { "openal", "mpg123", "sndfile", "pthread" } links { "openal", "sndfile", "pthread" }
filter "platforms:macosx-arm64-*oal" filter "platforms:macosx-arm64-*oal"
includedirs { "/opt/homebrew/opt/openal-soft/include" } includedirs { "/opt/homebrew/opt/openal-soft/include" }

View File

@ -64,10 +64,6 @@ elseif(${PROJECT}_AUDIO STREQUAL "MSS")
target_link_libraries(${EXECUTABLE} PRIVATE MilesSDK::MilesSDK) target_link_libraries(${EXECUTABLE} PRIVATE MilesSDK::MilesSDK)
endif() endif()
find_package(mpg123 REQUIRED)
target_link_libraries(${EXECUTABLE} PRIVATE
MPG123::libmpg123
)
if(${PROJECT}_WITH_OPUS) if(${PROJECT}_WITH_OPUS)
find_package(opusfile REQUIRED) find_package(opusfile REQUIRED)
target_link_libraries(${EXECUTABLE} PRIVATE target_link_libraries(${EXECUTABLE} PRIVATE

View File

@ -6,47 +6,46 @@
#ifdef AUDIO_OAL_USE_SNDFILE #ifdef AUDIO_OAL_USE_SNDFILE
#pragma comment( lib, "libsndfile-1.lib" ) #pragma comment( lib, "libsndfile-1.lib" )
#endif #endif
#ifdef AUDIO_OAL_USE_MPG123
#pragma comment( lib, "libmpg123-0.lib" )
#endif
#endif #endif
#ifdef AUDIO_OAL_USE_SNDFILE #ifdef AUDIO_OAL_USE_SNDFILE
#include <sndfile.h> #include <sndfile.h>
#endif #endif
#ifdef AUDIO_OAL_USE_MPG123
#include <mpg123.h>
#endif
#ifdef AUDIO_OAL_USE_OPUS #ifdef AUDIO_OAL_USE_OPUS
#include <opusfile.h> #include <opusfile.h>
#endif #endif
#define MINIMP3_IMPLEMENTATION
#include "minimp3_ex.h"
#include <queue> #include <queue>
#include <utility> #include <utility>
#ifdef MULTITHREADED_AUDIO #ifdef MULTITHREADED_AUDIO
#include <iostream> #define XPLAT_PTHREAD
#include <thread> #include "crossplatform.h"
#include <mutex>
#include <condition_variable>
#include "MusicManager.h" #include "MusicManager.h"
#include "stream.h" #include "stream.h"
std::thread gAudioThread; pthread_t gAudioThread;
std::mutex gAudioThreadQueueMutex; pthread_mutex_t gAudioThreadQueueMutex;
std::condition_variable gAudioThreadCv; pthread_cond_t gAudioThreadCv;
bool gAudioThreadTerm = false; bool gAudioThreadTerm = false;
std::queue<CStream*> gStreamsToProcess; // values are not unique, we will handle that ourself std::queue<CStream*> gStreamsToProcess; // values are not unique, we will handle that ourself
std::queue<std::pair<IDecoder*, void*>> gStreamsToClose; std::queue<std::pair<IDecoder*, void*>> gStreamsToClose;
#else
#include "stream.h"
#endif
#include "sampman.h" #else
#include "stream.h"
#ifndef _WIN32 #ifndef _WIN32
#include "crossplatform.h" #include "crossplatform.h"
#endif #endif
#endif // not MULTITHREADED_AUDIO
#include "sampman.h"
/* /*
As we ran onto an issue of having different volume levels for mono streams 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. and stereo streams we are now handling all the stereo panning ourselves.
@ -61,7 +60,7 @@ class CSortStereoBuffer
uint16* PcmBuf; uint16* PcmBuf;
size_t BufSize; size_t BufSize;
//#ifdef MULTITHREADED_AUDIO //#ifdef MULTITHREADED_AUDIO
// std::mutex Mutex; // pthread_mutex_t Mutex;
//#endif //#endif
public: public:
@ -91,12 +90,17 @@ public:
void SortStereo(void* buf, size_t size) void SortStereo(void* buf, size_t size)
{ {
//#ifdef MULTITHREADED_AUDIO //#ifdef MULTITHREADED_AUDIO
// std::lock_guard<std::mutex> lock(Mutex); // pthread_mutex_lock(&Mutex);
//#endif //#endif
uint16* InBuf = (uint16*)buf; uint16* InBuf = (uint16*)buf;
uint16* OutBuf = GetBuffer(size); uint16* OutBuf = GetBuffer(size);
if (!OutBuf) return; if (!OutBuf) {
//#ifdef MULTITHREADED_AUDIO
// pthread_mutex_unlock(&Mutex);
//#endif
return;
}
size_t rightStart = size / 4; size_t rightStart = size / 4;
for (size_t i = 0; i < size / 4; i++) for (size_t i = 0; i < size / 4; i++)
@ -106,6 +110,9 @@ public:
} }
memcpy(InBuf, OutBuf, size); memcpy(InBuf, OutBuf, size);
//#ifdef MULTITHREADED_AUDIO
// pthread_mutex_unlock(&Mutex);
//#endif
} }
}; };
@ -500,68 +507,35 @@ public:
}; };
#endif #endif
#ifdef AUDIO_OAL_USE_MPG123
class CMP3File : public IDecoder class CMP3File : public IDecoder
{ {
protected: mp3dec_ex_t m_handle;
mpg123_handle *m_pMH; mp3dec_frame_info_t m_frameInfo;
bool m_bOpened; bool m_bOpened;
uint32 m_nRate; uint32 m_nRate;
uint32 m_nChannels; uint32 m_nChannels;
const char* m_pPath;
bool m_bFileNotOpenedYet;
public: public:
CMP3File(const char *path) : CMP3File(const char *path) :
m_pMH(nil),
m_bOpened(false), m_bOpened(false),
m_nRate(0), m_nRate(0),
m_nChannels(0), m_nChannels(0)
m_pPath(path),
m_bFileNotOpenedYet(false)
{ {
m_pMH = mpg123_new(nil, nil); int res = mp3dec_ex_open(&m_handle, path, MP3D_SEEK_TO_SAMPLE);
if ( m_pMH ) if (res == 0)
{ {
mpg123_param(m_pMH, MPG123_FLAGS, MPG123_SEEKBUFFER | MPG123_GAPLESS, 0.0);
m_bOpened = true; m_bOpened = true;
m_bFileNotOpenedYet = true; m_nRate = m_handle.info.hz;
// It's possible to move this to audioFileOpsThread(), but effect isn't noticable + probably not compatible with our current cutscene audio handling m_nChannels = m_handle.info.channels;
#if 1
FileOpen();
#endif
} }
} }
void FileOpen() 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() ~CMP3File()
{ {
if ( m_pMH ) mp3dec_ex_close(&m_handle);
{
mpg123_close(m_pMH);
mpg123_delete(m_pMH);
m_pMH = nil;
}
} }
bool IsOpened() bool IsOpened()
@ -571,13 +545,13 @@ public:
uint32 GetSampleSize() uint32 GetSampleSize()
{ {
return sizeof(uint16); return sizeof(mp3d_sample_t); // uint16
} }
uint32 GetSampleCount() uint32 GetSampleCount()
{ {
if ( !IsOpened() || m_bFileNotOpenedYet ) return 0; if ( !IsOpened() ) return 0;
return mpg123_length(m_pMH); return m_handle.samples;
} }
uint32 GetSampleRate() uint32 GetSampleRate()
@ -592,33 +566,35 @@ public:
void Seek(uint32 milliseconds) void Seek(uint32 milliseconds)
{ {
if ( !IsOpened() || m_bFileNotOpenedYet ) return; if ( !IsOpened() ) return;
mpg123_seek(m_pMH, ms2samples(milliseconds), SEEK_SET); mp3dec_ex_seek(&m_handle, ms2samples(milliseconds));
} }
uint32 Tell() uint32 Tell()
{ {
if ( !IsOpened() || m_bFileNotOpenedYet ) return 0; if ( !IsOpened() ) return 0;
return samples2ms(mpg123_tell(m_pMH)); return samples2ms(m_handle.cur_sample);
} }
uint32 Decode(void *buffer) uint32 Decode(void *buffer)
{ {
if ( !IsOpened() || m_bFileNotOpenedYet ) return 0; if ( !IsOpened() ) return 0;
size_t size; size_t read_samples = mp3dec_ex_read(&m_handle, (mp3d_sample_t*)buffer, GetBufferSamples());
int err = mpg123_read(m_pMH, (unsigned char *)buffer, GetBufferSize(), &size); if (read_samples == 0)
return 0;
size_t read_bytes = read_samples * GetSampleSize();
#if defined(__LP64__) || defined(_WIN64) #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 #endif
if (err != MPG123_OK && err != MPG123_DONE) return 0;
if (GetChannels() == 2) if (GetChannels() == 2)
SortStereoBuffer.SortStereo(buffer, size); SortStereoBuffer.SortStereo(buffer, read_bytes);
return (uint32)size; return (uint32)read_bytes;
} }
}; };
#endif
#define VAG_LINE_SIZE (0x10) #define VAG_LINE_SIZE (0x10)
#define VAG_SAMPLES_IN_LINE (28) #define VAG_SAMPLES_IN_LINE (28)
@ -1013,28 +989,33 @@ CStream::FlagAsToBeProcessed(bool close)
if (!close && MusicManager.m_nMusicMode == MUSICMODE_CUTSCENE) if (!close && MusicManager.m_nMusicMode == MUSICMODE_CUTSCENE)
return; return;
gAudioThreadQueueMutex.lock(); pthread_mutex_lock(&gAudioThreadQueueMutex);
if (close) if (close)
gStreamsToClose.push(std::pair<IDecoder*, void*>(m_pSoundFile ? m_pSoundFile : nil, m_pBuffer ? m_pBuffer : nil)); gStreamsToClose.push(std::pair<IDecoder*, void*>(m_pSoundFile ? m_pSoundFile : nil, m_pBuffer ? m_pBuffer : nil));
else else
gStreamsToProcess.push(this); gStreamsToProcess.push(this);
gAudioThreadQueueMutex.unlock(); pthread_mutex_unlock(&gAudioThreadQueueMutex);
gAudioThreadCv.notify_one(); pthread_cond_broadcast(&gAudioThreadCv);
} }
void audioFileOpsThread() void* audioFileOpsThread(void* arg)
{ {
do do
{ {
CStream *stream; CStream *stream;
{ {
// Just a semaphore // Just a semaphore
std::unique_lock<std::mutex> queueMutex(gAudioThreadQueueMutex); pthread_mutex_lock(&gAudioThreadQueueMutex);
gAudioThreadCv.wait(queueMutex, [] { return gStreamsToProcess.size() > 0 || gStreamsToClose.size() > 0 || gAudioThreadTerm; });
if (gAudioThreadTerm) while (gStreamsToProcess.size() == 0 && gStreamsToClose.size() == 0 && !gAudioThreadTerm)
return; pthread_cond_wait(&gAudioThreadCv, &gAudioThreadQueueMutex);
if (gAudioThreadTerm) {
pthread_mutex_unlock(&gAudioThreadQueueMutex);
return nil;
}
if (!gStreamsToClose.empty()) { if (!gStreamsToClose.empty()) {
auto streamToClose = gStreamsToClose.front(); auto streamToClose = gStreamsToClose.front();
@ -1051,19 +1032,22 @@ void audioFileOpsThread()
if (!gStreamsToProcess.empty()) { if (!gStreamsToProcess.empty()) {
stream = gStreamsToProcess.front(); stream = gStreamsToProcess.front();
gStreamsToProcess.pop(); gStreamsToProcess.pop();
} else } else {
pthread_mutex_unlock(&gAudioThreadQueueMutex);
continue; 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; std::pair<ALuint, ALuint> buffers, *lastBufAddr;
bool insertBufsAfterCheck = false; bool insertBufsAfterCheck = false;
do { do {
if (!stream->IsOpened()) { if (!stream->IsOpened())
break; break;
}
if (stream->m_bReset) if (stream->m_bReset)
break; break;
@ -1082,9 +1066,9 @@ void audioFileOpsThread()
if (stream->m_bDoSeek) { if (stream->m_bDoSeek) {
stream->m_bDoSeek = false; stream->m_bDoSeek = false;
int pos = stream->m_SeekPos; int pos = stream->m_SeekPos;
lock.unlock(); pthread_mutex_unlock(&stream->m_mutex);
stream->m_pSoundFile->Seek(pos); 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 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()) { if (!stream->m_fillBuffers.empty()) {
lastBufAddr = &stream->m_fillBuffers.front(); lastBufAddr = &stream->m_fillBuffers.front();
buffers = *lastBufAddr; buffers = *lastBufAddr;
lock.unlock(); pthread_mutex_unlock(&stream->m_mutex);
ALuint alBuffers[2] = {buffers.first, buffers.second}; // left - right ALuint alBuffers[2] = {buffers.first, buffers.second}; // left - right
bool filled = stream->FillBuffer(alBuffers); bool filled = stream->FillBuffer(alBuffers);
lock.lock(); pthread_mutex_lock(&stream->m_mutex);
// Make sure queue isn't touched after we released mutex // Make sure queue isn't touched after we released mutex
if (!stream->m_fillBuffers.empty() && lastBufAddr == &stream->m_fillBuffers.front()) { if (!stream->m_fillBuffers.empty() && lastBufAddr == &stream->m_fillBuffers.front()) {
@ -1115,32 +1099,33 @@ void audioFileOpsThread()
} while (true); } while (true);
pthread_mutex_unlock(&stream->m_mutex);
} while(true); } while(true);
return nil;
} }
#endif #endif
void CStream::Initialise() void CStream::Initialise()
{ {
#ifdef AUDIO_OAL_USE_MPG123
mpg123_init();
#endif
#ifdef MULTITHREADED_AUDIO #ifdef MULTITHREADED_AUDIO
gAudioThread = std::thread(audioFileOpsThread); pthread_mutex_init(&gAudioThreadQueueMutex, NULL);
pthread_cond_init(&gAudioThreadCv, NULL);
pthread_create(&gAudioThread, NULL, &audioFileOpsThread, NULL);
#endif #endif
} }
void CStream::Terminate() void CStream::Terminate()
{ {
#ifdef AUDIO_OAL_USE_MPG123
mpg123_exit();
#endif
#ifdef MULTITHREADED_AUDIO #ifdef MULTITHREADED_AUDIO
gAudioThreadQueueMutex.lock(); pthread_mutex_lock(&gAudioThreadQueueMutex);
gAudioThreadTerm = true; gAudioThreadTerm = true;
gAudioThreadQueueMutex.unlock(); pthread_mutex_unlock(&gAudioThreadQueueMutex);
gAudioThreadCv.notify_one(); pthread_cond_broadcast(&gAudioThreadCv);
gAudioThread.join(); void *status;
pthread_join(gAudioThread, &status);
#endif #endif
} }
@ -1163,6 +1148,9 @@ CStream::CStream(ALuint *sources, ALuint (&buffers)[NUM_STREAMBUFFERS]) :
m_nLoopCount(1) m_nLoopCount(1)
{ {
#ifdef MULTITHREADED_AUDIO
pthread_mutex_init(&m_mutex, NULL);
#endif
} }
bool CStream::Open(const char* filename, uint32 overrideSampleRate) bool CStream::Open(const char* filename, uint32 overrideSampleRate)
@ -1170,7 +1158,7 @@ bool CStream::Open(const char* filename, uint32 overrideSampleRate)
if (IsOpened()) return false; if (IsOpened()) return false;
#ifdef MULTITHREADED_AUDIO #ifdef MULTITHREADED_AUDIO
std::unique_lock<std::mutex> lock(m_mutex); pthread_mutex_lock(&m_mutex);
m_bDoSeek = false; m_bDoSeek = false;
m_SeekPos = 0; m_SeekPos = 0;
@ -1205,10 +1193,8 @@ bool CStream::Open(const char* filename, uint32 overrideSampleRate)
#else #else
m_pSoundFile = new CWavFile(m_aFilename); m_pSoundFile = new CWavFile(m_aFilename);
#endif #endif
#ifdef AUDIO_OAL_USE_MPG123
else if (!strcasecmp(&m_aFilename[strlen(m_aFilename) - strlen(".mp3")], ".mp3")) else if (!strcasecmp(&m_aFilename[strlen(m_aFilename) - strlen(".mp3")], ".mp3"))
m_pSoundFile = new CMP3File(m_aFilename); m_pSoundFile = new CMP3File(m_aFilename);
#endif
else if (!strcasecmp(&m_aFilename[strlen(m_aFilename) - strlen(".vb")], ".VB")) else if (!strcasecmp(&m_aFilename[strlen(m_aFilename) - strlen(".vb")], ".VB"))
m_pSoundFile = new CVbFile(m_aFilename, overrideSampleRate); m_pSoundFile = new CVbFile(m_aFilename, overrideSampleRate);
#ifdef AUDIO_OAL_USE_OPUS #ifdef AUDIO_OAL_USE_OPUS
@ -1235,9 +1221,13 @@ bool CStream::Open(const char* filename, uint32 overrideSampleRate)
} }
#ifdef MULTITHREADED_AUDIO #ifdef MULTITHREADED_AUDIO
m_bIExist = true; m_bIExist = true;
pthread_mutex_unlock(&m_mutex);
#endif #endif
return true; return true;
} }
#ifdef MULTITHREADED_AUDIO
pthread_mutex_unlock(&m_mutex);
#endif
return false; return false;
} }
@ -1252,13 +1242,15 @@ void CStream::Close()
#ifdef MULTITHREADED_AUDIO #ifdef MULTITHREADED_AUDIO
{ {
std::lock_guard<std::mutex> lock(m_mutex); pthread_mutex_lock(&m_mutex);
Stop(); Stop();
ClearBuffers(); ClearBuffers();
m_bIExist = false; m_bIExist = false;
std::queue<std::pair<ALuint, ALuint>>().swap(m_fillBuffers); std::queue<std::pair<ALuint, ALuint>>().swap(m_fillBuffers);
tsQueue<std::pair<ALuint, ALuint>>().swapNts(m_queueBuffers); // TSness not required, mutex is acquired tsQueue<std::pair<ALuint, ALuint>>().swapNts(m_queueBuffers); // TSness not required, mutex is acquired
pthread_mutex_unlock(&m_mutex);
} }
FlagAsToBeProcessed(true); FlagAsToBeProcessed(true);
@ -1309,11 +1301,14 @@ bool CStream::IsPlaying()
return true; return true;
#ifdef MULTITHREADED_AUDIO #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 // 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; return true;
}
pthread_mutex_unlock(&m_mutex);
#endif #endif
} }
@ -1391,7 +1386,7 @@ void CStream::SetPosMS(uint32 nPos)
if ( !IsOpened() ) return; if ( !IsOpened() ) return;
#ifdef MULTITHREADED_AUDIO #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); 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 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); m_pSoundFile->Seek(nPos);
} }
ClearBuffers(); ClearBuffers();
#ifdef MULTITHREADED_AUDIO
pthread_mutex_unlock(&m_mutex);
#endif
// adding to gStreamsToProcess not needed, someone always calls Start() / BuffersShouldBeFilled() after SetPosMS // 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 #ifdef MULTITHREADED_AUDIO
if (lock) if (lock)
m_mutex.lock(); pthread_mutex_lock(&m_mutex);
#endif #endif
if (!imSureQueueIsEmpty) { if (!imSureQueueIsEmpty) {
@ -1534,7 +1532,7 @@ bool CStream::Setup(bool imSureQueueIsEmpty, bool lock)
} }
if (lock) if (lock)
m_mutex.unlock(); pthread_mutex_unlock(&m_mutex);
#else #else
m_pSoundFile->Seek(0); m_pSoundFile->Seek(0);
#endif #endif
@ -1593,10 +1591,15 @@ void CStream::Start()
if ( !HasSource() ) return; if ( !HasSource() ) return;
#ifdef MULTITHREADED_AUDIO #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 tsQueue<std::pair<ALuint, ALuint>>().swapNts(m_queueBuffers); // TSness not required, second thread always access it when stream mutex acquired
#endif #endif
BuffersShouldBeFilled(); BuffersShouldBeFilled();
#ifdef MULTITHREADED_AUDIO
pthread_mutex_unlock(&m_mutex);
#endif
} }
void CStream::Stop() void CStream::Stop()
@ -1658,7 +1661,7 @@ void CStream::Update()
if (m_nLoopCount != 1 && m_bActive && totalBuffers[0] == 0) if (m_nLoopCount != 1 && m_bActive && totalBuffers[0] == 0)
{ {
#ifdef MULTITHREADED_AUDIO #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 if (m_fillBuffers.empty() && m_queueBuffers.emptyNts()) // we already acquired stream mutex, which is enough for second thread. thus Nts variant
#endif #endif
@ -1668,6 +1671,9 @@ void CStream::Update()
if (m_nLoopCount != 0) if (m_nLoopCount != 0)
m_nLoopCount--; m_nLoopCount--;
} }
#ifdef MULTITHREADED_AUDIO
pthread_mutex_unlock(&m_mutex);
#endif
} }
else else
{ {
@ -1689,7 +1695,7 @@ void CStream::Update()
if (m_bActive && buffersProcessed[1]) if (m_bActive && buffersProcessed[1])
{ {
#ifdef MULTITHREADED_AUDIO #ifdef MULTITHREADED_AUDIO
m_mutex.lock(); pthread_mutex_lock(&m_mutex);
#endif #endif
while (!tempFillBuffer.empty()) { while (!tempFillBuffer.empty()) {
auto elem = tempFillBuffer.front(); auto elem = tempFillBuffer.front();
@ -1697,7 +1703,7 @@ void CStream::Update()
buffersQueuedButNotStarted = BufferShouldBeFilledAndQueued(&elem); buffersQueuedButNotStarted = BufferShouldBeFilledAndQueued(&elem);
} }
#ifdef MULTITHREADED_AUDIO #ifdef MULTITHREADED_AUDIO
m_mutex.unlock(); pthread_mutex_unlock(&m_mutex);
FlagAsToBeProcessed(); FlagAsToBeProcessed();
#endif #endif
@ -1721,7 +1727,7 @@ void CStream::ProviderInit()
SetLoopCount(m_nLoopCount); SetLoopCount(m_nLoopCount);
SetPosMS(m_nPosBeforeReset); SetPosMS(m_nPosBeforeReset);
#ifdef MULTITHREADED_AUDIO #ifdef MULTITHREADED_AUDIO
std::unique_lock<std::mutex> lock(m_mutex); pthread_mutex_lock(&m_mutex);
#endif #endif
if(m_bActive) if(m_bActive)
BuffersShouldBeFilled(); BuffersShouldBeFilled();
@ -1733,17 +1739,20 @@ void CStream::ProviderInit()
} else { } else {
#ifdef MULTITHREADED_AUDIO #ifdef MULTITHREADED_AUDIO
std::unique_lock<std::mutex> lock(m_mutex); pthread_mutex_lock(&m_mutex);
#endif #endif
m_bReset = false; m_bReset = false;
} }
#ifdef MULTITHREADED_AUDIO
pthread_mutex_unlock(&m_mutex);
#endif
} }
} }
void CStream::ProviderTerm() void CStream::ProviderTerm()
{ {
#ifdef MULTITHREADED_AUDIO #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. // unlike Close() we will reuse this stream, so clearing queues are important.
std::queue<std::pair<ALuint, ALuint>>().swap(m_fillBuffers); std::queue<std::pair<ALuint, ALuint>>().swap(m_fillBuffers);
@ -1754,6 +1763,9 @@ void CStream::ProviderTerm()
Stop(); Stop();
ClearBuffers(); ClearBuffers();
#ifdef MULTITHREADED_AUDIO
pthread_mutex_unlock(&m_mutex);
#endif
} }
#endif #endif

View File

@ -59,26 +59,32 @@ public:
template <typename T> class tsQueue template <typename T> class tsQueue
{ {
public: public:
tsQueue() : count(0) { } tsQueue() : count(0) {
pthread_mutex_init(&m_mutex, NULL);
}
void push(const T &value) void push(const T &value)
{ {
std::lock_guard<std::mutex> lock(m_mutex); pthread_mutex_lock(&m_mutex);
m_queue.push(value); m_queue.push(value);
count++; count++;
pthread_mutex_unlock(&m_mutex);
} }
bool peekPop(T *retVal) bool peekPop(T *retVal)
{ {
std::lock_guard<std::mutex> lock(m_mutex); pthread_mutex_lock(&m_mutex);
if (count == 0) if (count == 0) {
return false; pthread_mutex_unlock(&m_mutex);
return false;
}
*retVal = m_queue.front(); *retVal = m_queue.front();
m_queue.pop(); m_queue.pop();
count--; count--;
return true; pthread_mutex_unlock(&m_mutex);
} return true;
}
void swapNts(tsQueue<T> &replaceWith) void swapNts(tsQueue<T> &replaceWith)
{ {
@ -89,9 +95,11 @@ public:
/* /*
void swapTs(tsQueue<T> &replaceWith) void swapTs(tsQueue<T> &replaceWith)
{ {
std::lock_guard<std::mutex> lock(m_mutex); pthread_mutex_lock(&m_mutex);
std::lock_guard<std::mutex> lock2(replaceWith.m_mutex); pthread_mutex_lock(&replaceWith.m_mutex);
swapNts(replaceWith); swapNts(replaceWith);
pthread_mutex_unlock(&replaceWith.m_mutex);
pthread_mutex_unlock(&m_mutex);
} }
*/ */
@ -103,14 +111,16 @@ public:
/* /*
bool emptyTs() bool emptyTs()
{ {
std::lock_guard<std::mutex> lock(m_mutex); pthread_mutex_lock(&m_mutex);
return emptyNts(); bool isEmpty = emptyNts();
pthread_mutex_unlock(&m_mutex);
return isEmpty;
} }
*/ */
std::queue<T> m_queue; std::queue<T> m_queue;
int count; int count;
mutable std::mutex m_mutex; pthread_mutex_t m_mutex;
}; };
#endif #endif
class CStream class CStream
@ -124,10 +134,9 @@ class CStream
public: public:
#ifdef MULTITHREADED_AUDIO #ifdef MULTITHREADED_AUDIO
std::mutex m_mutex; pthread_mutex_t m_mutex;
std::queue<std::pair<ALuint, ALuint>> m_fillBuffers; // left and right buffer std::queue<std::pair<ALuint, ALuint>> m_fillBuffers; // left and right buffer
tsQueue<std::pair<ALuint, ALuint>> m_queueBuffers; tsQueue<std::pair<ALuint, ALuint>> m_queueBuffers;
// std::condition_variable m_closeCv;
bool m_bDoSeek; bool m_bDoSeek;
uint32 m_SeekPos; uint32 m_SeekPos;
bool m_bIExist; bool m_bIExist;

View File

@ -27,6 +27,10 @@
#endif #endif
#include "common.h" #include "common.h"
#ifdef MULTITHREADED_AUDIO
#define XPLAT_PTHREAD
#include <queue>
#endif
#include "crossplatform.h" #include "crossplatform.h"
#include "sampman.h" #include "sampman.h"
@ -36,11 +40,6 @@
#include "oal/channel.h" #include "oal/channel.h"
#include <utility> #include <utility>
#ifdef MULTITHREADED_AUDIO
#include <mutex>
#include <queue>
#include <condition_variable>
#endif
#include "oal/stream.h" #include "oal/stream.h"
#include "AudioManager.h" #include "AudioManager.h"

View File

@ -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_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 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_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 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 #ifdef AUDIO_OPUS
#define AUDIO_OAL_USE_OPUS // enable support of opus files #define AUDIO_OAL_USE_OPUS // enable support of opus files

1855
src/external/minimp3.h vendored Normal file

File diff suppressed because it is too large Load Diff

1394
src/external/minimp3_ex.h vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -279,3 +279,129 @@ char* casepath(char const* path, bool checkPathFirst)
return out; return out;
} }
#endif #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

View File

@ -30,7 +30,16 @@ enum eWinVersion
extern DWORD _dwOperatingSystemVersion; extern DWORD _dwOperatingSystemVersion;
#define fcaseopen fopen #define fcaseopen fopen
#define caserename rename #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 *strupr(char *str);
char *strlwr(char *str); char *strlwr(char *str);
@ -157,3 +166,37 @@ bool FindNextFile(HANDLE, WIN32_FIND_DATA*);
void FileTimeToSystemTime(time_t*, SYSTEMTIME*); void FileTimeToSystemTime(time_t*, SYSTEMTIME*);
void GetDateFormat(int, int, SYSTEMTIME*, int, char*, int); void GetDateFormat(int, int, SYSTEMTIME*, int, char*, int);
#endif #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.

View File

@ -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.