diff options
Diffstat (limited to 'apps/codecs/libgme/multi_buffer.c')
-rw-r--r-- | apps/codecs/libgme/multi_buffer.c | 390 |
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 | 20 | int const blip_buffer_extra = 32; // TODO: explain why this value |
21 | 21 | ||
22 | // Stereo_Buffer | 22 | void Tracked_init( struct Tracked_Blip_Buffer* this ) |
23 | 23 | { | |
24 | void 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 | ||
40 | blargg_err_t Buffer_set_sample_rate( struct Stereo_Buffer* this, long rate, int msec ) | 28 | void 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 | ||
51 | void Buffer_clock_rate( struct Stereo_Buffer* this, long rate ) | 34 | void 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 | ||
58 | void Buffer_bass_freq( struct Stereo_Buffer* this, int bass ) | 44 | unsigned 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 | ||
65 | struct channel_t Buffer_channel( struct Stereo_Buffer* this ) | 49 | static 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 | ||
70 | void Buffer_clear( struct Stereo_Buffer* this ) | 55 | void 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 | ||
79 | void Buffer_end_frame( struct Stereo_Buffer* this, blip_time_t clock_count ) | 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 ) | ||
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 | |
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 | ||
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 | ||
90 | long Buffer_read_samples( struct Stereo_Buffer* this, blip_sample_t* out, long count ) | 119 | static 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 | ||
135 | unsigned Buffer_channels_changed_count( struct Stereo_Buffer* this ) | 165 | void 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 | ||
140 | void Buffer_channels_changed( struct Stereo_Buffer* this ) | 177 | // Multi_Buffer |
178 | |||
179 | void 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 | ||
145 | void Buffer_mix_stereo( struct Stereo_Buffer* this, blip_sample_t* out_, blargg_long count ) | 206 | blargg_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 | ||
178 | void Buffer_mix_stereo_no_center( struct Stereo_Buffer* this, blip_sample_t* out_, blargg_long count ) | 217 | void 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 ) | 224 | void 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 ) | 231 | blargg_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 | ||
207 | void Buffer_mix_mono( struct Stereo_Buffer* this, blip_sample_t* out_, blargg_long count ) | 238 | struct 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 ) | 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 ) | ||
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 | } |