mirror of https://github.com/snes9xgit/snes9x.git
116 lines
3.2 KiB
C
116 lines
3.2 KiB
C
|
/* Simple fixed-point linear resampler by BearOso*/
|
||
|
|
||
|
#ifndef __LINEAR_RESAMPLER_H
|
||
|
#define __LINEAR_RESAMPLER_H
|
||
|
|
||
|
#include "resampler.h"
|
||
|
#include "snes9x.h"
|
||
|
|
||
|
static const int f_prec = 15;
|
||
|
static const uint32 f__one = (1 << f_prec);
|
||
|
|
||
|
#define lerp(t, a, b) (((((b) - (a)) * (t)) >> f_prec) + (a))
|
||
|
|
||
|
class LinearResampler : public Resampler
|
||
|
{
|
||
|
protected:
|
||
|
uint32 f__r_step;
|
||
|
uint32 f__inv_r_step;
|
||
|
uint32 f__r_frac;
|
||
|
int r_left, r_right;
|
||
|
|
||
|
public:
|
||
|
LinearResampler (int num_samples) : Resampler (num_samples)
|
||
|
{
|
||
|
f__r_frac = 0;
|
||
|
}
|
||
|
|
||
|
~LinearResampler ()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
void
|
||
|
time_ratio (double ratio)
|
||
|
{
|
||
|
if (ratio == 0.0)
|
||
|
ratio = 1.0;
|
||
|
f__r_step = (uint32) (ratio * f__one);
|
||
|
f__inv_r_step = (uint32) (f__one / ratio);
|
||
|
clear ();
|
||
|
}
|
||
|
|
||
|
void
|
||
|
clear (void)
|
||
|
{
|
||
|
ring_buffer::clear ();
|
||
|
f__r_frac = 0;
|
||
|
r_left = 0;
|
||
|
r_right = 0;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
read (short *data, int num_samples)
|
||
|
{
|
||
|
int i_position = start >> 1;
|
||
|
short *internal_buffer = (short *) buffer;
|
||
|
int o_position = 0;
|
||
|
int consumed = 0;
|
||
|
int max_samples = (buffer_size >> 1);
|
||
|
|
||
|
while (o_position < num_samples && consumed < buffer_size)
|
||
|
{
|
||
|
if (f__r_step == f__one)
|
||
|
{
|
||
|
data[o_position] = internal_buffer[i_position];
|
||
|
data[o_position + 1] = internal_buffer[i_position + 1];
|
||
|
|
||
|
o_position += 2;
|
||
|
i_position += 2;
|
||
|
if (i_position >= max_samples)
|
||
|
i_position -= max_samples;
|
||
|
consumed += 2;
|
||
|
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
while (f__r_frac <= f__one && o_position < num_samples)
|
||
|
{
|
||
|
data[o_position] = lerp (f__r_frac,
|
||
|
r_left,
|
||
|
internal_buffer[i_position]);
|
||
|
data[o_position + 1] = lerp (f__r_frac,
|
||
|
r_right,
|
||
|
internal_buffer[i_position + 1]);
|
||
|
|
||
|
o_position += 2;
|
||
|
|
||
|
f__r_frac += f__r_step;
|
||
|
}
|
||
|
|
||
|
if (f__r_frac > f__one)
|
||
|
{
|
||
|
f__r_frac -= f__one;
|
||
|
r_left = internal_buffer[i_position];
|
||
|
r_right = internal_buffer[i_position + 1];
|
||
|
i_position += 2;
|
||
|
if (i_position >= max_samples)
|
||
|
i_position -= max_samples;
|
||
|
consumed += 2;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
size -= consumed << 1;
|
||
|
start += consumed << 1;
|
||
|
if (start >= buffer_size)
|
||
|
start -= buffer_size;
|
||
|
}
|
||
|
|
||
|
inline int
|
||
|
avail (void)
|
||
|
{
|
||
|
return (((size >> 2) * f__inv_r_step) - ((f__r_frac * f__inv_r_step) >> f_prec)) >> (f_prec - 1);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
#endif /* __LINEAR_RESAMPLER_H */
|