summaryrefslogtreecommitdiff
path: root/lib/rbcodec/codecs/libgme/multi_buffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rbcodec/codecs/libgme/multi_buffer.c')
-rw-r--r--lib/rbcodec/codecs/libgme/multi_buffer.c286
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
6can redistribute it and/or modify it under the terms of the GNU Lesser
7General Public License as published by the Free Software Foundation; either
8version 2.1 of the License, or (at your option) any later version. This
9module is distributed in the hope that it will be useful, but WITHOUT ANY
10WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12details. You should have received a copy of the GNU Lesser General Public
13License along with this module; if not, write to the Free Software Foundation,
14Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
15
16#include "blargg_source.h"
17
18// Tracked_Blip_Buffer
19
20int const blip_buffer_extra = 32; // TODO: explain why this value
21
22void Tracked_init( struct Tracked_Blip_Buffer* this )
23{
24 Blip_init( &this->blip );
25 this->last_non_silence = 0;
26}
27
28void Tracked_clear( struct Tracked_Blip_Buffer* this )
29{
30 this->last_non_silence = 0;
31 Blip_clear( &this->blip );
32}
33
34void 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
44unsigned Tracked_non_silent( struct Tracked_Blip_Buffer* this )
45{
46 return this->last_non_silence | unsettled( &this->blip );
47}
48
49static 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
55void Tracked_remove_silence( struct Tracked_Blip_Buffer* this, int n )
56{
57 remove_( this, n );
58 Blip_remove_silence( &this->blip, n );
59}
60
61void Tracked_remove_samples( struct Tracked_Blip_Buffer* this, int n )
62{
63 remove_( this, n );
64 Blip_remove_samples( &this->blip, n );
65}
66
67void 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
76int 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
88void Mixer_init( struct Stereo_Mixer* this )
89{
90 this->samples_read = 0;
91}
92
93static 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
119static 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
165void 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
179void 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
206blargg_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
217void 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
224void 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
231blargg_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
238struct channel_t Buffer_channel( struct Multi_Buffer* this, int i )
239{
240 (void) i;
241 return this->chan;
242}
243
244void 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
252void 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
259int 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}