ref: e85a63eb7284b1f323b09b77436da43a28dcf9b1
dir: /src/pt2_downsample2x.c/
// for finding memory leaks in debug mode with Visual Studio
#if defined _DEBUG && defined _MSC_VER
#include <crtdbg.h>
#endif
#include <stdint.h>
#include <stdbool.h>
#include "pt2_helpers.h" // CLAMP
static double state[2];
/*
** - all-pass halfband filters (2x downsample) -
**
** 8bitbubsy: Not sure who coded these. Possibly aciddose,
** or maybe he found it on the internet somewhere...
*/
static double f(const double in, double *b, const double c)
{
const double x = (in - *b) * c;
const double out = *b + x;
*b = in + x;
return out;
}
double d2x(const double *input, double *b)
{
return (f(input[0], &b[0], 0.150634765625) + f(input[1], &b[1], -0.3925628662109375)) * 0.5;
}
// Warning: These can exceed original range because of undershoot/overshoot!
void downsample2xDouble(double *buffer, int32_t originalLength)
{
state[0] = state[1] = 0.0;
const double *input = buffer;
const int32_t length = originalLength / 2;
for (int32_t i = 0; i < length; i++, input += 2)
buffer[i] = d2x(input, state);
}
void downsample2xFloat(float *buffer, int32_t originalLength)
{
double in[2];
state[0] = state[1] = 0.0;
const float *input = buffer;
const int32_t length = originalLength / 2;
for (int32_t i = 0; i < length; i++, input += 2)
{
in[0] = input[0];
in[1] = input[1];
buffer[i] = (float)d2x(in, state);
}
}
// Warning: These are slow and use normalization to prevent clipping from undershoot/overshoot!
bool downsample2x8BitU(uint8_t *buffer, int32_t originalLength)
{
state[0] = state[1] = 0.0;
double *dBuffer = (double *)malloc(originalLength * sizeof (double));
if (dBuffer == NULL)
return false;
for (int32_t i = 0; i < originalLength; i++)
dBuffer[i] = (buffer[i] - 128) * (1.0 / (INT8_MAX+1.0));
const double *input = dBuffer;
double dPeak = 0.0;
const int32_t length = originalLength / 2;
for (int32_t i = 0; i < length; i++, input += 2)
{
double dOut = d2x(input, state);
dBuffer[i] = dOut;
dOut = ABS(dOut);
if (dOut > dPeak)
dPeak = dOut;
}
// normalize
double dAmp = 1.0;
if (dPeak > 0.0)
dAmp = INT8_MAX / dPeak;
for (int32_t i = 0; i < length; i++)
buffer[i] = (uint8_t)round(dBuffer[i] * dAmp) + 128;
free(dBuffer);
return true;
}
bool downsample2x8Bit(int8_t *buffer, int32_t originalLength)
{
state[0] = state[1] = 0.0;
double *dBuffer = (double *)malloc(originalLength * sizeof (double));
if (dBuffer == NULL)
return false;
for (int32_t i = 0; i < originalLength; i++)
dBuffer[i] = buffer[i] * (1.0 / (INT8_MAX+1.0));
const double *input = dBuffer;
double dPeak = 0.0;
const int32_t length = originalLength / 2;
for (int32_t i = 0; i < length; i++, input += 2)
{
double dOut = d2x(input, state);
dBuffer[i] = dOut;
dOut = ABS(dOut);
if (dOut > dPeak)
dPeak = dOut;
}
// normalize
double dAmp = 1.0;
if (dPeak > 0.0)
dAmp = INT8_MAX / dPeak;
for (int32_t i = 0; i < length; i++)
buffer[i] = (int8_t)round(dBuffer[i] * dAmp);
free(dBuffer);
return true;
}
bool downsample2x16Bit(int16_t *buffer, int32_t originalLength)
{
state[0] = state[1] = 0.0;
double *dBuffer = (double *)malloc(originalLength * sizeof (double));
if (dBuffer == NULL)
return false;
for (int32_t i = 0; i < originalLength; i++)
dBuffer[i] = buffer[i] * (1.0 / (INT16_MAX+1.0));
const double *input = dBuffer;
double dPeak = 0.0;
const int32_t length = originalLength / 2;
for (int32_t i = 0; i < length; i++, input += 2)
{
double dOut = d2x(input, state);
dBuffer[i] = dOut;
dOut = ABS(dOut);
if (dOut > dPeak)
dPeak = dOut;
}
// normalize
double dAmp = 1.0;
if (dPeak > 0.0)
dAmp = INT16_MAX / dPeak;
for (int32_t i = 0; i < length; i++)
buffer[i] = (int16_t)round(dBuffer[i] * dAmp);
free(dBuffer);
return true;
}
bool downsample2x32Bit(int32_t *buffer, int32_t originalLength)
{
state[0] = state[1] = 0.0;
double *dBuffer = (double *)malloc(originalLength * sizeof (double));
if (dBuffer == NULL)
return false;
for (int32_t i = 0; i < originalLength; i++)
dBuffer[i] = buffer[i] * (1.0 / (INT32_MAX+1.0));
const double *input = dBuffer;
double dPeak = 0.0;
const int32_t length = originalLength / 2;
for (int32_t i = 0; i < length; i++, input += 2)
{
double dOut = d2x(input, state);
dBuffer[i] = dOut;
dOut = ABS(dOut);
if (dOut > dPeak)
dPeak = dOut;
}
// normalize
double dAmp = 1.0;
if (dPeak > 0.0)
dAmp = INT32_MAX / dPeak;
for (int32_t i = 0; i < length; i++)
buffer[i] = (int32_t)round(dBuffer[i] * dAmp);
free(dBuffer);
return true;
}