Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/quicknes/nes_emu/Blip_Buffer.cpp
2 views
1
2
// Blip_Buffer 0.4.0. http://www.slack.net/~ant/
3
4
#include "Blip_Buffer.h"
5
6
#include <assert.h>
7
#include <limits.h>
8
#include <string.h>
9
#include <stdlib.h>
10
#include <math.h>
11
12
/* Copyright (C) 2003-2006 Shay Green. This module is free software; you
13
can redistribute it and/or modify it under the terms of the GNU Lesser
14
General Public License as published by the Free Software Foundation; either
15
version 2.1 of the License, or (at your option) any later version. This
16
module is distributed in the hope that it will be useful, but WITHOUT ANY
17
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
19
more details. You should have received a copy of the GNU Lesser General
20
Public License along with this module; if not, write to the Free Software
21
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
22
23
#ifdef BLARGG_ENABLE_OPTIMIZER
24
#include BLARGG_ENABLE_OPTIMIZER
25
#endif
26
27
int const buffer_extra = blip_widest_impulse_ + 2;
28
29
Blip_Buffer::Blip_Buffer()
30
{
31
factor_ = LONG_MAX;
32
offset_ = 0;
33
buffer_ = 0;
34
buffer_size_ = 0;
35
sample_rate_ = 0;
36
reader_accum = 0;
37
bass_shift = 0;
38
clock_rate_ = 0;
39
bass_freq_ = 16;
40
length_ = 0;
41
42
// assumptions code makes about implementation-defined features
43
#ifndef NDEBUG
44
// right shift of negative value preserves sign
45
buf_t_ i = -0x7FFFFFFE;
46
assert( (i >> 1) == -0x3FFFFFFF );
47
48
// casting to short truncates to 16 bits and sign-extends
49
i = 0x18000;
50
assert( (short) i == -0x8000 );
51
#endif
52
}
53
54
Blip_Buffer::~Blip_Buffer()
55
{
56
free( buffer_ );
57
}
58
59
void Blip_Buffer::clear( int entire_buffer )
60
{
61
offset_ = 0;
62
reader_accum = 0;
63
if ( buffer_ )
64
{
65
long count = (entire_buffer ? buffer_size_ : samples_avail());
66
memset( buffer_, 0, (count + buffer_extra) * sizeof (buf_t_) );
67
}
68
}
69
70
Blip_Buffer::blargg_err_t Blip_Buffer::set_sample_rate( long new_rate, int msec )
71
{
72
// start with maximum length that resampled time can represent
73
long new_size = (ULONG_MAX >> BLIP_BUFFER_ACCURACY) - buffer_extra - 64;
74
if ( msec != blip_max_length )
75
{
76
long s = (new_rate * (msec + 1) + 999) / 1000;
77
if ( s < new_size )
78
new_size = s;
79
else
80
assert( 0 ); // fails if requested buffer length exceeds limit
81
}
82
83
if ( buffer_size_ != new_size )
84
{
85
void* p = realloc( buffer_, (new_size + buffer_extra) * sizeof *buffer_ );
86
if ( !p )
87
return "Out of memory";
88
buffer_ = (buf_t_*) p;
89
}
90
91
buffer_size_ = new_size;
92
93
// update things based on the sample rate
94
sample_rate_ = new_rate;
95
length_ = new_size * 1000 / new_rate - 1;
96
if ( msec )
97
assert( length_ == msec ); // ensure length is same as that passed in
98
if ( clock_rate_ )
99
clock_rate( clock_rate_ );
100
bass_freq( bass_freq_ );
101
102
clear();
103
104
return 0; // success
105
}
106
107
blip_resampled_time_t Blip_Buffer::clock_rate_factor( long clock_rate ) const
108
{
109
double ratio = (double) sample_rate_ / clock_rate;
110
long factor = (long) floor( ratio * (1L << BLIP_BUFFER_ACCURACY) + 0.5 );
111
assert( factor > 0 || !sample_rate_ ); // fails if clock/output ratio is too large
112
return (blip_resampled_time_t) factor;
113
}
114
115
void Blip_Buffer::bass_freq( int freq )
116
{
117
bass_freq_ = freq;
118
int shift = 31;
119
if ( freq > 0 )
120
{
121
shift = 13;
122
long f = (freq << 16) / sample_rate_;
123
while ( (f >>= 1) && --shift ) { }
124
}
125
bass_shift = shift;
126
}
127
128
void Blip_Buffer::end_frame( blip_time_t t )
129
{
130
offset_ += t * factor_;
131
assert( samples_avail() <= (long) buffer_size_ ); // time outside buffer length
132
}
133
134
void Blip_Buffer::remove_silence( long count )
135
{
136
assert( count <= samples_avail() ); // tried to remove more samples than available
137
offset_ -= (blip_resampled_time_t) count << BLIP_BUFFER_ACCURACY;
138
}
139
140
long Blip_Buffer::count_samples( blip_time_t t ) const
141
{
142
unsigned long last_sample = resampled_time( t ) >> BLIP_BUFFER_ACCURACY;
143
unsigned long first_sample = offset_ >> BLIP_BUFFER_ACCURACY;
144
return (long) (last_sample - first_sample);
145
}
146
147
blip_time_t Blip_Buffer::count_clocks( long count ) const
148
{
149
if ( count > buffer_size_ )
150
count = buffer_size_;
151
blip_resampled_time_t time = (blip_resampled_time_t) count << BLIP_BUFFER_ACCURACY;
152
return (blip_time_t) ((time - offset_ + factor_ - 1) / factor_);
153
}
154
155
void Blip_Buffer::remove_samples( long count )
156
{
157
if ( count )
158
{
159
remove_silence( count );
160
161
// copy remaining samples to beginning and clear old samples
162
long remain = samples_avail() + buffer_extra;
163
memmove( buffer_, buffer_ + count, remain * sizeof *buffer_ );
164
memset( buffer_ + remain, 0, count * sizeof *buffer_ );
165
}
166
}
167
168
// Blip_Synth_
169
170
Blip_Synth_::Blip_Synth_( short* p, int w ) :
171
impulses( p ),
172
width( w )
173
{
174
volume_unit_ = 0.0;
175
kernel_unit = 0;
176
buf = 0;
177
last_amp = 0;
178
delta_factor = 0;
179
}
180
181
// TODO: apparently this is defined elsewhere too
182
#define pi my_pi
183
static double const pi = 3.1415926535897932384626433832795029;
184
185
static void gen_sinc( float* out, int count, double oversample, double treble, double cutoff )
186
{
187
if ( cutoff >= 0.999 )
188
cutoff = 0.999;
189
190
if ( treble < -300.0 )
191
treble = -300.0;
192
if ( treble > 5.0 )
193
treble = 5.0;
194
195
double const maxh = 4096.0;
196
double const rolloff = pow( 10.0, 1.0 / (maxh * 20.0) * treble / (1.0 - cutoff) );
197
double const pow_a_n = pow( rolloff, maxh - maxh * cutoff );
198
double const to_angle = pi / 2 / maxh / oversample;
199
for ( int i = 0; i < count; i++ )
200
{
201
double angle = ((i - count) * 2 + 1) * to_angle;
202
double c = rolloff * cos( (maxh - 1.0) * angle ) - cos( maxh * angle );
203
double cos_nc_angle = cos( maxh * cutoff * angle );
204
double cos_nc1_angle = cos( (maxh * cutoff - 1.0) * angle );
205
double cos_angle = cos( angle );
206
207
c = c * pow_a_n - rolloff * cos_nc1_angle + cos_nc_angle;
208
double d = 1.0 + rolloff * (rolloff - cos_angle - cos_angle);
209
double b = 2.0 - cos_angle - cos_angle;
210
double a = 1.0 - cos_angle - cos_nc_angle + cos_nc1_angle;
211
212
out [i] = (float) ((a * d + c * b) / (b * d)); // a / b + c / d
213
}
214
}
215
216
void blip_eq_t::generate( float* out, int count ) const
217
{
218
// lower cutoff freq for narrow kernels with their wider transition band
219
// (8 points->1.49, 16 points->1.15)
220
double oversample = blip_res * 2.25 / count + 0.85;
221
double half_rate = sample_rate * 0.5;
222
if ( cutoff_freq )
223
oversample = half_rate / cutoff_freq;
224
double cutoff = rolloff_freq * oversample / half_rate;
225
226
gen_sinc( out, count, blip_res * oversample, treble, cutoff );
227
228
// apply (half of) hamming window
229
double to_fraction = pi / (count - 1);
230
for ( int i = count; i--; )
231
out [i] *= 0.54 - 0.46 * cos( i * to_fraction );
232
}
233
234
void Blip_Synth_::adjust_impulse()
235
{
236
// sum pairs for each phase and add error correction to end of first half
237
int const size = impulses_size();
238
for ( int p = blip_res; p-- >= blip_res / 2; )
239
{
240
int p2 = blip_res - 2 - p;
241
long error = kernel_unit;
242
for ( int i = 1; i < size; i += blip_res )
243
{
244
error -= impulses [i + p ];
245
error -= impulses [i + p2];
246
}
247
if ( p == p2 )
248
error /= 2; // phase = 0.5 impulse uses same half for both sides
249
impulses [size - blip_res + p] += error;
250
//printf( "error: %ld\n", error );
251
}
252
253
//for ( int i = blip_res; i--; printf( "\n" ) )
254
// for ( int j = 0; j < width / 2; j++ )
255
// printf( "%5ld,", impulses [j * blip_res + i + 1] );
256
}
257
258
void Blip_Synth_::treble_eq( blip_eq_t const& eq )
259
{
260
float fimpulse [blip_res / 2 * (blip_widest_impulse_ - 1) + blip_res * 2];
261
262
int const half_size = blip_res / 2 * (width - 1);
263
eq.generate( &fimpulse [blip_res], half_size );
264
265
int i;
266
267
// need mirror slightly past center for calculation
268
for ( i = blip_res; i--; )
269
fimpulse [blip_res + half_size + i] = fimpulse [blip_res + half_size - 1 - i];
270
271
// starts at 0
272
for ( i = 0; i < blip_res; i++ )
273
fimpulse [i] = 0.0f;
274
275
// find rescale factor
276
double total = 0.0;
277
for ( i = 0; i < half_size; i++ )
278
total += fimpulse [blip_res + i];
279
280
//double const base_unit = 44800.0 - 128 * 18; // allows treble up to +0 dB
281
//double const base_unit = 37888.0; // allows treble to +5 dB
282
double const base_unit = 32768.0; // necessary for blip_unscaled to work
283
double rescale = base_unit / 2 / total;
284
kernel_unit = (long) base_unit;
285
286
// integrate, first difference, rescale, convert to int
287
double sum = 0.0;
288
double next = 0.0;
289
int const impulses_size = this->impulses_size();
290
for ( i = 0; i < impulses_size; i++ )
291
{
292
impulses [i] = (short) floor( (next - sum) * rescale + 0.5 );
293
sum += fimpulse [i];
294
next += fimpulse [i + blip_res];
295
}
296
adjust_impulse();
297
298
// volume might require rescaling
299
double vol = volume_unit_;
300
if ( vol )
301
{
302
volume_unit_ = 0.0;
303
volume_unit( vol );
304
}
305
}
306
307
void Blip_Synth_::volume_unit( double new_unit )
308
{
309
if ( new_unit != volume_unit_ )
310
{
311
// use default eq if it hasn't been set yet
312
if ( !kernel_unit )
313
treble_eq( -8.0 );
314
315
volume_unit_ = new_unit;
316
double factor = new_unit * (1L << blip_sample_bits) / kernel_unit;
317
318
if ( factor > 0.0 )
319
{
320
int shift = 0;
321
322
// if unit is really small, might need to attenuate kernel
323
while ( factor < 2.0 )
324
{
325
shift++;
326
factor *= 2.0;
327
}
328
329
if ( shift )
330
{
331
kernel_unit >>= shift;
332
assert( kernel_unit > 0 ); // fails if volume unit is too low
333
334
// keep values positive to avoid round-towards-zero of sign-preserving
335
// right shift for negative values
336
long offset = 0x8000 + (1 << (shift - 1));
337
long offset2 = 0x8000 >> shift;
338
for ( int i = impulses_size(); i--; )
339
impulses [i] = (short) (((impulses [i] + offset) >> shift) - offset2);
340
adjust_impulse();
341
}
342
}
343
delta_factor = (int) floor( factor + 0.5 );
344
//printf( "delta_factor: %d, kernel_unit: %d\n", delta_factor, kernel_unit );
345
}
346
}
347
348
long Blip_Buffer::read_samples( blip_sample_t* out, long max_samples, int stereo )
349
{
350
long count = samples_avail();
351
if ( count > max_samples )
352
count = max_samples;
353
354
if ( count )
355
{
356
int const sample_shift = blip_sample_bits - 16;
357
int const bass_shift = this->bass_shift;
358
long accum = reader_accum;
359
buf_t_* in = buffer_;
360
361
if ( !stereo )
362
{
363
for ( long n = count; n--; )
364
{
365
long s = accum >> sample_shift;
366
accum -= accum >> bass_shift;
367
accum += *in++;
368
*out++ = (blip_sample_t) s;
369
370
// clamp sample
371
if ( (blip_sample_t) s != s )
372
out [-1] = (blip_sample_t) (0x7FFF - (s >> 24));
373
}
374
}
375
else
376
{
377
for ( long n = count; n--; )
378
{
379
long s = accum >> sample_shift;
380
accum -= accum >> bass_shift;
381
accum += *in++;
382
*out = (blip_sample_t) s;
383
out += 2;
384
385
// clamp sample
386
if ( (blip_sample_t) s != s )
387
out [-2] = (blip_sample_t) (0x7FFF - (s >> 24));
388
}
389
}
390
391
reader_accum = accum;
392
remove_samples( count );
393
}
394
return count;
395
}
396
397
void Blip_Buffer::mix_samples( blip_sample_t const* in, long count )
398
{
399
buf_t_* out = buffer_ + (offset_ >> BLIP_BUFFER_ACCURACY) + blip_widest_impulse_ / 2;
400
401
int const sample_shift = blip_sample_bits - 16;
402
int prev = 0;
403
while ( count-- )
404
{
405
long s = (long) *in++ << sample_shift;
406
*out += s - prev;
407
prev = s;
408
++out;
409
}
410
*out -= prev;
411
}
412
413
414