diff options
Diffstat (limited to 'lib/rbcodec/codecs/libgme/multi_buffer.c')
-rw-r--r-- | lib/rbcodec/codecs/libgme/multi_buffer.c | 286 |
1 files changed, 286 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/libgme/multi_buffer.c b/lib/rbcodec/codecs/libgme/multi_buffer.c new file mode 100644 index 0000000000..554778c3de --- /dev/null +++ b/lib/rbcodec/codecs/libgme/multi_buffer.c | |||
@@ -0,0 +1,286 @@ | |||
1 | // Multi_Buffer 0.4.1. http://www.slack.net/~ant/ | ||
2 | |||
3 | #include "multi_buffer.h" | ||
4 | |||
5 | /* Copyright (C) 2003-2006 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 | // Tracked_Blip_Buffer | ||
19 | |||
20 | int const blip_buffer_extra = 32; // TODO: explain why this value | ||
21 | |||
22 | void Tracked_init( struct Tracked_Blip_Buffer* this ) | ||
23 | { | ||
24 | Blip_init( &this->blip ); | ||
25 | this->last_non_silence = 0; | ||
26 | } | ||
27 | |||
28 | void Tracked_clear( struct Tracked_Blip_Buffer* this ) | ||
29 | { | ||
30 | this->last_non_silence = 0; | ||
31 | Blip_clear( &this->blip ); | ||
32 | } | ||
33 | |||
34 | void Tracked_end_frame( struct Tracked_Blip_Buffer* this, blip_time_t t ) | ||
35 | { | ||
36 | Blip_end_frame( &this->blip, t ); | ||
37 | if ( this->blip.modified ) | ||
38 | { | ||
39 | this->blip.modified = false; | ||
40 | this->last_non_silence = Blip_samples_avail( &this->blip ) + blip_buffer_extra; | ||
41 | } | ||
42 | } | ||
43 | |||
44 | unsigned Tracked_non_silent( struct Tracked_Blip_Buffer* this ) | ||
45 | { | ||
46 | return this->last_non_silence | unsettled( &this->blip ); | ||
47 | } | ||
48 | |||
49 | static inline void remove_( struct Tracked_Blip_Buffer* this, int n ) | ||
50 | { | ||
51 | if ( (this->last_non_silence -= n) < 0 ) | ||
52 | this->last_non_silence = 0; | ||
53 | } | ||
54 | |||
55 | void Tracked_remove_silence( struct Tracked_Blip_Buffer* this, int n ) | ||
56 | { | ||
57 | remove_( this, n ); | ||
58 | Blip_remove_silence( &this->blip, n ); | ||
59 | } | ||
60 | |||
61 | void Tracked_remove_samples( struct Tracked_Blip_Buffer* this, int n ) | ||
62 | { | ||
63 | remove_( this, n ); | ||
64 | Blip_remove_samples( &this->blip, n ); | ||
65 | } | ||
66 | |||
67 | void Tracked_remove_all_samples( struct Tracked_Blip_Buffer* this ) | ||
68 | { | ||
69 | int avail = Blip_samples_avail( &this->blip ); | ||
70 | if ( !Tracked_non_silent( this ) ) | ||
71 | Tracked_remove_silence( this, avail ); | ||
72 | else | ||
73 | Tracked_remove_samples( this, avail ); | ||
74 | } | ||
75 | |||
76 | int Tracked_read_samples( struct Tracked_Blip_Buffer* this, blip_sample_t out [], int count ) | ||
77 | { | ||
78 | count = Blip_read_samples( &this->blip, out, count, false ); | ||
79 | remove_( this, count ); | ||
80 | return count; | ||
81 | } | ||
82 | |||
83 | // Stereo_Mixer | ||
84 | |||
85 | // mixers use a single index value to improve performance on register-challenged processors | ||
86 | // offset goes from negative to zero | ||
87 | |||
88 | void Mixer_init( struct Stereo_Mixer* this ) | ||
89 | { | ||
90 | this->samples_read = 0; | ||
91 | } | ||
92 | |||
93 | static void mix_mono( struct Stereo_Mixer* this, blip_sample_t out_ [], int count ) | ||
94 | { | ||
95 | int const bass = this->bufs [2]->blip.bass_shift_; | ||
96 | delta_t const* center = this->bufs [2]->blip.buffer_ + this->samples_read; | ||
97 | int center_sum = this->bufs [2]->blip.reader_accum_; | ||
98 | |||
99 | typedef blip_sample_t stereo_blip_sample_t [stereo]; | ||
100 | stereo_blip_sample_t* BLARGG_RESTRICT out = (stereo_blip_sample_t*) out_ + count; | ||
101 | int offset = -count; | ||
102 | do | ||
103 | { | ||
104 | int s = center_sum >> delta_bits; | ||
105 | |||
106 | center_sum -= center_sum >> bass; | ||
107 | center_sum += center [offset]; | ||
108 | |||
109 | BLIP_CLAMP( s, s ); | ||
110 | |||
111 | out [offset] [0] = (blip_sample_t) s; | ||
112 | out [offset] [1] = (blip_sample_t) s; | ||
113 | } | ||
114 | while ( ++offset ); | ||
115 | |||
116 | this->bufs [2]->blip.reader_accum_ = center_sum; | ||
117 | } | ||
118 | |||
119 | static void mix_stereo( struct Stereo_Mixer* this, blip_sample_t out_ [], int count ) | ||
120 | { | ||
121 | blip_sample_t* BLARGG_RESTRICT out = out_ + count * stereo; | ||
122 | // do left + center and right + center separately to reduce register load | ||
123 | struct Tracked_Blip_Buffer* const* buf = &this->bufs [2]; | ||
124 | while ( true ) // loop runs twice | ||
125 | { | ||
126 | --buf; | ||
127 | --out; | ||
128 | |||
129 | int const bass = this->bufs [2]->blip.bass_shift_; | ||
130 | delta_t const* side = (*buf)->blip.buffer_ + this->samples_read; | ||
131 | delta_t const* center = this->bufs [2]->blip.buffer_ + this->samples_read; | ||
132 | |||
133 | int side_sum = (*buf)->blip.reader_accum_; | ||
134 | int center_sum = this->bufs [2]->blip.reader_accum_; | ||
135 | |||
136 | int offset = -count; | ||
137 | do | ||
138 | { | ||
139 | int s = (center_sum + side_sum) >> delta_bits; | ||
140 | |||
141 | side_sum -= side_sum >> bass; | ||
142 | center_sum -= center_sum >> bass; | ||
143 | |||
144 | side_sum += side [offset]; | ||
145 | center_sum += center [offset]; | ||
146 | |||
147 | BLIP_CLAMP( s, s ); | ||
148 | |||
149 | ++offset; // before write since out is decremented to slightly before end | ||
150 | out [offset * stereo] = (blip_sample_t) s; | ||
151 | } | ||
152 | while ( offset ); | ||
153 | |||
154 | (*buf)->blip.reader_accum_ = side_sum; | ||
155 | |||
156 | if ( buf != this->bufs ) | ||
157 | continue; | ||
158 | |||
159 | // only end center once | ||
160 | this->bufs [2]->blip.reader_accum_ = center_sum; | ||
161 | break; | ||
162 | } | ||
163 | } | ||
164 | |||
165 | void Mixer_read_pairs( struct Stereo_Mixer* this, blip_sample_t out [], int count ) | ||
166 | { | ||
167 | // TODO: if caller never marks buffers as modified, uses mono | ||
168 | // except that buffer isn't cleared, so caller can encounter | ||
169 | // subtle problems and not realize the cause. | ||
170 | this->samples_read += count; | ||
171 | if ( Tracked_non_silent( this->bufs [0] ) | Tracked_non_silent( this->bufs [1] ) ) | ||
172 | mix_stereo( this, out, count ); | ||
173 | else | ||
174 | mix_mono( this, out, count ); | ||
175 | } | ||
176 | |||
177 | // Multi_Buffer | ||
178 | |||
179 | void Buffer_init( struct Multi_Buffer* this ) | ||
180 | { | ||
181 | int const spf = 2; | ||
182 | |||
183 | Tracked_init( &this->bufs [0] ); | ||
184 | Tracked_init( &this->bufs [1] ); | ||
185 | Tracked_init( &this->bufs [2] ); | ||
186 | |||
187 | Mixer_init( &this->mixer ); | ||
188 | |||
189 | this->length_ = 0; | ||
190 | this->sample_rate_ = 0; | ||
191 | this->channels_changed_count_ = 1; | ||
192 | this->channel_types_ = NULL; | ||
193 | this->channel_count_ = 0; | ||
194 | this->samples_per_frame_ = spf; | ||
195 | this->immediate_removal_ = true; | ||
196 | |||
197 | this->mixer.bufs [2] = &this->bufs [2]; | ||
198 | this->mixer.bufs [0] = &this->bufs [0]; | ||
199 | this->mixer.bufs [1] = &this->bufs [1]; | ||
200 | |||
201 | this->chan.center = &this->bufs [2].blip; | ||
202 | this->chan.left = &this->bufs [0].blip; | ||
203 | this->chan.right = &this->bufs [1].blip; | ||
204 | } | ||
205 | |||
206 | blargg_err_t Buffer_set_sample_rate( struct Multi_Buffer* this, int rate, int msec ) | ||
207 | { | ||
208 | int i; | ||
209 | for ( i = bufs_size; --i >= 0; ) | ||
210 | RETURN_ERR( Blip_set_sample_rate( &this->bufs [i].blip, rate, msec ) ); | ||
211 | |||
212 | this->sample_rate_ = Blip_sample_rate( &this->bufs [0].blip ); | ||
213 | this->length_ = Blip_length( &this->bufs [0].blip ); | ||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | void Buffer_clock_rate( struct Multi_Buffer* this, int rate ) | ||
218 | { | ||
219 | int i; | ||
220 | for ( i = bufs_size; --i >= 0; ) | ||
221 | Blip_set_clock_rate( &this->bufs [i].blip, rate ); | ||
222 | } | ||
223 | |||
224 | void Buffer_bass_freq( struct Multi_Buffer* this, int bass ) | ||
225 | { | ||
226 | int i; | ||
227 | for ( i = bufs_size; --i >= 0; ) | ||
228 | Blip_bass_freq( &this->bufs [i].blip, bass ); | ||
229 | } | ||
230 | |||
231 | blargg_err_t Buffer_set_channel_count( struct Multi_Buffer* this, int n, int const* types ) | ||
232 | { | ||
233 | this->channel_count_ = n; | ||
234 | this->channel_types_ = types; | ||
235 | return 0; | ||
236 | } | ||
237 | |||
238 | struct channel_t Buffer_channel( struct Multi_Buffer* this, int i ) | ||
239 | { | ||
240 | (void) i; | ||
241 | return this->chan; | ||
242 | } | ||
243 | |||
244 | void Buffer_clear( struct Multi_Buffer* this ) | ||
245 | { | ||
246 | int i; | ||
247 | this->mixer.samples_read = 0; | ||
248 | for ( i = bufs_size; --i >= 0; ) | ||
249 | Tracked_clear( &this->bufs [i] ); | ||
250 | } | ||
251 | |||
252 | void Buffer_end_frame( struct Multi_Buffer* this, blip_time_t clock_count ) | ||
253 | { | ||
254 | int i; | ||
255 | for ( i = bufs_size; --i >= 0; ) | ||
256 | Tracked_end_frame( &this->bufs [i], clock_count ); | ||
257 | } | ||
258 | |||
259 | int Buffer_read_samples( struct Multi_Buffer* this, blip_sample_t out [], int out_size ) | ||
260 | { | ||
261 | require( (out_size & 1) == 0 ); // must read an even number of samples | ||
262 | out_size = min( out_size, Buffer_samples_avail( this ) ); | ||
263 | |||
264 | int pair_count = (int) (out_size >> 1); | ||
265 | if ( pair_count ) | ||
266 | { | ||
267 | Mixer_read_pairs( &this->mixer, out, pair_count ); | ||
268 | |||
269 | if ( Buffer_samples_avail( this ) <= 0 || this->immediate_removal_ ) | ||
270 | { | ||
271 | int i; | ||
272 | for ( i = bufs_size; --i >= 0; ) | ||
273 | { | ||
274 | buf_t* b = &this->bufs [i]; | ||
275 | // TODO: might miss non-silence settling since it checks END of last read | ||
276 | if ( !Tracked_non_silent( b ) ) | ||
277 | Tracked_remove_silence( b, this->mixer.samples_read ); | ||
278 | else | ||
279 | Tracked_remove_samples( b, this->mixer.samples_read ); | ||
280 | } | ||
281 | this->mixer.samples_read = 0; | ||
282 | } | ||
283 | } | ||
284 | |||
285 | return out_size; | ||
286 | } | ||