/src/vlc/contrib/contrib-build/game-music-emu/gme/Fir_Resampler.cpp
Line | Count | Source |
1 | | // Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ |
2 | | |
3 | | #include "Fir_Resampler.h" |
4 | | |
5 | | #include <string.h> |
6 | | #include <stdlib.h> |
7 | | #include <stdio.h> |
8 | | #include <math.h> |
9 | | |
10 | | /* Copyright (C) 2004-2006 Shay Green. This module is free software; you |
11 | | can redistribute it and/or modify it under the terms of the GNU Lesser |
12 | | General Public License as published by the Free Software Foundation; either |
13 | | version 2.1 of the License, or (at your option) any later version. This |
14 | | module is distributed in the hope that it will be useful, but WITHOUT ANY |
15 | | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
16 | | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
17 | | details. You should have received a copy of the GNU Lesser General Public |
18 | | License along with this module; if not, write to the Free Software Foundation, |
19 | | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ |
20 | | |
21 | | #include "blargg_source.h" |
22 | | |
23 | | #undef PI |
24 | 17.7k | #define PI 3.1415926535897932384626433832795029 |
25 | | |
26 | | static void gen_sinc( double rolloff, int width, double offset, double spacing, double scale, |
27 | | int count, short* out ) |
28 | 893 | { |
29 | 893 | double const maxh = 256; |
30 | 893 | double const step = PI / maxh * spacing; |
31 | 893 | double const to_w = maxh * 2 / width; |
32 | 893 | double const pow_a_n = pow( rolloff, maxh ); |
33 | 893 | scale /= maxh * 2; |
34 | | |
35 | 893 | double angle = (count / 2 - 1 + offset) * -step; |
36 | 17.7k | while ( count-- ) |
37 | 16.8k | { |
38 | 16.8k | *out++ = 0; |
39 | 16.8k | double w = angle * to_w; |
40 | 16.8k | if ( fabs( w ) < PI ) |
41 | 16.5k | { |
42 | 16.5k | double rolloff_cos_a = rolloff * cos( angle ); |
43 | 16.5k | double num = 1 - rolloff_cos_a - |
44 | 16.5k | pow_a_n * cos( maxh * angle ) + |
45 | 16.5k | pow_a_n * rolloff * cos( (maxh - 1) * angle ); |
46 | 16.5k | double den = 1 - rolloff_cos_a - rolloff_cos_a + rolloff * rolloff; |
47 | 16.5k | double sinc = scale * num / den - scale; |
48 | | |
49 | 16.5k | out [-1] = (short) (cos( w ) * sinc + sinc); |
50 | 16.5k | } |
51 | 16.8k | angle += step; |
52 | 16.8k | } |
53 | 893 | } |
54 | | |
55 | | Fir_Resampler_::Fir_Resampler_( int width, sample_t* impulses_ ) : |
56 | 358 | width_( width ), |
57 | 358 | write_offset( width * stereo - stereo ), |
58 | 358 | impulses( impulses_ ) |
59 | 358 | { |
60 | 358 | write_pos = 0; |
61 | 358 | res = 1; |
62 | 358 | imp_phase = 0; |
63 | 358 | skip_bits = 0; |
64 | 358 | step = stereo; |
65 | 358 | ratio_ = 1.0; |
66 | 358 | } |
67 | | |
68 | 358 | Fir_Resampler_::~Fir_Resampler_() { } |
69 | | |
70 | | void Fir_Resampler_::clear() |
71 | 1.23k | { |
72 | 1.23k | imp_phase = 0; |
73 | 1.23k | if ( buf.size() ) |
74 | 945 | { |
75 | 945 | write_pos = &buf [write_offset]; |
76 | 945 | memset( buf.begin(), 0, write_offset * sizeof buf [0] ); |
77 | 945 | } |
78 | 1.23k | } |
79 | | |
80 | | blargg_err_t Fir_Resampler_::buffer_size( int new_size ) |
81 | 355 | { |
82 | 355 | RETURN_ERR( buf.resize( new_size + write_offset ) ); |
83 | 355 | clear(); |
84 | 355 | return 0; |
85 | 355 | } |
86 | | |
87 | | double Fir_Resampler_::time_ratio( double new_factor, double rolloff, double gain ) |
88 | 363 | { |
89 | 363 | ratio_ = new_factor; |
90 | | |
91 | 363 | double fstep = 0.0; |
92 | 363 | { |
93 | 363 | double least_error = 2; |
94 | 363 | double pos = 0; |
95 | 363 | res = -1; |
96 | 11.9k | for ( int r = 1; r <= max_res; r++ ) |
97 | 11.6k | { |
98 | 11.6k | pos += ratio_; |
99 | 11.6k | double nearest = floor( pos + 0.5 ); |
100 | 11.6k | double error = fabs( pos - nearest ); |
101 | 11.6k | if ( error < least_error ) |
102 | 798 | { |
103 | 798 | res = r; |
104 | 798 | fstep = nearest / res; |
105 | 798 | least_error = error; |
106 | 798 | } |
107 | 11.6k | } |
108 | 363 | } |
109 | | |
110 | 363 | skip_bits = 0; |
111 | | |
112 | 363 | step = stereo * (int) floor( fstep ); |
113 | | |
114 | 363 | ratio_ = fstep; |
115 | 363 | fstep = fmod( fstep, 1.0 ); |
116 | | |
117 | 363 | double filter = (ratio_ < 1.0) ? 1.0 : 1.0 / ratio_; |
118 | 363 | double pos = 0.0; |
119 | 363 | input_per_cycle = 0; |
120 | 1.25k | for ( int i = 0; i < res; i++ ) |
121 | 893 | { |
122 | 893 | gen_sinc( rolloff, int (width_ * filter + 1) & ~1, pos, filter, |
123 | 893 | double (0x7FFF * gain * filter), |
124 | 893 | (int) width_, impulses + i * width_ ); |
125 | | |
126 | 893 | pos += fstep; |
127 | 893 | input_per_cycle += step; |
128 | 893 | if ( pos >= 0.9999999 ) |
129 | 530 | { |
130 | 530 | pos -= 1.0; |
131 | 530 | skip_bits |= 1 << i; |
132 | 530 | input_per_cycle++; |
133 | 530 | } |
134 | 893 | } |
135 | | |
136 | 363 | clear(); |
137 | | |
138 | 363 | return ratio_; |
139 | 363 | } |
140 | | |
141 | | int Fir_Resampler_::input_needed( int32_t output_count ) const |
142 | 0 | { |
143 | 0 | int32_t input_count = 0; |
144 | |
|
145 | 0 | unsigned long skip = skip_bits >> imp_phase; |
146 | 0 | int remain = res - imp_phase; |
147 | 0 | while ( (output_count -= 2) > 0 ) |
148 | 0 | { |
149 | 0 | input_count += step + (skip & 1) * stereo; |
150 | 0 | skip >>= 1; |
151 | 0 | if ( !--remain ) |
152 | 0 | { |
153 | 0 | skip = skip_bits; |
154 | 0 | remain = res; |
155 | 0 | } |
156 | 0 | output_count -= 2; |
157 | 0 | } |
158 | |
|
159 | 0 | long input_extra = input_count - (write_pos - &buf [(width_ - 1) * stereo]); |
160 | 0 | if ( input_extra < 0 ) |
161 | 0 | input_extra = 0; |
162 | 0 | return input_extra; |
163 | 0 | } |
164 | | |
165 | | int Fir_Resampler_::avail_( int32_t input_count ) const |
166 | 0 | { |
167 | 0 | int cycle_count = input_count / input_per_cycle; |
168 | 0 | int output_count = cycle_count * res * stereo; |
169 | 0 | input_count -= cycle_count * input_per_cycle; |
170 | |
|
171 | 0 | uint32_t skip = skip_bits >> imp_phase; |
172 | 0 | int remain = res - imp_phase; |
173 | 0 | while ( input_count >= 0 ) |
174 | 0 | { |
175 | 0 | input_count -= step + (skip & 1) * stereo; |
176 | 0 | skip >>= 1; |
177 | 0 | if ( !--remain ) |
178 | 0 | { |
179 | 0 | skip = skip_bits; |
180 | 0 | remain = res; |
181 | 0 | } |
182 | 0 | output_count += 2; |
183 | 0 | } |
184 | 0 | return output_count; |
185 | 0 | } |
186 | | |
187 | | int Fir_Resampler_::skip_input( long count ) |
188 | 0 | { |
189 | 0 | int remain = write_pos - buf.begin(); |
190 | 0 | int max_count = remain - width_ * stereo; |
191 | 0 | if ( max_count < 0 ) |
192 | 0 | max_count = 0; |
193 | 0 | if ( count > max_count ) |
194 | 0 | count = max_count; |
195 | |
|
196 | 0 | remain -= count; |
197 | 0 | write_pos = &buf [remain]; |
198 | 0 | memmove( buf.begin(), &buf [count], remain * sizeof buf [0] ); |
199 | |
|
200 | 0 | return count; |
201 | 0 | } |