diff options
author | Andree Buschmann <AndreeBuschmann@t-online.de> | 2011-08-17 22:20:09 +0000 |
---|---|---|
committer | Andree Buschmann <AndreeBuschmann@t-online.de> | 2011-08-17 22:20:09 +0000 |
commit | 4d01ace73fdffca366211157b54418516b3a73b6 (patch) | |
tree | 8165a373967a826ba67826b60f55911ac344c028 /apps/codecs/libgme/resampler.c | |
parent | 4070f4f17b77a030049e146245fc9a399bb68204 (diff) | |
download | rockbox-4d01ace73fdffca366211157b54418516b3a73b6.tar.gz rockbox-4d01ace73fdffca366211157b54418516b3a73b6.zip |
Submit a patch to the VGM codec by Mauricio Gama which saves some more RAM through changes of the buffer configuration and an update of the resampler code. Additionally enable VGM for low memory targets and update the manual.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30327 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/codecs/libgme/resampler.c')
-rw-r--r-- | apps/codecs/libgme/resampler.c | 426 |
1 files changed, 163 insertions, 263 deletions
diff --git a/apps/codecs/libgme/resampler.c b/apps/codecs/libgme/resampler.c index a69a92cc53..e2e0734fc9 100644 --- a/apps/codecs/libgme/resampler.c +++ b/apps/codecs/libgme/resampler.c | |||
@@ -25,294 +25,194 @@ enum { shift = 14 }; | |||
25 | int const unit = 1 << shift; | 25 | int const unit = 1 << shift; |
26 | 26 | ||
27 | blargg_err_t Resampler_setup( struct Resampler* this, int fm_rate, int fm_gain, int rate, int gain ) | 27 | blargg_err_t Resampler_setup( struct Resampler* this, int fm_rate, int fm_gain, int rate, int gain ) |
28 | { | 28 | { |
29 | this->gain_ = (int)( ((1LL << gain_bits) * fm_gain * gain) / FP_ONE_GAIN ); | 29 | this->gain_ = (int)( ((1LL << gain_bits) * fm_gain * gain) / FP_ONE_GAIN ); |
30 | this->step = (int)( ((1LL << shift) * fm_rate) / rate + 1); | 30 | this->step = (int)( ((1LL << shift) * fm_rate) / rate + 1); |
31 | this->rate_ = this->step; | 31 | this->rate_ = this->step; |
32 | return 0; | 32 | return 0; |
33 | } | 33 | } |
34 | 34 | ||
35 | blargg_err_t Resampler_reset( struct Resampler* this, int pairs ) | 35 | blargg_err_t Resampler_reset( struct Resampler* this, int pairs ) |
36 | { | 36 | { |
37 | // expand allocations a bit | 37 | // expand allocations a bit |
38 | Resampler_resize( this, pairs ); | 38 | this->sample_buffer_size = (pairs + (pairs >> 2)) * 2; |
39 | this->resampler_size = this->oversamples_per_frame + (this->oversamples_per_frame >> 2); | 39 | Resampler_resize( this, pairs ); |
40 | 40 | this->resampler_size = this->oversamples_per_frame + (this->oversamples_per_frame >> 2); | |
41 | this->buffer_size = this->resampler_size; | 41 | |
42 | this->pos = 0; | 42 | this->buffer_size = this->resampler_size; |
43 | this->write_pos = 0; | 43 | this->pos = 0; |
44 | return 0; | 44 | this->write_pos = 0; |
45 | |||
46 | Resampler_clear( this ); | ||
47 | return 0; | ||
45 | } | 48 | } |
46 | 49 | ||
47 | void Resampler_resize( struct Resampler* this, int pairs ) | 50 | void Resampler_resize( struct Resampler* this, int pairs ) |
48 | { | 51 | { |
49 | int new_sample_buf_size = pairs * 2; | 52 | int new_sample_buf_size = pairs * 2; |
50 | if ( this->sample_buf_size != new_sample_buf_size ) | 53 | if ( this->sample_buf_size != new_sample_buf_size ) |
51 | { | 54 | { |
52 | this->sample_buf_size = new_sample_buf_size; | 55 | if ( new_sample_buf_size > this->sample_buffer_size ) |
53 | this->oversamples_per_frame = (int) ((pairs * this->rate_ * 2LL) / unit) + 2; | 56 | { |
54 | Resampler_clear( this ); | 57 | check(false); |
55 | } | 58 | return; |
59 | } | ||
60 | |||
61 | this->sample_buf_size = new_sample_buf_size; | ||
62 | this->oversamples_per_frame = (int) ((pairs * this->rate_ * 2LL) / unit) + 2; | ||
63 | Resampler_clear( this ); | ||
64 | } | ||
56 | } | 65 | } |
57 | 66 | ||
58 | static void mix_mono( struct Resampler* this, struct Stereo_Buffer* stereo_buf, dsample_t* out_ ) | 67 | void mix_samples( struct Resampler* this, struct Blip_Buffer* blip_buf, sample_t out_ [] ) |
59 | { | 68 | { |
60 | int const bass = BLIP_READER_BASS( stereo_buf->bufs [0] ); | 69 | int const bass = BLIP_READER_BASS( *blip_buf ); |
61 | BLIP_READER_BEGIN( sn, stereo_buf->bufs [0] ); | 70 | BLIP_READER_BEGIN( sn, *blip_buf ); |
62 | 71 | ||
63 | int count = this->sample_buf_size >> 1; | 72 | int count = this->sample_buf_size >> 1; |
64 | BLIP_READER_ADJ_( sn, count ); | 73 | BLIP_READER_ADJ_( sn, count ); |
65 | 74 | ||
66 | typedef dsample_t stereo_dsample_t [2]; | 75 | typedef sample_t stereo_dsample_t [2]; |
67 | stereo_dsample_t* BLARGG_RESTRICT out = (stereo_dsample_t*) out_ + count; | 76 | stereo_dsample_t* BLARGG_RESTRICT out = (stereo_dsample_t*) out_ + count; |
68 | stereo_dsample_t const* BLARGG_RESTRICT in = | 77 | stereo_dsample_t const* BLARGG_RESTRICT in = |
69 | (stereo_dsample_t const*) this->sample_buf + count; | 78 | (stereo_dsample_t const*) this->sample_buf + count; |
70 | int offset = -count; | 79 | int offset = -count; |
71 | int const gain = this->gain_; | 80 | int const gain = this->gain_; |
72 | do | 81 | do |
73 | { | 82 | { |
74 | int s = BLIP_READER_READ_RAW( sn ) >> (blip_sample_bits - 16); | 83 | int s = BLIP_READER_READ_RAW( sn ) >> (blip_sample_bits - 16); |
75 | BLIP_READER_NEXT_IDX_( sn, bass, offset ); | 84 | BLIP_READER_NEXT_IDX_( sn, bass, offset ); |
76 | 85 | ||
77 | int l = (in [offset] [0] * gain >> gain_bits) + s; | 86 | int l = (in [offset] [0] * gain >> gain_bits) + s; |
78 | int r = (in [offset] [1] * gain >> gain_bits) + s; | 87 | int r = (in [offset] [1] * gain >> gain_bits) + s; |
79 | 88 | ||
80 | BLIP_CLAMP( l, l ); | 89 | BLIP_CLAMP( l, l ); |
81 | out [offset] [0] = (blip_sample_t) l; | 90 | out [offset] [0] = (blip_sample_t) l; |
82 | 91 | ||
83 | BLIP_CLAMP( r, r ); | 92 | BLIP_CLAMP( r, r ); |
84 | out [offset] [1] = (blip_sample_t) r; | 93 | out [offset] [1] = (blip_sample_t) r; |
85 | } | 94 | } |
86 | while ( ++offset ); | 95 | while ( ++offset ); |
87 | 96 | ||
88 | BLIP_READER_END( sn, stereo_buf->bufs [0] ); | 97 | BLIP_READER_END( sn, *blip_buf ); |
89 | } | 98 | } |
90 | 99 | ||
91 | static void mix_stereo( struct Resampler* this, struct Stereo_Buffer* stereo_buf, dsample_t* out_ ) | 100 | sample_t const* resample_( struct Resampler* this, sample_t** out_, |
101 | sample_t const* out_end, sample_t const in [], int in_size ) | ||
92 | { | 102 | { |
93 | int const bass = BLIP_READER_BASS( stereo_buf->bufs [0] ); | 103 | in_size -= write_offset; |
94 | BLIP_READER_BEGIN( snc, stereo_buf->bufs [0] ); | 104 | if ( in_size > 0 ) |
95 | BLIP_READER_BEGIN( snl, stereo_buf->bufs [1] ); | 105 | { |
96 | BLIP_READER_BEGIN( snr, stereo_buf->bufs [2] ); | 106 | sample_t* BLARGG_RESTRICT out = *out_; |
97 | 107 | sample_t const* const in_end = in + in_size; | |
98 | int count = this->sample_buf_size >> 1; | 108 | |
99 | BLIP_READER_ADJ_( snc, count ); | 109 | int const step = this->step; |
100 | BLIP_READER_ADJ_( snl, count ); | 110 | int pos = this->pos; |
101 | BLIP_READER_ADJ_( snr, count ); | 111 | |
102 | 112 | // TODO: IIR filter, then linear resample | |
103 | typedef dsample_t stereo_dsample_t [2]; | 113 | // TODO: detect skipped sample, allowing merging of IIR and resample? |
104 | stereo_dsample_t* BLARGG_RESTRICT out = (stereo_dsample_t*) out_ + count; | 114 | |
105 | stereo_dsample_t const* BLARGG_RESTRICT in = | 115 | do |
106 | (stereo_dsample_t const*) this->sample_buf + count; | 116 | { |
107 | int offset = -count; | 117 | #define INTERP( i, out )\ |
108 | int const gain = this->gain_; | 118 | out = (in [0 + i] * (unit - pos) + ((in [2 + i] + in [4 + i] + in [6 + i]) << shift) +\ |
109 | do | 119 | in [8 + i] * pos) >> (shift + 2); |
110 | { | 120 | |
111 | int sc = BLIP_READER_READ_RAW( snc ) >> (blip_sample_bits - 16); | 121 | int out_0; |
112 | int sl = BLIP_READER_READ_RAW( snl ) >> (blip_sample_bits - 16); | 122 | INTERP( 0, out_0 ) |
113 | int sr = BLIP_READER_READ_RAW( snr ) >> (blip_sample_bits - 16); | 123 | INTERP( 1, out [0] = out_0; out [1] ) |
114 | BLIP_READER_NEXT_IDX_( snc, bass, offset ); | 124 | out += stereo; |
115 | BLIP_READER_NEXT_IDX_( snl, bass, offset ); | 125 | |
116 | BLIP_READER_NEXT_IDX_( snr, bass, offset ); | 126 | pos += step; |
117 | 127 | in += ((unsigned) pos >> shift) * stereo; | |
118 | int l = (in [offset] [0] * gain >> gain_bits) + sl + sc; | 128 | pos &= unit - 1; |
119 | int r = (in [offset] [1] * gain >> gain_bits) + sr + sc; | 129 | } |
120 | 130 | while ( in < in_end && out < out_end ); | |
121 | BLIP_CLAMP( l, l ); | 131 | |
122 | out [offset] [0] = (blip_sample_t) l; | 132 | this->pos = pos; |
123 | 133 | *out_ = out; | |
124 | BLIP_CLAMP( r, r ); | 134 | } |
125 | out [offset] [1] = (blip_sample_t) r; | 135 | return in; |
126 | } | ||
127 | while ( ++offset ); | ||
128 | |||
129 | BLIP_READER_END( snc, stereo_buf->bufs [0] ); | ||
130 | BLIP_READER_END( snl, stereo_buf->bufs [1] ); | ||
131 | BLIP_READER_END( snr, stereo_buf->bufs [2] ); | ||
132 | } | 136 | } |
133 | 137 | ||
134 | static void mix_stereo_no_center( struct Resampler* this, struct Stereo_Buffer* stereo_buf, dsample_t* out_ ) | 138 | inline int resample_wrapper( struct Resampler* this, sample_t out [], int* out_size, |
139 | sample_t const in [], int in_size ) | ||
135 | { | 140 | { |
136 | int const bass = BLIP_READER_BASS( stereo_buf->bufs [0] ); | 141 | assert( Resampler_rate( this ) ); |
137 | BLIP_READER_BEGIN( snl, stereo_buf->bufs [1] ); | ||
138 | BLIP_READER_BEGIN( snr, stereo_buf->bufs [2] ); | ||
139 | |||
140 | int count = this->sample_buf_size >> 1; | ||
141 | BLIP_READER_ADJ_( snl, count ); | ||
142 | BLIP_READER_ADJ_( snr, count ); | ||
143 | |||
144 | typedef dsample_t stereo_dsample_t [2]; | ||
145 | stereo_dsample_t* BLARGG_RESTRICT out = (stereo_dsample_t*) out_ + count; | ||
146 | stereo_dsample_t const* BLARGG_RESTRICT in = | ||
147 | (stereo_dsample_t const*) this->sample_buf + count; | ||
148 | int offset = -count; | ||
149 | int const gain = this->gain_; | ||
150 | do | ||
151 | { | ||
152 | int sl = BLIP_READER_READ_RAW( snl ) >> (blip_sample_bits - 16); | ||
153 | int sr = BLIP_READER_READ_RAW( snr ) >> (blip_sample_bits - 16); | ||
154 | BLIP_READER_NEXT_IDX_( snl, bass, offset ); | ||
155 | BLIP_READER_NEXT_IDX_( snr, bass, offset ); | ||
156 | |||
157 | int l = (in [offset] [0] * gain >> gain_bits) + sl; | ||
158 | int r = (in [offset] [1] * gain >> gain_bits) + sr; | ||
159 | |||
160 | BLIP_CLAMP( l, l ); | ||
161 | out [offset] [0] = (blip_sample_t) l; | ||
162 | |||
163 | BLIP_CLAMP( r, r ); | ||
164 | out [offset] [1] = (blip_sample_t) r; | ||
165 | } | ||
166 | while ( ++offset ); | ||
167 | |||
168 | BLIP_READER_END( snl, stereo_buf->bufs [1] ); | ||
169 | BLIP_READER_END( snr, stereo_buf->bufs [2] ); | ||
170 | } | ||
171 | 142 | ||
172 | static dsample_t const* resample_( struct Resampler* this, dsample_t** out_, | 143 | sample_t* out_ = out; |
173 | dsample_t const* out_end, dsample_t const in [], int in_size ) | 144 | int result = resample_( this, &out_, out + *out_size, in, in_size ) - in; |
174 | { | 145 | assert( out_ <= out + *out_size ); |
175 | in_size -= write_offset; | 146 | assert( result <= in_size ); |
176 | if ( in_size > 0 ) | ||
177 | { | ||
178 | dsample_t* BLIP_RESTRICT out = *out_; | ||
179 | dsample_t const* const in_end = in + in_size; | ||
180 | |||
181 | int const step = this->step; | ||
182 | int pos = this->pos; | ||
183 | |||
184 | // TODO: IIR filter, then linear resample | ||
185 | // TODO: detect skipped sample, allowing merging of IIR and resample? | ||
186 | |||
187 | do | ||
188 | { | ||
189 | #define INTERP( i, out )\ | ||
190 | out = (in [0 + i] * (unit - pos) + ((in [2 + i] + in [4 + i] + in [6 + i]) << shift) +\ | ||
191 | in [8 + i] * pos) >> (shift + 2); | ||
192 | |||
193 | int out_0; | ||
194 | INTERP( 0, out_0 ) | ||
195 | INTERP( 1, out [0] = out_0; out [1] ) | ||
196 | out += stereo; | ||
197 | |||
198 | pos += step; | ||
199 | in += ((unsigned) pos >> shift) * stereo; | ||
200 | pos &= unit - 1; | ||
201 | } | ||
202 | while ( in < in_end && out < out_end ); | ||
203 | |||
204 | this->pos = pos; | ||
205 | *out_ = out; | ||
206 | } | ||
207 | return in; | ||
208 | } | ||
209 | 147 | ||
210 | static inline int resample_wrapper( struct Resampler* this, dsample_t out [], int* out_size, | 148 | *out_size = out_ - out; |
211 | dsample_t const in [], int in_size ) | 149 | return result; |
212 | { | ||
213 | assert( Resampler_rate( this ) ); | ||
214 | |||
215 | dsample_t* out_ = out; | ||
216 | int result = resample_( this, &out_, out + *out_size, in, in_size ) - in; | ||
217 | assert( out_ <= out + *out_size ); | ||
218 | assert( result <= in_size ); | ||
219 | |||
220 | *out_size = out_ - out; | ||
221 | return result; | ||
222 | } | 150 | } |
223 | 151 | ||
224 | static int skip_input( struct Resampler* this, int count ) | 152 | int skip_input( struct Resampler* this, int count ) |
225 | { | 153 | { |
226 | this->write_pos -= count; | 154 | this->write_pos -= count; |
227 | if ( this->write_pos < 0 ) // occurs when downsampling | 155 | if ( this->write_pos < 0 ) // occurs when downsampling |
228 | { | 156 | { |
229 | count += this->write_pos; | 157 | count += this->write_pos; |
230 | this->write_pos = 0; | 158 | this->write_pos = 0; |
231 | } | 159 | } |
232 | memmove( this->buf, &this->buf [count], this->write_pos * sizeof this->buf [0] ); | 160 | memmove( this->buf, &this->buf [count], this->write_pos * sizeof this->buf [0] ); |
233 | return count; | 161 | return count; |
234 | } | 162 | } |
235 | 163 | ||
236 | static void play_frame_( struct Resampler* this, struct Stereo_Buffer* stereo_buf, dsample_t* out ) | 164 | void play_frame_( struct Resampler* this, struct Blip_Buffer* blip_buf, sample_t* out ) |
237 | { | 165 | { |
238 | long pair_count = this->sample_buf_size >> 1; | 166 | int pair_count = this->sample_buf_size >> 1; |
239 | blip_time_t blip_time = Blip_count_clocks( &stereo_buf->bufs [0], pair_count ); | 167 | blip_time_t blip_time = Blip_count_clocks( blip_buf, pair_count ); |
240 | int sample_count = this->oversamples_per_frame - this->write_pos + resampler_extra; | 168 | int sample_count = this->oversamples_per_frame - this->write_pos + resampler_extra; |
241 | 169 | ||
242 | int new_count = this->callback( this->callback_data, blip_time, sample_count, &this->buf [this->write_pos] ); | 170 | int new_count = this->callback( this->callback_data, blip_time, sample_count, &this->buf [this->write_pos] ); |
243 | assert( new_count < resampler_size ); | 171 | assert( new_count < this->resampler_size ); |
244 | 172 | ||
245 | Buffer_end_frame( stereo_buf, blip_time ); | 173 | Blip_end_frame( blip_buf, blip_time ); |
246 | /* Blip_end_frame( &stereo_buf->bufs [0], blip_time ); */ | 174 | assert( Blip_samples_avail( blip_buf ) == pair_count ); |
247 | assert( Blip_samples_avail( &stereo_buf->bufs [0] ) == pair_count * 2 ); | 175 | |
248 | 176 | this->write_pos += new_count; | |
249 | this->write_pos += new_count; | 177 | assert( (unsigned) this->write_pos <= this->buffer_size ); |
250 | assert( (unsigned) this->write_pos <= this->buffer_size ); | 178 | |
251 | 179 | int count = this->sample_buf_size; | |
252 | new_count = this->sample_buf_size; | 180 | if ( count ) |
253 | if ( new_count ) | 181 | skip_input( this, resample_wrapper( this, this->sample_buf, &count, this->buf, this->write_pos ) ); |
254 | skip_input( this, resample_wrapper( this, this->sample_buf, &new_count, this->buf, this->write_pos ) ); | 182 | assert( count == this->sample_buf_size ); |
255 | assert( new_count == (long) this->sample_buf_size ); | 183 | |
256 | 184 | mix_samples( this, blip_buf, out ); | |
257 | int bufs_used = stereo_buf->stereo_added | stereo_buf->was_stereo; | 185 | Blip_remove_samples( blip_buf, pair_count ); |
258 | if ( bufs_used <= 1 ) { | ||
259 | mix_mono( this, stereo_buf, out ); | ||
260 | Blip_remove_samples( &stereo_buf->bufs [0], pair_count ); | ||
261 | Blip_remove_silence( &stereo_buf->bufs [1], pair_count ); | ||
262 | Blip_remove_silence( &stereo_buf->bufs [2], pair_count ); | ||
263 | } | ||
264 | else if ( bufs_used & 1 ) { | ||
265 | mix_stereo( this, stereo_buf, out ); | ||
266 | Blip_remove_samples( &stereo_buf->bufs [0], pair_count ); | ||
267 | Blip_remove_samples( &stereo_buf->bufs [1], pair_count ); | ||
268 | Blip_remove_samples( &stereo_buf->bufs [2], pair_count ); | ||
269 | } | ||
270 | else { | ||
271 | mix_stereo_no_center( this, stereo_buf, out ); | ||
272 | Blip_remove_silence( &stereo_buf->bufs [0], pair_count ); | ||
273 | Blip_remove_samples( &stereo_buf->bufs [1], pair_count ); | ||
274 | Blip_remove_samples( &stereo_buf->bufs [2], pair_count ); | ||
275 | } | ||
276 | |||
277 | // to do: this might miss opportunities for optimization | ||
278 | if ( !Blip_samples_avail( &stereo_buf->bufs [0] ) ) | ||
279 | { | ||
280 | stereo_buf->was_stereo = stereo_buf->stereo_added; | ||
281 | stereo_buf->stereo_added = 0; | ||
282 | } | ||
283 | |||
284 | /* mix_mono( this, stereo_buf, out ); | ||
285 | Blip_remove_samples( &stereo_buf->bufs [0], pair_count ); */ | ||
286 | } | 186 | } |
287 | 187 | ||
288 | void Resampler_play( struct Resampler* this, long count, dsample_t* out, struct Stereo_Buffer* stereo_buf ) | 188 | void Resampler_play( struct Resampler* this, int count, sample_t* out, struct Blip_Buffer* blip_buf ) |
289 | { | 189 | { |
290 | // empty extra buffer | 190 | // empty extra buffer |
291 | long remain = this->sample_buf_size - this->buf_pos; | 191 | int remain = this->sample_buf_size - this->buf_pos; |
292 | if ( remain ) | 192 | if ( remain ) |
293 | { | 193 | { |
294 | if ( remain > count ) | 194 | if ( remain > count ) |
295 | remain = count; | 195 | remain = count; |
296 | count -= remain; | 196 | count -= remain; |
297 | memcpy( out, &this->sample_buf [this->buf_pos], remain * sizeof *out ); | 197 | memcpy( out, &this->sample_buf [this->buf_pos], remain * sizeof *out ); |
298 | out += remain; | 198 | out += remain; |
299 | this->buf_pos += remain; | 199 | this->buf_pos += remain; |
300 | } | 200 | } |
301 | 201 | ||
302 | // entire frames | 202 | // entire frames |
303 | while ( count >= (long) this->sample_buf_size ) | 203 | while ( count >= this->sample_buf_size ) |
304 | { | 204 | { |
305 | play_frame_( this, stereo_buf, out ); | 205 | play_frame_( this, blip_buf, out ); |
306 | out += this->sample_buf_size; | 206 | out += this->sample_buf_size; |
307 | count -= this->sample_buf_size; | 207 | count -= this->sample_buf_size; |
308 | } | 208 | } |
309 | 209 | ||
310 | // extra | 210 | // extra |
311 | if ( count ) | 211 | if ( count ) |
312 | { | 212 | { |
313 | play_frame_( this, stereo_buf, this->sample_buf ); | 213 | play_frame_( this, blip_buf, this->sample_buf ); |
314 | this->buf_pos = count; | 214 | this->buf_pos = count; |
315 | memcpy( out, this->sample_buf, count * sizeof *out ); | 215 | memcpy( out, this->sample_buf, count * sizeof *out ); |
316 | out += count; | 216 | out += count; |
317 | } | 217 | } |
318 | } | 218 | } |