diff options
author | Andree Buschmann <AndreeBuschmann@t-online.de> | 2011-08-31 19:19:49 +0000 |
---|---|---|
committer | Andree Buschmann <AndreeBuschmann@t-online.de> | 2011-08-31 19:19:49 +0000 |
commit | 13cbade08a07296d92e7a7d3e20475de0032cba1 (patch) | |
tree | 731a1a4a99d86632a719ae49e3b3d2a12e764a3a /apps/codecs/libgme/track_filter.c | |
parent | d089e104034fdf5562bea125d2cacf4ee486782a (diff) | |
download | rockbox-13cbade08a07296d92e7a7d3e20475de0032cba1.tar.gz rockbox-13cbade08a07296d92e7a7d3e20475de0032cba1.zip |
Update libgme to Blargg's Game_Music_Emu 0.6-pre.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30397 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/codecs/libgme/track_filter.c')
-rw-r--r-- | apps/codecs/libgme/track_filter.c | 294 |
1 files changed, 294 insertions, 0 deletions
diff --git a/apps/codecs/libgme/track_filter.c b/apps/codecs/libgme/track_filter.c new file mode 100644 index 0000000000..f468a8c4b6 --- /dev/null +++ b/apps/codecs/libgme/track_filter.c | |||
@@ -0,0 +1,294 @@ | |||
1 | // Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/ | ||
2 | |||
3 | #include "track_filter.h" | ||
4 | |||
5 | /* Copyright (C) 2003-2008 Shay Green. This module is free software; you | ||
6 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
7 | General Public License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. This | ||
9 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
10 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
11 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
12 | details. You should have received a copy of the GNU Lesser General Public | ||
13 | License along with this module; if not, write to the Free Software Foundation, | ||
14 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | ||
15 | |||
16 | #include "blargg_source.h" | ||
17 | |||
18 | int const fade_block_size = 512; | ||
19 | int const fade_shift = 8; // fade ends with gain at 1.0 / (1 << fade_shift) | ||
20 | int const silence_threshold = 8; | ||
21 | |||
22 | void track_create( struct Track_Filter* this ) | ||
23 | { | ||
24 | this->emu_ = NULL; | ||
25 | this->setup_.max_initial = 0; | ||
26 | this->setup_.lookahead = 0; | ||
27 | this->setup_.max_silence = indefinite_count; | ||
28 | this->silence_ignored_ = false; | ||
29 | track_stop( this ); | ||
30 | } | ||
31 | |||
32 | blargg_err_t track_init( struct Track_Filter* this, void* emu ) | ||
33 | { | ||
34 | this->emu_ = emu; | ||
35 | return 0; | ||
36 | } | ||
37 | |||
38 | void clear_time_vars( struct Track_Filter* this ) | ||
39 | { | ||
40 | this->emu_time = this->buf_remain; | ||
41 | this->out_time = 0; | ||
42 | this->silence_time = 0; | ||
43 | this->silence_count = 0; | ||
44 | } | ||
45 | |||
46 | void track_stop( struct Track_Filter* this ) | ||
47 | { | ||
48 | this->emu_track_ended_ = true; | ||
49 | this->track_ended_ = true; | ||
50 | this->fade_start = indefinite_count; | ||
51 | this->fade_step = 1; | ||
52 | this->buf_remain = 0; | ||
53 | this->emu_error = NULL; | ||
54 | clear_time_vars( this ); | ||
55 | } | ||
56 | |||
57 | blargg_err_t track_start( struct Track_Filter* this ) | ||
58 | { | ||
59 | this->emu_error = NULL; | ||
60 | track_stop( this ); | ||
61 | |||
62 | this->emu_track_ended_ = false; | ||
63 | this->track_ended_ = false; | ||
64 | |||
65 | if ( !this->silence_ignored_ ) | ||
66 | { | ||
67 | // play until non-silence or end of track | ||
68 | while ( this->emu_time < this->setup_.max_initial ) | ||
69 | { | ||
70 | fill_buf( this ); | ||
71 | if ( this->buf_remain | this->emu_track_ended_ ) | ||
72 | break; | ||
73 | } | ||
74 | } | ||
75 | |||
76 | clear_time_vars( this ); | ||
77 | return this->emu_error; | ||
78 | } | ||
79 | |||
80 | void end_track_if_error( struct Track_Filter* this, blargg_err_t err ) | ||
81 | { | ||
82 | if ( err ) | ||
83 | { | ||
84 | this->emu_error = err; | ||
85 | this->emu_track_ended_ = true; | ||
86 | } | ||
87 | } | ||
88 | |||
89 | blargg_err_t track_skip( struct Track_Filter* this, int count ) | ||
90 | { | ||
91 | this->emu_error = NULL; | ||
92 | this->out_time += count; | ||
93 | |||
94 | // remove from silence and buf first | ||
95 | { | ||
96 | int n = min( count, this->silence_count ); | ||
97 | this->silence_count -= n; | ||
98 | count -= n; | ||
99 | |||
100 | n = min( count, this->buf_remain ); | ||
101 | this->buf_remain -= n; | ||
102 | count -= n; | ||
103 | } | ||
104 | |||
105 | if ( count && !this->emu_track_ended_ ) | ||
106 | { | ||
107 | this->emu_time += count; | ||
108 | this->silence_time = this->emu_time; // would otherwise be invalid | ||
109 | end_track_if_error( this, skip_( this->emu_, count ) ); | ||
110 | } | ||
111 | |||
112 | if ( !(this->silence_count | this->buf_remain) ) // caught up to emulator, so update track ended | ||
113 | this->track_ended_ |= this->emu_track_ended_; | ||
114 | |||
115 | return this->emu_error; | ||
116 | } | ||
117 | |||
118 | blargg_err_t skippy_( struct Track_Filter* this, int count ) | ||
119 | { | ||
120 | while ( count && !this->emu_track_ended_ ) | ||
121 | { | ||
122 | int n = buf_size; | ||
123 | if ( n > count ) | ||
124 | n = count; | ||
125 | count -= n; | ||
126 | RETURN_ERR( play_( this->emu_, n, this->buf ) ); | ||
127 | } | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | // Fading | ||
132 | |||
133 | void track_set_fade( struct Track_Filter* this, int start, int length ) | ||
134 | { | ||
135 | this->fade_start = start; | ||
136 | this->fade_step = length / (fade_block_size * fade_shift); | ||
137 | if ( this->fade_step < 1 ) | ||
138 | this->fade_step = 1; | ||
139 | } | ||
140 | |||
141 | bool is_fading( struct Track_Filter* this ) | ||
142 | { | ||
143 | return this->out_time >= this->fade_start && this->fade_start != indefinite_count; | ||
144 | } | ||
145 | |||
146 | // unit / pow( 2.0, (double) x / step ) | ||
147 | static int int_log( int x, int step, int unit ) | ||
148 | { | ||
149 | int shift = x / step; | ||
150 | int fraction = (x - shift * step) * unit / step; | ||
151 | return ((unit - fraction) + (fraction >> 1)) >> shift; | ||
152 | } | ||
153 | |||
154 | void handle_fade( struct Track_Filter* this, sample_t out [], int out_count ) | ||
155 | { | ||
156 | int i; | ||
157 | for ( i = 0; i < out_count; i += fade_block_size ) | ||
158 | { | ||
159 | int const shift = 14; | ||
160 | int const unit = 1 << shift; | ||
161 | int gain = int_log( (this->out_time + i - this->fade_start) / fade_block_size, | ||
162 | this->fade_step, unit ); | ||
163 | if ( gain < (unit >> fade_shift) ) | ||
164 | this->track_ended_ = this->emu_track_ended_ = true; | ||
165 | |||
166 | sample_t* io = &out [i]; | ||
167 | for ( int count = min( fade_block_size, out_count - i ); count; --count ) | ||
168 | { | ||
169 | *io = (sample_t) ((*io * gain) >> shift); | ||
170 | ++io; | ||
171 | } | ||
172 | } | ||
173 | } | ||
174 | |||
175 | // Silence detection | ||
176 | |||
177 | void emu_play( struct Track_Filter* this, sample_t out [], int count ) | ||
178 | { | ||
179 | this->emu_time += count; | ||
180 | if ( !this->emu_track_ended_ ) | ||
181 | end_track_if_error( this, play_( this->emu_, count, out ) ); | ||
182 | else | ||
183 | memset( out, 0, count * sizeof *out ); | ||
184 | } | ||
185 | |||
186 | // number of consecutive silent samples at end | ||
187 | static int count_silence( sample_t begin [], int size ) | ||
188 | { | ||
189 | sample_t first = *begin; | ||
190 | *begin = silence_threshold * 2; // sentinel | ||
191 | sample_t* p = begin + size; | ||
192 | while ( (unsigned) (*--p + silence_threshold) <= (unsigned) silence_threshold * 2 ) { } | ||
193 | *begin = first; | ||
194 | return size - (p - begin); | ||
195 | } | ||
196 | |||
197 | // fill internal buffer and check it for silence | ||
198 | void fill_buf( struct Track_Filter* this ) | ||
199 | { | ||
200 | assert( !this->buf_remain ); | ||
201 | if ( !this->emu_track_ended_ ) | ||
202 | { | ||
203 | emu_play( this, this->buf, buf_size ); | ||
204 | int silence = count_silence( this->buf, buf_size ); | ||
205 | if ( silence < buf_size ) | ||
206 | { | ||
207 | this->silence_time = this->emu_time - silence; | ||
208 | this->buf_remain = buf_size; | ||
209 | return; | ||
210 | } | ||
211 | } | ||
212 | this->silence_count += buf_size; | ||
213 | } | ||
214 | |||
215 | blargg_err_t track_play( struct Track_Filter* this, int out_count, sample_t out [] ) | ||
216 | { | ||
217 | this->emu_error = NULL; | ||
218 | if ( this->track_ended_ ) | ||
219 | { | ||
220 | memset( out, 0, out_count * sizeof *out ); | ||
221 | } | ||
222 | else | ||
223 | { | ||
224 | assert( this->emu_time >= this->out_time ); | ||
225 | |||
226 | // prints nifty graph of how far ahead we are when searching for silence | ||
227 | //dprintf( "%*s \n", int ((emu_time - out_time) * 7 / 44100), "*" ); | ||
228 | |||
229 | // use any remaining silence samples | ||
230 | int pos = 0; | ||
231 | if ( this->silence_count ) | ||
232 | { | ||
233 | if ( !this->silence_ignored_ ) | ||
234 | { | ||
235 | // during a run of silence, run emulator at >=2x speed so it gets ahead | ||
236 | int ahead_time = this->setup_.lookahead * (this->out_time + out_count - this->silence_time) + | ||
237 | this->silence_time; | ||
238 | while ( this->emu_time < ahead_time && !(this->buf_remain | this->emu_track_ended_) ) | ||
239 | fill_buf( this ); | ||
240 | |||
241 | // end track if sufficient silence has been found | ||
242 | if ( this->emu_time - this->silence_time > this->setup_.max_silence ) | ||
243 | { | ||
244 | this->track_ended_ = this->emu_track_ended_ = true; | ||
245 | this->silence_count = out_count; | ||
246 | this->buf_remain = 0; | ||
247 | } | ||
248 | } | ||
249 | |||
250 | // fill from remaining silence | ||
251 | pos = min( this->silence_count, out_count ); | ||
252 | memset( out, 0, pos * sizeof *out ); | ||
253 | this->silence_count -= pos; | ||
254 | } | ||
255 | |||
256 | // use any remaining samples from buffer | ||
257 | if ( this->buf_remain ) | ||
258 | { | ||
259 | int n = min( this->buf_remain, (int) (out_count - pos) ); | ||
260 | memcpy( out + pos, this->buf + (buf_size - this->buf_remain), n * sizeof *out ); | ||
261 | this->buf_remain -= n; | ||
262 | pos += n; | ||
263 | } | ||
264 | |||
265 | // generate remaining samples normally | ||
266 | int remain = out_count - pos; | ||
267 | if ( remain ) | ||
268 | { | ||
269 | emu_play( this, out + pos, remain ); | ||
270 | this->track_ended_ |= this->emu_track_ended_; | ||
271 | |||
272 | if ( this->silence_ignored_ && !is_fading( this ) ) | ||
273 | { | ||
274 | // if left unupdated, ahead_time could become too large | ||
275 | this->silence_time = this->emu_time; | ||
276 | } | ||
277 | else | ||
278 | { | ||
279 | // check end for a new run of silence | ||
280 | int silence = count_silence( out + pos, remain ); | ||
281 | if ( silence < remain ) | ||
282 | this->silence_time = this->emu_time - silence; | ||
283 | |||
284 | if ( this->emu_time - this->silence_time >= buf_size ) | ||
285 | fill_buf( this ); // cause silence detection on next play() | ||
286 | } | ||
287 | } | ||
288 | |||
289 | if ( is_fading( this ) ) | ||
290 | handle_fade( this, out, out_count ); | ||
291 | } | ||
292 | this->out_time += out_count; | ||
293 | return this->emu_error; | ||
294 | } | ||