Show More
Commit Description:
Various UI improvements.
Commit Description:
Various UI improvements.
References:
File last commit:
Show/Diff file:
Action:
FNA/lib/FAudio/src/FAudio_internal.h
878 lines | 22.8 KiB | text/x-c | CLexer
878 lines | 22.8 KiB | text/x-c | CLexer
r0 | /* FAudio - XAudio Reimplementation for FNA | |||
* | ||||
* Copyright (c) 2011-2020 Ethan Lee, Luigi Auriemma, and the MonoGame Team | ||||
* | ||||
* This software is provided 'as-is', without any express or implied warranty. | ||||
* In no event will the authors be held liable for any damages arising from | ||||
* the use of this software. | ||||
* | ||||
* Permission is granted to anyone to use this software for any purpose, | ||||
* including commercial applications, and to alter it and redistribute it | ||||
* freely, subject to the following restrictions: | ||||
* | ||||
* 1. The origin of this software must not be misrepresented; you must not | ||||
* claim that you wrote the original software. If you use this software in a | ||||
* product, an acknowledgment in the product documentation would be | ||||
* appreciated but is not required. | ||||
* | ||||
* 2. Altered source versions must be plainly marked as such, and must not be | ||||
* misrepresented as being the original software. | ||||
* | ||||
* 3. This notice may not be removed or altered from any source distribution. | ||||
* | ||||
* Ethan "flibitijibibo" Lee <flibitijibibo@flibitijibibo.com> | ||||
* | ||||
*/ | ||||
#include "FAudio.h" | ||||
#include "FAPOBase.h" | ||||
#include <stdarg.h> | ||||
#ifdef FAUDIO_UNKNOWN_PLATFORM | ||||
#include <stdio.h> | ||||
#include <stdlib.h> | ||||
#include <string.h> | ||||
#include <math.h> | ||||
#include <assert.h> | ||||
#include <inttypes.h> | ||||
#define FAudio_malloc malloc | ||||
#define FAudio_realloc realloc | ||||
#define FAudio_free free | ||||
#define FAudio_alloca(x) alloca(uint8_t, x) | ||||
#define FAudio_dealloca(x) dealloca(x) | ||||
#define FAudio_zero(ptr, size) memset(ptr, '\0', size) | ||||
#define FAudio_memset(ptr, val, size) memset(ptr, val, size) | ||||
#define FAudio_memcpy(dst, src, size) memcpy(dst, src, size) | ||||
#define FAudio_memmove(dst, src, size) memmove(dst, src, size) | ||||
#define FAudio_memcmp(ptr1, ptr2, size) memcmp(ptr1, ptr2, size) | ||||
#define FAudio_strlen(ptr) strlen(ptr) | ||||
#define FAudio_strcmp(str1, str2) strcmp(str1, str2) | ||||
#define FAudio_strlcpy(ptr1, ptr2, size) strlcpy(ptr1, ptr2, size) | ||||
#define FAudio_pow(x, y) pow(x, y) | ||||
#define FAudio_log(x) log(x) | ||||
#define FAudio_log10(x) log10(x) | ||||
#define FAudio_sin(x) sin(x) | ||||
#define FAudio_cos(x) cos(x) | ||||
#define FAudio_tan(x) tan(x) | ||||
#define FAudio_acos(x) acos(x) | ||||
#define FAudio_ceil(x) ceil(x) | ||||
#define FAudio_floor(x) floor(x) | ||||
#define FAudio_abs(x) abs(x) | ||||
#define FAudio_ldexp(v, e) ldexp(v, e) | ||||
#define FAudio_exp(x) exp(x) | ||||
#define FAudio_cosf(x) cosf(x) | ||||
#define FAudio_sinf(x) sinf(x) | ||||
#define FAudio_sqrtf(x) sqrtf(x) | ||||
#define FAudio_acosf(x) acosf(x) | ||||
#define FAudio_atan2f(y, x) atan2f(y, x) | ||||
#define FAudio_fabsf(x) fabsf(x) | ||||
#define FAudio_qsort qsort | ||||
#define FAudio_assert assert | ||||
#define FAudio_snprintf snprintf | ||||
#define FAudio_vsnprintf vsnprintf | ||||
#define FAudio_Log(msg) fprintf(stderr, "%s\n", msg) | ||||
#define FAudio_getenv getenv | ||||
#define FAudio_PRIu64 PRIu64 | ||||
#define FAudio_PRIx64 PRIx64 | ||||
#else | ||||
#include <SDL_stdinc.h> | ||||
#include <SDL_assert.h> | ||||
#include <SDL_log.h> | ||||
#define FAudio_malloc SDL_malloc | ||||
#define FAudio_realloc SDL_realloc | ||||
#define FAudio_free SDL_free | ||||
#define FAudio_alloca(x) SDL_stack_alloc(uint8_t, x) | ||||
#define FAudio_dealloca(x) SDL_stack_free(x) | ||||
#define FAudio_zero(ptr, size) SDL_memset(ptr, '\0', size) | ||||
#define FAudio_memset(ptr, val, size) SDL_memset(ptr, val, size) | ||||
#define FAudio_memcpy(dst, src, size) SDL_memcpy(dst, src, size) | ||||
#define FAudio_memmove(dst, src, size) SDL_memmove(dst, src, size) | ||||
#define FAudio_memcmp(ptr1, ptr2, size) SDL_memcmp(ptr1, ptr2, size) | ||||
#define FAudio_strlen(ptr) SDL_strlen(ptr) | ||||
#define FAudio_strcmp(str1, str2) SDL_strcmp(str1, str2) | ||||
#define FAudio_strlcpy(ptr1, ptr2, size) SDL_strlcpy(ptr1, ptr2, size) | ||||
#define FAudio_pow(x, y) SDL_pow(x, y) | ||||
#define FAudio_log(x) SDL_log(x) | ||||
#define FAudio_log10(x) SDL_log10(x) | ||||
#define FAudio_sin(x) SDL_sin(x) | ||||
#define FAudio_cos(x) SDL_cos(x) | ||||
#define FAudio_tan(x) SDL_tan(x) | ||||
#define FAudio_acos(x) SDL_acos(x) | ||||
#define FAudio_ceil(x) SDL_ceil(x) | ||||
#define FAudio_floor(x) SDL_floor(x) | ||||
#define FAudio_abs(x) SDL_abs(x) | ||||
#define FAudio_ldexp(v, e) SDL_scalbn(v, e) | ||||
#define FAudio_exp(x) SDL_exp(x) | ||||
#define FAudio_cosf(x) SDL_cosf(x) | ||||
#define FAudio_sinf(x) SDL_sinf(x) | ||||
#define FAudio_sqrtf(x) SDL_sqrtf(x) | ||||
#define FAudio_acosf(x) SDL_acosf(x) | ||||
#define FAudio_atan2f(y, x) SDL_atan2f(y, x) | ||||
#define FAudio_fabsf(x) SDL_fabsf(x) | ||||
#define FAudio_qsort SDL_qsort | ||||
#ifdef FAUDIO_LOG_ASSERTIONS | ||||
#define FAudio_assert(condition) \ | ||||
{ \ | ||||
static uint8_t logged = 0; \ | ||||
if (!(condition) && !logged) \ | ||||
{ \ | ||||
SDL_Log("Assertion failed: %s", #condition); \ | ||||
logged = 1; \ | ||||
} \ | ||||
} | ||||
#else | ||||
#define FAudio_assert SDL_assert | ||||
#endif | ||||
#define FAudio_snprintf SDL_snprintf | ||||
#define FAudio_vsnprintf SDL_vsnprintf | ||||
#define FAudio_Log(msg) SDL_Log("%s", msg) | ||||
#define FAudio_getenv SDL_getenv | ||||
#define FAudio_PRIu64 SDL_PRIu64 | ||||
#define FAudio_PRIx64 SDL_PRIx64 | ||||
#endif | ||||
/* Easy Macros */ | ||||
#define FAudio_min(val1, val2) \ | ||||
(val1 < val2 ? val1 : val2) | ||||
#define FAudio_max(val1, val2) \ | ||||
(val1 > val2 ? val1 : val2) | ||||
#define FAudio_clamp(val, min, max) \ | ||||
(val > max ? max : (val < min ? min : val)) | ||||
/* Windows/Visual Studio cruft */ | ||||
#ifdef _WIN32 | ||||
#ifdef __cplusplus | ||||
/* C++ should have `inline`, but not `restrict` */ | ||||
#define restrict | ||||
#else | ||||
#define inline __inline | ||||
#if defined(_MSC_VER) | ||||
#if (_MSC_VER >= 1700) /* VS2012+ */ | ||||
#define restrict __restrict | ||||
#else /* VS2010- */ | ||||
#define restrict | ||||
#endif | ||||
#endif | ||||
#endif | ||||
#endif | ||||
/* C++ does not have restrict (though VS2012+ does have __restrict) */ | ||||
#if defined(__cplusplus) && !defined(restrict) | ||||
#define restrict | ||||
#endif | ||||
/* Threading Types */ | ||||
typedef void* FAudioThread; | ||||
typedef void* FAudioMutex; | ||||
typedef int32_t (FAUDIOCALL * FAudioThreadFunc)(void* data); | ||||
typedef enum FAudioThreadPriority | ||||
{ | ||||
FAUDIO_THREAD_PRIORITY_LOW, | ||||
FAUDIO_THREAD_PRIORITY_NORMAL, | ||||
FAUDIO_THREAD_PRIORITY_HIGH, | ||||
} FAudioThreadPriority; | ||||
/* Linked Lists */ | ||||
typedef struct LinkedList LinkedList; | ||||
struct LinkedList | ||||
{ | ||||
void* entry; | ||||
LinkedList *next; | ||||
}; | ||||
void LinkedList_AddEntry( | ||||
LinkedList **start, | ||||
void* toAdd, | ||||
FAudioMutex lock, | ||||
FAudioMallocFunc pMalloc | ||||
); | ||||
void LinkedList_PrependEntry( | ||||
LinkedList **start, | ||||
void* toAdd, | ||||
FAudioMutex lock, | ||||
FAudioMallocFunc pMalloc | ||||
); | ||||
void LinkedList_RemoveEntry( | ||||
LinkedList **start, | ||||
void* toRemove, | ||||
FAudioMutex lock, | ||||
FAudioFreeFunc pFree | ||||
); | ||||
/* Internal FAudio Types */ | ||||
typedef enum FAudioVoiceType | ||||
{ | ||||
FAUDIO_VOICE_SOURCE, | ||||
FAUDIO_VOICE_SUBMIX, | ||||
FAUDIO_VOICE_MASTER | ||||
} FAudioVoiceType; | ||||
typedef struct FAudioBufferEntry FAudioBufferEntry; | ||||
struct FAudioBufferEntry | ||||
{ | ||||
FAudioBuffer buffer; | ||||
FAudioBufferWMA bufferWMA; | ||||
FAudioBufferEntry *next; | ||||
}; | ||||
typedef void (FAUDIOCALL * FAudioDecodeCallback)( | ||||
FAudioVoice *voice, | ||||
FAudioBuffer *buffer, /* Buffer to decode */ | ||||
float *decodeCache, /* Decode into here */ | ||||
uint32_t samples /* Samples to decode */ | ||||
); | ||||
typedef void (FAUDIOCALL * FAudioResampleCallback)( | ||||
float *restrict dCache, | ||||
float *restrict resampleCache, | ||||
uint64_t *resampleOffset, | ||||
uint64_t resampleStep, | ||||
uint64_t toResample, | ||||
uint8_t channels | ||||
); | ||||
typedef void (FAUDIOCALL * FAudioMixCallback)( | ||||
uint32_t toMix, | ||||
uint32_t srcChans, | ||||
uint32_t dstChans, | ||||
float baseVolume, | ||||
float *restrict srcData, | ||||
float *restrict dstData, | ||||
float *restrict channelVolume, | ||||
float *restrict coefficients | ||||
); | ||||
typedef float FAudioFilterState[4]; | ||||
/* Operation Sets, original implementation by Tyler Glaiel */ | ||||
typedef struct FAudio_OPERATIONSET_Operation FAudio_OPERATIONSET_Operation; | ||||
void FAudio_OPERATIONSET_Commit(FAudio *audio, uint32_t OperationSet); | ||||
void FAudio_OPERATIONSET_CommitAll(FAudio *audio); | ||||
void FAudio_OPERATIONSET_Execute(FAudio *audio); | ||||
void FAudio_OPERATIONSET_ClearAll(FAudio *audio); | ||||
void FAudio_OPERATIONSET_ClearAllForVoice(FAudioVoice *voice); | ||||
void FAudio_OPERATIONSET_QueueEnableEffect( | ||||
FAudioVoice *voice, | ||||
uint32_t EffectIndex, | ||||
uint32_t OperationSet | ||||
); | ||||
void FAudio_OPERATIONSET_QueueDisableEffect( | ||||
FAudioVoice *voice, | ||||
uint32_t EffectIndex, | ||||
uint32_t OperationSet | ||||
); | ||||
void FAudio_OPERATIONSET_QueueSetEffectParameters( | ||||
FAudioVoice *voice, | ||||
uint32_t EffectIndex, | ||||
const void *pParameters, | ||||
uint32_t ParametersByteSize, | ||||
uint32_t OperationSet | ||||
); | ||||
void FAudio_OPERATIONSET_QueueSetFilterParameters( | ||||
FAudioVoice *voice, | ||||
const FAudioFilterParameters *pParameters, | ||||
uint32_t OperationSet | ||||
); | ||||
void FAudio_OPERATIONSET_QueueSetOutputFilterParameters( | ||||
FAudioVoice *voice, | ||||
FAudioVoice *pDestinationVoice, | ||||
const FAudioFilterParameters *pParameters, | ||||
uint32_t OperationSet | ||||
); | ||||
void FAudio_OPERATIONSET_QueueSetVolume( | ||||
FAudioVoice *voice, | ||||
float Volume, | ||||
uint32_t OperationSet | ||||
); | ||||
void FAudio_OPERATIONSET_QueueSetChannelVolumes( | ||||
FAudioVoice *voice, | ||||
uint32_t Channels, | ||||
const float *pVolumes, | ||||
uint32_t OperationSet | ||||
); | ||||
void FAudio_OPERATIONSET_QueueSetOutputMatrix( | ||||
FAudioVoice *voice, | ||||
FAudioVoice *pDestinationVoice, | ||||
uint32_t SourceChannels, | ||||
uint32_t DestinationChannels, | ||||
const float *pLevelMatrix, | ||||
uint32_t OperationSet | ||||
); | ||||
void FAudio_OPERATIONSET_QueueStart( | ||||
FAudioSourceVoice *voice, | ||||
uint32_t Flags, | ||||
uint32_t OperationSet | ||||
); | ||||
void FAudio_OPERATIONSET_QueueStop( | ||||
FAudioSourceVoice *voice, | ||||
uint32_t Flags, | ||||
uint32_t OperationSet | ||||
); | ||||
void FAudio_OPERATIONSET_QueueExitLoop( | ||||
FAudioSourceVoice *voice, | ||||
uint32_t OperationSet | ||||
); | ||||
void FAudio_OPERATIONSET_QueueSetFrequencyRatio( | ||||
FAudioSourceVoice *voice, | ||||
float Ratio, | ||||
uint32_t OperationSet | ||||
); | ||||
/* Public FAudio Types */ | ||||
struct FAudio | ||||
{ | ||||
uint8_t version; | ||||
uint8_t active; | ||||
uint32_t refcount; | ||||
uint32_t initFlags; | ||||
uint32_t updateSize; | ||||
FAudioMasteringVoice *master; | ||||
LinkedList *sources; | ||||
LinkedList *submixes; | ||||
LinkedList *callbacks; | ||||
FAudioMutex sourceLock; | ||||
FAudioMutex submixLock; | ||||
FAudioMutex callbackLock; | ||||
FAudioMutex operationLock; | ||||
FAudioWaveFormatExtensible mixFormat; | ||||
FAudio_OPERATIONSET_Operation *queuedOperations; | ||||
FAudio_OPERATIONSET_Operation *committedOperations; | ||||
/* Used to prevent destroying an active voice */ | ||||
FAudioSourceVoice *processingSource; | ||||
/* Temp storage for processing, interleaved PCM32F */ | ||||
#define EXTRA_DECODE_PADDING 2 | ||||
uint32_t decodeSamples; | ||||
uint32_t resampleSamples; | ||||
uint32_t effectChainSamples; | ||||
float *decodeCache; | ||||
float *resampleCache; | ||||
float *effectChainCache; | ||||
/* Allocator callbacks */ | ||||
FAudioMallocFunc pMalloc; | ||||
FAudioFreeFunc pFree; | ||||
FAudioReallocFunc pRealloc; | ||||
/* EngineProcedureEXT */ | ||||
void *clientEngineUser; | ||||
FAudioEngineProcedureEXT pClientEngineProc; | ||||
#ifndef FAUDIO_DISABLE_DEBUGCONFIGURATION | ||||
/* Debug Information */ | ||||
FAudioDebugConfiguration debug; | ||||
#endif /* FAUDIO_DISABLE_DEBUGCONFIGURATION */ | ||||
/* Platform opaque pointer */ | ||||
void *platform; | ||||
}; | ||||
struct FAudioVoice | ||||
{ | ||||
FAudio *audio; | ||||
uint32_t flags; | ||||
FAudioVoiceType type; | ||||
FAudioVoiceSends sends; | ||||
float **sendCoefficients; | ||||
FAudioMixCallback *sendMix; | ||||
FAudioFilterParameters *sendFilter; | ||||
FAudioFilterState **sendFilterState; | ||||
struct | ||||
{ | ||||
uint32_t count; | ||||
FAudioEffectDescriptor *desc; | ||||
void **parameters; | ||||
uint32_t *parameterSizes; | ||||
uint8_t *parameterUpdates; | ||||
uint8_t *inPlaceProcessing; | ||||
} effects; | ||||
FAudioFilterParameters filter; | ||||
FAudioFilterState *filterState; | ||||
FAudioMutex sendLock; | ||||
FAudioMutex effectLock; | ||||
FAudioMutex filterLock; | ||||
float volume; | ||||
float *channelVolume; | ||||
uint32_t outputChannels; | ||||
FAudioMutex volumeLock; | ||||
FAUDIONAMELESS union | ||||
{ | ||||
struct | ||||
{ | ||||
/* Sample storage */ | ||||
uint32_t decodeSamples; | ||||
uint32_t resampleSamples; | ||||
/* Resampler */ | ||||
float resampleFreq; | ||||
uint64_t resampleStep; | ||||
uint64_t resampleOffset; | ||||
uint64_t curBufferOffsetDec; | ||||
uint32_t curBufferOffset; | ||||
/* FFmpeg */ | ||||
#ifdef HAVE_FFMPEG | ||||
struct FAudioFFmpeg *ffmpeg; | ||||
#endif /* HAVE_FFMPEG*/ | ||||
/* Read-only */ | ||||
float maxFreqRatio; | ||||
FAudioWaveFormatEx *format; | ||||
FAudioDecodeCallback decode; | ||||
FAudioResampleCallback resample; | ||||
FAudioVoiceCallback *callback; | ||||
/* Dynamic */ | ||||
uint8_t active; | ||||
float freqRatio; | ||||
uint8_t newBuffer; | ||||
uint64_t totalSamples; | ||||
FAudioBufferEntry *bufferList; | ||||
FAudioBufferEntry *flushList; | ||||
FAudioMutex bufferLock; | ||||
} src; | ||||
struct | ||||
{ | ||||
/* Sample storage */ | ||||
uint32_t inputSamples; | ||||
uint32_t outputSamples; | ||||
float *inputCache; | ||||
uint64_t resampleStep; | ||||
FAudioResampleCallback resample; | ||||
/* Read-only */ | ||||
uint32_t inputChannels; | ||||
uint32_t inputSampleRate; | ||||
uint32_t processingStage; | ||||
} mix; | ||||
struct | ||||
{ | ||||
/* Output stream, allocated by Platform */ | ||||
float *output; | ||||
/* Needed when inputChannels != outputChannels */ | ||||
float *effectCache; | ||||
/* Read-only */ | ||||
uint32_t inputChannels; | ||||
uint32_t inputSampleRate; | ||||
} master; | ||||
}; | ||||
}; | ||||
/* Internal Functions */ | ||||
void FAudio_INTERNAL_InsertSubmixSorted( | ||||
LinkedList **start, | ||||
FAudioSubmixVoice *toAdd, | ||||
FAudioMutex lock, | ||||
FAudioMallocFunc pMalloc | ||||
); | ||||
void FAudio_INTERNAL_UpdateEngine(FAudio *audio, float *output); | ||||
void FAudio_INTERNAL_ResizeDecodeCache(FAudio *audio, uint32_t size); | ||||
void FAudio_INTERNAL_ResizeResampleCache(FAudio *audio, uint32_t size); | ||||
void FAudio_INTERNAL_ResizeEffectChainCache(FAudio *audio, uint32_t samples); | ||||
void FAudio_INTERNAL_AllocEffectChain( | ||||
FAudioVoice *voice, | ||||
const FAudioEffectChain *pEffectChain | ||||
); | ||||
void FAudio_INTERNAL_FreeEffectChain(FAudioVoice *voice); | ||||
uint32_t FAudio_INTERNAL_VoiceOutputFrequency( | ||||
FAudioVoice *voice, | ||||
const FAudioVoiceSends *pSendList | ||||
); | ||||
extern const float FAUDIO_INTERNAL_MATRIX_DEFAULTS[8][8][64]; | ||||
/* Debug */ | ||||
#ifdef FAUDIO_DISABLE_DEBUGCONFIGURATION | ||||
#define LOG_ERROR(engine, fmt, ...) | ||||
#define LOG_WARNING(engine, fmt, ...) | ||||
#define LOG_INFO(engine, fmt, ...) | ||||
#define LOG_DETAIL(engine, fmt, ...) | ||||
#define LOG_API_ENTER(engine) | ||||
#define LOG_API_EXIT(engine) | ||||
#define LOG_FUNC_ENTER(engine) | ||||
#define LOG_FUNC_EXIT(engine) | ||||
/* TODO: LOG_TIMING */ | ||||
#define LOG_MUTEX_CREATE(engine, mutex) | ||||
#define LOG_MUTEX_DESTROY(engine, mutex) | ||||
#define LOG_MUTEX_LOCK(engine, mutex) | ||||
#define LOG_MUTEX_UNLOCK(engine, mutex) | ||||
/* TODO: LOG_MEMORY */ | ||||
/* TODO: LOG_STREAMING */ | ||||
#define LOG_FORMAT(engine, waveFormat) | ||||
#else | ||||
#if defined(_MSC_VER) | ||||
/* VC doesn't support __attribute__ at all, and there's no replacement for format. */ | ||||
void FAudio_INTERNAL_debug( | ||||
FAudio *audio, | ||||
const char *file, | ||||
uint32_t line, | ||||
const char *func, | ||||
const char *fmt, | ||||
... | ||||
); | ||||
#if _MSC_VER <= 1700 /* <=2012 also doesn't support __func__ */ | ||||
#define __func__ __FUNCTION__ | ||||
#endif | ||||
#else | ||||
void FAudio_INTERNAL_debug( | ||||
FAudio *audio, | ||||
const char *file, | ||||
uint32_t line, | ||||
const char *func, | ||||
const char *fmt, | ||||
... | ||||
) __attribute__((format(printf,5,6))); | ||||
#endif | ||||
void FAudio_INTERNAL_debug_fmt( | ||||
FAudio *audio, | ||||
const char *file, | ||||
uint32_t line, | ||||
const char *func, | ||||
const FAudioWaveFormatEx *fmt | ||||
); | ||||
#define PRINT_DEBUG(engine, cond, type, fmt, ...) \ | ||||
if (engine->debug.TraceMask & FAUDIO_LOG_##cond) \ | ||||
{ \ | ||||
FAudio_INTERNAL_debug( \ | ||||
engine, \ | ||||
__FILE__, \ | ||||
__LINE__, \ | ||||
__func__, \ | ||||
type ": " fmt, \ | ||||
__VA_ARGS__ \ | ||||
); \ | ||||
} | ||||
#define LOG_ERROR(engine, fmt, ...) PRINT_DEBUG(engine, ERRORS, "ERROR", fmt, __VA_ARGS__) | ||||
#define LOG_WARNING(engine, fmt, ...) PRINT_DEBUG(engine, WARNINGS, "WARNING", fmt, __VA_ARGS__) | ||||
#define LOG_INFO(engine, fmt, ...) PRINT_DEBUG(engine, INFO, "INFO", fmt, __VA_ARGS__) | ||||
#define LOG_DETAIL(engine, fmt, ...) PRINT_DEBUG(engine, DETAIL, "DETAIL", fmt, __VA_ARGS__) | ||||
#define LOG_API_ENTER(engine) PRINT_DEBUG(engine, API_CALLS, "API Enter", "%s", __func__) | ||||
#define LOG_API_EXIT(engine) PRINT_DEBUG(engine, API_CALLS, "API Exit", "%s", __func__) | ||||
#define LOG_FUNC_ENTER(engine) PRINT_DEBUG(engine, FUNC_CALLS, "FUNC Enter", "%s", __func__) | ||||
#define LOG_FUNC_EXIT(engine) PRINT_DEBUG(engine, FUNC_CALLS, "FUNC Exit", "%s", __func__) | ||||
/* TODO: LOG_TIMING */ | ||||
#define LOG_MUTEX_CREATE(engine, mutex) PRINT_DEBUG(engine, LOCKS, "Mutex Create", "%p", mutex) | ||||
#define LOG_MUTEX_DESTROY(engine, mutex) PRINT_DEBUG(engine, LOCKS, "Mutex Destroy", "%p", mutex) | ||||
#define LOG_MUTEX_LOCK(engine, mutex) PRINT_DEBUG(engine, LOCKS, "Mutex Lock", "%p", mutex) | ||||
#define LOG_MUTEX_UNLOCK(engine, mutex) PRINT_DEBUG(engine, LOCKS, "Mutex Unlock", "%p", mutex) | ||||
/* TODO: LOG_MEMORY */ | ||||
/* TODO: LOG_STREAMING */ | ||||
#define LOG_FORMAT(engine, waveFormat) \ | ||||
if (engine->debug.TraceMask & FAUDIO_LOG_INFO) \ | ||||
{ \ | ||||
FAudio_INTERNAL_debug_fmt( \ | ||||
engine, \ | ||||
__FILE__, \ | ||||
__LINE__, \ | ||||
__func__, \ | ||||
waveFormat \ | ||||
); \ | ||||
} | ||||
#endif /* FAUDIO_DISABLE_DEBUGCONFIGURATION */ | ||||
/* FAPOFX Creators */ | ||||
#define CREATE_FAPOFX_FUNC(effect) \ | ||||
extern uint32_t FAPOFXCreate##effect( \ | ||||
FAPO **pEffect, \ | ||||
const void *pInitData, \ | ||||
uint32_t InitDataByteSize, \ | ||||
FAudioMallocFunc customMalloc, \ | ||||
FAudioFreeFunc customFree, \ | ||||
FAudioReallocFunc customRealloc, \ | ||||
uint8_t legacy \ | ||||
); | ||||
CREATE_FAPOFX_FUNC(EQ) | ||||
CREATE_FAPOFX_FUNC(MasteringLimiter) | ||||
CREATE_FAPOFX_FUNC(Reverb) | ||||
CREATE_FAPOFX_FUNC(Echo) | ||||
#undef CREATE_FAPOFX_FUNC | ||||
/* SIMD Stuff */ | ||||
/* Callbacks declared as functions (rather than function pointers) are | ||||
* scalar-only, for now. SIMD versions should be possible for these. | ||||
*/ | ||||
extern void (*FAudio_INTERNAL_Convert_U8_To_F32)( | ||||
const uint8_t *restrict src, | ||||
float *restrict dst, | ||||
uint32_t len | ||||
); | ||||
extern void (*FAudio_INTERNAL_Convert_S16_To_F32)( | ||||
const int16_t *restrict src, | ||||
float *restrict dst, | ||||
uint32_t len | ||||
); | ||||
extern void (*FAudio_INTERNAL_Convert_S32_To_F32)( | ||||
const int32_t *restrict src, | ||||
float *restrict dst, | ||||
uint32_t len | ||||
); | ||||
extern FAudioResampleCallback FAudio_INTERNAL_ResampleMono; | ||||
extern FAudioResampleCallback FAudio_INTERNAL_ResampleStereo; | ||||
extern void FAudio_INTERNAL_ResampleGeneric( | ||||
float *restrict dCache, | ||||
float *restrict resampleCache, | ||||
uint64_t *resampleOffset, | ||||
uint64_t resampleStep, | ||||
uint64_t toResample, | ||||
uint8_t channels | ||||
); | ||||
extern void (*FAudio_INTERNAL_Amplify)( | ||||
float *output, | ||||
uint32_t totalSamples, | ||||
float volume | ||||
); | ||||
#define MIX_FUNC(type) \ | ||||
extern void FAudio_INTERNAL_Mix_##type##_Scalar( \ | ||||
uint32_t toMix, \ | ||||
uint32_t srcChans, \ | ||||
uint32_t dstChans, \ | ||||
float baseVolume, \ | ||||
float *restrict srcData, \ | ||||
float *restrict dstData, \ | ||||
float *restrict channelVolume, \ | ||||
float *restrict coefficients \ | ||||
); | ||||
MIX_FUNC(Generic) | ||||
MIX_FUNC(1in_1out) | ||||
MIX_FUNC(1in_2out) | ||||
MIX_FUNC(1in_6out) | ||||
MIX_FUNC(1in_8out) | ||||
MIX_FUNC(2in_1out) | ||||
MIX_FUNC(2in_2out) | ||||
MIX_FUNC(2in_6out) | ||||
MIX_FUNC(2in_8out) | ||||
#undef MIX_FUNC | ||||
void FAudio_INTERNAL_InitSIMDFunctions(uint8_t hasSSE2, uint8_t hasNEON); | ||||
/* Decoders */ | ||||
#define DECODE_FUNC(type) \ | ||||
extern void FAudio_INTERNAL_Decode##type( \ | ||||
FAudioVoice *voice, \ | ||||
FAudioBuffer *buffer, \ | ||||
float *decodeCache, \ | ||||
uint32_t samples \ | ||||
); | ||||
DECODE_FUNC(PCM8) | ||||
DECODE_FUNC(PCM16) | ||||
DECODE_FUNC(PCM24) | ||||
DECODE_FUNC(PCM32) | ||||
DECODE_FUNC(PCM32F) | ||||
DECODE_FUNC(MonoMSADPCM) | ||||
DECODE_FUNC(StereoMSADPCM) | ||||
DECODE_FUNC(WMAERROR) | ||||
#ifdef HAVE_FFMPEG | ||||
DECODE_FUNC(FFMPEG) | ||||
#endif /* HAVE_FFMPEG */ | ||||
#undef DECODE_FUNC | ||||
/* FFmpeg */ | ||||
#ifdef HAVE_FFMPEG | ||||
uint32_t FAudio_FFMPEG_init(FAudioSourceVoice *pSourceVoice, uint32_t type); | ||||
void FAudio_FFMPEG_free(FAudioSourceVoice *voice); | ||||
void FAudio_FFMPEG_reset(FAudioSourceVoice *voice); | ||||
#endif /* HAVE_FFMPEG */ | ||||
/* Platform Functions */ | ||||
void FAudio_PlatformAddRef(void); | ||||
void FAudio_PlatformRelease(void); | ||||
void FAudio_PlatformInit( | ||||
FAudio *audio, | ||||
uint32_t flags, | ||||
uint32_t deviceIndex, | ||||
FAudioWaveFormatExtensible *mixFormat, | ||||
uint32_t *updateSize, | ||||
void** platformDevice | ||||
); | ||||
void FAudio_PlatformQuit(void* platformDevice); | ||||
uint32_t FAudio_PlatformGetDeviceCount(void); | ||||
uint32_t FAudio_PlatformGetDeviceDetails( | ||||
uint32_t index, | ||||
FAudioDeviceDetails *details | ||||
); | ||||
/* Threading */ | ||||
FAudioThread FAudio_PlatformCreateThread( | ||||
FAudioThreadFunc func, | ||||
const char *name, | ||||
void* data | ||||
); | ||||
void FAudio_PlatformWaitThread(FAudioThread thread, int32_t *retval); | ||||
void FAudio_PlatformThreadPriority(FAudioThreadPriority priority); | ||||
uint64_t FAudio_PlatformGetThreadID(void); | ||||
FAudioMutex FAudio_PlatformCreateMutex(void); | ||||
void FAudio_PlatformDestroyMutex(FAudioMutex mutex); | ||||
void FAudio_PlatformLockMutex(FAudioMutex mutex); | ||||
void FAudio_PlatformUnlockMutex(FAudioMutex mutex); | ||||
void FAudio_sleep(uint32_t ms); | ||||
/* Time */ | ||||
uint32_t FAudio_timems(void); | ||||
/* WaveFormatExtensible Helpers */ | ||||
static inline uint32_t GetMask(uint16_t channels) | ||||
{ | ||||
if (channels == 1) return SPEAKER_MONO; | ||||
if (channels == 2) return SPEAKER_STEREO; | ||||
if (channels == 3) return SPEAKER_2POINT1; | ||||
if (channels == 4) return SPEAKER_QUAD; | ||||
if (channels == 5) return SPEAKER_4POINT1; | ||||
if (channels == 6) return SPEAKER_5POINT1; | ||||
if (channels == 8) return SPEAKER_7POINT1; | ||||
FAudio_assert(0 && "Unrecognized speaker layout!"); | ||||
return 0; | ||||
} | ||||
static inline void WriteWaveFormatExtensible( | ||||
FAudioWaveFormatExtensible *fmt, | ||||
int channels, | ||||
int samplerate | ||||
) { | ||||
FAudio_assert(fmt != NULL); | ||||
fmt->Format.wBitsPerSample = 32; | ||||
fmt->Format.wFormatTag = FAUDIO_FORMAT_EXTENSIBLE; | ||||
fmt->Format.nChannels = channels; | ||||
fmt->Format.nSamplesPerSec = samplerate; | ||||
fmt->Format.nBlockAlign = ( | ||||
fmt->Format.nChannels * | ||||
(fmt->Format.wBitsPerSample / 8) | ||||
); | ||||
fmt->Format.nAvgBytesPerSec = ( | ||||
fmt->Format.nSamplesPerSec * | ||||
fmt->Format.nBlockAlign | ||||
); | ||||
fmt->Format.cbSize = sizeof(FAudioWaveFormatExtensible) - sizeof(FAudioWaveFormatEx); | ||||
fmt->Samples.wValidBitsPerSample = 32; | ||||
fmt->dwChannelMask = GetMask(fmt->Format.nChannels); | ||||
FAudio_memcpy(&fmt->SubFormat, &DATAFORMAT_SUBTYPE_IEEE_FLOAT, sizeof(FAudioGUID)); | ||||
} | ||||
/* Resampling */ | ||||
/* Okay, so here's what all this fixed-point goo is for: | ||||
* | ||||
* Inevitably you're going to run into weird sample rates, | ||||
* both from WaveBank data and from pitch shifting changes. | ||||
* | ||||
* How we deal with this is by calculating a fixed "step" | ||||
* value that steps from sample to sample at the speed needed | ||||
* to get the correct output sample rate, and the offset | ||||
* is stored as separate integer and fraction values. | ||||
* | ||||
* This allows us to do weird fractional steps between samples, | ||||
* while at the same time not letting it drift off into death | ||||
* thanks to floating point madness. | ||||
* | ||||
* Steps are stored in fixed-point with 32 bits for the fraction: | ||||
* | ||||
* 00000000000000000000000000000000 00000000000000000000000000000000 | ||||
* ^ Integer block (32) ^ Fraction block (32) | ||||
* | ||||
* For example, to get 1.5: | ||||
* 00000000000000000000000000000001 10000000000000000000000000000000 | ||||
* | ||||
* The Integer block works exactly like you'd expect. | ||||
* The Fraction block is divided by the Integer's "One" value. | ||||
* So, the above Fraction represented visually... | ||||
* 1 << 31 | ||||
* ------- | ||||
* 1 << 32 | ||||
* ... which, simplified, is... | ||||
* 1 << 0 | ||||
* ------ | ||||
* 1 << 1 | ||||
* ... in other words, 1 / 2, or 0.5. | ||||
*/ | ||||
#define FIXED_PRECISION 32 | ||||
#define FIXED_ONE (1LL << FIXED_PRECISION) | ||||
/* Quick way to drop parts */ | ||||
#define FIXED_FRACTION_MASK (FIXED_ONE - 1) | ||||
#define FIXED_INTEGER_MASK ~FIXED_FRACTION_MASK | ||||
/* Helper macros to convert fixed to float */ | ||||
#define DOUBLE_TO_FIXED(dbl) \ | ||||
((uint64_t) (dbl * FIXED_ONE + 0.5)) | ||||
#define FIXED_TO_DOUBLE(fxd) ( \ | ||||
(double) (fxd >> FIXED_PRECISION) + /* Integer part */ \ | ||||
((fxd & FIXED_FRACTION_MASK) * (1.0 / FIXED_ONE)) /* Fraction part */ \ | ||||
) | ||||
#define FIXED_TO_FLOAT(fxd) ( \ | ||||
(float) (fxd >> FIXED_PRECISION) + /* Integer part */ \ | ||||
((fxd & FIXED_FRACTION_MASK) * (1.0f / FIXED_ONE)) /* Fraction part */ \ | ||||
) | ||||
#ifdef FAUDIO_DUMP_VOICES | ||||
/* File writing structure */ | ||||
typedef size_t (FAUDIOCALL * FAudio_writefunc)( | ||||
void *data, | ||||
const void *src, | ||||
size_t size, | ||||
size_t count | ||||
); | ||||
typedef size_t (FAUDIOCALL * FAudio_sizefunc)( | ||||
void *data | ||||
); | ||||
typedef struct FAudioIOStreamOut | ||||
{ | ||||
void *data; | ||||
FAudio_readfunc read; | ||||
FAudio_writefunc write; | ||||
FAudio_seekfunc seek; | ||||
FAudio_sizefunc size; | ||||
FAudio_closefunc close; | ||||
void *lock; | ||||
} FAudioIOStreamOut; | ||||
FAudioIOStreamOut* FAudio_fopen_out(const char *path, const char *mode); | ||||
void FAudio_close_out(FAudioIOStreamOut *io); | ||||
#endif /* FAUDIO_DUMP_VOICES */ | ||||
/* vim: set noexpandtab shiftwidth=8 tabstop=8: */ | ||||