mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-22 00:06:59 +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.
|
||||
// mini_al - v0.8.12 - 2018-11-27
|
||||
// mini_al - v0.8.13 - 2018-12-04
|
||||
//
|
||||
// David Reid - davidreidsoftware@gmail.com
|
||||
|
||||
@@ -24688,8 +24688,8 @@ float g_malChannelPlaneRatios[MAL_CHANNEL_POSITION_COUNT][6] = {
|
||||
{ 0.0f, 0.5f, 0.5f, 0.0f, 0.0f, 0.0f}, // MAL_CHANNEL_FRONT_RIGHT
|
||||
{ 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f}, // MAL_CHANNEL_FRONT_CENTER
|
||||
{ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, // MAL_CHANNEL_LFE
|
||||
{ 0.5f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f}, // MAL_CHANNEL_BACK_LEFT
|
||||
{ 0.0f, 0.5f, 0.0f, 0.0f, 0.5f, 0.0f}, // MAL_CHANNEL_BACK_RIGHT
|
||||
{ 0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f}, // MAL_CHANNEL_BACK_LEFT
|
||||
{ 0.0f, 0.5f, 0.0f, 0.5f, 0.0f, 0.0f}, // MAL_CHANNEL_BACK_RIGHT
|
||||
{ 0.25f, 0.0f, 0.75f, 0.0f, 0.0f, 0.0f}, // MAL_CHANNEL_FRONT_LEFT_CENTER
|
||||
{ 0.0f, 0.25f, 0.75f, 0.0f, 0.0f, 0.0f}, // MAL_CHANNEL_FRONT_RIGHT_CENTER
|
||||
{ 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f}, // MAL_CHANNEL_BACK_CENTER
|
||||
@@ -28485,6 +28485,10 @@ mal_uint64 mal_sine_wave_read_ex(mal_sine_wave* pSineWave, mal_uint64 frameCount
|
||||
// REVISION HISTORY
|
||||
// ================
|
||||
//
|
||||
// v0.8.13 - 2018-12-04
|
||||
// - Core Audio: Fix a bug with channel mapping.
|
||||
// - Fix a bug with channel routing where the back/left and back/right channels have the wrong weight.
|
||||
//
|
||||
// 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.
|
||||
|
||||
+285
-31
@@ -25,7 +25,6 @@ Requirements:
|
||||
- Must have different modes on how to handle the last of the input samples. Certain situations (streaming) requires
|
||||
the last input samples to be cached in the internal structure for the windowing algorithm. Other situations require
|
||||
all of the input samples to be consumed in order to output the correct total sample count.
|
||||
- Pointers passed into the onRead() callback must be guaranteed to be aligned to MAL_SIMD_ALIGNMENT.
|
||||
|
||||
|
||||
Other Notes:
|
||||
@@ -38,8 +37,9 @@ 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.
|
||||
- Ratios need to be in the range of MAL_RESAMPLER_MIN_RATIO and MAL_RESAMPLER_MAX_RATIO. This is enough to convert
|
||||
to and from 8000 and 384000, which is the smallest and largest standard rates supported by mini_al. If you need
|
||||
extreme ratios then you will need to chain resamplers together.
|
||||
*/
|
||||
#ifndef mal_resampler_h
|
||||
#define mal_resampler_h
|
||||
@@ -47,7 +47,9 @@ Random Notes:
|
||||
#define MAL_RESAMPLER_SEEK_NO_CLIENT_READ (1 << 0) /* When set, does not read anything from the client when seeking. This does _not_ call onRead(). */
|
||||
#define MAL_RESAMPLER_SEEK_INPUT_RATE (1 << 1) /* When set, treats the specified frame count based on the input sample rate rather than the output sample rate. */
|
||||
|
||||
#ifndef MAL_RESAMPLER_CACHE_SIZE_IN_BYTES
|
||||
#define MAL_RESAMPLER_CACHE_SIZE_IN_BYTES 4096
|
||||
#endif
|
||||
|
||||
typedef struct mal_resampler mal_resampler;
|
||||
|
||||
@@ -55,9 +57,10 @@ typedef struct mal_resampler mal_resampler;
|
||||
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_init_proc) (mal_resampler* pResampler);
|
||||
typedef mal_uint64 (* mal_resampler_read_f32_proc)(mal_resampler* pResampler, mal_uint64 frameCount, float** ppFrames);
|
||||
typedef mal_uint64 (* mal_resampler_read_s16_proc)(mal_resampler* pResampler, mal_uint64 frameCount, mal_int16** ppFrames);
|
||||
typedef mal_uint64 (* mal_resampler_seek_proc) (mal_resampler* pResampler, mal_uint64 frameCount, mal_uint32 options);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
@@ -90,14 +93,15 @@ 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 firstCachedFrameOffset;
|
||||
mal_uint16 cacheLengthInFrames; /* The number of valid frames sitting in the cache. May be less than the cache's capacity. */
|
||||
} cache; /* Keep this as the first member of this structure for SIMD alignment purposes. */
|
||||
mal_uint32 cacheStrideInFrames; /* The number of the samples between channels in the cache. The first sample for channel 0 is cacheStrideInFrames*0. The first sample for channel 1 is cacheStrideInFrames*1, etc. */
|
||||
mal_uint16 cacheLengthInFrames; /* The number of valid frames sitting in the cache, including the filter window. May be less than the cache's capacity. */
|
||||
mal_uint16 windowLength;
|
||||
double windowTime; /* By input rate. Relative to the start of the cache. */
|
||||
mal_resampler_config config;
|
||||
mal_resampler_init_proc init;
|
||||
mal_resampler_read_proc read;
|
||||
mal_resampler_read_f32_proc readF32;
|
||||
mal_resampler_read_s16_proc readS16;
|
||||
mal_resampler_seek_proc seek;
|
||||
};
|
||||
|
||||
@@ -118,6 +122,8 @@ mal_result mal_resampler_set_rate(mal_resampler* pResampler, mal_uint32 sampleRa
|
||||
|
||||
/*
|
||||
Dynamically adjusts the sample rate by a ratio.
|
||||
|
||||
The ratio is in/out.
|
||||
*/
|
||||
mal_result mal_resampler_set_rate_ratio(mal_resampler* pResampler, double ratio);
|
||||
|
||||
@@ -159,6 +165,10 @@ 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.
|
||||
|
||||
This can return a negative value if nothing has yet been loaded into the internal cache. This will happen if this is called
|
||||
immediately after initialization, before the first read has been performed. It may also happen if only a few samples have
|
||||
been read from the client.
|
||||
*/
|
||||
double mal_resampler_get_cached_input_time(mal_resampler* pResampler);
|
||||
|
||||
@@ -168,6 +178,8 @@ 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.
|
||||
|
||||
This can return a negative value. See mal_resampler_get_cached_input_time() for details.
|
||||
*/
|
||||
double mal_resampler_get_cached_output_time(mal_resampler* pResampler);
|
||||
|
||||
@@ -202,20 +214,33 @@ mal_uint64 mal_resampler_get_expected_output_frame_count(mal_resampler* pResampl
|
||||
#ifdef MINI_AL_IMPLEMENTATION
|
||||
|
||||
#ifndef MAL_RESAMPLER_MIN_RATIO
|
||||
#define MAL_RESAMPLER_MIN_RATIO 0.001
|
||||
#define MAL_RESAMPLER_MIN_RATIO 0.02083333
|
||||
#endif
|
||||
#ifndef MAL_RESAMPLER_MAX_RATIO
|
||||
#define MAL_RESAMPLER_MAX_RATIO 100.0
|
||||
#define MAL_RESAMPLER_MAX_RATIO 48.0
|
||||
#endif
|
||||
|
||||
mal_uint64 mal_resampler_read__linear(mal_resampler* pResampler, mal_uint64 frameCount, void** ppFrames);
|
||||
mal_result mal_resampler_init__linear(mal_resampler* pResampler);
|
||||
mal_uint64 mal_resampler_read_f32__linear(mal_resampler* pResampler, mal_uint64 frameCount, float** ppFrames);
|
||||
mal_uint64 mal_resampler_read_s16__linear(mal_resampler* pResampler, mal_uint64 frameCount, mal_int16** ppFrames);
|
||||
mal_uint64 mal_resampler_seek__linear(mal_resampler* pResampler, mal_uint64 frameCount, mal_uint32 options);
|
||||
|
||||
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_f32__sinc(mal_resampler* pResampler, mal_uint64 frameCount, float** ppFrames);
|
||||
mal_uint64 mal_resampler_read_s16__sinc(mal_resampler* pResampler, mal_uint64 frameCount, mal_int16** ppFrames);
|
||||
mal_uint64 mal_resampler_seek__sinc(mal_resampler* pResampler, mal_uint64 frameCount, mal_uint32 options);
|
||||
|
||||
/* TODO: Add this to mini_al.h */
|
||||
static MAL_INLINE float mal_fractional_part_f32(float x)
|
||||
{
|
||||
return x - ((mal_int32)x);
|
||||
}
|
||||
|
||||
static MAL_INLINE double mal_fractional_part_f64(double x)
|
||||
{
|
||||
return x - ((mal_int64)x);
|
||||
}
|
||||
|
||||
#if 0
|
||||
#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))
|
||||
|
||||
@@ -237,7 +262,21 @@ This does not work for formats that do not have a clean mapping to a primitive C
|
||||
name[iChannel] = (type*)((mal_uint8*)MAL_ALIGN_PTR(name##Unaligned, MAL_SIMD_ALIGNMENT) + (iChannel*((size) & ~((MAL_SIMD_ALIGNMENT)-1)))); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
#define mal_filter_window_length_left(length) ((length) >> 1)
|
||||
#define mal_filter_window_length_right(length) ((length) - mal_filter_window_length_left(length))
|
||||
|
||||
static MAL_INLINE mal_uint16 mal_resampler_window_length_left(const mal_resampler* pResampler)
|
||||
{
|
||||
return mal_filter_window_length_left(pResampler->windowLength);
|
||||
}
|
||||
|
||||
static MAL_INLINE mal_uint16 mal_resampler_window_length_right(const mal_resampler* pResampler)
|
||||
{
|
||||
return mal_filter_window_length_right(pResampler->windowLength);
|
||||
}
|
||||
|
||||
|
||||
mal_result mal_resampler_init(const mal_resampler_config* pConfig, mal_resampler* pResampler)
|
||||
{
|
||||
@@ -270,19 +309,27 @@ mal_result mal_resampler_init(const mal_resampler_config* pConfig, mal_resampler
|
||||
switch (pResampler->config.algorithm) {
|
||||
case mal_resampler_algorithm_linear:
|
||||
{
|
||||
pResampler->init = NULL;
|
||||
pResampler->read = mal_resampler_read__linear;
|
||||
pResampler->seek = mal_resampler_seek__linear;
|
||||
pResampler->init = mal_resampler_init__linear;
|
||||
pResampler->readF32 = mal_resampler_read_f32__linear;
|
||||
pResampler->readS16 = mal_resampler_read_s16__linear;
|
||||
pResampler->seek = mal_resampler_seek__linear;
|
||||
} break;
|
||||
|
||||
case mal_resampler_algorithm_sinc:
|
||||
{
|
||||
pResampler->init = mal_resampler_init__sinc;
|
||||
pResampler->read = mal_resampler_read__sinc;
|
||||
pResampler->seek = mal_resampler_seek__sinc;
|
||||
pResampler->init = mal_resampler_init__sinc;
|
||||
pResampler->readF32 = mal_resampler_read_f32__sinc;
|
||||
pResampler->readS16 = mal_resampler_read_s16__sinc;
|
||||
pResampler->seek = mal_resampler_seek__sinc;
|
||||
} break;
|
||||
}
|
||||
|
||||
if (pResampler->config.format == mal_format_f32) {
|
||||
pResampler->cacheStrideInFrames = mal_countof(pResampler->cache.f32) / pResampler->config.channels;
|
||||
} else {
|
||||
pResampler->cacheStrideInFrames = mal_countof(pResampler->cache.s16) / pResampler->config.channels;
|
||||
}
|
||||
|
||||
if (pResampler->init != NULL) {
|
||||
mal_result result = pResampler->init(pResampler);
|
||||
if (result != MAL_SUCCESS) {
|
||||
@@ -290,6 +337,12 @@ mal_result mal_resampler_init(const mal_resampler_config* pConfig, mal_resampler
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
After initializing the backend, we'll need to pre-fill the filter with zeroes. This has already been half done via
|
||||
the call to mal_zero_object() at the top of this function, but we need to increment the frame counter to complete it.
|
||||
*/
|
||||
pResampler->cacheLengthInFrames = mal_resampler_window_length_left(pResampler);
|
||||
|
||||
return MAL_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -335,9 +388,19 @@ mal_result mal_resampler_set_rate_ratio(mal_resampler* pResampler, double ratio)
|
||||
return MAL_SUCCESS;
|
||||
}
|
||||
|
||||
typedef union
|
||||
{
|
||||
float* f32[MAL_MAX_CHANNELS];
|
||||
mal_int16* s16[MAL_MAX_CHANNELS];
|
||||
} mal_resampler_deinterleaved_pointers;
|
||||
|
||||
mal_uint64 mal_resampler_read(mal_resampler* pResampler, mal_uint64 frameCount, void** ppFrames)
|
||||
{
|
||||
if (pResampler == NULL || pResampler->read == NULL) {
|
||||
mal_uint64 totalFramesRead;
|
||||
mal_resampler_deinterleaved_pointers runningFramesOut;
|
||||
mal_bool32 atEnd = MAL_FALSE;
|
||||
|
||||
if (pResampler == NULL) {
|
||||
return 0; /* Invalid arguments. */
|
||||
}
|
||||
|
||||
@@ -351,7 +414,158 @@ mal_uint64 mal_resampler_read(mal_resampler* pResampler, mal_uint64 frameCount,
|
||||
}
|
||||
|
||||
|
||||
return pResampler->read(pResampler, frameCount, ppFrames);
|
||||
if (pResampler->config.format == mal_format_f32) {
|
||||
mal_assert(pResampler->readF32 != NULL);
|
||||
} else {
|
||||
mal_assert(pResampler->readS16 != NULL);
|
||||
}
|
||||
|
||||
|
||||
/* Initialization of the running frame pointers. */
|
||||
for (mal_uint32 iChannel = 0; iChannel < pResampler->config.channels; ++iChannel) {
|
||||
runningFramesOut.f32[iChannel] = (float*)ppFrames[iChannel];
|
||||
}
|
||||
|
||||
/*
|
||||
The backend read callbacks are only called for ranges that can be read entirely from cache. This simplifies each backend
|
||||
because they do not need to worry about cache reloading logic. Instead we do all of the cache reloading stuff from here.
|
||||
*/
|
||||
|
||||
totalFramesRead = 0;
|
||||
while (totalFramesRead < frameCount) {
|
||||
double cachedOutputTime;
|
||||
mal_uint64 framesRemaining = frameCount - totalFramesRead;
|
||||
mal_uint64 framesToReadRightNow = framesRemaining;
|
||||
|
||||
/* We need to make sure we don't read more than what's already in the buffer at a time. */
|
||||
cachedOutputTime = mal_resampler_get_cached_output_time(pResampler);
|
||||
if (cachedOutputTime > 0) {
|
||||
if (framesRemaining > cachedOutputTime) {
|
||||
framesToReadRightNow = (mal_uint64)floor(cachedOutputTime);
|
||||
}
|
||||
|
||||
/*
|
||||
At this point we should know how many frames can be read this iteration. We need an optimization for when the ratio=1
|
||||
and the current time is a whole number. In this case we need to do a direct copy without any processing.
|
||||
*/
|
||||
if (pResampler->config.ratio == 1 && mal_fractional_part_f64(pResampler->windowTime) == 0) {
|
||||
/*
|
||||
No need to read from the backend - just copy the input straight over without any processing. We start reading from
|
||||
the right side of the filter window.
|
||||
*/
|
||||
mal_uint16 iFirstSample = (mal_uint16)pResampler->windowTime + mal_resampler_window_length_left(pResampler);
|
||||
if (pResampler->config.format == mal_format_f32) {
|
||||
for (mal_uint16 iChannel = 0; iChannel < pResampler->config.channels; ++iChannel) {
|
||||
for (mal_uint16 iFrame = 0; iFrame < framesToReadRightNow; ++iFrame) {
|
||||
runningFramesOut.f32[iChannel][iFrame] = pResampler->cache.f32[pResampler->cacheStrideInFrames*iChannel + iFirstSample + iFrame];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (mal_uint16 iChannel = 0; iChannel < pResampler->config.channels; ++iChannel) {
|
||||
for (mal_uint16 iFrame = 0; iFrame < framesToReadRightNow; ++iFrame) {
|
||||
runningFramesOut.s16[iChannel][iFrame] = pResampler->cache.s16[pResampler->cacheStrideInFrames*iChannel + iFirstSample + iFrame];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Need to read from the backend. */
|
||||
mal_uint64 framesJustRead;
|
||||
if (pResampler->config.format == mal_format_f32) {
|
||||
framesJustRead = pResampler->readF32(pResampler, framesToReadRightNow, runningFramesOut.f32);
|
||||
} else {
|
||||
framesJustRead = pResampler->readS16(pResampler, framesToReadRightNow, runningFramesOut.s16);
|
||||
}
|
||||
|
||||
if (framesJustRead != framesToReadRightNow) {
|
||||
mal_assert(MAL_FALSE);
|
||||
break; /* Should never hit this. */
|
||||
}
|
||||
}
|
||||
|
||||
/* Move time forward. */
|
||||
pResampler->windowTime += (framesToReadRightNow * pResampler->config.ratio);
|
||||
|
||||
if (pResampler->config.format == mal_format_f32) {
|
||||
for (mal_uint32 iChannel = 0; iChannel < pResampler->config.channels; ++iChannel) {
|
||||
runningFramesOut.f32[iChannel] += framesToReadRightNow;
|
||||
}
|
||||
} else {
|
||||
for (mal_uint32 iChannel = 0; iChannel < pResampler->config.channels; ++iChannel) {
|
||||
runningFramesOut.s16[iChannel] += framesToReadRightNow;
|
||||
}
|
||||
}
|
||||
|
||||
/* We don't want to reload the buffer if we've finished reading. */
|
||||
totalFramesRead += framesToReadRightNow;
|
||||
if (totalFramesRead == frameCount) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
We need to exit if we've reached the end of the input buffer. We do not want to attempt to read more data, nor
|
||||
do we want to read in zeroes to fill out the requested frame count (frameCount).
|
||||
*/
|
||||
if (atEnd) {
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
If we get here it means we need to reload the buffer from the client and keep iterating. To reload the buffer we
|
||||
need to move the remaining data down to the front of the buffer, adjust the window time, then read more from the
|
||||
client. If we have already reached the end of the client's data, we don't want to attempt to read more.
|
||||
*/
|
||||
{
|
||||
mal_uint32 framesToReadFromClient;
|
||||
mal_uint32 framesReadFromClient;
|
||||
mal_uint16 framesToConsume;
|
||||
|
||||
mal_assert(pResampler->windowTime < 65536);
|
||||
mal_assert(pResampler->windowTime <= pResampler->cacheLengthInFrames);
|
||||
|
||||
framesToConsume = (mal_uint16)pResampler->windowTime;
|
||||
|
||||
pResampler->windowTime -= framesToConsume;
|
||||
pResampler->cacheLengthInFrames -= framesToConsume;
|
||||
|
||||
if (pResampler->config.format == mal_format_f32) {
|
||||
for (mal_int32 i = 0; i < pResampler->cacheLengthInFrames; ++i) {
|
||||
pResampler->cache.f32[i] = pResampler->cache.f32[i + framesToConsume];
|
||||
}
|
||||
framesToReadFromClient = mal_countof(pResampler->cache.f32) - pResampler->cacheLengthInFrames;
|
||||
} else {
|
||||
for (mal_int32 i = 0; i < pResampler->cacheLengthInFrames; ++i) {
|
||||
pResampler->cache.s16[i] = pResampler->cache.s16[i + framesToConsume];
|
||||
}
|
||||
framesToReadFromClient = mal_countof(pResampler->cache.s16) - pResampler->cacheLengthInFrames;
|
||||
}
|
||||
|
||||
/* Here is where we need to read more data from the client. We need to construct some deinterleaved buffers first, though. */
|
||||
mal_resampler_deinterleaved_pointers clientDst;
|
||||
if (pResampler->config.format == mal_format_f32) {
|
||||
for (mal_uint32 iChannel = 0; iChannel < pResampler->config.channels; ++iChannel) {
|
||||
clientDst.f32[iChannel] = pResampler->cache.f32 + (pResampler->cacheStrideInFrames*iChannel + pResampler->cacheLengthInFrames);
|
||||
}
|
||||
framesReadFromClient = pResampler->config.onRead(pResampler, framesToReadFromClient, clientDst.f32);
|
||||
} else {
|
||||
for (mal_uint32 iChannel = 0; iChannel < pResampler->config.channels; ++iChannel) {
|
||||
clientDst.s16[iChannel] = pResampler->cache.s16 + (pResampler->cacheStrideInFrames*iChannel + pResampler->cacheLengthInFrames);
|
||||
}
|
||||
framesReadFromClient = pResampler->config.onRead(pResampler, framesToReadFromClient, clientDst.s16);
|
||||
}
|
||||
|
||||
mal_assert(framesReadFromClient <= framesToReadFromClient);
|
||||
if (framesReadFromClient < framesToReadFromClient) {
|
||||
/* We have reached the end of the input buffer. We do _not_ want to attempt to read any more data from the client in this case. */
|
||||
atEnd = MAL_TRUE;
|
||||
}
|
||||
|
||||
mal_assert(framesReadFromClient <= 65535);
|
||||
pResampler->cacheLengthInFrames += (mal_uint16)framesReadFromClient;
|
||||
}
|
||||
}
|
||||
|
||||
return totalFramesRead;
|
||||
}
|
||||
|
||||
mal_uint64 mal_resampler_seek(mal_resampler* pResampler, mal_uint64 frameCount, mal_uint32 options)
|
||||
@@ -364,8 +578,10 @@ mal_uint64 mal_resampler_seek(mal_resampler* pResampler, mal_uint64 frameCount,
|
||||
return 0; /* Nothing to do, so return early. */
|
||||
}
|
||||
|
||||
/* TODO: Do seeking. */
|
||||
(void)options;
|
||||
|
||||
return pResampler->seek(pResampler, frameCount, options);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -379,7 +595,7 @@ 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)
|
||||
static MAL_INLINE 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
|
||||
@@ -388,10 +604,10 @@ double mal_resampler__calculate_cached_input_time(mal_resampler* pResampler)
|
||||
*/
|
||||
double cachedInputTime = pResampler->cacheLengthInFrames;
|
||||
if (pResampler->config.endOfInputMode == mal_resampler_end_of_input_mode_consume) {
|
||||
cachedInputTime -= (pResampler->windowTime + (pResampler->windowLength >> 1));
|
||||
cachedInputTime -= (pResampler->windowTime + mal_resampler_window_length_left(pResampler));
|
||||
} else {
|
||||
cachedInputTime -= (pResampler->windowTime + pResampler->windowLength);
|
||||
}
|
||||
}
|
||||
|
||||
return cachedInputTime;
|
||||
}
|
||||
@@ -405,7 +621,7 @@ double mal_resampler_get_cached_input_time(mal_resampler* pResampler)
|
||||
return mal_resampler__calculate_cached_input_time(pResampler);
|
||||
}
|
||||
|
||||
double mal_resampler__calculate_cached_output_time(mal_resampler* pResampler)
|
||||
static MAL_INLINE double mal_resampler__calculate_cached_output_time(mal_resampler* pResampler)
|
||||
{
|
||||
return mal_resampler__calculate_cached_input_time(pResampler) / pResampler->config.ratio;
|
||||
}
|
||||
@@ -472,7 +688,31 @@ mal_uint64 mal_resampler_get_expected_output_frame_count(mal_resampler* pResampl
|
||||
/*
|
||||
Linear
|
||||
*/
|
||||
mal_uint64 mal_resampler_read__linear(mal_resampler* pResampler, mal_uint64 frameCount, void** ppFrames)
|
||||
mal_result mal_resampler_init__linear(mal_resampler* pResampler)
|
||||
{
|
||||
mal_assert(pResampler != NULL);
|
||||
|
||||
/* The linear implementation always has a window length of 2. */
|
||||
pResampler->windowLength = 2;
|
||||
|
||||
return MAL_SUCCESS;
|
||||
}
|
||||
|
||||
mal_uint64 mal_resampler_read_f32__linear(mal_resampler* pResampler, mal_uint64 frameCount, float** ppFrames)
|
||||
{
|
||||
mal_assert(pResampler != NULL);
|
||||
mal_assert(pResampler->config.onRead != NULL);
|
||||
mal_assert(frameCount > 0);
|
||||
mal_assert(ppFrames != NULL);
|
||||
|
||||
/* TODO: Implement me. */
|
||||
(void)pResampler;
|
||||
(void)frameCount;
|
||||
(void)ppFrames;
|
||||
return 0;
|
||||
}
|
||||
|
||||
mal_uint64 mal_resampler_read_s16__linear(mal_resampler* pResampler, mal_uint64 frameCount, mal_int16** ppFrames)
|
||||
{
|
||||
mal_assert(pResampler != NULL);
|
||||
mal_assert(pResampler->config.onRead != NULL);
|
||||
@@ -511,7 +751,21 @@ mal_result mal_resampler_init__sinc(mal_resampler* pResampler)
|
||||
return MAL_SUCCESS;
|
||||
}
|
||||
|
||||
mal_uint64 mal_resampler_read__sinc(mal_resampler* pResampler, mal_uint64 frameCount, void** ppFrames)
|
||||
mal_uint64 mal_resampler_read_f32__sinc(mal_resampler* pResampler, mal_uint64 frameCount, float** ppFrames)
|
||||
{
|
||||
mal_assert(pResampler != NULL);
|
||||
mal_assert(pResampler->config.onRead != NULL);
|
||||
mal_assert(frameCount > 0);
|
||||
mal_assert(ppFrames != NULL);
|
||||
|
||||
/* TODO: Implement me. */
|
||||
(void)pResampler;
|
||||
(void)frameCount;
|
||||
(void)ppFrames;
|
||||
return 0;
|
||||
}
|
||||
|
||||
mal_uint64 mal_resampler_read_s16__sinc(mal_resampler* pResampler, mal_uint64 frameCount, mal_int16** ppFrames)
|
||||
{
|
||||
mal_assert(pResampler != NULL);
|
||||
mal_assert(pResampler->config.onRead != NULL);
|
||||
|
||||
@@ -262,7 +262,30 @@
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\research\tests\mal_resampler_test_0.c" />
|
||||
<ClCompile Include="..\debugging\source\mal_router_1.c">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\examples\simple_playback.c">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\research\tests\mal_resampler_test_0.c">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">false</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">false</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="mal_dithering.c">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
|
||||
@@ -39,6 +39,12 @@
|
||||
<ClCompile Include="..\research\tests\mal_resampler_test_0.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\examples\simple_playback.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\debugging\source\mal_router_1.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\mini_al.h">
|
||||
|
||||
Reference in New Issue
Block a user