comparison Plugins/Input/console/Fir_Resampler.h @ 493:c04dff121e1d trunk

[svn] hostile merge, phase 2: reimport based on new plugin code
author nenolod
date Tue, 24 Jan 2006 20:19:01 -0800
parents
children
comparison
equal deleted inserted replaced
492:ccb68bad47b2 493:c04dff121e1d
1
2 // Finite impulse response (FIR) resampler with adjustable FIR size
3
4 // Game_Music_Emu 0.3.0
5
6 #ifndef FIR_RESAMPLER_H
7 #define FIR_RESAMPLER_H
8
9 #include "blargg_common.h"
10 #include <string.h>
11
12 class Fir_Resampler_ {
13 public:
14
15 // Use Fir_Resampler<width> (below)
16
17 // Set input/output resampling ratio and optionally low-pass rolloff and gain.
18 // Returns actual ratio used (rounded to internal precision).
19 double time_ratio( double factor, double rolloff = 0.999, double gain = 1.0 );
20
21 // Current input/output ratio
22 double ratio() const { return ratio_; }
23
24 // Input
25
26 typedef short sample_t;
27
28 // Resize and clear input buffer
29 blargg_err_t buffer_size( int );
30
31 // Clear input buffer. At least two output samples will be available after
32 // two input samples are written.
33 void clear();
34
35 // Number of input samples that can be written
36 int max_write() const { return buf.end() - write_pos; }
37
38 // Pointer to place to write input samples
39 sample_t* buffer() { return write_pos; }
40
41 // Notify resampler that 'count' input samples have been written
42 void write( long count );
43
44 // Number of input samples in buffer
45 int written() const { return write_pos - &buf [write_offset]; }
46
47 // Skip 'count' input samples. Returns number of samples actually skipped.
48 int skip_input( long count );
49
50 // Output
51
52 // Number of extra input samples needed until 'count' output samples are available
53 int input_needed( long count ) const;
54
55 // Number of output samples available
56 int avail() const { return avail_( write_pos - &buf [width_ * stereo] ); }
57
58 public:
59 ~Fir_Resampler_();
60 protected:
61 enum { stereo = 2 };
62 enum { max_res = 32 };
63 blargg_vector<sample_t> buf;
64 sample_t* write_pos;
65 int res;
66 int imp;
67 int const width_;
68 int const write_offset;
69 unsigned long skip_bits;
70 int step;
71 int input_per_cycle;
72 double ratio_;
73 sample_t* impulses;
74
75 Fir_Resampler_( int width, sample_t* );
76 int avail_( long input_count ) const;
77 };
78
79 // Width is number of points in FIR. Must be even and 4 or more. More points give
80 // better quality and rolloff effectiveness, and take longer to calculate.
81 template<int width>
82 class Fir_Resampler : public Fir_Resampler_ {
83 BOOST_STATIC_ASSERT( width >= 4 && width % 2 == 0 );
84 short impulses [max_res] [width];
85 public:
86 Fir_Resampler() : Fir_Resampler_( width, impulses [0] ) { }
87
88 // Read at most 'count' samples. Returns number of samples actually read.
89 typedef short sample_t;
90 int read( sample_t* out, long count );
91 };
92
93 // End of public interface
94
95 inline void Fir_Resampler_::write( long count )
96 {
97 write_pos += count;
98 assert( write_pos <= buf.end() );
99 }
100
101 template<int width>
102 int Fir_Resampler<width>::read( sample_t* out_begin, long count )
103 {
104 sample_t* out = out_begin;
105 const sample_t* in = buf.begin();
106 sample_t* end_pos = write_pos;
107 unsigned long skip = skip_bits >> this->imp;
108 sample_t const* imp = impulses [this->imp];
109 int remain = res - this->imp;
110 int const step = this->step;
111
112 count >>= 1;
113
114 if ( end_pos - in >= width * stereo )
115 {
116 end_pos -= width * stereo;
117 do
118 {
119 count--;
120
121 // accumulate in extended precision
122 long l = 0;
123 long r = 0;
124
125 const sample_t* i = in;
126 if ( count < 0 )
127 break;
128
129 for ( int n = width / 2; n; --n )
130 {
131 int pt0 = imp [0];
132 l += pt0 * i [0];
133 r += pt0 * i [1];
134 int pt1 = imp [1];
135 imp += 2;
136 l += pt1 * i [2];
137 r += pt1 * i [3];
138 i += 4;
139 }
140
141 remain--;
142
143 l >>= 15;
144 r >>= 15;
145
146 in += (skip * stereo) & stereo;
147 skip >>= 1;
148 in += step;
149
150 if ( !remain )
151 {
152 imp = impulses [0];
153 skip = skip_bits;
154 remain = res;
155 }
156
157 out [0] = l;
158 out [1] = r;
159 out += 2;
160 }
161 while ( in <= end_pos );
162 }
163
164 this->imp = res - remain;
165
166 int left = write_pos - in;
167 write_pos = &buf [left];
168 memmove( buf.begin(), in, left * sizeof *in );
169
170 return out - out_begin;
171 }
172
173 #endif
174