mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-24 09:14:04 +02:00
Merge branch 'dev' of https://github.com/dr-soft/mini_al into dev
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
// Audio playback and capture library. Public domain. See "unlicense" statement at the end of this file.
|
// Audio playback and capture library. Public domain. See "unlicense" statement at the end of this file.
|
||||||
// mini_al - v0.8.11 - 2018-11-21
|
// mini_al - v0.8.12 - 2018-11-27
|
||||||
//
|
//
|
||||||
// David Reid - davidreidsoftware@gmail.com
|
// David Reid - davidreidsoftware@gmail.com
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
// - OSS (FreeBSD)
|
// - OSS (FreeBSD)
|
||||||
// - OpenSL|ES (Android only)
|
// - OpenSL|ES (Android only)
|
||||||
// - OpenAL
|
// - OpenAL
|
||||||
// - SDL
|
// - SDL2
|
||||||
// - Null (Silence)
|
// - Null (Silence)
|
||||||
//
|
//
|
||||||
// Supported Formats:
|
// Supported Formats:
|
||||||
@@ -77,8 +77,7 @@
|
|||||||
//
|
//
|
||||||
// Building for Emscripten
|
// Building for Emscripten
|
||||||
// -----------------------
|
// -----------------------
|
||||||
// The Emscripten build currently uses SDL 1.2 for it's backend which means specifying "-s USE_SDL=2" is unecessary
|
// The Emscripten build uses SDL2 and requires "-s USE_SDL=2" on the command line.
|
||||||
// as of this version.
|
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// Playback Example
|
// Playback Example
|
||||||
@@ -1840,16 +1839,11 @@ struct mal_context
|
|||||||
mal_handle hSDL; // SDL
|
mal_handle hSDL; // SDL
|
||||||
mal_proc SDL_InitSubSystem;
|
mal_proc SDL_InitSubSystem;
|
||||||
mal_proc SDL_QuitSubSystem;
|
mal_proc SDL_QuitSubSystem;
|
||||||
mal_proc SDL_CloseAudio;
|
|
||||||
mal_proc SDL_OpenAudio;
|
|
||||||
mal_proc SDL_PauseAudio;
|
|
||||||
mal_proc SDL_GetNumAudioDevices;
|
mal_proc SDL_GetNumAudioDevices;
|
||||||
mal_proc SDL_GetAudioDeviceName;
|
mal_proc SDL_GetAudioDeviceName;
|
||||||
mal_proc SDL_CloseAudioDevice;
|
mal_proc SDL_CloseAudioDevice;
|
||||||
mal_proc SDL_OpenAudioDevice;
|
mal_proc SDL_OpenAudioDevice;
|
||||||
mal_proc SDL_PauseAudioDevice;
|
mal_proc SDL_PauseAudioDevice;
|
||||||
|
|
||||||
mal_bool32 usingSDL1;
|
|
||||||
} sdl;
|
} sdl;
|
||||||
#endif
|
#endif
|
||||||
#ifdef MAL_SUPPORT_NULL
|
#ifdef MAL_SUPPORT_NULL
|
||||||
@@ -19564,8 +19558,6 @@ mal_result mal_context_init__openal(mal_context* pContext)
|
|||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
#ifdef MAL_HAS_SDL
|
#ifdef MAL_HAS_SDL
|
||||||
|
|
||||||
//#define MAL_USE_SDL_1
|
|
||||||
|
|
||||||
#define MAL_SDL_INIT_AUDIO 0x00000010
|
#define MAL_SDL_INIT_AUDIO 0x00000010
|
||||||
#define MAL_AUDIO_U8 0x0008
|
#define MAL_AUDIO_U8 0x0008
|
||||||
#define MAL_AUDIO_S16 0x8010
|
#define MAL_AUDIO_S16 0x8010
|
||||||
@@ -19582,11 +19574,6 @@ mal_result mal_context_init__openal(mal_context* pContext)
|
|||||||
#define SDL_MAIN_HANDLED
|
#define SDL_MAIN_HANDLED
|
||||||
#ifdef MAL_EMSCRIPTEN
|
#ifdef MAL_EMSCRIPTEN
|
||||||
#include <SDL/SDL.h>
|
#include <SDL/SDL.h>
|
||||||
|
|
||||||
// For now just use SDL 1.2 with Emscripten. This avoids the need for "-s USE_SDL=2" at compile time.
|
|
||||||
#ifndef MAL_USE_SDL_1
|
|
||||||
#define MAL_USE_SDL_1
|
|
||||||
#endif
|
|
||||||
#else
|
#else
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -19618,11 +19605,8 @@ typedef int (* MAL_PFN_SDL_InitSubSystem)(mal_uint32 flags);
|
|||||||
typedef void (* MAL_PFN_SDL_QuitSubSystem)(mal_uint32 flags);
|
typedef void (* MAL_PFN_SDL_QuitSubSystem)(mal_uint32 flags);
|
||||||
typedef int (* MAL_PFN_SDL_GetNumAudioDevices)(int iscapture);
|
typedef int (* MAL_PFN_SDL_GetNumAudioDevices)(int iscapture);
|
||||||
typedef const char* (* MAL_PFN_SDL_GetAudioDeviceName)(int index, int iscapture);
|
typedef const char* (* MAL_PFN_SDL_GetAudioDeviceName)(int index, int iscapture);
|
||||||
typedef void (* MAL_PFN_SDL_CloseAudio)(void);
|
|
||||||
typedef void (* MAL_PFN_SDL_CloseAudioDevice)(MAL_SDL_AudioDeviceID dev);
|
typedef void (* MAL_PFN_SDL_CloseAudioDevice)(MAL_SDL_AudioDeviceID dev);
|
||||||
typedef int (* MAL_PFN_SDL_OpenAudio)(MAL_SDL_AudioSpec* desired, MAL_SDL_AudioSpec* obtained);
|
|
||||||
typedef MAL_SDL_AudioDeviceID (* MAL_PFN_SDL_OpenAudioDevice)(const char* device, int iscapture, const MAL_SDL_AudioSpec* desired, MAL_SDL_AudioSpec* obtained, int allowed_changes);
|
typedef MAL_SDL_AudioDeviceID (* MAL_PFN_SDL_OpenAudioDevice)(const char* device, int iscapture, const MAL_SDL_AudioSpec* desired, MAL_SDL_AudioSpec* obtained, int allowed_changes);
|
||||||
typedef void (* MAL_PFN_SDL_PauseAudio)(int pause_on);
|
|
||||||
typedef void (* MAL_PFN_SDL_PauseAudioDevice)(MAL_SDL_AudioDeviceID dev, int pause_on);
|
typedef void (* MAL_PFN_SDL_PauseAudioDevice)(MAL_SDL_AudioDeviceID dev, int pause_on);
|
||||||
|
|
||||||
MAL_SDL_AudioFormat mal_format_to_sdl(mal_format format)
|
MAL_SDL_AudioFormat mal_format_to_sdl(mal_format format)
|
||||||
@@ -19665,68 +19649,42 @@ mal_result mal_context_enumerate_devices__sdl(mal_context* pContext, mal_enum_de
|
|||||||
mal_assert(pContext != NULL);
|
mal_assert(pContext != NULL);
|
||||||
mal_assert(callback != NULL);
|
mal_assert(callback != NULL);
|
||||||
|
|
||||||
#ifndef MAL_USE_SDL_1
|
mal_bool32 isTerminated = MAL_FALSE;
|
||||||
if (!pContext->sdl.usingSDL1) {
|
|
||||||
mal_bool32 isTerminated = MAL_FALSE;
|
|
||||||
|
|
||||||
// Playback
|
// Playback
|
||||||
if (!isTerminated) {
|
if (!isTerminated) {
|
||||||
int deviceCount = ((MAL_PFN_SDL_GetNumAudioDevices)pContext->sdl.SDL_GetNumAudioDevices)(0);
|
int deviceCount = ((MAL_PFN_SDL_GetNumAudioDevices)pContext->sdl.SDL_GetNumAudioDevices)(0);
|
||||||
for (int i = 0; i < deviceCount; ++i) {
|
for (int i = 0; i < deviceCount; ++i) {
|
||||||
mal_device_info deviceInfo;
|
|
||||||
mal_zero_object(&deviceInfo);
|
|
||||||
|
|
||||||
deviceInfo.id.sdl = i;
|
|
||||||
mal_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), ((MAL_PFN_SDL_GetAudioDeviceName)pContext->sdl.SDL_GetAudioDeviceName)(i, 0), (size_t)-1);
|
|
||||||
|
|
||||||
mal_bool32 cbResult = callback(pContext, mal_device_type_playback, &deviceInfo, pUserData);
|
|
||||||
if (cbResult == MAL_FALSE) {
|
|
||||||
isTerminated = MAL_TRUE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Capture
|
|
||||||
if (!isTerminated) {
|
|
||||||
int deviceCount = ((MAL_PFN_SDL_GetNumAudioDevices)pContext->sdl.SDL_GetNumAudioDevices)(1);
|
|
||||||
for (int i = 0; i < deviceCount; ++i) {
|
|
||||||
mal_device_info deviceInfo;
|
|
||||||
mal_zero_object(&deviceInfo);
|
|
||||||
|
|
||||||
deviceInfo.id.sdl = i;
|
|
||||||
mal_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), ((MAL_PFN_SDL_GetAudioDeviceName)pContext->sdl.SDL_GetAudioDeviceName)(i, 1), (size_t)-1);
|
|
||||||
|
|
||||||
mal_bool32 cbResult = callback(pContext, mal_device_type_capture, &deviceInfo, pUserData);
|
|
||||||
if (cbResult == MAL_FALSE) {
|
|
||||||
isTerminated = MAL_TRUE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
// SDL1 only uses default devices, and does not support capture.
|
|
||||||
mal_bool32 cbResult = MAL_TRUE;
|
|
||||||
|
|
||||||
// Playback.
|
|
||||||
if (cbResult) {
|
|
||||||
mal_device_info deviceInfo;
|
mal_device_info deviceInfo;
|
||||||
mal_zero_object(&deviceInfo);
|
mal_zero_object(&deviceInfo);
|
||||||
mal_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MAL_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
|
|
||||||
cbResult = callback(pContext, mal_device_type_playback, &deviceInfo, pUserData);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0 // No capture with SDL1.
|
deviceInfo.id.sdl = i;
|
||||||
// Capture.
|
mal_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), ((MAL_PFN_SDL_GetAudioDeviceName)pContext->sdl.SDL_GetAudioDeviceName)(i, 0), (size_t)-1);
|
||||||
if (cbResult) {
|
|
||||||
|
mal_bool32 cbResult = callback(pContext, mal_device_type_playback, &deviceInfo, pUserData);
|
||||||
|
if (cbResult == MAL_FALSE) {
|
||||||
|
isTerminated = MAL_TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Capture
|
||||||
|
if (!isTerminated) {
|
||||||
|
int deviceCount = ((MAL_PFN_SDL_GetNumAudioDevices)pContext->sdl.SDL_GetNumAudioDevices)(1);
|
||||||
|
for (int i = 0; i < deviceCount; ++i) {
|
||||||
mal_device_info deviceInfo;
|
mal_device_info deviceInfo;
|
||||||
mal_zero_object(&deviceInfo);
|
mal_zero_object(&deviceInfo);
|
||||||
mal_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MAL_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
|
|
||||||
cbResult = callback(pContext, mal_device_type_capture, &deviceInfo, pUserData);
|
deviceInfo.id.sdl = i;
|
||||||
|
mal_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), ((MAL_PFN_SDL_GetAudioDeviceName)pContext->sdl.SDL_GetAudioDeviceName)(i, 1), (size_t)-1);
|
||||||
|
|
||||||
|
mal_bool32 cbResult = callback(pContext, mal_device_type_capture, &deviceInfo, pUserData);
|
||||||
|
if (cbResult == MAL_FALSE) {
|
||||||
|
isTerminated = MAL_TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return MAL_SUCCESS;
|
return MAL_SUCCESS;
|
||||||
@@ -19737,24 +19695,7 @@ mal_result mal_context_get_device_info__sdl(mal_context* pContext, mal_device_ty
|
|||||||
mal_assert(pContext != NULL);
|
mal_assert(pContext != NULL);
|
||||||
(void)shareMode;
|
(void)shareMode;
|
||||||
|
|
||||||
#ifndef MAL_USE_SDL_1
|
if (pDeviceID == NULL) {
|
||||||
if (!pContext->sdl.usingSDL1) {
|
|
||||||
if (pDeviceID == NULL) {
|
|
||||||
if (deviceType == mal_device_type_playback) {
|
|
||||||
pDeviceInfo->id.sdl = 0;
|
|
||||||
mal_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MAL_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
|
|
||||||
} else {
|
|
||||||
pDeviceInfo->id.sdl = 0;
|
|
||||||
mal_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MAL_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pDeviceInfo->id.sdl = pDeviceID->sdl;
|
|
||||||
mal_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), ((MAL_PFN_SDL_GetAudioDeviceName)pContext->sdl.SDL_GetAudioDeviceName)(pDeviceID->sdl, (deviceType == mal_device_type_playback) ? 0 : 1), (size_t)-1);
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
// SDL1 uses default devices.
|
|
||||||
if (deviceType == mal_device_type_playback) {
|
if (deviceType == mal_device_type_playback) {
|
||||||
pDeviceInfo->id.sdl = 0;
|
pDeviceInfo->id.sdl = 0;
|
||||||
mal_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MAL_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
|
mal_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MAL_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
|
||||||
@@ -19762,6 +19703,9 @@ mal_result mal_context_get_device_info__sdl(mal_context* pContext, mal_device_ty
|
|||||||
pDeviceInfo->id.sdl = 0;
|
pDeviceInfo->id.sdl = 0;
|
||||||
mal_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MAL_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
|
mal_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MAL_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
pDeviceInfo->id.sdl = pDeviceID->sdl;
|
||||||
|
mal_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), ((MAL_PFN_SDL_GetAudioDeviceName)pContext->sdl.SDL_GetAudioDeviceName)(pDeviceID->sdl, (deviceType == mal_device_type_playback) ? 0 : 1), (size_t)-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// To get an accurate idea on the backend's native format we need to open the device. Not ideal, but it's the only way. An
|
// To get an accurate idea on the backend's native format we need to open the device. Not ideal, but it's the only way. An
|
||||||
@@ -19785,40 +19729,20 @@ mal_result mal_context_get_device_info__sdl(mal_context* pContext, mal_device_ty
|
|||||||
MAL_SDL_AudioSpec desiredSpec, obtainedSpec;
|
MAL_SDL_AudioSpec desiredSpec, obtainedSpec;
|
||||||
mal_zero_memory(&desiredSpec, sizeof(desiredSpec));
|
mal_zero_memory(&desiredSpec, sizeof(desiredSpec));
|
||||||
|
|
||||||
#ifndef MAL_USE_SDL_1
|
int isCapture = (deviceType == mal_device_type_playback) ? 0 : 1;
|
||||||
if (!pContext->sdl.usingSDL1) {
|
|
||||||
int isCapture = (deviceType == mal_device_type_playback) ? 0 : 1;
|
|
||||||
|
|
||||||
const char* pDeviceName = NULL;
|
const char* pDeviceName = NULL;
|
||||||
if (pDeviceID != NULL) {
|
if (pDeviceID != NULL) {
|
||||||
pDeviceName = ((MAL_PFN_SDL_GetAudioDeviceName)pContext->sdl.SDL_GetAudioDeviceName)(pDeviceID->sdl, isCapture);
|
pDeviceName = ((MAL_PFN_SDL_GetAudioDeviceName)pContext->sdl.SDL_GetAudioDeviceName)(pDeviceID->sdl, isCapture);
|
||||||
}
|
|
||||||
|
|
||||||
MAL_SDL_AudioDeviceID tempDeviceID = ((MAL_PFN_SDL_OpenAudioDevice)pContext->sdl.SDL_OpenAudioDevice)(pDeviceName, isCapture, &desiredSpec, &obtainedSpec, MAL_SDL_AUDIO_ALLOW_ANY_CHANGE);
|
|
||||||
if (tempDeviceID == 0) {
|
|
||||||
return mal_context_post_error(pContext, NULL, MAL_LOG_LEVEL_ERROR, "Failed to open SDL device.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE);
|
|
||||||
}
|
|
||||||
|
|
||||||
((MAL_PFN_SDL_CloseAudioDevice)pContext->sdl.SDL_CloseAudioDevice)(tempDeviceID);
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
// SDL1 uses default devices.
|
|
||||||
(void)pDeviceID;
|
|
||||||
|
|
||||||
// SDL1 only supports playback as far as I can tell.
|
|
||||||
if (deviceType != mal_device_type_playback) {
|
|
||||||
return MAL_NO_DEVICE;
|
|
||||||
}
|
|
||||||
|
|
||||||
MAL_SDL_AudioDeviceID tempDeviceID = ((MAL_PFN_SDL_OpenAudio)pContext->sdl.SDL_OpenAudio)(&desiredSpec, &obtainedSpec);
|
|
||||||
if (tempDeviceID != 0) {
|
|
||||||
return mal_context_post_error(pContext, NULL, MAL_LOG_LEVEL_ERROR, "Failed to open SDL device.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE);
|
|
||||||
}
|
|
||||||
|
|
||||||
((MAL_PFN_SDL_CloseAudio)pContext->sdl.SDL_CloseAudio)();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MAL_SDL_AudioDeviceID tempDeviceID = ((MAL_PFN_SDL_OpenAudioDevice)pContext->sdl.SDL_OpenAudioDevice)(pDeviceName, isCapture, &desiredSpec, &obtainedSpec, MAL_SDL_AUDIO_ALLOW_ANY_CHANGE);
|
||||||
|
if (tempDeviceID == 0) {
|
||||||
|
return mal_context_post_error(pContext, NULL, MAL_LOG_LEVEL_ERROR, "Failed to open SDL device.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE);
|
||||||
|
}
|
||||||
|
|
||||||
|
((MAL_PFN_SDL_CloseAudioDevice)pContext->sdl.SDL_CloseAudioDevice)(tempDeviceID);
|
||||||
|
|
||||||
pDeviceInfo->minChannels = obtainedSpec.channels;
|
pDeviceInfo->minChannels = obtainedSpec.channels;
|
||||||
pDeviceInfo->maxChannels = obtainedSpec.channels;
|
pDeviceInfo->maxChannels = obtainedSpec.channels;
|
||||||
pDeviceInfo->minSampleRate = obtainedSpec.freq;
|
pDeviceInfo->minSampleRate = obtainedSpec.freq;
|
||||||
@@ -19845,14 +19769,7 @@ void mal_device_uninit__sdl(mal_device* pDevice)
|
|||||||
{
|
{
|
||||||
mal_assert(pDevice != NULL);
|
mal_assert(pDevice != NULL);
|
||||||
|
|
||||||
#ifndef MAL_USE_SDL_1
|
((MAL_PFN_SDL_CloseAudioDevice)pDevice->pContext->sdl.SDL_CloseAudioDevice)(pDevice->sdl.deviceID);
|
||||||
if (!pDevice->pContext->sdl.usingSDL1) {
|
|
||||||
((MAL_PFN_SDL_CloseAudioDevice)pDevice->pContext->sdl.SDL_CloseAudioDevice)(pDevice->sdl.deviceID);
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
((MAL_PFN_SDL_CloseAudio)pDevice->pContext->sdl.SDL_CloseAudio)();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -19864,7 +19781,7 @@ void mal_audio_callback__sdl(void* pUserData, mal_uint8* pBuffer, int bufferSize
|
|||||||
mal_uint32 bufferSizeInFrames = (mal_uint32)bufferSizeInBytes / mal_get_bytes_per_frame(pDevice->internalFormat, pDevice->internalChannels);
|
mal_uint32 bufferSizeInFrames = (mal_uint32)bufferSizeInBytes / mal_get_bytes_per_frame(pDevice->internalFormat, pDevice->internalChannels);
|
||||||
|
|
||||||
#ifdef MAL_DEBUG_OUTPUT
|
#ifdef MAL_DEBUG_OUTPUT
|
||||||
printf("[SDL] Callback: bufferSizeInBytes=%d, bufferSizeInFrames=%d\n", bufferSizeInBytes, bufferSizeInFrames);
|
printf("[SDL] Callback: bufferSizeInBytes=%d, bufferSizeInFrames=%d\n", bufferSizeInBytes, bufferSizeInFrames);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (pDevice->type == mal_device_type_playback) {
|
if (pDevice->type == mal_device_type_playback) {
|
||||||
@@ -19912,41 +19829,16 @@ mal_result mal_device_init__sdl(mal_context* pContext, mal_device_type type, con
|
|||||||
desiredSpec.format = MAL_AUDIO_F32;
|
desiredSpec.format = MAL_AUDIO_F32;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef MAL_USE_SDL_1
|
int isCapture = (type == mal_device_type_playback) ? 0 : 1;
|
||||||
if (!pDevice->pContext->sdl.usingSDL1) {
|
|
||||||
int isCapture = (type == mal_device_type_playback) ? 0 : 1;
|
|
||||||
|
|
||||||
const char* pDeviceName = NULL;
|
const char* pDeviceName = NULL;
|
||||||
if (pDeviceID != NULL) {
|
if (pDeviceID != NULL) {
|
||||||
pDeviceName = ((MAL_PFN_SDL_GetAudioDeviceName)pDevice->pContext->sdl.SDL_GetAudioDeviceName)(pDeviceID->sdl, isCapture);
|
pDeviceName = ((MAL_PFN_SDL_GetAudioDeviceName)pDevice->pContext->sdl.SDL_GetAudioDeviceName)(pDeviceID->sdl, isCapture);
|
||||||
}
|
}
|
||||||
|
|
||||||
pDevice->sdl.deviceID = ((MAL_PFN_SDL_OpenAudioDevice)pDevice->pContext->sdl.SDL_OpenAudioDevice)(pDeviceName, isCapture, &desiredSpec, &obtainedSpec, MAL_SDL_AUDIO_ALLOW_ANY_CHANGE);
|
pDevice->sdl.deviceID = ((MAL_PFN_SDL_OpenAudioDevice)pDevice->pContext->sdl.SDL_OpenAudioDevice)(pDeviceName, isCapture, &desiredSpec, &obtainedSpec, MAL_SDL_AUDIO_ALLOW_ANY_CHANGE);
|
||||||
if (pDevice->sdl.deviceID == 0) {
|
if (pDevice->sdl.deviceID == 0) {
|
||||||
return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "Failed to open SDL2 device.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE);
|
return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "Failed to open SDL2 device.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE);
|
||||||
}
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
// SDL1 uses default devices.
|
|
||||||
(void)pDeviceID;
|
|
||||||
|
|
||||||
// SDL1 only supports playback as far as I can tell.
|
|
||||||
if (type != mal_device_type_playback) {
|
|
||||||
return MAL_NO_DEVICE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// SDL1 does not support floating point formats.
|
|
||||||
if (desiredSpec.format == MAL_AUDIO_F32) {
|
|
||||||
desiredSpec.format = MAL_AUDIO_S16;
|
|
||||||
}
|
|
||||||
|
|
||||||
int deviceID = ((MAL_PFN_SDL_OpenAudio)pDevice->pContext->sdl.SDL_OpenAudio)(&desiredSpec, &obtainedSpec);
|
|
||||||
if (deviceID < 0) {
|
|
||||||
return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "Failed to open SDL1 device.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE);
|
|
||||||
}
|
|
||||||
|
|
||||||
pDevice->sdl.deviceID = (mal_uint32)deviceID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pDevice->internalFormat = mal_format_from_sdl(obtainedSpec.format);
|
pDevice->internalFormat = mal_format_from_sdl(obtainedSpec.format);
|
||||||
@@ -19958,7 +19850,6 @@ mal_result mal_device_init__sdl(mal_context* pContext, mal_device_type type, con
|
|||||||
|
|
||||||
#ifdef MAL_DEBUG_OUTPUT
|
#ifdef MAL_DEBUG_OUTPUT
|
||||||
printf("=== SDL CONFIG ===\n");
|
printf("=== SDL CONFIG ===\n");
|
||||||
printf(" SDL VERSION: %s\n", pDevice->pContext->sdl.usingSDL1 ? "1" : "2");
|
|
||||||
printf(" FORMAT: %s -> %s\n", mal_get_format_name(pConfig->format), mal_get_format_name(pDevice->internalFormat));
|
printf(" FORMAT: %s -> %s\n", mal_get_format_name(pConfig->format), mal_get_format_name(pDevice->internalFormat));
|
||||||
printf(" CHANNELS: %d -> %d\n", desiredSpec.channels, obtainedSpec.channels);
|
printf(" CHANNELS: %d -> %d\n", desiredSpec.channels, obtainedSpec.channels);
|
||||||
printf(" SAMPLE RATE: %d -> %d\n", desiredSpec.freq, obtainedSpec.freq);
|
printf(" SAMPLE RATE: %d -> %d\n", desiredSpec.freq, obtainedSpec.freq);
|
||||||
@@ -19972,15 +19863,7 @@ mal_result mal_device__start_backend__sdl(mal_device* pDevice)
|
|||||||
{
|
{
|
||||||
mal_assert(pDevice != NULL);
|
mal_assert(pDevice != NULL);
|
||||||
|
|
||||||
#ifndef MAL_USE_SDL_1
|
((MAL_PFN_SDL_PauseAudioDevice)pDevice->pContext->sdl.SDL_PauseAudioDevice)(pDevice->sdl.deviceID, 0);
|
||||||
if (!pDevice->pContext->sdl.usingSDL1) {
|
|
||||||
((MAL_PFN_SDL_PauseAudioDevice)pDevice->pContext->sdl.SDL_PauseAudioDevice)(pDevice->sdl.deviceID, 0);
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
((MAL_PFN_SDL_PauseAudio)pDevice->pContext->sdl.SDL_PauseAudio)(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return MAL_SUCCESS;
|
return MAL_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19988,14 +19871,7 @@ mal_result mal_device__stop_backend__sdl(mal_device* pDevice)
|
|||||||
{
|
{
|
||||||
mal_assert(pDevice != NULL);
|
mal_assert(pDevice != NULL);
|
||||||
|
|
||||||
#ifndef MAL_USE_SDL_1
|
((MAL_PFN_SDL_PauseAudioDevice)pDevice->pContext->sdl.SDL_PauseAudioDevice)(pDevice->sdl.deviceID, 1);
|
||||||
if (!pDevice->pContext->sdl.usingSDL1) {
|
|
||||||
((MAL_PFN_SDL_PauseAudioDevice)pDevice->pContext->sdl.SDL_PauseAudioDevice)(pDevice->sdl.deviceID, 1);
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
((MAL_PFN_SDL_PauseAudio)pDevice->pContext->sdl.SDL_PauseAudio)(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
mal_device__set_state(pDevice, MAL_STATE_STOPPED);
|
mal_device__set_state(pDevice, MAL_STATE_STOPPED);
|
||||||
mal_stop_proc onStop = pDevice->onStop;
|
mal_stop_proc onStop = pDevice->onStop;
|
||||||
@@ -20024,14 +19900,11 @@ mal_result mal_context_init__sdl(mal_context* pContext)
|
|||||||
// Run-time linking.
|
// Run-time linking.
|
||||||
const char* libNames[] = {
|
const char* libNames[] = {
|
||||||
#if defined(MAL_WIN32)
|
#if defined(MAL_WIN32)
|
||||||
"SDL2.dll",
|
"SDL2.dll"
|
||||||
"SDL.dll"
|
|
||||||
#elif defined(MAL_APPLE)
|
#elif defined(MAL_APPLE)
|
||||||
"SDL2.framework/SDL2",
|
"SDL2.framework/SDL2"
|
||||||
"SDL.framework/SDL"
|
|
||||||
#else
|
#else
|
||||||
"libSDL2-2.0.so.0",
|
"libSDL2-2.0.so.0"
|
||||||
"libSDL-1.2.so.0"
|
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -20048,41 +19921,21 @@ mal_result mal_context_init__sdl(mal_context* pContext)
|
|||||||
|
|
||||||
pContext->sdl.SDL_InitSubSystem = mal_dlsym(pContext->sdl.hSDL, "SDL_InitSubSystem");
|
pContext->sdl.SDL_InitSubSystem = mal_dlsym(pContext->sdl.hSDL, "SDL_InitSubSystem");
|
||||||
pContext->sdl.SDL_QuitSubSystem = mal_dlsym(pContext->sdl.hSDL, "SDL_QuitSubSystem");
|
pContext->sdl.SDL_QuitSubSystem = mal_dlsym(pContext->sdl.hSDL, "SDL_QuitSubSystem");
|
||||||
pContext->sdl.SDL_CloseAudio = mal_dlsym(pContext->sdl.hSDL, "SDL_CloseAudio");
|
|
||||||
pContext->sdl.SDL_OpenAudio = mal_dlsym(pContext->sdl.hSDL, "SDL_OpenAudio");
|
|
||||||
pContext->sdl.SDL_PauseAudio = mal_dlsym(pContext->sdl.hSDL, "SDL_PauseAudio");
|
|
||||||
#ifndef MAL_USE_SDL_1
|
|
||||||
pContext->sdl.SDL_GetNumAudioDevices = mal_dlsym(pContext->sdl.hSDL, "SDL_GetNumAudioDevices");
|
pContext->sdl.SDL_GetNumAudioDevices = mal_dlsym(pContext->sdl.hSDL, "SDL_GetNumAudioDevices");
|
||||||
pContext->sdl.SDL_GetAudioDeviceName = mal_dlsym(pContext->sdl.hSDL, "SDL_GetAudioDeviceName");
|
pContext->sdl.SDL_GetAudioDeviceName = mal_dlsym(pContext->sdl.hSDL, "SDL_GetAudioDeviceName");
|
||||||
pContext->sdl.SDL_CloseAudioDevice = mal_dlsym(pContext->sdl.hSDL, "SDL_CloseAudioDevice");
|
pContext->sdl.SDL_CloseAudioDevice = mal_dlsym(pContext->sdl.hSDL, "SDL_CloseAudioDevice");
|
||||||
pContext->sdl.SDL_OpenAudioDevice = mal_dlsym(pContext->sdl.hSDL, "SDL_OpenAudioDevice");
|
pContext->sdl.SDL_OpenAudioDevice = mal_dlsym(pContext->sdl.hSDL, "SDL_OpenAudioDevice");
|
||||||
pContext->sdl.SDL_PauseAudioDevice = mal_dlsym(pContext->sdl.hSDL, "SDL_PauseAudioDevice");
|
pContext->sdl.SDL_PauseAudioDevice = mal_dlsym(pContext->sdl.hSDL, "SDL_PauseAudioDevice");
|
||||||
#endif
|
|
||||||
#else
|
#else
|
||||||
// Compile-time linking.
|
// Compile-time linking.
|
||||||
pContext->sdl.SDL_InitSubSystem = (mal_proc)SDL_InitSubSystem;
|
pContext->sdl.SDL_InitSubSystem = (mal_proc)SDL_InitSubSystem;
|
||||||
pContext->sdl.SDL_QuitSubSystem = (mal_proc)SDL_QuitSubSystem;
|
pContext->sdl.SDL_QuitSubSystem = (mal_proc)SDL_QuitSubSystem;
|
||||||
pContext->sdl.SDL_CloseAudio = (mal_proc)SDL_CloseAudio;
|
|
||||||
pContext->sdl.SDL_OpenAudio = (mal_proc)SDL_OpenAudio;
|
|
||||||
pContext->sdl.SDL_PauseAudio = (mal_proc)SDL_PauseAudio;
|
|
||||||
#ifndef MAL_USE_SDL_1
|
|
||||||
pContext->sdl.SDL_GetNumAudioDevices = (mal_proc)SDL_GetNumAudioDevices;
|
pContext->sdl.SDL_GetNumAudioDevices = (mal_proc)SDL_GetNumAudioDevices;
|
||||||
pContext->sdl.SDL_GetAudioDeviceName = (mal_proc)SDL_GetAudioDeviceName;
|
pContext->sdl.SDL_GetAudioDeviceName = (mal_proc)SDL_GetAudioDeviceName;
|
||||||
pContext->sdl.SDL_CloseAudioDevice = (mal_proc)SDL_CloseAudioDevice;
|
pContext->sdl.SDL_CloseAudioDevice = (mal_proc)SDL_CloseAudioDevice;
|
||||||
pContext->sdl.SDL_OpenAudioDevice = (mal_proc)SDL_OpenAudioDevice;
|
pContext->sdl.SDL_OpenAudioDevice = (mal_proc)SDL_OpenAudioDevice;
|
||||||
pContext->sdl.SDL_PauseAudioDevice = (mal_proc)SDL_PauseAudioDevice;
|
pContext->sdl.SDL_PauseAudioDevice = (mal_proc)SDL_PauseAudioDevice;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
|
||||||
// We need to determine whether or not we are using SDL2 or SDL1. We can know this by looking at whether or not certain
|
|
||||||
// function pointers are NULL.
|
|
||||||
if (pContext->sdl.SDL_GetNumAudioDevices == NULL ||
|
|
||||||
pContext->sdl.SDL_GetAudioDeviceName == NULL ||
|
|
||||||
pContext->sdl.SDL_CloseAudioDevice == NULL ||
|
|
||||||
pContext->sdl.SDL_OpenAudioDevice == NULL ||
|
|
||||||
pContext->sdl.SDL_PauseAudioDevice == NULL) {
|
|
||||||
pContext->sdl.usingSDL1 = MAL_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
int resultSDL = ((MAL_PFN_SDL_InitSubSystem)pContext->sdl.SDL_InitSubSystem)(MAL_SDL_INIT_AUDIO);
|
int resultSDL = ((MAL_PFN_SDL_InitSubSystem)pContext->sdl.SDL_InitSubSystem)(MAL_SDL_INIT_AUDIO);
|
||||||
if (resultSDL != 0) {
|
if (resultSDL != 0) {
|
||||||
@@ -28562,6 +28415,11 @@ mal_uint64 mal_sine_wave_read_ex(mal_sine_wave* pSineWave, mal_uint64 frameCount
|
|||||||
// REVISION HISTORY
|
// REVISION HISTORY
|
||||||
// ================
|
// ================
|
||||||
//
|
//
|
||||||
|
// v0.8.12 - 2018-11-27
|
||||||
|
// - Drop support for SDL 1.2. The Emscripten build now requires "-s USE_SDL=2".
|
||||||
|
// - Fix a linking error with ALSA.
|
||||||
|
// - Fix a bug on iOS where the device name is not set correctly.
|
||||||
|
//
|
||||||
// v0.8.11 - 2018-11-21
|
// v0.8.11 - 2018-11-21
|
||||||
// - iOS bug fixes.
|
// - iOS bug fixes.
|
||||||
// - Minor tweaks to PulseAudio.
|
// - Minor tweaks to PulseAudio.
|
||||||
|
|||||||
+97
-270
@@ -5,7 +5,6 @@ This is research into a new resampler for mini_al. Not yet complete.
|
|||||||
|
|
||||||
Requirements:
|
Requirements:
|
||||||
- Selection of different algorithms. The following at a minimum:
|
- Selection of different algorithms. The following at a minimum:
|
||||||
- Passthrough
|
|
||||||
- Linear with optional filtering
|
- Linear with optional filtering
|
||||||
- Sinc
|
- Sinc
|
||||||
- Floating point pipeline for f32 and fixed point integer pipeline for s16
|
- Floating point pipeline for f32 and fixed point integer pipeline for s16
|
||||||
@@ -39,6 +38,8 @@ Other Notes:
|
|||||||
Random Notes:
|
Random Notes:
|
||||||
- You cannot change the algorithm after initialization.
|
- You cannot change the algorithm after initialization.
|
||||||
- It is recommended to keep the mal_resampler object aligned to MAL_SIMD_ALIGNMENT, though it is not necessary.
|
- It is recommended to keep the mal_resampler object aligned to MAL_SIMD_ALIGNMENT, though it is not necessary.
|
||||||
|
- Ratios need to be in the range of MAL_RESAMPLER_MIN_RATIO and MAL_RESAMPLER_MAX_RATIO. If you need extreme ratios
|
||||||
|
then you will need to chain resamplers together.
|
||||||
*/
|
*/
|
||||||
#ifndef mal_resampler_h
|
#ifndef mal_resampler_h
|
||||||
#define mal_resampler_h
|
#define mal_resampler_h
|
||||||
@@ -51,22 +52,18 @@ Random Notes:
|
|||||||
typedef struct mal_resampler mal_resampler;
|
typedef struct mal_resampler mal_resampler;
|
||||||
|
|
||||||
/* Client callbacks. */
|
/* Client callbacks. */
|
||||||
typedef mal_uint32 (* mal_resampler_read_from_client_proc) (mal_resampler* pResampler, mal_uint32 frameCount, void** ppFrames);
|
typedef mal_uint32 (* mal_resampler_read_from_client_proc)(mal_resampler* pResampler, mal_uint32 frameCount, void** ppFrames);
|
||||||
|
|
||||||
/* Backend functions. */
|
/* Backend functions. */
|
||||||
typedef mal_result (* mal_resampler_init_proc) (mal_resampler* pResampler);
|
typedef mal_result (* mal_resampler_init_proc)(mal_resampler* pResampler);
|
||||||
typedef mal_uint64 (* mal_resampler_read_proc) (mal_resampler* pResampler, mal_uint64 frameCount, void** ppFrames);
|
typedef mal_uint64 (* mal_resampler_read_proc)(mal_resampler* pResampler, mal_uint64 frameCount, void** ppFrames);
|
||||||
typedef mal_uint64 (* mal_resampler_seek_proc) (mal_resampler* pResampler, mal_uint64 frameCount, mal_uint32 options);
|
typedef mal_uint64 (* mal_resampler_seek_proc)(mal_resampler* pResampler, mal_uint64 frameCount, mal_uint32 options);
|
||||||
typedef mal_result (* mal_resampler_get_cached_time_proc) (mal_resampler* pResampler, double* pInputTime, double* pOutputTime);
|
|
||||||
typedef mal_uint64 (* mal_resampler_get_required_input_frame_count_proc) (mal_resampler* pResampler, mal_uint64 outputFrameCount);
|
|
||||||
typedef mal_uint64 (* mal_resampler_get_expected_output_frame_count_proc)(mal_resampler* pResampler, mal_uint64 inputFrameCount);
|
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
mal_resample_algorithm_sinc = 0, /* Default. */
|
mal_resampler_algorithm_sinc = 0, /* Default. */
|
||||||
mal_resample_algorithm_linear, /* Fastest. */
|
mal_resampler_algorithm_linear, /* Fastest. */
|
||||||
mal_resample_algorithm_passthrough /* No resampling. */
|
} mal_resampler_algorithm;
|
||||||
} mal_resample_algorithm;
|
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
@@ -81,7 +78,7 @@ typedef struct
|
|||||||
mal_uint32 sampleRateIn;
|
mal_uint32 sampleRateIn;
|
||||||
mal_uint32 sampleRateOut;
|
mal_uint32 sampleRateOut;
|
||||||
double ratio; /* ratio = in/out */
|
double ratio; /* ratio = in/out */
|
||||||
mal_resample_algorithm algorithm;
|
mal_resampler_algorithm algorithm;
|
||||||
mal_resampler_end_of_input_mode endOfInputMode;
|
mal_resampler_end_of_input_mode endOfInputMode;
|
||||||
mal_resampler_read_from_client_proc onRead;
|
mal_resampler_read_from_client_proc onRead;
|
||||||
void* pUserData;
|
void* pUserData;
|
||||||
@@ -94,7 +91,7 @@ struct mal_resampler
|
|||||||
float f32[MAL_RESAMPLER_CACHE_SIZE_IN_BYTES/sizeof(float)];
|
float f32[MAL_RESAMPLER_CACHE_SIZE_IN_BYTES/sizeof(float)];
|
||||||
mal_int16 s16[MAL_RESAMPLER_CACHE_SIZE_IN_BYTES/sizeof(mal_int16)];
|
mal_int16 s16[MAL_RESAMPLER_CACHE_SIZE_IN_BYTES/sizeof(mal_int16)];
|
||||||
} cache; /* Do not use directly. Keep this as the first member of this structure for SIMD alignment purposes. */
|
} cache; /* Do not use directly. Keep this as the first member of this structure for SIMD alignment purposes. */
|
||||||
mal_uint16 firstCachedFrame;
|
mal_uint16 firstCachedFrameOffset;
|
||||||
mal_uint16 cacheLengthInFrames; /* The number of valid frames sitting in the cache. May be less than the cache's capacity. */
|
mal_uint16 cacheLengthInFrames; /* The number of valid frames sitting in the cache. May be less than the cache's capacity. */
|
||||||
mal_uint16 windowLength;
|
mal_uint16 windowLength;
|
||||||
double windowTime; /* By input rate. Relative to the start of the cache. */
|
double windowTime; /* By input rate. Relative to the start of the cache. */
|
||||||
@@ -102,9 +99,6 @@ struct mal_resampler
|
|||||||
mal_resampler_init_proc init;
|
mal_resampler_init_proc init;
|
||||||
mal_resampler_read_proc read;
|
mal_resampler_read_proc read;
|
||||||
mal_resampler_seek_proc seek;
|
mal_resampler_seek_proc seek;
|
||||||
mal_resampler_get_cached_time_proc getCachedTime;
|
|
||||||
mal_resampler_get_required_input_frame_count_proc getRequiredInputFrameCount;
|
|
||||||
mal_resampler_get_expected_output_frame_count_proc getExpectedOutputFrameCount;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -149,8 +143,6 @@ mal_uint64 mal_resampler_seek(mal_resampler* pResampler, mal_uint64 frameCount,
|
|||||||
Retrieves the number of cached input frames.
|
Retrieves the number of cached input frames.
|
||||||
|
|
||||||
This is equivalent to: (mal_uint64)ceil(mal_resampler_get_cached_input_time(pResampler));
|
This is equivalent to: (mal_uint64)ceil(mal_resampler_get_cached_input_time(pResampler));
|
||||||
|
|
||||||
See also: mal_resampler_get_cached_frame_counts()
|
|
||||||
*/
|
*/
|
||||||
mal_uint64 mal_resampler_get_cached_input_frame_count(mal_resampler* pResampler);
|
mal_uint64 mal_resampler_get_cached_input_frame_count(mal_resampler* pResampler);
|
||||||
|
|
||||||
@@ -158,20 +150,24 @@ mal_uint64 mal_resampler_get_cached_input_frame_count(mal_resampler* pResampler)
|
|||||||
Retrieves the number of whole output frames that can be calculated from the currently cached input frames.
|
Retrieves the number of whole output frames that can be calculated from the currently cached input frames.
|
||||||
|
|
||||||
This is equivalent to: (mal_uint64)floor(mal_resampler_get_cached_output_time(pResampler));
|
This is equivalent to: (mal_uint64)floor(mal_resampler_get_cached_output_time(pResampler));
|
||||||
|
|
||||||
See also: mal_resampler_get_cached_frame_counts()
|
|
||||||
*/
|
*/
|
||||||
mal_uint64 mal_resampler_get_cached_output_frame_count(mal_resampler* pResampler);
|
mal_uint64 mal_resampler_get_cached_output_frame_count(mal_resampler* pResampler);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The same as mal_resampler_get_cached_input_frame_count(), except returns a fractional value representing the exact amount
|
The same as mal_resampler_get_cached_input_frame_count(), except returns a fractional value representing the exact amount
|
||||||
of time in input rate making up the cached input.
|
of time in input rate making up the cached input.
|
||||||
|
|
||||||
|
When the end of input mode is set to mal_resampler_end_of_input_mode_no_consume, the input frames currently sitting in the
|
||||||
|
window are not included in the calculation.
|
||||||
*/
|
*/
|
||||||
double mal_resampler_get_cached_input_time(mal_resampler* pResampler);
|
double mal_resampler_get_cached_input_time(mal_resampler* pResampler);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The same as mal_resampler_get_cached_output_frame_count(), except returns a fractional value representing the exact amount
|
The same as mal_resampler_get_cached_output_frame_count(), except returns a fractional value representing the exact amount
|
||||||
of time in output rate making up the cached output.
|
of time in output rate making up the cached output.
|
||||||
|
|
||||||
|
When the end of input mode is set to mal_resampler_end_of_input_mode_no_consume, the input frames currently sitting in the
|
||||||
|
window are not included in the calculation.
|
||||||
*/
|
*/
|
||||||
double mal_resampler_get_cached_output_time(mal_resampler* pResampler);
|
double mal_resampler_get_cached_output_time(mal_resampler* pResampler);
|
||||||
|
|
||||||
@@ -192,10 +188,10 @@ Calculates the number of whole output frames that would be output after fully re
|
|||||||
input frames from the client.
|
input frames from the client.
|
||||||
|
|
||||||
A detail to keep in mind is how cached input frames are handled. This function calculates the output frame count based on
|
A detail to keep in mind is how cached input frames are handled. This function calculates the output frame count based on
|
||||||
inputFrameCount + mal_resampler_get_cached_input_frame_count(). It essentially calcualtes how many output frames will be
|
inputFrameCount + mal_resampler_get_cached_input_time(). It essentially calcualtes how many output frames will be returned
|
||||||
returned if an additional inputFrameCount frames were read from the client and consumed by the resampler. You can adjust
|
if an additional inputFrameCount frames were read from the client and consumed by the resampler. You can adjust the return
|
||||||
the return value by mal_resampler_get_cached_output_frame_count() which calculates the number of output frames that can be
|
value by mal_resampler_get_cached_output_frame_count() which calculates the number of output frames that can be output from
|
||||||
output from the currently cached input.
|
the currently cached input.
|
||||||
|
|
||||||
When the end of input mode is set to mal_resampler_end_of_input_mode_no_consume, the input frames sitting in the filter
|
When the end of input mode is set to mal_resampler_end_of_input_mode_no_consume, the input frames sitting in the filter
|
||||||
window are not included in the calculation.
|
window are not included in the calculation.
|
||||||
@@ -204,27 +200,23 @@ mal_uint64 mal_resampler_get_expected_output_frame_count(mal_resampler* pResampl
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MINI_AL_IMPLEMENTATION
|
#ifdef MINI_AL_IMPLEMENTATION
|
||||||
mal_uint64 mal_resampler_read__passthrough(mal_resampler* pResampler, mal_uint64 frameCount, void** ppFrames);
|
|
||||||
mal_uint64 mal_resampler_seek__passthrough(mal_resampler* pResampler, mal_uint64 frameCount, mal_uint32 options);
|
#ifndef MAL_RESAMPLER_MIN_RATIO
|
||||||
mal_result mal_resampler_get_cached_time__passthrough(mal_resampler* pResampler, double* pInputTime, double* pOutputTime);
|
#define MAL_RESAMPLER_MIN_RATIO 0.001
|
||||||
mal_uint64 mal_resampler_get_required_input_frame_count__passthrough(mal_resampler* pResampler, mal_uint64 outputFrameCount);
|
#endif
|
||||||
mal_uint64 mal_resampler_get_expected_output_frame_count__passthrough(mal_resampler* pResampler, mal_uint64 inputFrameCount);
|
#ifndef MAL_RESAMPLER_MAX_RATIO
|
||||||
|
#define MAL_RESAMPLER_MAX_RATIO 100.0
|
||||||
|
#endif
|
||||||
|
|
||||||
mal_uint64 mal_resampler_read__linear(mal_resampler* pResampler, mal_uint64 frameCount, void** ppFrames);
|
mal_uint64 mal_resampler_read__linear(mal_resampler* pResampler, mal_uint64 frameCount, void** ppFrames);
|
||||||
mal_uint64 mal_resampler_seek__linear(mal_resampler* pResampler, mal_uint64 frameCount, mal_uint32 options);
|
mal_uint64 mal_resampler_seek__linear(mal_resampler* pResampler, mal_uint64 frameCount, mal_uint32 options);
|
||||||
mal_result mal_resampler_get_cached_time__linear(mal_resampler* pResampler, double* pInputTime, double* pOutputTime);
|
|
||||||
mal_uint64 mal_resampler_get_required_input_frame_count__linear(mal_resampler* pResampler, mal_uint64 outputFrameCount);
|
|
||||||
mal_uint64 mal_resampler_get_expected_output_frame_count__linear(mal_resampler* pResampler, mal_uint64 inputFrameCount);
|
|
||||||
|
|
||||||
mal_result mal_resampler_init__sinc(mal_resampler* pResampler);
|
mal_result mal_resampler_init__sinc(mal_resampler* pResampler);
|
||||||
mal_uint64 mal_resampler_read__sinc(mal_resampler* pResampler, mal_uint64 frameCount, void** ppFrames);
|
mal_uint64 mal_resampler_read__sinc(mal_resampler* pResampler, mal_uint64 frameCount, void** ppFrames);
|
||||||
mal_uint64 mal_resampler_seek__sinc(mal_resampler* pResampler, mal_uint64 frameCount, mal_uint32 options);
|
mal_uint64 mal_resampler_seek__sinc(mal_resampler* pResampler, mal_uint64 frameCount, mal_uint32 options);
|
||||||
mal_result mal_resampler_get_cached_time__sinc(mal_resampler* pResampler, double* pInputTime, double* pOutputTime);
|
|
||||||
mal_uint64 mal_resampler_get_required_input_frame_count__sinc(mal_resampler* pResampler, mal_uint64 outputFrameCount);
|
|
||||||
mal_uint64 mal_resampler_get_expected_output_frame_count__sinc(mal_resampler* pResampler, mal_uint64 inputFrameCount);
|
|
||||||
|
|
||||||
/* TODO: Add this to mini_al.h */
|
/* TODO: Add this to mini_al.h */
|
||||||
#define MAL_ALIGN_INT(val, alignment) (((val) + ((alignment-1))) & ~((alignment)-1))
|
#define MAL_ALIGN_INT(val, alignment) (((val) + ((alignment)-1)) & ~((alignment)-1))
|
||||||
#define MAL_ALIGN_PTR(ptr, alignment) (void*)MAL_ALIGN_INT(((mal_uintptr)(ptr)), (alignment))
|
#define MAL_ALIGN_PTR(ptr, alignment) (void*)MAL_ALIGN_INT(((mal_uintptr)(ptr)), (alignment))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -276,34 +268,18 @@ mal_result mal_resampler_init(const mal_resampler_config* pConfig, mal_resampler
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (pResampler->config.algorithm) {
|
switch (pResampler->config.algorithm) {
|
||||||
case mal_resample_algorithm_passthrough:
|
case mal_resampler_algorithm_linear:
|
||||||
{
|
{
|
||||||
pResampler->init = NULL;
|
pResampler->init = NULL;
|
||||||
pResampler->read = mal_resampler_read__passthrough;
|
pResampler->read = mal_resampler_read__linear;
|
||||||
pResampler->seek = mal_resampler_seek__passthrough;
|
pResampler->seek = mal_resampler_seek__linear;
|
||||||
pResampler->getCachedTime = mal_resampler_get_cached_time__passthrough;
|
|
||||||
pResampler->getRequiredInputFrameCount = mal_resampler_get_required_input_frame_count__passthrough;
|
|
||||||
pResampler->getExpectedOutputFrameCount = mal_resampler_get_expected_output_frame_count__passthrough;
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case mal_resample_algorithm_linear:
|
case mal_resampler_algorithm_sinc:
|
||||||
{
|
{
|
||||||
pResampler->init = NULL;
|
pResampler->init = mal_resampler_init__sinc;
|
||||||
pResampler->read = mal_resampler_read__linear;
|
pResampler->read = mal_resampler_read__sinc;
|
||||||
pResampler->seek = mal_resampler_seek__linear;
|
pResampler->seek = mal_resampler_seek__sinc;
|
||||||
pResampler->getCachedTime = mal_resampler_get_cached_time__linear;
|
|
||||||
pResampler->getRequiredInputFrameCount = mal_resampler_get_required_input_frame_count__linear;
|
|
||||||
pResampler->getExpectedOutputFrameCount = mal_resampler_get_expected_output_frame_count__linear;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case mal_resample_algorithm_sinc:
|
|
||||||
{
|
|
||||||
pResampler->init = mal_resampler_init__sinc;
|
|
||||||
pResampler->read = mal_resampler_read__sinc;
|
|
||||||
pResampler->seek = mal_resampler_seek__sinc;
|
|
||||||
pResampler->getCachedTime = mal_resampler_get_cached_time__sinc;
|
|
||||||
pResampler->getRequiredInputFrameCount = mal_resampler_get_required_input_frame_count__sinc;
|
|
||||||
pResampler->getExpectedOutputFrameCount = mal_resampler_get_expected_output_frame_count__sinc;
|
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,9 +308,14 @@ mal_result mal_resampler_set_rate(mal_resampler* pResampler, mal_uint32 sampleRa
|
|||||||
return MAL_INVALID_ARGS;
|
return MAL_INVALID_ARGS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double ratio = (double)pResampler->config.sampleRateIn / (double)pResampler->config.sampleRateOut;
|
||||||
|
if (ratio < MAL_RESAMPLER_MIN_RATIO || ratio > MAL_RESAMPLER_MAX_RATIO) {
|
||||||
|
return MAL_INVALID_ARGS; /* Ratio is too extreme. */
|
||||||
|
}
|
||||||
|
|
||||||
pResampler->config.sampleRateIn = sampleRateIn;
|
pResampler->config.sampleRateIn = sampleRateIn;
|
||||||
pResampler->config.sampleRateOut = sampleRateOut;
|
pResampler->config.sampleRateOut = sampleRateOut;
|
||||||
pResampler->config.ratio = (double)pResampler->config.sampleRateIn / (double)pResampler->config.sampleRateOut;
|
pResampler->config.ratio = ratio;
|
||||||
|
|
||||||
return MAL_SUCCESS;
|
return MAL_SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -345,8 +326,8 @@ mal_result mal_resampler_set_rate_ratio(mal_resampler* pResampler, double ratio)
|
|||||||
return MAL_INVALID_ARGS;
|
return MAL_INVALID_ARGS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ratio == 0) {
|
if (ratio < MAL_RESAMPLER_MIN_RATIO || ratio > MAL_RESAMPLER_MAX_RATIO) {
|
||||||
return MAL_INVALID_ARGS;
|
return MAL_INVALID_ARGS; /* Ratio is too extreme. */
|
||||||
}
|
}
|
||||||
|
|
||||||
pResampler->config.ratio = ratio;
|
pResampler->config.ratio = ratio;
|
||||||
@@ -369,6 +350,7 @@ mal_uint64 mal_resampler_read(mal_resampler* pResampler, mal_uint64 frameCount,
|
|||||||
return mal_resampler_seek(pResampler, frameCount, 0);
|
return mal_resampler_seek(pResampler, frameCount, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return pResampler->read(pResampler, frameCount, ppFrames);
|
return pResampler->read(pResampler, frameCount, ppFrames);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -382,6 +364,7 @@ mal_uint64 mal_resampler_seek(mal_resampler* pResampler, mal_uint64 frameCount,
|
|||||||
return 0; /* Nothing to do, so return early. */
|
return 0; /* Nothing to do, so return early. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return pResampler->seek(pResampler, frameCount, options);
|
return pResampler->seek(pResampler, frameCount, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -396,43 +379,50 @@ mal_uint64 mal_resampler_get_cached_output_frame_count(mal_resampler* pResampler
|
|||||||
return (mal_uint64)floor(mal_resampler_get_cached_output_time(pResampler));
|
return (mal_uint64)floor(mal_resampler_get_cached_output_time(pResampler));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double mal_resampler__calculate_cached_input_time(mal_resampler* pResampler)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
The cached input time depends on whether or not the end of the input is being consumed. If so, it's the difference between the
|
||||||
|
last cached frame and the halfway point of the window, rounded down. Otherwise it's between the last cached frame and the end
|
||||||
|
of the window.
|
||||||
|
*/
|
||||||
|
double cachedInputTime = pResampler->cacheLengthInFrames;
|
||||||
|
if (pResampler->config.endOfInputMode == mal_resampler_end_of_input_mode_consume) {
|
||||||
|
cachedInputTime -= (pResampler->windowTime + (pResampler->windowLength >> 1));
|
||||||
|
} else {
|
||||||
|
cachedInputTime -= (pResampler->windowTime + pResampler->windowLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cachedInputTime;
|
||||||
|
}
|
||||||
|
|
||||||
double mal_resampler_get_cached_input_time(mal_resampler* pResampler)
|
double mal_resampler_get_cached_input_time(mal_resampler* pResampler)
|
||||||
{
|
{
|
||||||
if (pResampler == NULL || pResampler->getCachedTime == NULL) {
|
if (pResampler == NULL) {
|
||||||
return 0; /* Invalid args. */
|
return 0; /* Invalid args. */
|
||||||
}
|
}
|
||||||
|
|
||||||
double inputTime = 0;
|
return mal_resampler__calculate_cached_input_time(pResampler);
|
||||||
double outputTime = 0;
|
}
|
||||||
mal_result result = pResampler->getCachedTime(pResampler, &inputTime, &outputTime);
|
|
||||||
if (result != MAL_SUCCESS) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return inputTime;
|
double mal_resampler__calculate_cached_output_time(mal_resampler* pResampler)
|
||||||
|
{
|
||||||
|
return mal_resampler__calculate_cached_input_time(pResampler) / pResampler->config.ratio;
|
||||||
}
|
}
|
||||||
|
|
||||||
double mal_resampler_get_cached_output_time(mal_resampler* pResampler)
|
double mal_resampler_get_cached_output_time(mal_resampler* pResampler)
|
||||||
{
|
{
|
||||||
if (pResampler == NULL || pResampler->getCachedTime == NULL) {
|
if (pResampler == NULL) {
|
||||||
return 0; /* Invalid args. */
|
return 0; /* Invalid args. */
|
||||||
}
|
}
|
||||||
|
|
||||||
double inputTime = 0;
|
return mal_resampler__calculate_cached_output_time(pResampler);
|
||||||
double outputTime = 0;
|
|
||||||
mal_result result = pResampler->getCachedTime(pResampler, &inputTime, &outputTime);
|
|
||||||
if (result != MAL_SUCCESS) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return outputTime;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
mal_uint64 mal_resampler_get_required_input_frame_count(mal_resampler* pResampler, mal_uint64 outputFrameCount)
|
mal_uint64 mal_resampler_get_required_input_frame_count(mal_resampler* pResampler, mal_uint64 outputFrameCount)
|
||||||
{
|
{
|
||||||
if (pResampler == NULL || pResampler->getRequiredInputFrameCount == NULL) {
|
if (pResampler == NULL) {
|
||||||
return 0; /* Invalid args. */
|
return 0; /* Invalid args. */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -440,12 +430,33 @@ mal_uint64 mal_resampler_get_required_input_frame_count(mal_resampler* pResample
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return pResampler->getRequiredInputFrameCount(pResampler, outputFrameCount);
|
/* First grab the amount of output time sitting in the cache. */
|
||||||
|
double cachedOutputTime = mal_resampler__calculate_cached_output_time(pResampler);
|
||||||
|
if (cachedOutputTime >= outputFrameCount) {
|
||||||
|
return 0; /* All of the necessary input data is cached. No additional data is required from the client. */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Getting here means more input data will be required. A detail to consider here is that we are accepting an unsigned 64-bit integer
|
||||||
|
for the output frame count, however we need to consider sub-frame timing which we're doing by using a double. There will not be
|
||||||
|
enough precision in the double to represent the whole 64-bit range of the input variable. For now I'm not handling this explicitly
|
||||||
|
because I think it's unlikely outputFrameCount will be set to something so huge anyway, but it will be something to think about in
|
||||||
|
order to get this working properly for the whole 64-bit range.
|
||||||
|
|
||||||
|
The return value must always be larger than 0 after this point. If it's not we have an error.
|
||||||
|
*/
|
||||||
|
double nonCachedOutputTime = outputFrameCount - cachedOutputTime;
|
||||||
|
mal_assert(nonCachedOutputTime > 0);
|
||||||
|
|
||||||
|
mal_uint64 requiredInputFrames = (mal_uint64)ceil(nonCachedOutputTime * pResampler->config.ratio);
|
||||||
|
mal_assert(requiredInputFrames > 0);
|
||||||
|
|
||||||
|
return requiredInputFrames;
|
||||||
}
|
}
|
||||||
|
|
||||||
mal_uint64 mal_resampler_get_expected_output_frame_count(mal_resampler* pResampler, mal_uint64 inputFrameCount)
|
mal_uint64 mal_resampler_get_expected_output_frame_count(mal_resampler* pResampler, mal_uint64 inputFrameCount)
|
||||||
{
|
{
|
||||||
if (pResampler == NULL || pResampler->getExpectedOutputFrameCount == NULL) {
|
if (pResampler == NULL) {
|
||||||
return 0; /* Invalid args. */
|
return 0; /* Invalid args. */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -453,132 +464,8 @@ mal_uint64 mal_resampler_get_expected_output_frame_count(mal_resampler* pResampl
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return pResampler->getExpectedOutputFrameCount(pResampler, inputFrameCount);
|
/* What we're actually calculating here is how many whole output frames will be calculated after consuming inputFrameCount + mal_resampler_get_cached_input_time(). */
|
||||||
}
|
return (mal_uint64)floor((mal_resampler__calculate_cached_input_time(pResampler) + inputFrameCount) / pResampler->config.ratio);
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Passthrough
|
|
||||||
*/
|
|
||||||
mal_uint64 mal_resampler_read__passthrough(mal_resampler* pResampler, mal_uint64 frameCount, void** ppFrames)
|
|
||||||
{
|
|
||||||
mal_assert(pResampler != NULL);
|
|
||||||
mal_assert(pResampler->config.onRead != NULL);
|
|
||||||
mal_assert(frameCount > 0);
|
|
||||||
mal_assert(ppFrames != NULL);
|
|
||||||
|
|
||||||
/*
|
|
||||||
It's tempting to to just call pResampler->config.onRead() and pass in ppFrames directly, however this violates
|
|
||||||
our requirement that all buffers passed into onRead() are aligned to MAL_SIMD_ALIGNMENT. If any of the ppFrames
|
|
||||||
buffers are misaligned we need to read into a temporary buffer.
|
|
||||||
*/
|
|
||||||
mal_bool32 isOutputBufferAligned = MAL_TRUE;
|
|
||||||
for (mal_uint32 iChannel = 0; iChannel < pResampler->config.channels; ++iChannel) {
|
|
||||||
if (((mal_uintptr)ppFrames[iChannel] & (MAL_SIMD_ALIGNMENT-1)) != 0) {
|
|
||||||
isOutputBufferAligned = MAL_FALSE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (frameCount <= 0xFFFFFFFF && isOutputBufferAligned) {
|
|
||||||
return pResampler->config.onRead(pResampler, (mal_uint32)frameCount, ppFrames); /* Fast path. */
|
|
||||||
} else {
|
|
||||||
MAL_DECLARE_ALIGNED_STACK_BUFFER(float, ppRunningFrames, 4096, pResampler->config.channels);
|
|
||||||
|
|
||||||
mal_uint64 totalFramesRead = 0;
|
|
||||||
while (frameCount > 0) {
|
|
||||||
mal_uint64 framesToReadNow = (pResampler->config.format == mal_format_f32) ? ppRunningFramesFrameCount : ppRunningFramesFrameCount*2; /* x2 for the s16 frame count because ppRunningFramesFrameCount is based on f32. */
|
|
||||||
if (framesToReadNow > frameCount) {
|
|
||||||
framesToReadNow = frameCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
mal_uint32 framesJustRead = pResampler->config.onRead(pResampler, (mal_uint32)framesToReadNow, (void**)ppRunningFrames);
|
|
||||||
if (framesJustRead == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
totalFramesRead += framesJustRead;
|
|
||||||
frameCount -= framesJustRead;
|
|
||||||
|
|
||||||
mal_uint32 bytesJustRead = framesJustRead * mal_get_bytes_per_sample(pResampler->config.format);
|
|
||||||
for (mal_uint32 iChannel = 0; iChannel < pResampler->config.channels; ++iChannel) {
|
|
||||||
mal_copy_memory(ppFrames[iChannel], ppRunningFrames[iChannel], bytesJustRead);
|
|
||||||
ppFrames[iChannel] = mal_offset_ptr(ppFrames[iChannel], bytesJustRead);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (framesJustRead < framesToReadNow) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return totalFramesRead;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mal_uint64 mal_resampler_seek__passthrough(mal_resampler* pResampler, mal_uint64 frameCount, mal_uint32 options)
|
|
||||||
{
|
|
||||||
mal_assert(pResampler != NULL);
|
|
||||||
mal_assert(pResampler->config.onRead != NULL);
|
|
||||||
mal_assert(frameCount > 0);
|
|
||||||
|
|
||||||
if ((options & MAL_RESAMPLER_SEEK_NO_CLIENT_READ) != 0) {
|
|
||||||
return frameCount; /* No input from onRead(), so just return immediately. */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Getting here means we need to read from onRead(). In this case we just read into a trash buffer. */
|
|
||||||
MAL_DECLARE_ALIGNED_STACK_BUFFER(float, trash, 4096, pResampler->config.channels);
|
|
||||||
|
|
||||||
mal_uint64 totalFramesRead = 0;
|
|
||||||
while (frameCount > 0) {
|
|
||||||
mal_uint64 framesToRead = trashFrameCount;
|
|
||||||
if (framesToRead > frameCount) {
|
|
||||||
framesToRead = frameCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
mal_uint64 framesRead = pResampler->config.onRead(pResampler, (mal_uint32)framesToRead, (void**)trash);
|
|
||||||
totalFramesRead += framesRead;
|
|
||||||
frameCount -= framesRead;
|
|
||||||
|
|
||||||
/* Don't get stuck in a loop if the client returns no samples. */
|
|
||||||
if (framesRead < framesToRead) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return totalFramesRead;
|
|
||||||
}
|
|
||||||
|
|
||||||
mal_result mal_resampler_get_cached_time__passthrough(mal_resampler* pResampler, double* pInputTime, double* pOutputTime)
|
|
||||||
{
|
|
||||||
mal_assert(pResampler != NULL);
|
|
||||||
mal_assert(pInputTime != NULL);
|
|
||||||
mal_assert(pOutputTime != NULL);
|
|
||||||
|
|
||||||
/* The passthrough implementation never caches, so this is always 0. */
|
|
||||||
*pInputTime = 0;
|
|
||||||
*pOutputTime = 0;
|
|
||||||
|
|
||||||
return MAL_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
mal_uint64 mal_resampler_get_required_input_frame_count__passthrough(mal_resampler* pResampler, mal_uint64 outputFrameCount)
|
|
||||||
{
|
|
||||||
mal_assert(pResampler != NULL);
|
|
||||||
mal_assert(outputFrameCount > 0);
|
|
||||||
|
|
||||||
/* For passthrough input and output is the same. */
|
|
||||||
(void)pResampler;
|
|
||||||
return outputFrameCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
mal_uint64 mal_resampler_get_expected_output_frame_count__passthrough(mal_resampler* pResampler, mal_uint64 inputFrameCount)
|
|
||||||
{
|
|
||||||
mal_assert(pResampler != NULL);
|
|
||||||
mal_assert(inputFrameCount > 0);
|
|
||||||
|
|
||||||
/* For passthrough input and output is the same. */
|
|
||||||
(void)pResampler;
|
|
||||||
return inputFrameCount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -612,36 +499,6 @@ mal_uint64 mal_resampler_seek__linear(mal_resampler* pResampler, mal_uint64 fram
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
mal_result mal_resampler_get_cached_time__linear(mal_resampler* pResampler, double* pInputTime, double* pOutputTime)
|
|
||||||
{
|
|
||||||
mal_assert(pResampler != NULL);
|
|
||||||
mal_assert(pInputTime != NULL);
|
|
||||||
mal_assert(pOutputTime != NULL);
|
|
||||||
|
|
||||||
/* TODO: Implement me. */
|
|
||||||
return MAL_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
mal_uint64 mal_resampler_get_required_input_frame_count__linear(mal_resampler* pResampler, mal_uint64 outputFrameCount)
|
|
||||||
{
|
|
||||||
mal_assert(pResampler != NULL);
|
|
||||||
mal_assert(outputFrameCount > 0);
|
|
||||||
|
|
||||||
/* TODO: Implement me. */
|
|
||||||
(void)pResampler;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
mal_uint64 mal_resampler_get_expected_output_frame_count__linear(mal_resampler* pResampler, mal_uint64 inputFrameCount)
|
|
||||||
{
|
|
||||||
mal_assert(pResampler != NULL);
|
|
||||||
mal_assert(inputFrameCount > 0);
|
|
||||||
|
|
||||||
/* TODO: Implement me. */
|
|
||||||
(void)pResampler;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Sinc
|
Sinc
|
||||||
@@ -681,34 +538,4 @@ mal_uint64 mal_resampler_seek__sinc(mal_resampler* pResampler, mal_uint64 frameC
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
mal_result mal_resampler_get_cached_time__sinc(mal_resampler* pResampler, double* pInputTime, double* pOutputTime)
|
|
||||||
{
|
|
||||||
mal_assert(pResampler != NULL);
|
|
||||||
mal_assert(pInputTime != NULL);
|
|
||||||
mal_assert(pOutputTime != NULL);
|
|
||||||
|
|
||||||
/* TODO: Implement me. */
|
|
||||||
return MAL_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
mal_uint64 mal_resampler_get_required_input_frame_count__sinc(mal_resampler* pResampler, mal_uint64 outputFrameCount)
|
|
||||||
{
|
|
||||||
mal_assert(pResampler != NULL);
|
|
||||||
mal_assert(outputFrameCount > 0);
|
|
||||||
|
|
||||||
/* TODO: Implement me. */
|
|
||||||
(void)pResampler;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
mal_uint64 mal_resampler_get_expected_output_frame_count__sinc(mal_resampler* pResampler, mal_uint64 inputFrameCount)
|
|
||||||
{
|
|
||||||
mal_assert(pResampler != NULL);
|
|
||||||
mal_assert(inputFrameCount > 0);
|
|
||||||
|
|
||||||
/* TODO: Implement me. */
|
|
||||||
(void)pResampler;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -322,6 +322,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\mini_al.h" />
|
<ClInclude Include="..\mini_al.h" />
|
||||||
|
<ClInclude Include="..\research\mal_resampler.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
|||||||
@@ -44,5 +44,8 @@
|
|||||||
<ClInclude Include="..\mini_al.h">
|
<ClInclude Include="..\mini_al.h">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\research\mal_resampler.h">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
Reference in New Issue
Block a user