1 // Finite impulse response (FIR) resampler with adjustable FIR size
2 
3 // $package
4 #ifndef FIR_RESAMPLER_H
5 #define FIR_RESAMPLER_H
6 
7 #include "Resampler.h"
8 
9 template<int width>
10 class Fir_Resampler;
11 
12 // Use one of these typedefs
13 typedef Fir_Resampler< 8> Fir_Resampler_Fast;
14 typedef Fir_Resampler<16> Fir_Resampler_Norm;
15 typedef Fir_Resampler<24> Fir_Resampler_Good;
16 
17 // Implementation
18 class Fir_Resampler_ : public Resampler {
19 protected:
20 	virtual blargg_err_t set_rate_( double );
21 	virtual void clear_();
22 
23 protected:
24 	enum { stereo = 2 };
25 	enum { max_res = 32 }; // TODO: eliminate and keep impulses on freestore?
26 	sample_t const* imp;
27 	int const width_;
28 	sample_t* impulses;
29 
30 	Fir_Resampler_( int width, sample_t [] );
31 };
32 
33 // Width is number of points in FIR. More points give better quality and
34 // rolloff effectiveness, and take longer to calculate.
35 template<int width>
36 class Fir_Resampler : public Fir_Resampler_ {
37 	enum { min_width = (width < 4 ? 4 : width) };
38 	enum { adj_width = min_width / 4 * 4 + 2 };
39 	enum { write_offset = adj_width * stereo };
40 	short impulses [max_res * (adj_width + 2)];
41 public:
Fir_Resampler()42 	Fir_Resampler() : Fir_Resampler_( adj_width, impulses ) { }
43 
44 protected:
45 	virtual sample_t const* resample_( sample_t**, sample_t const*, sample_t const [], int );
46 };
47 
48 template<int width>
resample_(sample_t ** out_,sample_t const * out_end,sample_t const in[],int in_size)49 Resampler::sample_t const* Fir_Resampler<width>::resample_( sample_t** out_,
50 		sample_t const* out_end, sample_t const in [], int in_size )
51 {
52 	in_size -= write_offset;
53 	if ( in_size > 0 )
54 	{
55 		sample_t* BLARGG_RESTRICT out = *out_;
56 		sample_t const* const in_end = in + in_size;
57 		sample_t const* imp = this->imp;
58 
59 		do
60 		{
61 			// accumulate in extended precision
62 			int pt = imp [0];
63 			int l = pt * in [0];
64 			int r = pt * in [1];
65 			if ( out >= out_end )
66 				break;
67 			for ( int n = (adj_width - 2) / 2; n; --n )
68 			{
69 				pt = imp [1];
70 				l += pt * in [2];
71 				r += pt * in [3];
72 
73 				// pre-increment more efficient on some RISC processors
74 				imp += 2;
75 				pt = imp [0];
76 				r += pt * in [5];
77 				in += 4;
78 				l += pt * in [0];
79 			}
80 			pt = imp [1];
81 			l += pt * in [2];
82 			r += pt * in [3];
83 
84 			// these two "samples" after the end of the impulse give the
85 			// proper offsets to the next input sample and next impulse
86 			in  = (sample_t const*) ((char const*) in  + imp [2]); // some negative value
87 			imp = (sample_t const*) ((char const*) imp + imp [3]); // small positive or large negative
88 
89 			out [0] = sample_t (l >> 15);
90 			out [1] = sample_t (r >> 15);
91 			out += 2;
92 		}
93 		while ( in < in_end );
94 
95 		this->imp = imp;
96 		*out_ = out;
97 	}
98 	return in;
99 }
100 
101 #endif
102