1
2// Blip_Buffer 0.3.3. http://www.slack.net/~ant/libs/
3
4#include "Blip_Buffer.h"
5
6#include <string.h>
7#include <math.h>
8
9/* Copyright (C) 2003-2005 Shay Green. This module is free software; you
10can redistribute it and/or modify it under the terms of the GNU Lesser
11General Public License as published by the Free Software Foundation; either
12version 2.1 of the License, or (at your option) any later version. This
13module is distributed in the hope that it will be useful, but WITHOUT ANY
14WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
16more details. You should have received a copy of the GNU Lesser General
17Public License along with this module; if not, write to the Free Software
18Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
19
20#include BLARGG_SOURCE_BEGIN
21
22Blip_Buffer::Blip_Buffer()
23{
24 samples_per_sec = 44100;
25 buffer_ = NULL;
26
27 // try to cause assertion failure if buffer is used before these are set
28 clocks_per_sec = 0;
29 factor_ = ~0ul;
30 offset_ = 0;
31 buffer_size_ = 0;
32 length_ = 0;
33
34 bass_freq_ = 16;
35}
36
37void Blip_Buffer::clear( bool entire_buffer )
38{
39 long count = (entire_buffer ? buffer_size_ : samples_avail());
40 offset_ = 0;
41 reader_accum = 0;
42 memset( buffer_, sample_offset & 0xFF, (count + widest_impulse_) * sizeof (buf_t_) );
43}
44
45blargg_err_t Blip_Buffer::sample_rate( long new_rate, int msec )
46{
47 unsigned new_size = (UINT_MAX >> BLIP_BUFFER_ACCURACY) + 1 - widest_impulse_ - 64;
48 if ( msec != blip_default_length )
49 {
50 size_t s = (new_rate * (msec + 1) + 999) / 1000;
51 if ( s < new_size )
52 new_size = s;
53 else
54 require( false ); // requested buffer length exceeds limit
55 }
56
57 if ( buffer_size_ != new_size )
58 {
59 delete [] buffer_;
60 buffer_ = NULL; // allow for exception in allocation below
61 buffer_size_ = 0;
62 offset_ = 0;
63
64 buffer_ = BLARGG_NEW buf_t_ [new_size + widest_impulse_];
65 BLARGG_CHECK_ALLOC( buffer_ );
66 }
67
68 buffer_size_ = new_size;
69 length_ = new_size * 1000 / new_rate - 1;
70 if ( msec )
71 assert( length_ == msec ); // ensure length is same as that passed in
72
73 samples_per_sec = new_rate;
74 if ( clocks_per_sec )
75 clock_rate( clocks_per_sec ); // recalculate factor
76
77 bass_freq( bass_freq_ ); // recalculate shift
78
79 clear();
80
81 return blargg_success;
82}
83
84void Blip_Buffer::clock_rate( long cps )
85{
86 clocks_per_sec = cps;
87 factor_ = (unsigned long) floor( (double) samples_per_sec / cps *
88 (1L << BLIP_BUFFER_ACCURACY) + 0.5 );
89 require( factor_ > 0 ); // clock_rate/sample_rate ratio is too large
90}
91
92Blip_Buffer::~Blip_Buffer()
93{
94 delete [] buffer_;
95}
96
97void Blip_Buffer::bass_freq( int freq )
98{
99 bass_freq_ = freq;
100 if ( freq == 0 ) {
101 bass_shift = 31; // 32 or greater invokes undefined behavior elsewhere
102 return;
103 }
104 bass_shift = 1 + (int) floor( 1.442695041 * log( 0.124 * samples_per_sec / freq ) );
105 if ( bass_shift < 0 )
106 bass_shift = 0;
107 if ( bass_shift > 24 )
108 bass_shift = 24;
109}
110
111long Blip_Buffer::count_samples( blip_time_t t ) const {
112 return (resampled_time( t ) >> BLIP_BUFFER_ACCURACY) - (offset_ >> BLIP_BUFFER_ACCURACY);
113}
114
115void Blip_Impulse_::init( blip_pair_t_* imps, int w, int r, int fb )
116{
117 fine_bits = fb;
118 width = w;
119 impulses = (imp_t*) imps;
120 generate = true;
121 volume_unit_ = -1.0;
122 res = r;
123 buf = NULL;
124
125 impulse = &impulses [width * res * 2 * (fine_bits ? 2 : 1)];
126 offset = 0;
127}
128
129const int impulse_bits = 15;
130const long impulse_amp = 1L << impulse_bits;
131const long impulse_offset = impulse_amp / 2;
132
133void Blip_Impulse_::scale_impulse( int unit, imp_t* imp_in ) const
134{
135 long offset = ((long) unit << impulse_bits) - impulse_offset * unit +
136 (1 << (impulse_bits - 1));
137 imp_t* imp = imp_in;
138 imp_t* fimp = impulse;
139 for ( int n = res / 2 + 1; n--; )
140 {
141 int error = unit;
142 for ( int nn = width; nn--; )
143 {
144 long a = ((long) *fimp++ * unit + offset) >> impulse_bits;
145 error -= a - unit;
146 *imp++ = (imp_t) a;
147 }
148
149 // add error to middle
150 imp [-width / 2 - 1] += (imp_t) error;
151 }
152
153 if ( res > 2 ) {
154 // second half is mirror-image
155 const imp_t* rev = imp - width - 1;
156 for ( int nn = (res / 2 - 1) * width - 1; nn--; )
157 *imp++ = *--rev;
158 *imp++ = (imp_t) unit;
159 }
160
161 // copy to odd offset
162 *imp++ = (imp_t) unit;
163 memcpy( imp, imp_in, (res * width - 1) * sizeof *imp );
164}
165
166const int max_res = 1 << blip_res_bits_;
167
168void Blip_Impulse_::fine_volume_unit()
169{
170 // to do: find way of merging in-place without temporary buffer
171
172 imp_t temp [max_res * 2 * Blip_Buffer::widest_impulse_];
173 scale_impulse( (offset & 0xffff) << fine_bits, temp );
174 imp_t* imp2 = impulses + res * 2 * width;
175 scale_impulse( offset & 0xffff, imp2 );
176
177 // merge impulses
178 imp_t* imp = impulses;
179 imp_t* src2 = temp;
180 for ( int n = res / 2 * 2 * width; n--; ) {
181 *imp++ = *imp2++;
182 *imp++ = *imp2++;
183 *imp++ = *src2++;
184 *imp++ = *src2++;
185 }
186}
187
188void Blip_Impulse_::volume_unit( double new_unit )
189{
190 if ( new_unit == volume_unit_ )
191 return;
192
193 if ( generate )
194 treble_eq( blip_eq_t( -8.87, 8800, 44100 ) );
195
196 volume_unit_ = new_unit;
197
198 offset = 0x10001 * (unsigned long) floor( volume_unit_ * 0x10000 + 0.5 );
199
200 if ( fine_bits )
201 fine_volume_unit();
202 else
203 scale_impulse( offset & 0xffff, impulses );
204}
205
206static const double pi = 3.1415926535897932384626433832795029L;
207
208void Blip_Impulse_::treble_eq( const blip_eq_t& new_eq )
209{
210 if ( !generate && new_eq.treble == eq.treble && new_eq.cutoff == eq.cutoff &&
211 new_eq.sample_rate == eq.sample_rate )
212 return; // already calculated with same parameters
213
214 generate = false;
215 eq = new_eq;
216
217 double treble = pow( 10.0, 1.0 / 20 * eq.treble ); // dB (-6dB = 0.50)
218 if ( treble < 0.000005 )
219 treble = 0.000005;
220
221 const double treble_freq = 22050.0; // treble level at 22 kHz harmonic
222 const double sample_rate = eq.sample_rate;
223 const double pt = treble_freq * 2 / sample_rate;
224 double cutoff = eq.cutoff * 2 / sample_rate;
225 if ( cutoff >= pt * 0.95 || cutoff >= 0.95 ) {
226 cutoff = 0.5;
227 treble = 1.0;
228 }
229
230 // DSF Synthesis (See T. Stilson & J. Smith (1996),
231 // Alias-free digital synthesis of classic analog waveforms)
232
233 // reduce adjacent impulse interference by using small part of wide impulse
234 const double n_harm = 4096;
235 const double rolloff = pow( treble, 1.0 / (n_harm * pt - n_harm * cutoff) );
236 const double rescale = 1.0 / pow( rolloff, n_harm * cutoff );
237
238 const double pow_a_n = rescale * pow( rolloff, n_harm );
239 const double pow_a_nc = rescale * pow( rolloff, n_harm * cutoff );
240
241 double total = 0.0;
242 const double to_angle = pi / 2 / n_harm / max_res;
243
244 float buf [max_res * (Blip_Buffer::widest_impulse_ - 2) / 2];
245 const int size = max_res * (width - 2) / 2;
246 for ( int i = size; i--; )
247 {
248 double angle = (i * 2 + 1) * to_angle;
249
250 // equivalent
251 //double y = dsf( angle, n_harm * cutoff, 1.0 );
252 //y -= rescale * dsf( angle, n_harm * cutoff, rolloff );
253 //y += rescale * dsf( angle, n_harm, rolloff );
254
255 const double cos_angle = cos( angle );
256 const double cos_nc_angle = cos( n_harm * cutoff * angle );
257 const double cos_nc1_angle = cos( (n_harm * cutoff - 1.0) * angle );
258
259 double b = 2.0 - 2.0 * cos_angle;
260 double a = 1.0 - cos_angle - cos_nc_angle + cos_nc1_angle;
261
262 double d = 1.0 + rolloff * (rolloff - 2.0 * cos_angle);
263 double c = pow_a_n * rolloff * cos( (n_harm - 1.0) * angle ) -
264 pow_a_n * cos( n_harm * angle ) -
265 pow_a_nc * rolloff * cos_nc1_angle +
266 pow_a_nc * cos_nc_angle;
267
268 // optimization of a / b + c / d
269 double y = (a * d + c * b) / (b * d);
270
271 // fixed window which affects wider impulses more
272 if ( width > 12 ) {
273 double window = cos( n_harm / 1.25 / Blip_Buffer::widest_impulse_ * angle );
274 y *= window * window;
275 }
276
277 total += (float) y;
278 buf [i] = (float) y;
279 }
280
281 // integrate runs of length 'max_res'
282 double factor = impulse_amp * 0.5 / total; // 0.5 accounts for other mirrored half
283 imp_t* imp = impulse;
284 const int step = max_res / res;
285 int offset = res > 1 ? max_res : max_res / 2;
286 for ( int n = res / 2 + 1; n--; offset -= step )
287 {
288 for ( int w = -width / 2; w < width / 2; w++ )
289 {
290 double sum = 0;
291 for ( int i = max_res; i--; )
292 {
293 int index = w * max_res + offset + i;
294 if ( index < 0 )
295 index = -index - 1;
296 if ( index < size )
297 sum += buf [index];
298 }
299 *imp++ = (imp_t) floor( sum * factor + (impulse_offset + 0.5) );
300 }
301 }
302
303 // rescale
304 double unit = volume_unit_;
305 if ( unit >= 0 ) {
306 volume_unit_ = -1;
307 volume_unit( unit );
308 }
309}
310
311void Blip_Buffer::remove_samples( long count )
312{
313 require( buffer_ ); // sample rate must have been set
314
315 if ( !count ) // optimization
316 return;
317
318 remove_silence( count );
319
320 // Allows synthesis slightly past time passed to end_frame(), as long as it's
321 // not more than an output sample.
322 // to do: kind of hacky, could add run_until() which keeps track of extra synthesis
323 int const copy_extra = 1;
324
325 // copy remaining samples to beginning and clear old samples
326 long remain = samples_avail() + widest_impulse_ + copy_extra;
327 if ( count >= remain )
328 memmove( buffer_, buffer_ + count, remain * sizeof (buf_t_) );
329 else
330 memcpy( buffer_, buffer_ + count, remain * sizeof (buf_t_) );
331 memset( buffer_ + remain, sample_offset & 0xFF, count * sizeof (buf_t_) );
332}
333
334#include BLARGG_ENABLE_OPTIMIZER
335
336long Blip_Buffer::read_samples( blip_sample_t* out, long max_samples, bool stereo )
337{
338 require( buffer_ ); // sample rate must have been set
339
340 long count = samples_avail();
341 if ( count > max_samples )
342 count = max_samples;
343
344 if ( !count )
345 return 0; // optimization
346
347 int sample_offset = this->sample_offset;
348 int bass_shift = this->bass_shift;
349 buf_t_* buf = buffer_;
350 long accum = reader_accum;
351
352 if ( !stereo ) {
353 for ( long n = count; n--; ) {
354 long s = accum >> accum_fract;
355 accum -= accum >> bass_shift;
356 accum += (long (*buf++) - sample_offset) << accum_fract;
357 *out++ = (blip_sample_t) s;
358
359 // clamp sample
360 if ( (BOOST::int16_t) s != s )
361 out [-1] = blip_sample_t (0x7FFF - (s >> 24));
362 }
363 }
364 else {
365 for ( long n = count; n--; ) {
366 long s = accum >> accum_fract;
367 accum -= accum >> bass_shift;
368 accum += (long (*buf++) - sample_offset) << accum_fract;
369 *out = (blip_sample_t) s;
370 out += 2;
371
372 // clamp sample
373 if ( (BOOST::int16_t) s != s )
374 out [-2] = blip_sample_t (0x7FFF - (s >> 24));
375 }
376 }
377
378 reader_accum = accum;
379
380 remove_samples( count );
381
382 return count;
383}
384
385void Blip_Buffer::mix_samples( const blip_sample_t* in, long count )
386{
387 buf_t_* buf = &buffer_ [(offset_ >> BLIP_BUFFER_ACCURACY) + (widest_impulse_ / 2 - 1)];
388
389 int prev = 0;
390 while ( count-- ) {
391 int s = *in++;
392 *buf += s - prev;
393 prev = s;
394 ++buf;
395 }
396 *buf -= *--in;
397}
398
399