Remove old research code.

This code has now been integrated into miniaudio.h.
This commit is contained in:
David Reid
2020-02-01 11:23:43 +10:00
parent bbe7ff9e2b
commit 5974dd6375
6 changed files with 0 additions and 4157 deletions
File diff suppressed because it is too large Load Diff
-457
View File
@@ -1,457 +0,0 @@
#ifndef ma_lpf_h
#define ma_lpf_h
/**************************************************************************************************************************************************************
Biquad Filter
=============
Biquad filtering is achieved with the `ma_biquad` API. Example:
```c
ma_biquad_config config = ma_biquad_config_init(ma_format_f32, channels, a0, a1, a2, b0, b1, b2);
ma_result result = ma_biquad_init(&config, &biquad);
if (result != MA_SUCCESS) {
// Error.
}
...
ma_biquad_process_pcm_frames(&biquad, pFramesOut, pFramesIn, frameCount);
```
Biquad filtering is implemented using transposed direct form 2. The denominator coefficients are a0, a1 and a2, and the numerator coefficients are b0, b1 and
b2. The a0 coefficient is required and coefficients must not be pre-normalized.
Supported formats are ma_format_s16 and ma_format_f32. If you need to use a different format you need to convert it yourself beforehand. When using
ma_format_s16 the biquad filter will use fixed point arithmetic. When using ma_format_f32, floating point arithmetic will be used.
Input and output frames are always interleaved.
Filtering can be applied in-place by passing in the same pointer for both the input and output buffers, like so:
```c
ma_biquad_process_pcm_frames(&biquad, pMyData, pMyData, frameCount);
```
If you need to change the values of the coefficients, but maintain the values in the registers you can do so with `ma_biquad_reinit()`. This is useful if you
need to change the properties of the filter while keeping the values of registers valid to avoid glitching or whatnot. Do not use `ma_biquad_init()` for this
as it will do a full initialization which involves clearing the registers to 0. Note that changing the format or channel count after initialization is invalid
and will result in an error.
**************************************************************************************************************************************************************/
typedef union
{
float f32;
ma_int32 s32;
} ma_biquad_coefficient;
typedef struct
{
ma_format format;
ma_uint32 channels;
double a0;
double a1;
double a2;
double b0;
double b1;
double b2;
} ma_biquad_config;
ma_biquad_config ma_biquad_config_init(ma_format format, ma_uint32 channels, double a0, double a1, double a2, double b0, double b1, double b2);
typedef struct
{
ma_format format;
ma_uint32 channels;
ma_biquad_coefficient a1;
ma_biquad_coefficient a2;
ma_biquad_coefficient b0;
ma_biquad_coefficient b1;
ma_biquad_coefficient b2;
ma_biquad_coefficient r1[MA_MAX_CHANNELS];
ma_biquad_coefficient r2[MA_MAX_CHANNELS];
} ma_biquad;
ma_result ma_biquad_init(const ma_biquad_config* pConfig, ma_biquad* pBQ);
ma_result ma_biquad_reinit(const ma_biquad_config* pConfig, ma_biquad* pBQ);
ma_result ma_biquad_process_pcm_frames(ma_biquad* pBQ, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
ma_uint32 ma_biquad_get_latency(ma_biquad* pBQ);
/**************************************************************************************************************************************************************
Low-Pass Filter
===============
Low-pass filtering is achieved with the `ma_lpf` API. Example:
```c
ma_lpf_config config = ma_lpf_config_init(ma_format_f32, channels, sampleRate, cutoffFrequency);
ma_result result = ma_lpf_init(&config, &lpf);
if (result != MA_SUCCESS) {
// Error.
}
...
ma_lpf_process_pcm_frames(&lpf, pFramesOut, pFramesIn, frameCount);
```
Supported formats are ma_format_s16 and ma_format_f32. If you need to use a different format you need to convert it yourself beforehand. Input and output
frames are always interleaved.
Filtering can be applied in-place by passing in the same pointer for both the input and output buffers, like so:
```c
ma_lpf_process_pcm_frames(&lpf, pMyData, pMyData, frameCount);
```
The low-pass filter is implemented as a biquad filter. If you need increase the filter order, simply chain multiple low-pass filters together.
```c
for (iFilter = 0; iFilter < filterCount; iFilter += 1) {
ma_lpf_process_pcm_frames(&lpf[iFilter], pMyData, pMyData, frameCount);
}
```
If you need to change the configuration of the filter, but need to maintain the state of internal registers you can do so with `ma_lpf_reinit()`. This may be
useful if you need to change the sample rate and/or cutoff frequency dynamically while maintaing smooth transitions. Note that changing the format or channel
count after initialization is invalid and will result in an error.
**************************************************************************************************************************************************************/
typedef struct
{
ma_format format;
ma_uint32 channels;
ma_uint32 sampleRate;
double cutoffFrequency;
} ma_lpf_config;
ma_lpf_config ma_lpf_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency);
typedef struct
{
ma_biquad bq; /* The low-pass filter is implemented as a biquad filter. */
} ma_lpf;
ma_result ma_lpf_init(const ma_lpf_config* pConfig, ma_lpf* pLPF);
ma_result ma_lpf_reinit(const ma_lpf_config* pConfig, ma_lpf* pLPF);
ma_result ma_lpf_process_pcm_frames(ma_lpf* pLPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
ma_uint32 ma_lpf_get_latency(ma_lpf* pLPF);
#endif /* ma_lpf_h */
#if defined(MINIAUDIO_IMPLEMENTATION)
#ifndef MA_BIQUAD_FIXED_POINT_SHIFT
#define MA_BIQUAD_FIXED_POINT_SHIFT 14
#endif
static ma_int32 ma_biquad_float_to_fp(double x)
{
return (ma_int32)(x * (1 << MA_BIQUAD_FIXED_POINT_SHIFT));
}
ma_biquad_config ma_biquad_config_init(ma_format format, ma_uint32 channels, double a0, double a1, double a2, double b0, double b1, double b2)
{
ma_biquad_config config;
MA_ZERO_OBJECT(&config);
config.format = format;
config.channels = channels;
config.a0 = a0;
config.a1 = a1;
config.a2 = a2;
config.b0 = b0;
config.b1 = b1;
config.b2 = b2;
return config;
}
ma_result ma_biquad_init(const ma_biquad_config* pConfig, ma_biquad* pBQ)
{
if (pBQ == NULL) {
return MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pBQ);
if (pConfig == NULL) {
return MA_INVALID_ARGS;
}
return ma_biquad_reinit(pConfig, pBQ);
}
ma_result ma_biquad_reinit(const ma_biquad_config* pConfig, ma_biquad* pBQ)
{
if (pBQ == NULL || pConfig == NULL) {
return MA_INVALID_ARGS;
}
if (pConfig->a0 == 0) {
return MA_INVALID_ARGS; /* Division by zero. */
}
/* Only supporting f32 and s16. */
if (pConfig->format != ma_format_f32 && pConfig->format != ma_format_s16) {
return MA_INVALID_ARGS;
}
/* The format cannot be changed after initialization. */
if (pBQ->format != pConfig->format) {
return MA_INVALID_OPERATION;
}
/* The channel count cannot be changed after initialization. */
if (pBQ->channels != pConfig->channels) {
return MA_INVALID_OPERATION;
}
pBQ->format = pConfig->format;
pBQ->channels = pConfig->channels;
/* Normalize. */
if (pConfig->format == ma_format_f32) {
pBQ->a1.f32 = (float)(pConfig->a1 / pConfig->a0);
pBQ->a2.f32 = (float)(pConfig->a2 / pConfig->a0);
pBQ->b0.f32 = (float)(pConfig->b0 / pConfig->a0);
pBQ->b1.f32 = (float)(pConfig->b1 / pConfig->a0);
pBQ->b2.f32 = (float)(pConfig->b2 / pConfig->a0);
} else {
pBQ->a1.s32 = ma_biquad_float_to_fp(pConfig->a1 / pConfig->a0);
pBQ->a2.s32 = ma_biquad_float_to_fp(pConfig->a2 / pConfig->a0);
pBQ->b0.s32 = ma_biquad_float_to_fp(pConfig->b0 / pConfig->a0);
pBQ->b1.s32 = ma_biquad_float_to_fp(pConfig->b1 / pConfig->a0);
pBQ->b2.s32 = ma_biquad_float_to_fp(pConfig->b2 / pConfig->a0);
}
return MA_SUCCESS;
}
static MA_INLINE void ma_biquad_process_pcm_frame_f32__direct_form_2_transposed(ma_biquad* pBQ, float* pY, const float* pX)
{
ma_uint32 c;
const float a1 = pBQ->a1.f32;
const float a2 = pBQ->a2.f32;
const float b0 = pBQ->b0.f32;
const float b1 = pBQ->b1.f32;
const float b2 = pBQ->b2.f32;
for (c = 0; c < pBQ->channels; c += 1) {
float r1 = pBQ->r1[c].f32;
float r2 = pBQ->r2[c].f32;
float x = pX[c];
float y;
y = b0*x + r1;
r1 = b1*x - a1*y + r2;
r2 = b2*x - a2*y;
pY[c] = y;
pBQ->r1[c].f32 = r1;
pBQ->r2[c].f32 = r2;
}
}
static MA_INLINE void ma_biquad_process_pcm_frame_f32(ma_biquad* pBQ, float* pY, const float* pX)
{
ma_biquad_process_pcm_frame_f32__direct_form_2_transposed(pBQ, pY, pX);
}
static MA_INLINE void ma_biquad_process_pcm_frame_s16__direct_form_2_transposed(ma_biquad* pBQ, ma_int16* pY, const ma_int16* pX)
{
ma_uint32 c;
const ma_int32 a1 = pBQ->a1.s32;
const ma_int32 a2 = pBQ->a2.s32;
const ma_int32 b0 = pBQ->b0.s32;
const ma_int32 b1 = pBQ->b1.s32;
const ma_int32 b2 = pBQ->b2.s32;
for (c = 0; c < pBQ->channels; c += 1) {
ma_int32 r1 = pBQ->r1[c].s32;
ma_int32 r2 = pBQ->r2[c].s32;
ma_int32 x = pX[c];
ma_int32 y;
y = (b0*x + r1) >> MA_BIQUAD_FIXED_POINT_SHIFT;
r1 = (b1*x - a1*y + r2);
r2 = (b2*x - a2*y);
pY[c] = (ma_int16)ma_clamp(y, -32768, 32767);
pBQ->r1[c].s32 = r1;
pBQ->r2[c].s32 = r2;
}
}
static MA_INLINE void ma_biquad_process_pcm_frame_s16(ma_biquad* pBQ, ma_int16* pY, const ma_int16* pX)
{
ma_biquad_process_pcm_frame_s16__direct_form_2_transposed(pBQ, pY, pX);
}
ma_result ma_biquad_process_pcm_frames(ma_biquad* pBQ, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
{
ma_uint32 n;
if (pBQ == NULL || pFramesOut == NULL || pFramesIn == NULL) {
return MA_INVALID_ARGS;
}
/* Note that the logic below needs to support in-place filtering. That is, it must support the case where pFramesOut and pFramesIn are the same. */
if (pBQ->format == ma_format_f32) {
/* */ float* pY = ( float*)pFramesOut;
const float* pX = (const float*)pFramesIn;
for (n = 0; n < frameCount; n += 1) {
ma_biquad_process_pcm_frame_f32__direct_form_2_transposed(pBQ, pY, pX);
pY += pBQ->channels;
pX += pBQ->channels;
}
} else if (pBQ->format == ma_format_s16) {
/* */ ma_int16* pY = ( ma_int16*)pFramesOut;
const ma_int16* pX = (const ma_int16*)pFramesIn;
for (n = 0; n < frameCount; n += 1) {
ma_biquad_process_pcm_frame_s16__direct_form_2_transposed(pBQ, pY, pX);
pY += pBQ->channels;
pX += pBQ->channels;
}
} else {
MA_ASSERT(MA_FALSE);
return MA_INVALID_ARGS; /* Format not supported. Should never hit this because it's checked in ma_biquad_init() and ma_biquad_reinit(). */
}
return MA_SUCCESS;
}
ma_uint32 ma_biquad_get_latency(ma_biquad* pBQ)
{
if (pBQ == NULL) {
return 0;
}
return 2;
}
ma_lpf_config ma_lpf_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency)
{
ma_lpf_config config;
MA_ZERO_OBJECT(&config);
config.format = format;
config.channels = channels;
config.sampleRate = sampleRate;
config.cutoffFrequency = cutoffFrequency;
return config;
}
static MA_INLINE ma_biquad_config ma_lpf__get_biquad_config(const ma_lpf_config* pConfig)
{
ma_biquad_config bqConfig;
double q;
double w;
double s;
double c;
double a;
MA_ASSERT(pConfig != NULL);
q = 1 / sqrt(2);
w = 2 * MA_PI_D * pConfig->cutoffFrequency / pConfig->sampleRate;
s = sin(w);
c = cos(w);
a = s / (2*q);
bqConfig.a0 = 1 + a;
bqConfig.a1 = -2 * c;
bqConfig.a2 = 1 - a;
bqConfig.b0 = (1 - c) / 2;
bqConfig.b1 = 1 - c;
bqConfig.b2 = (1 - c) / 2;
bqConfig.format = pConfig->format;
bqConfig.channels = pConfig->channels;
return bqConfig;
}
ma_result ma_lpf_init(const ma_lpf_config* pConfig, ma_lpf* pLPF)
{
ma_result result;
ma_biquad_config bqConfig;
if (pLPF == NULL) {
return MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pLPF);
if (pConfig == NULL) {
return MA_INVALID_ARGS;
}
bqConfig = ma_lpf__get_biquad_config(pConfig);
result = ma_biquad_init(&bqConfig, &pLPF->bq);
if (result != MA_SUCCESS) {
return result;
}
return MA_SUCCESS;
}
ma_result ma_lpf_reinit(const ma_lpf_config* pConfig, ma_lpf* pLPF)
{
ma_result result;
ma_biquad_config bqConfig;
if (pLPF == NULL || pConfig == NULL) {
return MA_INVALID_ARGS;
}
bqConfig = ma_lpf__get_biquad_config(pConfig);
result = ma_biquad_reinit(&bqConfig, &pLPF->bq);
if (result != MA_SUCCESS) {
return result;
}
return MA_SUCCESS;
}
static MA_INLINE void ma_lpf_process_pcm_frame_s16(ma_lpf* pLPF, ma_int16* pFrameOut, const ma_int16* pFrameIn)
{
ma_biquad_process_pcm_frame_s16(&pLPF->bq, pFrameOut, pFrameIn);
}
static MA_INLINE void ma_lpf_process_pcm_frame_f32(ma_lpf* pLPF, float* pFrameOut, const float* pFrameIn)
{
ma_biquad_process_pcm_frame_f32(&pLPF->bq, pFrameOut, pFrameIn);
}
ma_result ma_lpf_process_pcm_frames(ma_lpf* pLPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
{
if (pLPF == NULL) {
return MA_INVALID_ARGS;
}
return ma_biquad_process_pcm_frames(&pLPF->bq, pFramesOut, pFramesIn, frameCount);
}
ma_uint32 ma_lpf_get_latency(ma_lpf* pLPF)
{
if (pLPF == NULL) {
return 0;
}
return ma_biquad_get_latency(&pLPF->bq);
}
#endif
File diff suppressed because it is too large Load Diff
-109
View File
@@ -1,109 +0,0 @@
#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 "../../extras/dr_wav.h" /* Enables WAV decoding. */
#define MA_DEBUG_OUTPUT
#define MINIAUDIO_IMPLEMENTATION
#include "../../miniaudio.h"
#include "../ma_lpf.h"
ma_lpf g_lpf;
void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount)
{
ma_uint32 framesProcessed = 0;
ma_decoder* pDecoder = (ma_decoder*)pDevice->pUserData;
if (pDecoder == NULL) {
return;
}
/* We need to read into a temporary buffer and then run it through the low pass filter. */
while (framesProcessed < frameCount) {
float tempBuffer[4096];
ma_uint32 framesToProcessThisIteration;
framesToProcessThisIteration = frameCount - framesProcessed;
if (framesToProcessThisIteration > ma_countof(tempBuffer)/pDecoder->internalChannels) {
framesToProcessThisIteration = ma_countof(tempBuffer)/pDecoder->internalChannels;
}
#if 0
ma_decoder_read_pcm_frames(pDecoder, ma_offset_ptr(pOutput, framesProcessed * ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels)), framesToProcessThisIteration);
#else
ma_decoder_read_pcm_frames(pDecoder, tempBuffer, framesToProcessThisIteration);
/* Out the results from the low pass filter straight into our output buffer. */
ma_lpf_process(&g_lpf, ma_offset_ptr(pOutput, framesProcessed * ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels)), tempBuffer, framesToProcessThisIteration);
#endif
framesProcessed += framesToProcessThisIteration;
}
(void)pInput;
}
int main(int argc, char** argv)
{
ma_result result;
ma_decoder_config decoderConfig;
ma_decoder decoder;
ma_lpf_config lpfConfig;
ma_device_config deviceConfig;
ma_device device;
if (argc < 2) {
printf("No input file.\n");
return -1;
}
decoderConfig = ma_decoder_config_init(ma_format_f32, 0, 0);
result = ma_decoder_init_file(argv[1], &decoderConfig, &decoder);
if (result != MA_SUCCESS) {
return -2;
}
lpfConfig.format = decoderConfig.format;
lpfConfig.channels = decoder.internalChannels;
lpfConfig.sampleRate = decoder.internalSampleRate;
lpfConfig.cutoffFrequency = lpfConfig.sampleRate / 4;
result = ma_lpf_init(&lpfConfig, &g_lpf);
if (result != MA_SUCCESS) {
return -100;
}
deviceConfig = ma_device_config_init(ma_device_type_playback);
deviceConfig.playback.format = decoder.outputFormat;
deviceConfig.playback.channels = decoder.outputChannels;
deviceConfig.sampleRate = decoder.outputSampleRate;
deviceConfig.dataCallback = data_callback;
deviceConfig.pUserData = &decoder;
if (ma_device_init(NULL, &deviceConfig, &device) != MA_SUCCESS) {
printf("Failed to open playback device.\n");
ma_decoder_uninit(&decoder);
return -3;
}
if (ma_device_start(&device) != MA_SUCCESS) {
printf("Failed to start playback device.\n");
ma_device_uninit(&device);
ma_decoder_uninit(&decoder);
return -4;
}
printf("Press Enter to quit...");
getchar();
ma_device_uninit(&device);
ma_decoder_uninit(&decoder);
return 0;
}
-186
View File
@@ -1,186 +0,0 @@
#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 "../../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
#define OUTPUT_FILE "output.wav"
ma_sine_wave sineWave;
ma_uint32 on_read(ma_resampler* pResampler, ma_uint32 frameCount, void** ppFramesOut)
{
ma_assert(pResampler->config.format == ma_format_f32);
return (ma_uint32)ma_sine_wave_read_f32_ex(&sineWave, frameCount, pResampler->config.channels, pResampler->config.layout, (float**)ppFramesOut);
}
int main(int argc, char** argv)
{
ma_result result;
ma_resampler_config resamplerConfig;
ma_resampler resampler;
ma_zero_object(&resamplerConfig);
resamplerConfig.format = ma_format_f32;
resamplerConfig.channels = CHANNELS;
resamplerConfig.sampleRateIn = SAMPLE_RATE_IN;
resamplerConfig.sampleRateOut = SAMPLE_RATE_OUT;
resamplerConfig.algorithm = ma_resampler_algorithm_linear;
resamplerConfig.endOfInputMode = ma_resampler_end_of_input_mode_consume;
resamplerConfig.layout = ma_stream_layout_interleaved;
resamplerConfig.onRead = on_read;
resamplerConfig.pUserData = NULL;
result = ma_resampler_init(&resamplerConfig, &resampler);
if (result != MA_SUCCESS) {
printf("Failed to initialize resampler.\n");
return -1;
}
ma_sine_wave_init(0.5, 400, resamplerConfig.sampleRateIn, &sineWave);
// Write to a WAV file. We'll do about 10 seconds worth, making sure we read in chunks to make sure everything is seamless.
drwav_data_format format;
format.container = drwav_container_riff;
format.format = DR_WAVE_FORMAT_IEEE_FLOAT;
format.channels = resampler.config.channels;
format.sampleRate = resampler.config.sampleRateOut;
format.bitsPerSample = 32;
drwav* pWavWriter = drwav_open_file_write(OUTPUT_FILE, &format);
float buffer[SAMPLE_RATE_IN*CHANNELS];
float* pBuffer = buffer;
ma_uint32 iterations = 10;
ma_uint32 framesToReadPerIteration = ma_countof(buffer)/CHANNELS;
for (ma_uint32 i = 0; i < iterations; ++i) {
ma_uint32 framesRead = (ma_uint32)ma_resampler_read(&resampler, framesToReadPerIteration, &pBuffer);
drwav_write(pWavWriter, framesRead*CHANNELS, buffer);
}
//float** test = &buffer;
drwav_close(pWavWriter);
(void)argc;
(void)argv;
return 0;
}
#endif
-317
View File
@@ -1,317 +0,0 @@
#define MINIAUDIO_SPEEX_RESAMPLER_IMPLEMENTATION
#include "../../extras/speex_resampler/ma_speex_resampler.h"
#define MA_DEBUG_OUTPUT
#define MINIAUDIO_IMPLEMENTATION
#include "../../miniaudio.h"
#include "../ma_resampler.h"
int init_resampler(ma_uint32 rateIn, ma_uint32 rateOut, ma_resample_algorithm algorithm, ma_resampler* pResampler)
{
ma_result result;
ma_resampler_config config;
config = ma_resampler_config_init(ma_format_s16, 1, rateIn, rateOut, algorithm);
result = ma_resampler_init(&config, pResampler);
if (result != MA_SUCCESS) {
return (int)result;
}
return 0;
}
int do_count_query_test__required_input__fixed_interval(ma_resampler* pResampler, ma_uint64 frameCountPerIteration)
{
int result = 0;
ma_int16 input[4096];
ma_int16 i;
MA_ASSERT(frameCountPerIteration < ma_countof(input));
/* Fill the input buffer with sequential numbers so we can get an idea on the state of things. Useful for inspecting the linear backend in particular. */
for (i = 0; i < ma_countof(input); i += 1) {
input[i] = i;
}
for (i = 0; i < ma_countof(input); i += (ma_int16)frameCountPerIteration) {
ma_int16 output[4096];
ma_uint64 outputFrameCount;
ma_uint64 inputFrameCount;
ma_uint64 requiredInputFrameCount;
/* We retrieve the required number of input frames for the specified number of output frames, and then compare with what we actually get when reading. */
requiredInputFrameCount = ma_resampler_get_required_input_frame_count(pResampler, frameCountPerIteration);
outputFrameCount = frameCountPerIteration;
inputFrameCount = ma_countof(input);
result = ma_resampler_process_pcm_frames(pResampler, input, &inputFrameCount, output, &outputFrameCount);
if (result != MA_SUCCESS) {
printf("Failed to process frames.");
return result;
}
if (inputFrameCount != requiredInputFrameCount) {
printf("ERROR: Predicted vs actual input count mismatch: predicted=%d, actual=%d\n", (int)requiredInputFrameCount, (int)inputFrameCount);
result = -1;
}
}
if (result != 0) {
printf("FAILED\n");
} else {
printf("PASSED\n");
}
return result;
}
int do_count_query_test__required_input__by_algorithm_and_rate__fixed_interval(ma_resample_algorithm algorithm, ma_uint32 rateIn, ma_uint32 rateOut, ma_uint64 frameCountPerIteration)
{
int result;
ma_resampler resampler;
result = init_resampler(rateIn, rateOut, algorithm, &resampler);
if (result != 0) {
return 0;
}
result = do_count_query_test__required_input__fixed_interval(&resampler, frameCountPerIteration);
ma_resampler_uninit(&resampler);
return result;
}
int do_count_query_test__required_input__by_algorithm__fixed_interval(ma_resample_algorithm algorithm, ma_uint64 frameCountPerIteration)
{
int result;
result = do_count_query_test__required_input__by_algorithm_and_rate__fixed_interval(algorithm, 44100, 48000, frameCountPerIteration);
if (result != 0) {
return result;
}
result = do_count_query_test__required_input__by_algorithm_and_rate__fixed_interval(algorithm, 48000, 44100, frameCountPerIteration);
if (result != 0) {
return result;
}
result = do_count_query_test__required_input__by_algorithm_and_rate__fixed_interval(algorithm, 44100, 192000, frameCountPerIteration);
if (result != 0) {
return result;
}
result = do_count_query_test__required_input__by_algorithm_and_rate__fixed_interval(algorithm, 192000, 44100, frameCountPerIteration);
if (result != 0) {
return result;
}
return result;
}
int do_count_query_tests__required_input__by_algorithm(ma_resample_algorithm algorithm)
{
int result;
result = do_count_query_test__required_input__by_algorithm__fixed_interval(algorithm, 1);
if (result != 0) {
return result;
}
result = do_count_query_test__required_input__by_algorithm__fixed_interval(algorithm, 16);
if (result != 0) {
return result;
}
result = do_count_query_test__required_input__by_algorithm__fixed_interval(algorithm, 127);
if (result != 0) {
return result;
}
return 0;
}
int do_count_query_tests__required_input()
{
int result;
printf("Linear\n");
result = do_count_query_tests__required_input__by_algorithm(ma_resample_algorithm_linear);
if (result != 0) {
return result;
}
printf("Speex\n");
result = do_count_query_tests__required_input__by_algorithm(ma_resample_algorithm_speex);
if (result != 0) {
return result;
}
return 0;
}
int do_count_query_test__expected_output__fixed_interval(ma_resampler* pResampler, ma_uint64 frameCountPerIteration)
{
int result = 0;
ma_int16 input[4096];
ma_int16 i;
MA_ASSERT(frameCountPerIteration < ma_countof(input));
/* Fill the input buffer with sequential numbers so we can get an idea on the state of things. Useful for inspecting the linear backend in particular. */
for (i = 0; i < ma_countof(input); i += 1) {
input[i] = i;
}
for (i = 0; i < ma_countof(input); i += (ma_int16)frameCountPerIteration) {
ma_int16 output[4096];
ma_uint64 outputFrameCount;
ma_uint64 inputFrameCount;
ma_uint64 expectedOutputFrameCount;
/* We retrieve the required number of input frames for the specified number of output frames, and then compare with what we actually get when reading. */
expectedOutputFrameCount = ma_resampler_get_expected_output_frame_count(pResampler, frameCountPerIteration);
outputFrameCount = ma_countof(output);
inputFrameCount = frameCountPerIteration;
result = ma_resampler_process_pcm_frames(pResampler, input, &inputFrameCount, output, &outputFrameCount);
if (result != MA_SUCCESS) {
printf("Failed to process frames.");
return result;
}
if (outputFrameCount != expectedOutputFrameCount) {
printf("ERROR: Predicted vs actual output count mismatch: predicted=%d, actual=%d\n", (int)expectedOutputFrameCount, (int)outputFrameCount);
result = -1;
}
}
if (result != 0) {
printf("FAILED\n");
} else {
printf("PASSED\n");
}
return result;
}
int do_count_query_test__expected_output__by_algorithm_and_rate__fixed_interval(ma_resample_algorithm algorithm, ma_uint32 rateIn, ma_uint32 rateOut, ma_uint64 frameCountPerIteration)
{
int result;
ma_resampler resampler;
result = init_resampler(rateIn, rateOut, algorithm, &resampler);
if (result != 0) {
return 0;
}
result = do_count_query_test__expected_output__fixed_interval(&resampler, frameCountPerIteration);
ma_resampler_uninit(&resampler);
return result;
}
int do_count_query_test__expected_output__by_algorithm__fixed_interval(ma_resample_algorithm algorithm, ma_uint64 frameCountPerIteration)
{
int result;
result = do_count_query_test__expected_output__by_algorithm_and_rate__fixed_interval(algorithm, 44100, 48000, frameCountPerIteration);
if (result != 0) {
return result;
}
result = do_count_query_test__expected_output__by_algorithm_and_rate__fixed_interval(algorithm, 48000, 44100, frameCountPerIteration);
if (result != 0) {
return result;
}
result = do_count_query_test__expected_output__by_algorithm_and_rate__fixed_interval(algorithm, 44100, 192000, frameCountPerIteration);
if (result != 0) {
return result;
}
result = do_count_query_test__expected_output__by_algorithm_and_rate__fixed_interval(algorithm, 192000, 44100, frameCountPerIteration);
if (result != 0) {
return result;
}
return result;
}
int do_count_query_tests__expected_output__by_algorithm(ma_resample_algorithm algorithm)
{
int result;
result = do_count_query_test__expected_output__by_algorithm__fixed_interval(algorithm, 1);
if (result != 0) {
return result;
}
result = do_count_query_test__expected_output__by_algorithm__fixed_interval(algorithm, 16);
if (result != 0) {
return result;
}
result = do_count_query_test__expected_output__by_algorithm__fixed_interval(algorithm, 127);
if (result != 0) {
return result;
}
return 0;
}
int do_count_query_tests__expected_output()
{
int result;
printf("Linear\n");
result = do_count_query_tests__expected_output__by_algorithm(ma_resample_algorithm_linear);
if (result != 0) {
return result;
}
printf("Speex\n");
result = do_count_query_tests__expected_output__by_algorithm(ma_resample_algorithm_speex);
if (result != 0) {
return result;
}
return 0;
}
int do_count_query_tests()
{
int result;
result = do_count_query_tests__expected_output();
if (result != 0) {
return result;
}
result = do_count_query_tests__required_input();
if (result != 0) {
return result;
}
return 0;
}
int main(int argc, char** argv)
{
int result;
(void)argc;
(void)argv;
result = do_count_query_tests();
if (result != 0) {
return result;
}
return 0;
}