comparison src/console/Fir_Resampler.cxx @ 12:3da1b8942b8b trunk

[svn] - remove src/Input src/Output src/Effect src/General src/Visualization src/Container
author nenolod
date Mon, 18 Sep 2006 03:14:20 -0700
parents src/Input/console/Fir_Resampler.cxx@13389e613d67
children fb513e10174e
comparison
equal deleted inserted replaced
11:cff1d04026ae 12:3da1b8942b8b
1
2 // Game_Music_Emu 0.3.0. http://www.slack.net/~ant/
3
4 #include "Fir_Resampler.h"
5
6 #include <string.h>
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <math.h>
10
11 /* Copyright (C) 2004-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
21
22 #include BLARGG_SOURCE_BEGIN
23
24 // to do: fix problems with rolloff < 0.99 or so, and rolloff == 1.0, and related problems
25
26 // Sinc impulse genertor
27
28 const bool show_impulse = 0;
29
30 static const double pi = 3.1415926535897932384626433832795029L;
31
32 class Dsf {
33 double rolloff;
34 double factor;
35 public:
36 Dsf( double r ) : rolloff( r )
37 {
38 factor = 1.0;
39 //if ( rolloff < 1.0 )
40 // factor = 1.0 / (*this)( 0 );
41 }
42
43 double operator () ( double angle ) const
44 {
45 double const n_harm = 256;
46 angle /= n_harm;
47 double pow_a_n = pow( rolloff, n_harm );
48 //double rescale = 1.0 / n_harm;
49
50 double num = 1.0 - rolloff * cos( angle ) -
51 pow_a_n * cos( n_harm * angle ) +
52 pow_a_n * rolloff * cos( (n_harm - 1) * angle );
53 double den = 1 + rolloff * (rolloff - 2 * cos( angle ));
54
55 return (num / den - 1) / n_harm * factor;
56 }
57 };
58
59 template<class Sinc>
60 void gen_sinc( int width, double offset, double spacing, int count, double scale, short* p,
61 const Sinc& sinc )
62 {
63 double range = pi * (width / 2);
64 double step = pi * spacing;
65 double a = -step * (count / 2 - 1);
66 a -= offset * step;
67
68 while ( count-- )
69 {
70 double w = a / range;
71 double y = 0.0;
72 if ( fabs( w ) < 1.0 )
73 {
74 double window = cos( pi * w ) * 0.5 + 0.5;
75 y = sinc( a ) * window;
76 }
77
78 *p++ = (short) (y * scale);
79 a += step;
80 }
81 }
82
83 /*
84 static double plain_sinc( double a )
85 {
86 return fabs( a ) < 0.00001 ? 1.0 : sin( a ) / a;
87 }
88 */
89
90 // Fir_Resampler
91
92 Fir_Resampler_::Fir_Resampler_( int width, sample_t* impulses_ ) :
93 width_( width ),
94 write_offset( width * stereo - stereo ),
95 impulses( impulses_ )
96 {
97 write_pos = NULL;
98 res = 1;
99 imp = 0;
100 skip_bits = 0;
101 step = stereo;
102 ratio_ = 1.0;
103 }
104
105 Fir_Resampler_::~Fir_Resampler_()
106 {
107 }
108
109 void Fir_Resampler_::clear()
110 {
111 imp = 0;
112 if ( buf.size() )
113 {
114 write_pos = &buf [write_offset];
115 memset( buf.begin(), 0, write_offset * sizeof buf [0] );
116 }
117 }
118
119 blargg_err_t Fir_Resampler_::buffer_size( int new_size )
120 {
121 BLARGG_RETURN_ERR( buf.resize( new_size + write_offset ) );
122 clear();
123 return blargg_success;
124 }
125
126 double Fir_Resampler_::time_ratio( double new_factor, double rolloff, double gain )
127 {
128 ratio_ = new_factor;
129
130 double fstep = 0.0;
131 {
132 double least_error = 2;
133 double pos = 0;
134 res = -1;
135 for ( int r = 1; r <= max_res; r++ )
136 {
137 pos += ratio_;
138 double nearest = floor( pos + 0.5 );
139 double error = fabs( pos - nearest );
140 if ( error < least_error )
141 {
142 res = r;
143 fstep = nearest / res;
144 least_error = error;
145 }
146 }
147 }
148
149 skip_bits = 0;
150
151 step = stereo * (int) floor( fstep );
152
153 ratio_ = fstep;
154 fstep = fmod( fstep, 1.0 );
155
156 double filter = (ratio_ < 1.0) ? 1.0 : 1.0 / ratio_;
157 double pos = 0.0;
158 input_per_cycle = 0;
159 Dsf dsf( rolloff );
160 for ( int i = 0; i < res; i++ )
161 {
162 if ( show_impulse )
163 printf( "pos = %f\n", pos );
164
165 gen_sinc( int (width_ * filter + 1) & ~1, pos, filter, (int) width_,
166 double (0x7fff * gain * filter), impulses + i * width_, dsf );
167
168 if ( show_impulse )
169 {
170 for ( int j = 0; j < width_; j++ )
171 printf( "%d ", (int) impulses [i * width_ + j] );
172 printf( "\n" );
173 }
174
175 pos += fstep;
176 input_per_cycle += step;
177 if ( pos >= 0.9999999 )
178 {
179 pos -= 1.0;
180 skip_bits |= 1 << i;
181 input_per_cycle++;
182 }
183 }
184
185 if ( show_impulse )
186 {
187 printf( "skip = %8lX\n", (long) skip_bits );
188 printf( "step = %d\n", step );
189 }
190
191 clear();
192
193 return ratio_;
194 }
195
196 int Fir_Resampler_::input_needed( long output_count ) const
197 {
198 long input_count = 0;
199
200 unsigned long skip = skip_bits >> imp;
201 int remain = res - imp;
202 while ( (output_count -= 2) > 0 )
203 {
204 input_count += step + (skip & 1) * stereo;
205 skip >>= 1;
206 if ( !--remain )
207 {
208 skip = skip_bits;
209 remain = res;
210 }
211 output_count -= 2;
212 }
213
214 long input_extra = input_count - (write_pos - &buf [(width_ - 1) * stereo]);
215 if ( input_extra < 0 )
216 input_extra = 0;
217 return input_extra;
218 }
219
220 int Fir_Resampler_::avail_( long input_count ) const
221 {
222 int cycle_count = input_count / input_per_cycle;
223 int output_count = cycle_count * res * stereo;
224 input_count -= cycle_count * input_per_cycle;
225
226 unsigned long skip = skip_bits >> imp;
227 int remain = res - imp;
228 while ( input_count >= 0 )
229 {
230 input_count -= step + (skip & 1) * stereo;
231 skip >>= 1;
232 if ( !--remain )
233 {
234 skip = skip_bits;
235 remain = res;
236 }
237 output_count += 2;
238 }
239 return output_count;
240 }
241
242 int Fir_Resampler_::skip_input( long count )
243 {
244 int remain = write_pos - buf.begin();
245 int avail = remain - width_ * stereo;
246 if ( avail < 0 ) avail = 0; // inserted
247 if ( count > avail )
248 count = avail;
249
250 remain -= count;
251 write_pos = &buf [remain];
252 memmove( buf.begin(), &buf [count], remain * sizeof buf [0] );
253
254 return count;
255 }
256