mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-22 00:06:59 +02:00
More prototyping work on the new resampler.
This commit is contained in:
+112
-164
@@ -51,22 +51,19 @@ 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_passthrough /* No resampling. */
|
||||||
} mal_resample_algorithm;
|
} mal_resampler_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.
|
||||||
@@ -206,25 +202,16 @@ mal_uint64 mal_resampler_get_expected_output_frame_count(mal_resampler* pResampl
|
|||||||
#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_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_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);
|
|
||||||
|
|
||||||
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 +263,25 @@ 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_passthrough:
|
||||||
{
|
{
|
||||||
pResampler->init = NULL;
|
pResampler->init = NULL;
|
||||||
pResampler->read = mal_resampler_read__passthrough;
|
pResampler->read = mal_resampler_read__passthrough;
|
||||||
pResampler->seek = mal_resampler_seek__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;
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case mal_resample_algorithm_linear:
|
case mal_resampler_algorithm_linear:
|
||||||
{
|
{
|
||||||
pResampler->init = NULL;
|
pResampler->init = NULL;
|
||||||
pResampler->read = mal_resampler_read__linear;
|
pResampler->read = mal_resampler_read__linear;
|
||||||
pResampler->seek = mal_resampler_seek__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;
|
} break;
|
||||||
|
|
||||||
case mal_resample_algorithm_sinc:
|
case mal_resampler_algorithm_sinc:
|
||||||
{
|
{
|
||||||
pResampler->init = mal_resampler_init__sinc;
|
pResampler->init = mal_resampler_init__sinc;
|
||||||
pResampler->read = mal_resampler_read__sinc;
|
pResampler->read = mal_resampler_read__sinc;
|
||||||
pResampler->seek = mal_resampler_seek__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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -369,6 +347,13 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Special case for passthrough. That has a specialized function for reading for efficiency. */
|
||||||
|
if (pResampler->config.algorithm == mal_resampler_algorithm_passthrough) {
|
||||||
|
return pResampler->read(pResampler, frameCount, ppFrames);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return pResampler->read(pResampler, frameCount, ppFrames);
|
return pResampler->read(pResampler, frameCount, ppFrames);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -382,6 +367,13 @@ 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. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Special case for passthrough. That has a specialized function for reading for efficiency. */
|
||||||
|
if (pResampler->config.algorithm == mal_resampler_algorithm_passthrough) {
|
||||||
|
return pResampler->seek(pResampler, frameCount, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return pResampler->seek(pResampler, frameCount, options);
|
return pResampler->seek(pResampler, frameCount, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -396,43 +388,60 @@ 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;
|
/* Special case for passthrough. Nothing is ever cached. */
|
||||||
double outputTime = 0;
|
if (pResampler->config.algorithm == mal_resampler_algorithm_passthrough) {
|
||||||
mal_result result = pResampler->getCachedTime(pResampler, &inputTime, &outputTime);
|
|
||||||
if (result != MAL_SUCCESS) {
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return inputTime;
|
return mal_resampler__calculate_cached_input_time(pResampler);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
/* Special case for passthrough. Nothing is ever cached. */
|
||||||
double outputTime = 0;
|
if (pResampler->config.algorithm == mal_resampler_algorithm_passthrough) {
|
||||||
mal_result result = pResampler->getCachedTime(pResampler, &inputTime, &outputTime);
|
|
||||||
if (result != MAL_SUCCESS) {
|
|
||||||
return 0;
|
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)
|
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 +449,38 @@ mal_uint64 mal_resampler_get_required_input_frame_count(mal_resampler* pResample
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return pResampler->getRequiredInputFrameCount(pResampler, outputFrameCount);
|
/* Special case for passthrough. */
|
||||||
|
if (pResampler->config.algorithm == mal_resampler_algorithm_passthrough) {
|
||||||
|
return 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,7 +488,13 @@ mal_uint64 mal_resampler_get_expected_output_frame_count(mal_resampler* pResampl
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return pResampler->getExpectedOutputFrameCount(pResampler, inputFrameCount);
|
/* Special case for passthrough. */
|
||||||
|
if (pResampler->config.algorithm == mal_resampler_algorithm_passthrough) {
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -548,39 +589,6 @@ mal_uint64 mal_resampler_seek__passthrough(mal_resampler* pResampler, mal_uint64
|
|||||||
return totalFramesRead;
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Linear
|
Linear
|
||||||
@@ -612,36 +620,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 +659,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