Mercurial > audlegacy
comparison Plugins/Input/console/Fir_Resampler.cpp @ 90:252843aac42f trunk
[svn] Import the initial sources for console music support.
author | nenolod |
---|---|
date | Tue, 01 Nov 2005 19:57:26 -0800 |
parents | |
children | 84aabc053b6e |
comparison
equal
deleted
inserted
replaced
89:feeda0dda3ce | 90:252843aac42f |
---|---|
1 | |
2 // Game_Music_Emu 0.2.4. http://www.slack.net/~ant/libs/ | |
3 | |
4 #include "Fir_Resampler.h" | |
5 | |
6 #include <stdio.h> | |
7 #include <string.h> | |
8 #include <stdlib.h> | |
9 #include <math.h> | |
10 | |
11 /* Copyright (C) 2003-2005 Shay Green. This module is free software; you | |
12 can redistribute it and/or modify it under the terms of the GNU Lesser | |
13 General Public License as published by the Free Software Foundation; either | |
14 version 2.1 of the License, or (at your option) any later version. This | |
15 module is distributed in the hope that it will be useful, but WITHOUT ANY | |
16 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |
17 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for | |
18 more details. You should have received a copy of the GNU Lesser General | |
19 Public License along with this module; if not, write to the Free Software | |
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ | |
21 | |
22 #include BLARGG_SOURCE_BEGIN | |
23 | |
24 static const double pi = 3.1415926535897932384626433832795029L; | |
25 | |
26 const bool show_impulse = 0; | |
27 | |
28 class Dsf { | |
29 double rolloff; | |
30 double factor; | |
31 public: | |
32 Dsf( double r ) : rolloff( r ) { | |
33 factor = 1.0; | |
34 //if ( rolloff < 1.0 ) | |
35 // factor = 1.0 / (*this)( 0 ); | |
36 } | |
37 | |
38 double operator () ( double angle ) const | |
39 { | |
40 double const n_harm = 256; | |
41 angle /= n_harm; | |
42 double pow_a_n = pow( rolloff, n_harm ); | |
43 double rescale = 1.0 / n_harm; | |
44 | |
45 double num = 1.0 - rolloff * cos( angle ) - | |
46 pow_a_n * cos( n_harm * angle ) + | |
47 pow_a_n * rolloff * cos( (n_harm - 1) * angle ); | |
48 double den = 1 + rolloff * (rolloff - 2 * cos( angle )); | |
49 | |
50 return (num / den - 1) / n_harm * factor; | |
51 } | |
52 }; | |
53 | |
54 template<class T,class Sinc> | |
55 void gen_sinc( int width, double offset, double spacing, int count, double scale, T* p, | |
56 const Sinc& sinc ) | |
57 { | |
58 double range = pi * (width / 2); | |
59 double step = pi * spacing; | |
60 double a = -step * (count / 2 - 1); | |
61 a -= offset * step; | |
62 | |
63 while ( count-- ) | |
64 { | |
65 double w = a / range; | |
66 double y = 0.0; | |
67 if ( fabs( w ) < 1.0 ) | |
68 { | |
69 y = cos( pi * w ) * 0.5 + 0.5; | |
70 y *= sinc( a ); | |
71 } | |
72 | |
73 *p++ = y * scale; | |
74 a += step; | |
75 } | |
76 } | |
77 | |
78 static double plain_sinc( double a ) { | |
79 return fabs( a ) < 0.00001 ? 1.0 : sin( a ) / a; | |
80 } | |
81 | |
82 Fir_Resampler::Fir_Resampler() | |
83 { | |
84 res = 1; | |
85 skip_bits = 0; | |
86 step = 2; | |
87 buf = NULL; | |
88 write_pos = NULL; | |
89 buf_size = 0; | |
90 } | |
91 | |
92 Fir_Resampler::~Fir_Resampler() { | |
93 free( buf ); | |
94 } | |
95 | |
96 void Fir_Resampler::clear() | |
97 { | |
98 imp = 0; | |
99 if ( buf ) { | |
100 write_pos = buf + latency; | |
101 memset( buf, 0, (write_pos - buf) * sizeof *buf ); | |
102 } | |
103 } | |
104 | |
105 blargg_err_t Fir_Resampler::buffer_size( int new_size ) | |
106 { | |
107 new_size += latency; | |
108 void* new_buf = realloc( buf, new_size * sizeof *buf ); | |
109 if ( !new_buf ) | |
110 return "Out of memory"; | |
111 buf = (sample_t*) new_buf; | |
112 buf_size = new_size; | |
113 clear(); | |
114 return blargg_success; | |
115 } | |
116 | |
117 double Fir_Resampler::time_ratio( double ratio, double rolloff, double volume ) | |
118 { | |
119 this->ratio = ratio; | |
120 | |
121 double fstep = 0.0; | |
122 { | |
123 double least_error = 2; | |
124 double pos = 0; | |
125 res = -1; | |
126 for ( int r = 1; r <= max_res; r++ ) { | |
127 pos += ratio; | |
128 double nearest = floor( pos + 0.5 ); | |
129 double error = fabs( pos - nearest ); | |
130 if ( error < least_error ) { | |
131 res = r; | |
132 fstep = nearest / res; | |
133 least_error = error; | |
134 } | |
135 } | |
136 } | |
137 | |
138 skip_bits = 0; | |
139 | |
140 step = 2 * (int) floor( fstep ); | |
141 | |
142 ratio = fstep; | |
143 fstep = fmod( fstep, 1.0 ); | |
144 | |
145 double filter = (ratio < 1.0) ? 1.0 : 1.0 / ratio; | |
146 double pos = 0.0; | |
147 Dsf dsf( rolloff ); | |
148 for ( int i = 0; i < res; i++ ) | |
149 { | |
150 if ( show_impulse ) | |
151 printf( "pos = %f\n", pos ); | |
152 | |
153 gen_sinc( int (width * filter + 1) & ~1, pos, filter, (int) width, | |
154 double (0x7fff * volume * filter), impulses [i], dsf ); | |
155 | |
156 if ( show_impulse ) { | |
157 for ( int j = 0; j < width; j++ ) | |
158 printf( "%d ", (int) impulses [i] [j] ); | |
159 printf( "\n" ); | |
160 } | |
161 | |
162 pos += fstep; | |
163 if ( pos >= 0.9999999 ) { | |
164 pos -= 1.0; | |
165 skip_bits |= 1 << i; | |
166 } | |
167 } | |
168 | |
169 if ( show_impulse ) { | |
170 printf( "skip = %X\n", skip_bits ); | |
171 printf( "step = %d\n", step ); | |
172 } | |
173 | |
174 clear(); | |
175 | |
176 return ratio; | |
177 } | |
178 | |
179 #include BLARGG_ENABLE_OPTIMIZER | |
180 | |
181 int Fir_Resampler::read( sample_t* out_begin, int count ) | |
182 { | |
183 sample_t* out = out_begin; | |
184 const sample_t* in = buf; | |
185 sample_t* end_pos = write_pos; | |
186 unsigned long skip = skip_bits >> imp; | |
187 sample_t const* imp = impulses [this->imp]; | |
188 int remain = res - this->imp; | |
189 int const step = this->step; | |
190 | |
191 count = (count >> 1) + 1; | |
192 | |
193 // to do: optimize loop to use a single counter rather than 'in' and 'count' | |
194 | |
195 if ( end_pos - in >= width * 2 ) | |
196 { | |
197 end_pos -= width * 2; | |
198 do | |
199 { | |
200 count--; | |
201 | |
202 // accumulate in extended precision | |
203 long l = 0; | |
204 long r = 0; | |
205 | |
206 const sample_t* i = in; | |
207 if ( !count ) | |
208 break; | |
209 | |
210 for ( int n = width / 2; n--; ) | |
211 { | |
212 int pt0 = imp [0]; | |
213 int pt1 = imp [1]; | |
214 imp += 2; | |
215 l += (pt0 * i [0]) + (pt1 * i [2]); | |
216 r += (pt0 * i [1]) + (pt1 * i [3]); | |
217 i += 4; | |
218 } | |
219 | |
220 remain--; | |
221 | |
222 l >>= 15; | |
223 r >>= 15; | |
224 | |
225 in += step + ((skip * 2) & 2); | |
226 skip >>= 1; | |
227 | |
228 if ( !remain ) { | |
229 imp = impulses [0]; | |
230 skip = skip_bits; | |
231 remain = res; | |
232 } | |
233 | |
234 out [0] = l; | |
235 out [1] = r; | |
236 out += 2; | |
237 } | |
238 while ( in <= end_pos ); | |
239 } | |
240 | |
241 this->imp = res - remain; | |
242 | |
243 int left = write_pos - in; | |
244 write_pos = buf + left; | |
245 assert( unsigned (write_pos - buf) <= buf_size ); | |
246 memmove( buf, in, left * sizeof *in ); | |
247 | |
248 return out - out_begin; | |
249 } | |
250 | |
251 int Fir_Resampler::skip_input( int count ) | |
252 { | |
253 int remain = write_pos - buf; | |
254 int avail = remain - width * 2; | |
255 if ( count > avail ) | |
256 count = avail; | |
257 | |
258 remain -= count; | |
259 write_pos = buf + remain; | |
260 assert( unsigned (write_pos - buf) <= buf_size ); | |
261 memmove( buf, buf + count, remain * sizeof *buf ); | |
262 | |
263 return count; | |
264 } | |
265 | |
266 /* | |
267 int Fir_Resampler::skip( int count ) | |
268 { | |
269 count = int (count * ratio) & ~1; | |
270 count = skip_input( count ); | |
271 return int (count / ratio) & ~1; | |
272 } | |
273 */ |