diff --git a/research/ma_resampler.h b/research/ma_resampler.h
index 9f71781e..41794f57 100644
--- a/research/ma_resampler.h
+++ b/research/ma_resampler.h
@@ -1,3 +1,200 @@
+/* Resampling research. Public domain. */
+
+#ifndef ma_resampler_h
+#define ma_resampler_h
+
+typedef enum
+{
+ ma_resample_algorithm_linear = 0, /* Default. Fastest. */
+ ma_resample_algorithm_sinc /* Slower. */
+} ma_resample_algorithm;
+
+/*
+Simple high-level API for resampling 32-bit floating point samples.
+
+Use ma_calculate_frame_count_after_src() to determine the required output buffer size.
+*/
+ma_result ma_resample_f32(ma_resample_algorithm algorithm, ma_uint32 sampleRateOut, ma_uint32 sampleRateIn, ma_uint64 sampleCountOut, float* pSamplesOut, ma_uint64 sampleCountIn, float* pSamplesIn);
+
+#endif /* ma_resampler_h */
+
+/*
+Implementation
+*/
+#ifdef MINIAUDIO_IMPLEMENTATION
+
+#ifndef MA_RESAMPLER_MIN_RATIO
+#define MA_RESAMPLER_MIN_RATIO 0.02083333
+#endif
+#ifndef MA_RESAMPLER_MAX_RATIO
+#define MA_RESAMPLER_MAX_RATIO 48.0
+#endif
+
+ma_result ma_resample_f32__linear(ma_uint32 sampleRateOut, ma_uint32 sampleRateIn, ma_uint64 sampleCountOut, float* pSamplesOut, ma_uint64 sampleCountIn, float* pSamplesIn)
+{
+ double ratio = (double)sampleRateIn / (double)sampleRateOut;
+ double timeIn = 0;
+ double timeOut = 0;
+
+ /* Fast path if the sample rates are the same. */
+ if (sampleRateOut == sampleRateIn) {
+ MA_COPY_MEMORY(pSamplesOut, pSamplesIn, (size_t)ma_min(sampleCountOut, sampleCountIn) * sizeof(float));
+ return MA_SUCCESS;
+ }
+
+ /* Do nothing if there's no input. */
+ if (sampleCountOut == 0 || sampleCountIn == 0) {
+ return MA_SUCCESS;
+ }
+
+
+ /* The first output sample should always be the same as the input sample. */
+ pSamplesOut[0] = pSamplesIn[0];
+ timeIn += ratio;
+ timeOut += 1;
+
+ for (;;) {
+ ma_uint64 iTimeIn;
+ ma_uint64 iTimeOut;
+
+ iTimeIn = (ma_uint64)timeIn;
+ if (iTimeIn >= sampleCountIn) {
+ break;
+ }
+
+ iTimeOut = (ma_uint64)timeOut;
+ if (iTimeOut >= sampleCountOut) {
+ break;
+ }
+
+ /* To linearly interpolate we need the previous and next input samples. */
+ {
+ ma_uint64 iTimeInPrev = iTimeIn;
+ ma_uint64 iTimeInNext = (ma_uint64)ceil(timeIn);
+
+ if (iTimeInNext >= sampleCountIn) {
+ iTimeInNext = iTimeInPrev; /* <-- We could instead terminate here which would make the output a few samples shorter. */
+ }
+
+ pSamplesOut[iTimeOut] = ma_mix_f32_fast(pSamplesIn[iTimeInPrev], pSamplesIn[iTimeInNext], (float)(timeIn - iTimeIn));
+
+ /* Try some kind of low-pass filter. */
+ #if 1
+ {
+ double cutoff = ma_min(sampleRateIn, sampleRateOut) * 0.5;
+ double RC = 1.0/(cutoff*MA_TAU_D);
+ double dt = 1.0/sampleRateOut;
+ float alpha = (float)(dt/(RC+dt));
+ pSamplesOut[iTimeOut] = pSamplesOut[iTimeOut-1] + (alpha*(pSamplesOut[iTimeOut] - pSamplesOut[iTimeOut-1]));
+ }
+ #endif
+ }
+
+ timeIn += ratio;
+ timeOut += 1;
+ }
+
+ return MA_INVALID_ARGS;
+}
+
+
+double ma_sinc_hann(double n, int N)
+{
+ double s = sin(MA_PI_D*n/N);
+ return s*s;
+}
+
+ma_result ma_resample_f32__sinc(ma_uint32 sampleRateOut, ma_uint32 sampleRateIn, ma_uint64 sampleCountOut, float* pSamplesOut, ma_uint64 sampleCountIn, float* pSamplesIn)
+{
+ double ratio = (double)sampleRateIn / (double)sampleRateOut;
+ double timeIn = 0;
+ double timeOut = 0;
+ double samplingPeriodIn = 1.0/sampleRateIn;
+ int windowWidth = 32;
+
+ /* Fast path if the sample rates are the same. */
+ if (sampleRateOut == sampleRateIn) {
+ MA_COPY_MEMORY(pSamplesOut, pSamplesIn, (size_t)ma_min(sampleCountOut, sampleCountIn) * sizeof(float));
+ return MA_SUCCESS;
+ }
+
+ /* Do nothing if there's no input. */
+ if (sampleCountOut == 0 || sampleCountIn == 0) {
+ return MA_SUCCESS;
+ }
+
+
+ /* The first output sample should always be the same as the input sample. */
+ pSamplesOut[0] = pSamplesIn[0];
+ timeIn += ratio;
+ timeOut += 1;
+
+ for (;;) {
+ ma_uint64 iTimeIn;
+ ma_uint64 iTimeOut;
+
+ iTimeIn = (ma_uint64)timeIn;
+ if (iTimeIn >= sampleCountIn) {
+ break;
+ }
+
+ iTimeOut = (ma_uint64)timeOut;
+ if (iTimeOut >= sampleCountOut) {
+ break;
+ }
+
+ /* To linearly interpolate we need the previous and next input samples. */
+ {
+ ma_uint64 iTimeInPrev = iTimeIn;
+ ma_uint64 iTimeInNext = (ma_uint64)ceil(timeIn);
+
+ if (iTimeInNext >= sampleCountIn) {
+ iTimeInNext = iTimeInPrev; /* <-- We could instead terminate here which would make the output a few samples shorter. */
+ }
+
+
+
+ #if 0
+ pSamplesOut[iTimeOut] = ma_mix_f32_fast(pSamplesIn[iTimeInPrev], pSamplesIn[iTimeInNext], (float)(timeIn - iTimeIn));
+ #else
+ pSamplesOut[iTimeOut] = 0;
+ for (int i = -windowWidth; i < windowWidth; i += 1) {
+ if ((i < 0 && -i < iTimeIn) || i > 0 && i < sampleCountIn) {
+#if 0
+ double t = (iTimeIn+n);
+ double s = ma_sinc(sampleRateIn*t);
+ pSamplesOut[iTimeOut] += pSamplesIn[(ma_uint64)(iTimeIn+n)] * s;
+#endif
+ }
+ }
+ #endif
+ }
+
+ timeIn += ratio;
+ timeOut += 1;
+ }
+
+ return MA_INVALID_ARGS;
+}
+
+ma_result ma_resample_f32(ma_resample_algorithm algorithm, ma_uint32 sampleRateOut, ma_uint32 sampleRateIn, ma_uint64 sampleCountOut, float* pSamplesOut, ma_uint64 sampleCountIn, float* pSamplesIn)
+{
+ if (pSamplesOut == NULL || pSamplesIn == NULL) {
+ return MA_INVALID_ARGS;
+ }
+
+ switch (algorithm)
+ {
+ case ma_resample_algorithm_linear: return ma_resample_f32__linear(sampleRateOut, sampleRateIn, sampleCountOut, pSamplesOut, sampleCountIn, pSamplesIn);
+ case ma_resample_algorithm_sinc: return ma_resample_f32__sinc (sampleRateOut, sampleRateIn, sampleCountOut, pSamplesOut, sampleCountIn, pSamplesIn);
+ default: return MA_INVALID_ARGS;
+ }
+}
+
+#endif /* MINIAUDIO_IMPLEMENTATION */
+
+
+#if 0
/*
Consider this code public domain.
@@ -1204,3 +1401,4 @@ ma_uint64 ma_resampler_seek__sinc(ma_resampler* pResampler, ma_uint64 frameCount
}
#endif
+#endif /* 0 (Old Implementation)*/
\ No newline at end of file
diff --git a/research/tests/ma_resampler_test_0.c b/research/tests/ma_resampler_test_0.c
index d775dc48..a2e74746 100644
--- a/research/tests/ma_resampler_test_0.c
+++ b/research/tests/ma_resampler_test_0.c
@@ -1,11 +1,122 @@
+#define DR_FLAC_IMPLEMENTATION
+#include "../../extras/dr_flac.h" /* Enables FLAC decoding. */
+#define DR_MP3_IMPLEMENTATION
+#include "../../extras/dr_mp3.h" /* Enables MP3 decoding. */
#define DR_WAV_IMPLEMENTATION
-#include "../../../../dr_libs/dr_wav.h"
+#include "../../extras/dr_wav.h" /* Enables WAV decoding. */
+
#define MA_DEBUG_OUTPUT
#define MINIAUDIO_IMPLEMENTATION
#include "../../miniaudio.h"
#include "../ma_resampler.h"
+#define USE_NEW_RESAMPLER 1
+
+ma_uint64 g_outputFrameCount;
+void* g_pRunningFrameData;
+
+void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount)
+{
+ ma_uint32 framesToCopy;
+
+ framesToCopy = frameCount;
+ if (framesToCopy > (ma_uint32)g_outputFrameCount) {
+ framesToCopy = (ma_uint32)g_outputFrameCount;
+ }
+
+ MA_COPY_MEMORY(pOutput, g_pRunningFrameData, framesToCopy * ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels));
+
+ g_pRunningFrameData = ma_offset_ptr(g_pRunningFrameData, framesToCopy * ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels));
+ g_outputFrameCount -= framesToCopy;
+
+ (void)pInput;
+}
+
+int main(int argc, char** argv)
+{
+ ma_result result;
+ ma_decoder_config decoderConfig;
+ ma_uint64 inputFrameCount;
+ void* pInputFrameData;
+ ma_uint64 outputFrameCount = 0;
+ void* pOutputFrameData = NULL;
+ ma_device_config deviceConfig;
+ ma_device device;
+ ma_backend backend;
+
+ /* This example just resamples the input file to an exclusive device's native sample rate. */
+ if (argc < 2) {
+ printf("No input file.\n");
+ return -1;
+ }
+
+ decoderConfig = ma_decoder_config_init(ma_format_f32, 1, 0);
+
+ result = ma_decode_file(argv[1], &decoderConfig, &inputFrameCount, &pInputFrameData);
+ if (result != MA_SUCCESS) {
+ return (int)result;
+ }
+
+ backend = ma_backend_wasapi;
+
+ deviceConfig = ma_device_config_init(ma_device_type_playback);
+#if USE_NEW_RESAMPLER
+ deviceConfig.playback.shareMode = ma_share_mode_exclusive; /* <-- We need to use exclusive mode to ensure there's no resampling going on by the OS. */
+ deviceConfig.sampleRate = 0; /* <-- Always use the device's native sample rate. */
+#else
+ deviceConfig.playback.shareMode = ma_share_mode_shared; /* <-- We need to use exclusive mode to ensure there's no resampling going on by the OS. */
+ deviceConfig.sampleRate = decoderConfig.sampleRate;
+#endif
+ deviceConfig.playback.format = decoderConfig.format;
+ deviceConfig.playback.channels = decoderConfig.channels;
+ deviceConfig.dataCallback = data_callback;
+ deviceConfig.pUserData = NULL;
+
+ if (ma_device_init(NULL, &deviceConfig, &device) != MA_SUCCESS) {
+ printf("Failed to open playback device.\n");
+ ma_free(pInputFrameData);
+ return -3;
+ }
+
+#if USE_NEW_RESAMPLER
+ /* Resample. */
+ outputFrameCount = ma_calculate_frame_count_after_src(device.sampleRate, decoderConfig.sampleRate, inputFrameCount);
+ pOutputFrameData = ma_malloc((size_t)(outputFrameCount * ma_get_bytes_per_frame(device.playback.format, device.playback.channels)));
+ if (pOutputFrameData == NULL) {
+ printf("Out of memory.\n");
+ ma_free(pInputFrameData);
+ ma_device_uninit(&device);
+ }
+
+ ma_resample_f32(ma_resample_algorithm_sinc, device.playback.internalSampleRate, decoderConfig.sampleRate, outputFrameCount, pOutputFrameData, inputFrameCount, pInputFrameData);
+
+ g_pRunningFrameData = pOutputFrameData;
+ g_outputFrameCount = outputFrameCount;
+#else
+ g_pRunningFrameData = pInputFrameData;
+ g_outputFrameCount = inputFrameCount;
+#endif
+
+ if (ma_device_start(&device) != MA_SUCCESS) {
+ printf("Failed to start playback device.\n");
+ ma_device_uninit(&device);
+ ma_free(pInputFrameData);
+ ma_free(pOutputFrameData);
+ return -4;
+ }
+
+ printf("Press Enter to quit...");
+ getchar();
+
+ ma_device_uninit(&device);
+ ma_free(pInputFrameData);
+ ma_free(pOutputFrameData);
+
+ return 0;
+}
+
+#if 0
#define SAMPLE_RATE_IN 44100
#define SAMPLE_RATE_OUT 44100
#define CHANNELS 1
@@ -71,4 +182,5 @@ int main(int argc, char** argv)
(void)argc;
(void)argv;
return 0;
-}
\ No newline at end of file
+}
+#endif
diff --git a/tests/ma_test_0.vcxproj b/tests/ma_test_0.vcxproj
index b667c6b3..34fe9def 100644
--- a/tests/ma_test_0.vcxproj
+++ b/tests/ma_test_0.vcxproj
@@ -319,12 +319,12 @@
true
- false
- false
- false
- false
- false
- false
+ true
+ true
+ true
+ true
+ true
+ true
true
@@ -335,12 +335,12 @@
true
- true
- true
- true
- true
- true
- true
+ false
+ false
+ false
+ false
+ false
+ false
true