BizHawk/waterbox/pcfx/sound/OwlResampler.h

160 lines
3.8 KiB
C++

#ifndef __NES_FILTER_H
#define __NES_FILTER_H
#include <vector>
class OwlResampler;
class RavenBuffer;
struct StateMem;
class OwlBuffer
{
public:
enum { HRBUF_LEFTOVER_PADDING = 8192 };
enum { HRBUF_OVERFLOW_PADDING = 32 }; // For deltas and impulse responses and whatnot that are dangling off the end(>= final timestamp) sorta.
union I32_F_Pudding
{
int32 i32;
float f;
};
OwlBuffer();
~OwlBuffer();
INLINE int32* Buf(void)
{
return &HRBuf[HRBUF_LEFTOVER_PADDING].i32;
}
INLINE I32_F_Pudding* BufPudding(void)
{
return &HRBuf[HRBUF_LEFTOVER_PADDING];
}
void Integrate(unsigned count, unsigned lp_shift = 0, unsigned hp_shift = 0, RavenBuffer* mixin0 = NULL, RavenBuffer* mixin1 = NULL); // Convenience function.
void ResampleSkipped(unsigned count);
void ZeroLeftover(void);
private:
I32_F_Pudding HRBuf[HRBUF_LEFTOVER_PADDING + 65536 + HRBUF_OVERFLOW_PADDING];
int32 accum;
int64 filter_state[2];
//
// Resampler state:
//
int32 leftover;
// Index into the input buffer
uint32 InputIndex;
// Current input phase
uint32 InputPhase;
// DC bias removal filter thingy
int64 debias;
friend class OwlResampler;
};
class RavenBuffer
{
public:
RavenBuffer();
~RavenBuffer();
INLINE int32* Buf(void)
{
return &BB[0];
}
void Process(unsigned count, bool integrate = true, uint32 lp_shift = 0);
void Finish(unsigned count);
friend class OwlBuffer;
private:
int32 BB[65536 + OwlBuffer::HRBUF_OVERFLOW_PADDING];
int32 accum;
int64 filter_state[2];
};
class OwlResampler
{
public:
// Resamples from input_rate to output_rate, allowing for rate_error(output_rate +/- output_rate*rate_error)
// error in the resample ratio.
//
// debias_corner is the cheap high-pass DC bias removal filter coefficient. Higher values will result in more bias removal(and
// case a high-pass filter effect), while lower values will lower this effect. It should be <= output_rate / 64, to be on the safe side(prevent
// multiplication overflow). A value of 0 will disable its effect.
//
// quality is an arbitrary control of quality(0 for lowest quality, 5 for highest quality)
//
// nyq_fudge may be a tasty sleep drug.
//
OwlResampler(double input_rate, double output_rate, double rate_error, double debias_corner, int quality, double nyq_fudge = 1.0) MDFN_COLD;
OwlResampler(const OwlResampler &resamp) MDFN_COLD;
~OwlResampler() MDFN_COLD;
INLINE int32 Resample(OwlBuffer* in, const uint32 in_count, int16* out, const uint32 max_out_count, const bool reverse = false)
{
return (this->*OwlResampler::Resample_)(in, in_count, out, max_out_count, reverse);
}
void ResetBufResampState(OwlBuffer* buf);
// Get the InputRate / OutputRate ratio, expressed as a / b
void GetRatio(int32 *a, int32 *b)
{
*a = Ratio_Dividend;
*b = Ratio_Divisor;
}
private:
// Copy of the parameters passed to the constructor
double InputRate, OutputRate, RateError, DebiasCorner;
int Quality;
// Number of phases.
uint32 NumPhases;
uint32 NumPhases_Padded;
// Coefficients(in each phase, not total)
uint32 NumCoeffs;
struct PhaseInfo
{
// One pointer for each phase
float* Coeffs;
// In the FIR loop: InputPhase = PInfos[InputPhase].Next
uint32 Next;
// Incrementor for InputIndex. In the FIR loop, after updating InputPhase: InputIndex += PInfos[InputPhase].Step
uint32 Step;
};
std::vector<PhaseInfo> PInfos;
std::vector<float> CoeffsBuffer;
std::vector<int32> IntermediateBuffer; //int32 boobuf[8192];
template<unsigned TA_SIMD_Type>
int32 T_Resample(OwlBuffer* in, const uint32 in_count, int16* out, const uint32 max_out_count, const bool reverse);
int32 (OwlResampler::*Resample_)(OwlBuffer* in, const uint32 in_count, int16* out, const uint32 max_out_count, const bool reverse);
uint16 debias_multiplier;
// for GetRatio()
int32 Ratio_Dividend;
int32 Ratio_Divisor;
};
#endif