summaryrefslogtreecommitdiff
path: root/apps/codecs/libgme/multi_buffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/codecs/libgme/multi_buffer.c')
-rw-r--r--apps/codecs/libgme/multi_buffer.c390
1 files changed, 225 insertions, 165 deletions
diff --git a/apps/codecs/libgme/multi_buffer.c b/apps/codecs/libgme/multi_buffer.c
index 26cb8cdec6..554778c3de 100644
--- a/apps/codecs/libgme/multi_buffer.c
+++ b/apps/codecs/libgme/multi_buffer.c
@@ -1,4 +1,4 @@
1// Blip_Buffer 0.4.1. http://www.slack.net/~ant/ 1// Multi_Buffer 0.4.1. http://www.slack.net/~ant/
2 2
3#include "multi_buffer.h" 3#include "multi_buffer.h"
4 4
@@ -15,212 +15,272 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
15 15
16#include "blargg_source.h" 16#include "blargg_source.h"
17 17
18#ifdef BLARGG_ENABLE_OPTIMIZER 18// Tracked_Blip_Buffer
19 #include BLARGG_ENABLE_OPTIMIZER 19
20#endif 20int const blip_buffer_extra = 32; // TODO: explain why this value
21 21
22// Stereo_Buffer 22void Tracked_init( struct Tracked_Blip_Buffer* this )
23 23{
24void Buffer_init( struct Stereo_Buffer* this ) 24 Blip_init( &this->blip );
25{ 25 this->last_non_silence = 0;
26 Blip_init( &this->bufs [0] );
27 Blip_init( &this->bufs [1] );
28 Blip_init( &this->bufs [2] );
29
30 this->chan.center = &this->bufs [0];
31 this->chan.left = &this->bufs [1];
32 this->chan.right = &this->bufs [2];
33
34 this->length_ = 0;
35 this->sample_rate_ = 0;
36 this->channels_changed_count_ = 1;
37 this->samples_per_frame_ = 2;
38} 26}
39 27
40blargg_err_t Buffer_set_sample_rate( struct Stereo_Buffer* this, long rate, int msec ) 28void Tracked_clear( struct Tracked_Blip_Buffer* this )
41{ 29{
42 int i; 30 this->last_non_silence = 0;
43 for ( i = 0; i < buf_count; i++ ) 31 Blip_clear( &this->blip );
44 RETURN_ERR( Blip_set_sample_rate( &this->bufs[i], rate, msec ) );
45
46 this->sample_rate_ = Blip_sample_rate( &this->bufs [0] );
47 this->length_ = Blip_length( &this->bufs [0] );
48 return 0;
49} 32}
50 33
51void Buffer_clock_rate( struct Stereo_Buffer* this, long rate ) 34void Tracked_end_frame( struct Tracked_Blip_Buffer* this, blip_time_t t )
52{ 35{
53 int i; 36 Blip_end_frame( &this->blip, t );
54 for ( i = 0; i < buf_count; i++ ) 37 if ( this->blip.modified )
55 Blip_set_clock_rate( &this->bufs [i], rate ); 38 {
39 this->blip.modified = false;
40 this->last_non_silence = Blip_samples_avail( &this->blip ) + blip_buffer_extra;
41 }
56} 42}
57 43
58void Buffer_bass_freq( struct Stereo_Buffer* this, int bass ) 44unsigned Tracked_non_silent( struct Tracked_Blip_Buffer* this )
59{ 45{
60 unsigned i; 46 return this->last_non_silence | unsettled( &this->blip );
61 for ( i = 0; i < buf_count; i++ )
62 Blip_bass_freq( &this->bufs [i], bass );
63} 47}
64 48
65struct channel_t Buffer_channel( struct Stereo_Buffer* this ) 49static inline void remove_( struct Tracked_Blip_Buffer* this, int n )
66{ 50{
67 return this->chan; 51 if ( (this->last_non_silence -= n) < 0 )
52 this->last_non_silence = 0;
68} 53}
69 54
70void Buffer_clear( struct Stereo_Buffer* this ) 55void Tracked_remove_silence( struct Tracked_Blip_Buffer* this, int n )
71{ 56{
72 this->stereo_added = 0; 57 remove_( this, n );
73 this->was_stereo = false; 58 Blip_remove_silence( &this->blip, n );
74 int i;
75 for ( i = 0; i < buf_count; i++ )
76 Blip_clear( &this->bufs [i], 1 );
77} 59}
78 60
79void Buffer_end_frame( struct Stereo_Buffer* this, blip_time_t clock_count ) 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 )
80{ 89{
81 this->stereo_added = 0; 90 this->samples_read = 0;
82 unsigned i; 91}
83 for ( i = 0; i < buf_count; i++ ) 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
84 { 103 {
85 this->stereo_added |= Blip_clear_modified( &this->bufs [i] ) << i; 104 int s = center_sum >> delta_bits;
86 Blip_end_frame( &this->bufs [i], clock_count ); 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;
87 } 113 }
114 while ( ++offset );
115
116 this->bufs [2]->blip.reader_accum_ = center_sum;
88} 117}
89 118
90long Buffer_read_samples( struct Stereo_Buffer* this, blip_sample_t* out, long count ) 119static void mix_stereo( struct Stereo_Mixer* this, blip_sample_t out_ [], int count )
91{ 120{
92 require( !(count & 1) ); // count must be even 121 blip_sample_t* BLARGG_RESTRICT out = out_ + count * stereo;
93 count = (unsigned) count / 2; 122 // do left + center and right + center separately to reduce register load
94 123 struct Tracked_Blip_Buffer* const* buf = &this->bufs [2];
95 long avail = Blip_samples_avail( &this->bufs [0] ); 124 while ( true ) // loop runs twice
96 if ( count > avail )
97 count = avail;
98 if ( count )
99 { 125 {
100 int bufs_used = this->stereo_added | this->was_stereo; 126 --buf;
101 //dprintf( "%X\n", bufs_used ); 127 --out;
102 if ( bufs_used <= 1 ) 128
103 { 129 int const bass = this->bufs [2]->blip.bass_shift_;
104 Buffer_mix_mono( this, out, count ); 130 delta_t const* side = (*buf)->blip.buffer_ + this->samples_read;
105 Blip_remove_samples( &this->bufs [0], count ); 131 delta_t const* center = this->bufs [2]->blip.buffer_ + this->samples_read;
106 Blip_remove_silence( &this->bufs [1], count ); 132
107 Blip_remove_silence( &this->bufs [2], count ); 133 int side_sum = (*buf)->blip.reader_accum_;
108 } 134 int center_sum = this->bufs [2]->blip.reader_accum_;
109 else if ( bufs_used & 1 ) 135
110 { 136 int offset = -count;
111 Buffer_mix_stereo( this, out, count ); 137 do
112 Blip_remove_samples( &this->bufs [0], count );
113 Blip_remove_samples( &this->bufs [1], count );
114 Blip_remove_samples( &this->bufs [2], count );
115 }
116 else
117 {
118 Buffer_mix_stereo_no_center( this, out, count );
119 Blip_remove_silence( &this->bufs [0], count );
120 Blip_remove_samples( &this->bufs [1], count );
121 Blip_remove_samples( &this->bufs [2], count );
122 }
123
124 // to do: this might miss opportunities for optimization
125 if ( !Blip_samples_avail( &this->bufs [0] ) )
126 { 138 {
127 this->was_stereo = this->stereo_added; 139 int s = (center_sum + side_sum) >> delta_bits;
128 this->stereo_added = 0; 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;
129 } 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;
130 } 162 }
131
132 return count * 2;
133} 163}
134 164
135unsigned Buffer_channels_changed_count( struct Stereo_Buffer* this ) 165void Mixer_read_pairs( struct Stereo_Mixer* this, blip_sample_t out [], int count )
136{ 166{
137 return this->channels_changed_count_; 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 );
138} 175}
139 176
140void Buffer_channels_changed( struct Stereo_Buffer* this ) 177// Multi_Buffer
178
179void Buffer_init( struct Multi_Buffer* this )
141{ 180{
142 this->channels_changed_count_++; 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;
143} 204}
144 205
145void Buffer_mix_stereo( struct Stereo_Buffer* this, blip_sample_t* out_, blargg_long count ) 206blargg_err_t Buffer_set_sample_rate( struct Multi_Buffer* this, int rate, int msec )
146{ 207{
147 blip_sample_t* BLIP_RESTRICT out = out_; 208 int i;
148 int const bass = BLIP_READER_BASS( this->bufs [1] ); 209 for ( i = bufs_size; --i >= 0; )
149 BLIP_READER_BEGIN( left, this->bufs [1] ); 210 RETURN_ERR( Blip_set_sample_rate( &this->bufs [i].blip, rate, msec ) );
150 BLIP_READER_BEGIN( right, this->bufs [2] ); 211
151 BLIP_READER_BEGIN( center, this->bufs [0] ); 212 this->sample_rate_ = Blip_sample_rate( &this->bufs [0].blip );
152 213 this->length_ = Blip_length( &this->bufs [0].blip );
153 for ( ; count; --count ) 214 return 0;
154 {
155 int c = BLIP_READER_READ( center );
156 blargg_long l = c + BLIP_READER_READ( left );
157 blargg_long r = c + BLIP_READER_READ( right );
158 if ( (int16_t) l != l )
159 l = 0x7FFF - (l >> 24);
160
161 BLIP_READER_NEXT( center, bass );
162 if ( (int16_t) r != r )
163 r = 0x7FFF - (r >> 24);
164
165 BLIP_READER_NEXT( left, bass );
166 BLIP_READER_NEXT( right, bass );
167
168 out [0] = l;
169 out [1] = r;
170 out += 2;
171 }
172
173 BLIP_READER_END( center, this->bufs [0] );
174 BLIP_READER_END( right, this->bufs [2] );
175 BLIP_READER_END( left, this->bufs [1] );
176} 215}
177 216
178void Buffer_mix_stereo_no_center( struct Stereo_Buffer* this, blip_sample_t* out_, blargg_long count ) 217void Buffer_clock_rate( struct Multi_Buffer* this, int rate )
179{ 218{
180 blip_sample_t* BLIP_RESTRICT out = out_; 219 int i;
181 int const bass = BLIP_READER_BASS( this->bufs [1] ); 220 for ( i = bufs_size; --i >= 0; )
182 BLIP_READER_BEGIN( left, this->bufs [1] ); 221 Blip_set_clock_rate( &this->bufs [i].blip, rate );
183 BLIP_READER_BEGIN( right, this->bufs [2] ); 222}
184 223
185 for ( ; count; --count ) 224void Buffer_bass_freq( struct Multi_Buffer* this, int bass )
186 { 225{
187 blargg_long l = BLIP_READER_READ( left ); 226 int i;
188 if ( (int16_t) l != l ) 227 for ( i = bufs_size; --i >= 0; )
189 l = 0x7FFF - (l >> 24); 228 Blip_bass_freq( &this->bufs [i].blip, bass );
190 229}
191 blargg_long r = BLIP_READER_READ( right ); 230
192 if ( (int16_t) r != r ) 231blargg_err_t Buffer_set_channel_count( struct Multi_Buffer* this, int n, int const* types )
193 r = 0x7FFF - (r >> 24); 232{
194 233 this->channel_count_ = n;
195 BLIP_READER_NEXT( left, bass ); 234 this->channel_types_ = types;
196 BLIP_READER_NEXT( right, bass ); 235 return 0;
197
198 out [0] = l;
199 out [1] = r;
200 out += 2;
201 }
202
203 BLIP_READER_END( right, this->bufs [2] );
204 BLIP_READER_END( left, this->bufs [1] );
205} 236}
206 237
207void Buffer_mix_mono( struct Stereo_Buffer* this, blip_sample_t* out_, blargg_long count ) 238struct channel_t Buffer_channel( struct Multi_Buffer* this, int i )
208{ 239{
209 blip_sample_t* BLIP_RESTRICT out = out_; 240 (void) i;
210 int const bass = BLIP_READER_BASS( this->bufs [0] ); 241 return this->chan;
211 BLIP_READER_BEGIN( center, this->bufs [0] ); 242}
212 243
213 for ( ; count; --count ) 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 )
214 { 266 {
215 blargg_long s = BLIP_READER_READ( center ); 267 Mixer_read_pairs( &this->mixer, out, pair_count );
216 if ( (int16_t) s != s ) 268
217 s = 0x7FFF - (s >> 24); 269 if ( Buffer_samples_avail( this ) <= 0 || this->immediate_removal_ )
218 270 {
219 BLIP_READER_NEXT( center, bass ); 271 int i;
220 out [0] = s; 272 for ( i = bufs_size; --i >= 0; )
221 out [1] = s; 273 {
222 out += 2; 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 }
223 } 283 }
224 284
225 BLIP_READER_END( center, this->bufs [0] ); 285 return out_size;
226} 286}