Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/genplus-gx32/core/sound/blip_buf.c
2 views
1
/* blip_buf $vers. http://www.slack.net/~ant/ */
2
3
/* Modified for Genesis Plus GX by EkeEke (01/09/12) */
4
/* - disabled assertions checks (define #BLIP_ASSERT to re-enable) */
5
/* - fixed multiple time-frames support & removed m->avail */
6
/* - modified blip_read_samples to always output to stereo streams */
7
/* - added blip_mix_samples function (see blip_buf.h) */
8
9
#include "blip_buf.h"
10
11
#ifdef BLIP_ASSERT
12
#include <assert.h>
13
#endif
14
#include <limits.h>
15
#include <string.h>
16
#include <stdlib.h>
17
18
/* Library Copyright (C) 2003-2009 Shay Green. This library is free software;
19
you can redistribute it and/or modify it under the terms of the GNU Lesser
20
General Public License as published by the Free Software Foundation; either
21
version 2.1 of the License, or (at your option) any later version. This
22
library is distributed in the hope that it will be useful, but WITHOUT ANY
23
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
24
A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
25
details. You should have received a copy of the GNU Lesser General Public
26
License along with this module; if not, write to the Free Software Foundation,
27
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
28
29
30
#if defined (BLARGG_TEST) && BLARGG_TEST
31
#include "blargg_test.h"
32
#endif
33
34
/* Equivalent to ULONG_MAX >= 0xFFFFFFFF00000000.
35
Avoids constants that don't fit in 32 bits. */
36
#if ULONG_MAX/0xFFFFFFFF > 0xFFFFFFFF
37
typedef unsigned long fixed_t;
38
enum { pre_shift = 32 };
39
40
#elif defined(ULLONG_MAX)
41
typedef unsigned long long fixed_t;
42
enum { pre_shift = 32 };
43
44
#else
45
typedef unsigned fixed_t;
46
enum { pre_shift = 0 };
47
48
#endif
49
50
enum { time_bits = pre_shift + 20 };
51
52
static fixed_t const time_unit = (fixed_t) 1 << time_bits;
53
54
enum { bass_shift = 9 }; /* affects high-pass filter breakpoint frequency */
55
enum { end_frame_extra = 2 }; /* allows deltas slightly after frame length */
56
57
enum { half_width = 8 };
58
enum { buf_extra = half_width*2 + end_frame_extra };
59
enum { phase_bits = 5 };
60
enum { phase_count = 1 << phase_bits };
61
enum { delta_bits = 15 };
62
enum { delta_unit = 1 << delta_bits };
63
enum { frac_bits = time_bits - pre_shift };
64
65
/* We could eliminate avail and encode whole samples in offset, but that would
66
limit the total buffered samples to blip_max_frame. That could only be
67
increased by decreasing time_bits, which would reduce resample ratio accuracy.
68
*/
69
70
struct blip_t
71
{
72
fixed_t factor;
73
fixed_t offset;
74
int size;
75
int integrator;
76
};
77
78
typedef int buf_t;
79
80
/* probably not totally portable */
81
#define SAMPLES( buf ) ((buf_t*) ((buf) + 1))
82
83
/* Arithmetic (sign-preserving) right shift */
84
#define ARITH_SHIFT( n, shift ) \
85
((n) >> (shift))
86
87
enum { max_sample = +32767 };
88
enum { min_sample = -32768 };
89
90
#define CLAMP( n ) \
91
{\
92
if ( n > max_sample ) n = max_sample;\
93
else if ( n < min_sample) n = min_sample;\
94
}
95
96
#ifdef BLIP_ASSERT
97
static void check_assumptions( void )
98
{
99
int n;
100
101
#if INT_MAX < 0x7FFFFFFF || UINT_MAX < 0xFFFFFFFF
102
#error "int must be at least 32 bits"
103
#endif
104
105
assert( (-3 >> 1) == -2 ); /* right shift must preserve sign */
106
107
n = max_sample * 2;
108
CLAMP( n );
109
assert( n == max_sample );
110
111
n = min_sample * 2;
112
CLAMP( n );
113
assert( n == min_sample );
114
115
assert( blip_max_ratio <= time_unit );
116
assert( blip_max_frame <= (fixed_t) -1 >> time_bits );
117
}
118
#endif
119
120
blip_t* blip_new( int size )
121
{
122
blip_t* m;
123
#ifdef BLIP_ASSERT
124
assert( size >= 0 );
125
#endif
126
127
m = (blip_t*) malloc( sizeof *m + (size + buf_extra) * sizeof (buf_t) );
128
if ( m )
129
{
130
m->factor = time_unit / blip_max_ratio;
131
m->size = size;
132
blip_clear( m );
133
#ifdef BLIP_ASSERT
134
check_assumptions();
135
#endif
136
}
137
return m;
138
}
139
140
void blip_delete( blip_t* m )
141
{
142
if ( m != NULL )
143
{
144
/* Clear fields in case user tries to use after freeing */
145
memset( m, 0, sizeof *m );
146
free( m );
147
}
148
}
149
150
void blip_set_rates( blip_t* m, double clock_rate, double sample_rate )
151
{
152
double factor = time_unit * sample_rate / clock_rate;
153
m->factor = (fixed_t) factor;
154
155
#ifdef BLIP_ASSERT
156
/* Fails if clock_rate exceeds maximum, relative to sample_rate */
157
assert( 0 <= factor - m->factor && factor - m->factor < 1 );
158
#endif
159
160
/* Avoid requiring math.h. Equivalent to
161
m->factor = (int) ceil( factor ) */
162
if ( m->factor < factor )
163
m->factor++;
164
165
/* At this point, factor is most likely rounded up, but could still
166
have been rounded down in the floating-point calculation. */
167
}
168
169
void blip_clear( blip_t* m )
170
{
171
/* We could set offset to 0, factor/2, or factor-1. 0 is suitable if
172
factor is rounded up. factor-1 is suitable if factor is rounded down.
173
Since we don't know rounding direction, factor/2 accommodates either,
174
with the slight loss of showing an error in half the time. Since for
175
a 64-bit factor this is years, the halving isn't a problem. */
176
177
m->offset = m->factor / 2;
178
m->integrator = 0;
179
memset( SAMPLES( m ), 0, (m->size + buf_extra) * sizeof (buf_t) );
180
}
181
182
int blip_clocks_needed( const blip_t* m, int samples )
183
{
184
fixed_t needed;
185
186
#ifdef BLIP_ASSERT
187
/* Fails if buffer can't hold that many more samples */
188
assert( (samples >= 0) && (((m->offset >> time_bits) + samples) <= m->size) );
189
#endif
190
191
needed = (fixed_t) samples * time_unit;
192
if ( needed < m->offset )
193
return 0;
194
195
return (needed - m->offset + m->factor - 1) / m->factor;
196
}
197
198
void blip_end_frame( blip_t* m, unsigned t )
199
{
200
m->offset += t * m->factor;
201
202
#ifdef BLIP_ASSERT
203
/* Fails if buffer size was exceeded */
204
assert( (m->offset >> time_bits) <= m->size );
205
#endif
206
}
207
208
int blip_samples_avail( const blip_t* m )
209
{
210
return (m->offset >> time_bits);
211
}
212
213
static void remove_samples( blip_t* m, int count )
214
{
215
buf_t* buf = SAMPLES( m );
216
int remain = (m->offset >> time_bits) + buf_extra - count;
217
m->offset -= count * time_unit;
218
219
memmove( &buf [0], &buf [count], remain * sizeof buf [0] );
220
memset( &buf [remain], 0, count * sizeof buf [0] );
221
}
222
223
int blip_read_samples( blip_t* m, short out [], int count)
224
{
225
#ifdef BLIP_ASSERT
226
assert( count >= 0 );
227
228
if ( count > (m->offset >> time_bits) )
229
count = m->offset >> time_bits;
230
231
if ( count )
232
#endif
233
{
234
buf_t const* in = SAMPLES( m );
235
buf_t const* end = in + count;
236
int sum = m->integrator;
237
do
238
{
239
/* Eliminate fraction */
240
int s = ARITH_SHIFT( sum, delta_bits );
241
242
sum += *in++;
243
244
CLAMP( s );
245
246
*out = s;
247
out += 2;
248
249
/* High-pass filter */
250
sum -= s << (delta_bits - bass_shift);
251
}
252
while ( in != end );
253
m->integrator = sum;
254
255
remove_samples( m, count );
256
}
257
258
return count;
259
}
260
261
int blip_mix_samples( blip_t* m, short out [], int count)
262
{
263
#ifdef BLIP_ASSERT
264
assert( count >= 0 );
265
266
if ( count > (m->offset >> time_bits) )
267
count = m->offset >> time_bits;
268
269
if ( count )
270
#endif
271
{
272
buf_t const* in = SAMPLES( m );
273
buf_t const* end = in + count;
274
int sum = m->integrator;
275
do
276
{
277
/* Eliminate fraction */
278
int s = ARITH_SHIFT( sum, delta_bits );
279
280
sum += *in++;
281
282
/* High-pass filter */
283
sum -= s << (delta_bits - bass_shift);
284
285
/* Add current buffer value */
286
s += *out;
287
288
CLAMP( s );
289
290
*out = s;
291
out += 2;
292
}
293
while ( in != end );
294
m->integrator = sum;
295
296
remove_samples( m, count );
297
}
298
299
return count;
300
}
301
302
/* Things that didn't help performance on x86:
303
__attribute__((aligned(128)))
304
#define short int
305
restrict
306
*/
307
308
/* Sinc_Generator( 0.9, 0.55, 4.5 ) */
309
static short const bl_step [phase_count + 1] [half_width] =
310
{
311
{ 43, -115, 350, -488, 1136, -914, 5861,21022},
312
{ 44, -118, 348, -473, 1076, -799, 5274,21001},
313
{ 45, -121, 344, -454, 1011, -677, 4706,20936},
314
{ 46, -122, 336, -431, 942, -549, 4156,20829},
315
{ 47, -123, 327, -404, 868, -418, 3629,20679},
316
{ 47, -122, 316, -375, 792, -285, 3124,20488},
317
{ 47, -120, 303, -344, 714, -151, 2644,20256},
318
{ 46, -117, 289, -310, 634, -17, 2188,19985},
319
{ 46, -114, 273, -275, 553, 117, 1758,19675},
320
{ 44, -108, 255, -237, 471, 247, 1356,19327},
321
{ 43, -103, 237, -199, 390, 373, 981,18944},
322
{ 42, -98, 218, -160, 310, 495, 633,18527},
323
{ 40, -91, 198, -121, 231, 611, 314,18078},
324
{ 38, -84, 178, -81, 153, 722, 22,17599},
325
{ 36, -76, 157, -43, 80, 824, -241,17092},
326
{ 34, -68, 135, -3, 8, 919, -476,16558},
327
{ 32, -61, 115, 34, -60, 1006, -683,16001},
328
{ 29, -52, 94, 70, -123, 1083, -862,15422},
329
{ 27, -44, 73, 106, -184, 1152,-1015,14824},
330
{ 25, -36, 53, 139, -239, 1211,-1142,14210},
331
{ 22, -27, 34, 170, -290, 1261,-1244,13582},
332
{ 20, -20, 16, 199, -335, 1301,-1322,12942},
333
{ 18, -12, -3, 226, -375, 1331,-1376,12293},
334
{ 15, -4, -19, 250, -410, 1351,-1408,11638},
335
{ 13, 3, -35, 272, -439, 1361,-1419,10979},
336
{ 11, 9, -49, 292, -464, 1362,-1410,10319},
337
{ 9, 16, -63, 309, -483, 1354,-1383, 9660},
338
{ 7, 22, -75, 322, -496, 1337,-1339, 9005},
339
{ 6, 26, -85, 333, -504, 1312,-1280, 8355},
340
{ 4, 31, -94, 341, -507, 1278,-1205, 7713},
341
{ 3, 35, -102, 347, -506, 1238,-1119, 7082},
342
{ 1, 40, -110, 350, -499, 1190,-1021, 6464},
343
{ 0, 43, -115, 350, -488, 1136, -914, 5861}
344
};
345
346
/* Shifting by pre_shift allows calculation using unsigned int rather than
347
possibly-wider fixed_t. On 32-bit platforms, this is likely more efficient.
348
And by having pre_shift 32, a 32-bit platform can easily do the shift by
349
simply ignoring the low half. */
350
351
void blip_add_delta( blip_t* m, unsigned time, int delta )
352
{
353
unsigned fixed = (unsigned) ((time * m->factor + m->offset) >> pre_shift);
354
buf_t* out = SAMPLES( m ) + (fixed >> frac_bits);
355
356
int const phase_shift = frac_bits - phase_bits;
357
int phase = fixed >> phase_shift & (phase_count - 1);
358
short const* in = bl_step [phase];
359
short const* rev = bl_step [phase_count - phase];
360
361
int interp = fixed >> (phase_shift - delta_bits) & (delta_unit - 1);
362
int delta2 = (delta * interp) >> delta_bits;
363
delta -= delta2;
364
365
#ifdef BLIP_ASSERT
366
/* Fails if buffer size was exceeded */
367
assert( out <= &SAMPLES( m ) [m->size + end_frame_extra] );
368
#endif
369
370
out [0] += in[0]*delta + in[half_width+0]*delta2;
371
out [1] += in[1]*delta + in[half_width+1]*delta2;
372
out [2] += in[2]*delta + in[half_width+2]*delta2;
373
out [3] += in[3]*delta + in[half_width+3]*delta2;
374
out [4] += in[4]*delta + in[half_width+4]*delta2;
375
out [5] += in[5]*delta + in[half_width+5]*delta2;
376
out [6] += in[6]*delta + in[half_width+6]*delta2;
377
out [7] += in[7]*delta + in[half_width+7]*delta2;
378
379
in = rev;
380
out [ 8] += in[7]*delta + in[7-half_width]*delta2;
381
out [ 9] += in[6]*delta + in[6-half_width]*delta2;
382
out [10] += in[5]*delta + in[5-half_width]*delta2;
383
out [11] += in[4]*delta + in[4-half_width]*delta2;
384
out [12] += in[3]*delta + in[3-half_width]*delta2;
385
out [13] += in[2]*delta + in[2-half_width]*delta2;
386
out [14] += in[1]*delta + in[1-half_width]*delta2;
387
out [15] += in[0]*delta + in[0-half_width]*delta2;
388
}
389
390
void blip_add_delta_fast( blip_t* m, unsigned time, int delta )
391
{
392
unsigned fixed = (unsigned) ((time * m->factor + m->offset) >> pre_shift);
393
buf_t* out = SAMPLES( m ) + (fixed >> frac_bits);
394
395
int interp = fixed >> (frac_bits - delta_bits) & (delta_unit - 1);
396
int delta2 = delta * interp;
397
398
#ifdef BLIP_ASSERT
399
/* Fails if buffer size was exceeded */
400
assert( out <= &SAMPLES( m ) [m->size + end_frame_extra] );
401
#endif
402
403
out [7] += delta * delta_unit - delta2;
404
out [8] += delta2;
405
}
406
407