diff --git a/mini_al.h b/mini_al.h index 5f6f2ef8..05b03774 100644 --- a/mini_al.h +++ b/mini_al.h @@ -1,5 +1,5 @@ // 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 @@ -25,7 +25,7 @@ // - OSS (FreeBSD) // - OpenSL|ES (Android only) // - OpenAL -// - SDL +// - SDL2 // - Null (Silence) // // Supported Formats: @@ -77,8 +77,7 @@ // // Building for Emscripten // ----------------------- -// The Emscripten build currently uses SDL 1.2 for it's backend which means specifying "-s USE_SDL=2" is unecessary -// as of this version. +// The Emscripten build uses SDL2 and requires "-s USE_SDL=2" on the command line. // // // Playback Example @@ -1840,16 +1839,11 @@ struct mal_context mal_handle hSDL; // SDL mal_proc SDL_InitSubSystem; mal_proc SDL_QuitSubSystem; - mal_proc SDL_CloseAudio; - mal_proc SDL_OpenAudio; - mal_proc SDL_PauseAudio; mal_proc SDL_GetNumAudioDevices; mal_proc SDL_GetAudioDeviceName; mal_proc SDL_CloseAudioDevice; mal_proc SDL_OpenAudioDevice; mal_proc SDL_PauseAudioDevice; - - mal_bool32 usingSDL1; } sdl; #endif #ifdef MAL_SUPPORT_NULL @@ -19564,8 +19558,6 @@ mal_result mal_context_init__openal(mal_context* pContext) /////////////////////////////////////////////////////////////////////////////// #ifdef MAL_HAS_SDL -//#define MAL_USE_SDL_1 - #define MAL_SDL_INIT_AUDIO 0x00000010 #define MAL_AUDIO_U8 0x0008 #define MAL_AUDIO_S16 0x8010 @@ -19582,11 +19574,6 @@ mal_result mal_context_init__openal(mal_context* pContext) #define SDL_MAIN_HANDLED #ifdef MAL_EMSCRIPTEN #include - - // 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 #include #endif @@ -19618,11 +19605,8 @@ typedef int (* MAL_PFN_SDL_InitSubSystem)(mal_uint32 flags); typedef void (* MAL_PFN_SDL_QuitSubSystem)(mal_uint32 flags); typedef int (* MAL_PFN_SDL_GetNumAudioDevices)(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 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 void (* MAL_PFN_SDL_PauseAudio)(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) @@ -19665,68 +19649,42 @@ mal_result mal_context_enumerate_devices__sdl(mal_context* pContext, mal_enum_de mal_assert(pContext != NULL); mal_assert(callback != NULL); -#ifndef MAL_USE_SDL_1 - if (!pContext->sdl.usingSDL1) { - mal_bool32 isTerminated = MAL_FALSE; + mal_bool32 isTerminated = MAL_FALSE; - // Playback - if (!isTerminated) { - int deviceCount = ((MAL_PFN_SDL_GetNumAudioDevices)pContext->sdl.SDL_GetNumAudioDevices)(0); - 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) { + // Playback + if (!isTerminated) { + int deviceCount = ((MAL_PFN_SDL_GetNumAudioDevices)pContext->sdl.SDL_GetNumAudioDevices)(0); + for (int i = 0; i < deviceCount; ++i) { mal_device_info 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. - // Capture. - if (cbResult) { + 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); - 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; @@ -19737,24 +19695,7 @@ mal_result mal_context_get_device_info__sdl(mal_context* pContext, mal_device_ty mal_assert(pContext != NULL); (void)shareMode; -#ifndef MAL_USE_SDL_1 - 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 (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); @@ -19762,6 +19703,9 @@ mal_result mal_context_get_device_info__sdl(mal_context* pContext, mal_device_ty 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); } // 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_zero_memory(&desiredSpec, sizeof(desiredSpec)); -#ifndef MAL_USE_SDL_1 - if (!pContext->sdl.usingSDL1) { - int isCapture = (deviceType == mal_device_type_playback) ? 0 : 1; + int isCapture = (deviceType == mal_device_type_playback) ? 0 : 1; - const char* pDeviceName = NULL; - if (pDeviceID != NULL) { - 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)(); + const char* pDeviceName = NULL; + if (pDeviceID != NULL) { + 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); + pDeviceInfo->minChannels = obtainedSpec.channels; pDeviceInfo->maxChannels = obtainedSpec.channels; pDeviceInfo->minSampleRate = obtainedSpec.freq; @@ -19845,14 +19769,7 @@ void mal_device_uninit__sdl(mal_device* pDevice) { mal_assert(pDevice != NULL); -#ifndef MAL_USE_SDL_1 - 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)(); - } + ((MAL_PFN_SDL_CloseAudioDevice)pDevice->pContext->sdl.SDL_CloseAudioDevice)(pDevice->sdl.deviceID); } @@ -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); #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 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; } -#ifndef MAL_USE_SDL_1 - if (!pDevice->pContext->sdl.usingSDL1) { - int isCapture = (type == mal_device_type_playback) ? 0 : 1; + int isCapture = (type == mal_device_type_playback) ? 0 : 1; - const char* pDeviceName = NULL; - if (pDeviceID != NULL) { - pDeviceName = ((MAL_PFN_SDL_GetAudioDeviceName)pDevice->pContext->sdl.SDL_GetAudioDeviceName)(pDeviceID->sdl, isCapture); - } + const char* pDeviceName = NULL; + if (pDeviceID != NULL) { + 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); - 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); - } - } 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->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) { + return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "Failed to open SDL2 device.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); } 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 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(" CHANNELS: %d -> %d\n", desiredSpec.channels, obtainedSpec.channels); 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); -#ifndef MAL_USE_SDL_1 - 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); - } - + ((MAL_PFN_SDL_PauseAudioDevice)pDevice->pContext->sdl.SDL_PauseAudioDevice)(pDevice->sdl.deviceID, 0); return MAL_SUCCESS; } @@ -19988,14 +19871,7 @@ mal_result mal_device__stop_backend__sdl(mal_device* pDevice) { mal_assert(pDevice != NULL); -#ifndef MAL_USE_SDL_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_PFN_SDL_PauseAudioDevice)pDevice->pContext->sdl.SDL_PauseAudioDevice)(pDevice->sdl.deviceID, 1); mal_device__set_state(pDevice, MAL_STATE_STOPPED); mal_stop_proc onStop = pDevice->onStop; @@ -20024,14 +19900,11 @@ mal_result mal_context_init__sdl(mal_context* pContext) // Run-time linking. const char* libNames[] = { #if defined(MAL_WIN32) - "SDL2.dll", - "SDL.dll" + "SDL2.dll" #elif defined(MAL_APPLE) - "SDL2.framework/SDL2", - "SDL.framework/SDL" + "SDL2.framework/SDL2" #else - "libSDL2-2.0.so.0", - "libSDL-1.2.so.0" + "libSDL2-2.0.so.0" #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_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_GetAudioDeviceName = mal_dlsym(pContext->sdl.hSDL, "SDL_GetAudioDeviceName"); 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_PauseAudioDevice = mal_dlsym(pContext->sdl.hSDL, "SDL_PauseAudioDevice"); -#endif #else // Compile-time linking. pContext->sdl.SDL_InitSubSystem = (mal_proc)SDL_InitSubSystem; 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_GetAudioDeviceName = (mal_proc)SDL_GetAudioDeviceName; pContext->sdl.SDL_CloseAudioDevice = (mal_proc)SDL_CloseAudioDevice; pContext->sdl.SDL_OpenAudioDevice = (mal_proc)SDL_OpenAudioDevice; pContext->sdl.SDL_PauseAudioDevice = (mal_proc)SDL_PauseAudioDevice; #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); if (resultSDL != 0) { @@ -28562,6 +28415,11 @@ mal_uint64 mal_sine_wave_read_ex(mal_sine_wave* pSineWave, mal_uint64 frameCount // 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 // - iOS bug fixes. // - Minor tweaks to PulseAudio. diff --git a/research/mal_resampler.h b/research/mal_resampler.h index 9ffd38b1..9266854b 100644 --- a/research/mal_resampler.h +++ b/research/mal_resampler.h @@ -5,7 +5,6 @@ This is research into a new resampler for mini_al. Not yet complete. Requirements: - Selection of different algorithms. The following at a minimum: - - Passthrough - Linear with optional filtering - Sinc - Floating point pipeline for f32 and fixed point integer pipeline for s16 @@ -39,6 +38,8 @@ Other Notes: Random Notes: - 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. +- 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 #define mal_resampler_h @@ -51,22 +52,18 @@ Random Notes: typedef struct mal_resampler mal_resampler; /* 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. */ -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_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 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_seek_proc)(mal_resampler* pResampler, mal_uint64 frameCount, mal_uint32 options); typedef enum { - mal_resample_algorithm_sinc = 0, /* Default. */ - mal_resample_algorithm_linear, /* Fastest. */ - mal_resample_algorithm_passthrough /* No resampling. */ -} mal_resample_algorithm; + mal_resampler_algorithm_sinc = 0, /* Default. */ + mal_resampler_algorithm_linear, /* Fastest. */ +} mal_resampler_algorithm; typedef enum { @@ -81,7 +78,7 @@ typedef struct mal_uint32 sampleRateIn; mal_uint32 sampleRateOut; double ratio; /* ratio = in/out */ - mal_resample_algorithm algorithm; + mal_resampler_algorithm algorithm; mal_resampler_end_of_input_mode endOfInputMode; mal_resampler_read_from_client_proc onRead; void* pUserData; @@ -94,7 +91,7 @@ struct mal_resampler float f32[MAL_RESAMPLER_CACHE_SIZE_IN_BYTES/sizeof(float)]; 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. */ - 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 windowLength; 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_read_proc read; 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. 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); @@ -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. 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); /* 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. + +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); /* 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. + +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); @@ -192,10 +188,10 @@ Calculates the number of whole output frames that would be output after fully re 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 -inputFrameCount + mal_resampler_get_cached_input_frame_count(). It essentially calcualtes how many output frames will be -returned if an additional inputFrameCount frames were read from the client and consumed by the resampler. You can adjust -the return value by mal_resampler_get_cached_output_frame_count() which calculates the number of output frames that can be -output from the currently cached input. +inputFrameCount + mal_resampler_get_cached_input_time(). It essentially calcualtes how many output frames will be returned +if an additional inputFrameCount frames were read from the client and consumed by the resampler. You can adjust the return +value by mal_resampler_get_cached_output_frame_count() which calculates the number of output frames that can be output from +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 window are not included in the calculation. @@ -204,27 +200,23 @@ mal_uint64 mal_resampler_get_expected_output_frame_count(mal_resampler* pResampl #endif #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); -mal_result mal_resampler_get_cached_time__passthrough(mal_resampler* pResampler, double* pInputTime, double* pOutputTime); -mal_uint64 mal_resampler_get_required_input_frame_count__passthrough(mal_resampler* pResampler, mal_uint64 outputFrameCount); -mal_uint64 mal_resampler_get_expected_output_frame_count__passthrough(mal_resampler* pResampler, mal_uint64 inputFrameCount); + +#ifndef MAL_RESAMPLER_MIN_RATIO +#define MAL_RESAMPLER_MIN_RATIO 0.001 +#endif +#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_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_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_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 */ -#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)) /* @@ -276,34 +268,18 @@ mal_result mal_resampler_init(const mal_resampler_config* pConfig, mal_resampler } switch (pResampler->config.algorithm) { - case mal_resample_algorithm_passthrough: + case mal_resampler_algorithm_linear: { - pResampler->init = NULL; - pResampler->read = mal_resampler_read__passthrough; - pResampler->seek = mal_resampler_seek__passthrough; - 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; + pResampler->init = NULL; + pResampler->read = mal_resampler_read__linear; + pResampler->seek = mal_resampler_seek__linear; } break; - case mal_resample_algorithm_linear: + case mal_resampler_algorithm_sinc: { - pResampler->init = NULL; - pResampler->read = mal_resampler_read__linear; - pResampler->seek = mal_resampler_seek__linear; - 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; + pResampler->init = mal_resampler_init__sinc; + pResampler->read = mal_resampler_read__sinc; + pResampler->seek = mal_resampler_seek__sinc; } break; } @@ -332,9 +308,14 @@ mal_result mal_resampler_set_rate(mal_resampler* pResampler, mal_uint32 sampleRa 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.sampleRateOut = sampleRateOut; - pResampler->config.ratio = (double)pResampler->config.sampleRateIn / (double)pResampler->config.sampleRateOut; + pResampler->config.ratio = ratio; return MAL_SUCCESS; } @@ -345,8 +326,8 @@ mal_result mal_resampler_set_rate_ratio(mal_resampler* pResampler, double ratio) return MAL_INVALID_ARGS; } - if (ratio == 0) { - return MAL_INVALID_ARGS; + if (ratio < MAL_RESAMPLER_MIN_RATIO || ratio > MAL_RESAMPLER_MAX_RATIO) { + return MAL_INVALID_ARGS; /* Ratio is too extreme. */ } 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 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 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)); } +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) { - if (pResampler == NULL || pResampler->getCachedTime == NULL) { + if (pResampler == NULL) { return 0; /* Invalid args. */ } - double inputTime = 0; - double outputTime = 0; - mal_result result = pResampler->getCachedTime(pResampler, &inputTime, &outputTime); - if (result != MAL_SUCCESS) { - return 0; - } + return mal_resampler__calculate_cached_input_time(pResampler); +} - 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) { - if (pResampler == NULL || pResampler->getCachedTime == NULL) { + if (pResampler == NULL) { return 0; /* Invalid args. */ } - double inputTime = 0; - double outputTime = 0; - mal_result result = pResampler->getCachedTime(pResampler, &inputTime, &outputTime); - if (result != MAL_SUCCESS) { - return 0; - } - - return outputTime; + return mal_resampler__calculate_cached_output_time(pResampler); } 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. */ } @@ -440,12 +430,33 @@ mal_uint64 mal_resampler_get_required_input_frame_count(mal_resampler* pResample 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) { - if (pResampler == NULL || pResampler->getExpectedOutputFrameCount == NULL) { + if (pResampler == NULL) { return 0; /* Invalid args. */ } @@ -453,132 +464,8 @@ mal_uint64 mal_resampler_get_expected_output_frame_count(mal_resampler* pResampl return 0; } - return pResampler->getExpectedOutputFrameCount(pResampler, inputFrameCount); -} - - -/* -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; + /* 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); } @@ -612,36 +499,6 @@ mal_uint64 mal_resampler_seek__linear(mal_resampler* pResampler, mal_uint64 fram 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 @@ -681,34 +538,4 @@ mal_uint64 mal_resampler_seek__sinc(mal_resampler* pResampler, mal_uint64 frameC 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 diff --git a/tests/mal_test_0.vcxproj b/tests/mal_test_0.vcxproj index 594a236c..1420d766 100644 --- a/tests/mal_test_0.vcxproj +++ b/tests/mal_test_0.vcxproj @@ -322,6 +322,7 @@ + diff --git a/tests/mal_test_0.vcxproj.filters b/tests/mal_test_0.vcxproj.filters index ac4dbbc9..8e66fa8c 100644 --- a/tests/mal_test_0.vcxproj.filters +++ b/tests/mal_test_0.vcxproj.filters @@ -44,5 +44,8 @@ Source Files + + Source Files + \ No newline at end of file