summaryrefslogtreecommitdiff
path: root/plugins/gme/game-music-emu-0.5.5/gme/Blip_Buffer.h
blob: 4cc526d2f1c2d92f0587745291eb26985cc3b702 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
// Band-limited sound synthesis buffer

// Blip_Buffer 0.4.1
#ifndef BLIP_BUFFER_H
#define BLIP_BUFFER_H

	// internal
	#include <limits.h>
	#if INT_MAX < 0x7FFFFFFF
		#error "int must be at least 32 bits"
	#endif
	
	typedef int blip_long;
	typedef unsigned blip_ulong;

// Time unit at source clock rate
typedef blip_long blip_time_t;

// Output samples are 16-bit signed, with a range of -32768 to 32767
typedef short blip_sample_t;
enum { blip_sample_max = 32767 };

class Blip_Buffer {
public:
	typedef const char* blargg_err_t;
	
	// Set output sample rate and buffer length in milliseconds (1/1000 sec, defaults
	// to 1/4 second), then clear buffer. Returns NULL on success, otherwise if there
	// isn't enough memory, returns error without affecting current buffer setup.
	blargg_err_t set_sample_rate( long samples_per_sec, int msec_length = 1000 / 4 );
	
	// Set number of source time units per second
	void clock_rate( long );
	
	// End current time frame of specified duration and make its samples available
	// (along with any still-unread samples) for reading with read_samples(). Begins
	// a new time frame at the end of the current frame.
	void end_frame( blip_time_t time );
	
	// Read at most 'max_samples' out of buffer into 'dest', removing them from from
	// the buffer. Returns number of samples actually read and removed. If stereo is
	// true, increments 'dest' one extra time after writing each sample, to allow
	// easy interleving of two channels into a stereo output buffer.
	long read_samples( blip_sample_t* dest, long max_samples, int stereo = 0 );
	
// Additional optional features

	// Current output sample rate
	long sample_rate() const;
	
	// Length of buffer, in milliseconds
	int length() const;
	
	// Number of source time units per second
	long clock_rate() const;
	
	// Set frequency high-pass filter frequency, where higher values reduce bass more
	void bass_freq( int frequency );
	
	// Number of samples delay from synthesis to samples read out
	int output_latency() const;
	
	// Remove all available samples and clear buffer to silence. If 'entire_buffer' is
	// false, just clears out any samples waiting rather than the entire buffer.
	void clear( int entire_buffer = 1 );
	
	// Number of samples available for reading with read_samples()
	long samples_avail() const;
	
	// Remove 'count' samples from those waiting to be read
	void remove_samples( long count );
	
// Experimental features
	
	// Count number of clocks needed until 'count' samples will be available.
	// If buffer can't even hold 'count' samples, returns number of clocks until
	// buffer becomes full.
	blip_time_t count_clocks( long count ) const;
	
	// Number of raw samples that can be mixed within frame of specified duration.
	long count_samples( blip_time_t duration ) const;
	
	// Mix 'count' samples from 'buf' into buffer.
	void mix_samples( blip_sample_t const* buf, long count );
	
	// not documented yet
	void set_modified() { modified_ = 1; }
	int clear_modified() { int b = modified_; modified_ = 0; return b; }
	typedef blip_ulong blip_resampled_time_t;
	void remove_silence( long count );
	blip_resampled_time_t resampled_duration( int t ) const     { return t * factor_; }
	blip_resampled_time_t resampled_time( blip_time_t t ) const { return t * factor_ + offset_; }
	blip_resampled_time_t clock_rate_factor( long clock_rate ) const;
public:
	Blip_Buffer();
	~Blip_Buffer();
	
	// Deprecated
	typedef blip_resampled_time_t resampled_time_t;
	blargg_err_t sample_rate( long r ) { return set_sample_rate( r ); }
	blargg_err_t sample_rate( long r, int msec ) { return set_sample_rate( r, msec ); }
private:
	// noncopyable
	Blip_Buffer( const Blip_Buffer& );
	Blip_Buffer& operator = ( const Blip_Buffer& );
public:
	typedef blip_time_t buf_t_;
	blip_ulong factor_;
	blip_resampled_time_t offset_;
	buf_t_* buffer_;
	blip_long buffer_size_;
	blip_long reader_accum_;
	int bass_shift_;
private:
	long sample_rate_;
	long clock_rate_;
	int bass_freq_;
	int length_;
	int modified_;
	friend class Blip_Reader;
};

#ifdef HAVE_CONFIG_H
	#include "config.h"
#endif

// Number of bits in resample ratio fraction. Higher values give a more accurate ratio
// but reduce maximum buffer size.
#ifndef BLIP_BUFFER_ACCURACY
	#define BLIP_BUFFER_ACCURACY 16
#endif

// Number bits in phase offset. Fewer than 6 bits (64 phase offsets) results in
// noticeable broadband noise when synthesizing high frequency square waves.
// Affects size of Blip_Synth objects since they store the waveform directly.
#ifndef BLIP_PHASE_BITS
	#if BLIP_BUFFER_FAST
		#define BLIP_PHASE_BITS 8
	#else
		#define BLIP_PHASE_BITS 6
	#endif
#endif

	// Internal
	typedef blip_ulong blip_resampled_time_t;
	int const blip_widest_impulse_ = 16;
	int const blip_buffer_extra_ = blip_widest_impulse_ + 2;
	int const blip_res = 1 << BLIP_PHASE_BITS;
	class blip_eq_t;
	
	class Blip_Synth_Fast_ {
	public:
		Blip_Buffer* buf;
		int last_amp;
		int delta_factor;
		
		void volume_unit( double );
		Blip_Synth_Fast_();
		void treble_eq( blip_eq_t const& ) { }
	};
	
	class Blip_Synth_ {
	public:
		Blip_Buffer* buf;
		int last_amp;
		int delta_factor;
		
		void volume_unit( double );
		Blip_Synth_( short* impulses, int width );
		void treble_eq( blip_eq_t const& );
	private:
		double volume_unit_;
		short* const impulses;
		int const width;
		blip_long kernel_unit;
		int impulses_size() const { return blip_res / 2 * width + 1; }
		void adjust_impulse();
	};

// Quality level. Start with blip_good_quality.
const int blip_med_quality  = 8;
const int blip_good_quality = 12;
const int blip_high_quality = 16;

// Range specifies the greatest expected change in amplitude. Calculate it
// by finding the difference between the maximum and minimum expected
// amplitudes (max - min).
template<int quality,int range>
class Blip_Synth {
public:
	// Set overall volume of waveform
	void volume( double v ) { impl.volume_unit( v * (1.0 / (range < 0 ? -range : range)) ); }
	
	// Configure low-pass filter (see blip_buffer.txt)
	void treble_eq( blip_eq_t const& eq )       { impl.treble_eq( eq ); }
	
	// Get/set Blip_Buffer used for output
	Blip_Buffer* output() const                 { return impl.buf; }
	void output( Blip_Buffer* b )               { impl.buf = b; impl.last_amp = 0; }
	
	// Update amplitude of waveform at given time. Using this requires a separate
	// Blip_Synth for each waveform.
	void update( blip_time_t time, int amplitude );

// Low-level interface

	// Add an amplitude transition of specified delta, optionally into specified buffer
	// rather than the one set with output(). Delta can be positive or negative.
	// The actual change in amplitude is delta * (volume / range)
	void offset( blip_time_t, int delta, Blip_Buffer* ) const;
	void offset( blip_time_t t, int delta ) const { offset( t, delta, impl.buf ); }
	
	// Works directly in terms of fractional output samples. Contact author for more info.
	void offset_resampled( blip_resampled_time_t, int delta, Blip_Buffer* ) const;
	
	// Same as offset(), except code is inlined for higher performance
	void offset_inline( blip_time_t t, int delta, Blip_Buffer* buf ) const {
		offset_resampled( t * buf->factor_ + buf->offset_, delta, buf );
	}
	void offset_inline( blip_time_t t, int delta ) const {
		offset_resampled( t * impl.buf->factor_ + impl.buf->offset_, delta, impl.buf );
	}
	
private:
#if BLIP_BUFFER_FAST
	Blip_Synth_Fast_ impl;
#else
	Blip_Synth_ impl;
	typedef short imp_t;
	imp_t impulses [blip_res * (quality / 2) + 1];
public:
	Blip_Synth() : impl( impulses, quality ) { }
#endif
};

// Low-pass equalization parameters
class blip_eq_t {
public:
	// Logarithmic rolloff to treble dB at half sampling rate. Negative values reduce
	// treble, small positive values (0 to 5.0) increase treble.
	blip_eq_t( double treble_db = 0 );
	
	// See blip_buffer.txt
	blip_eq_t( double treble, long rolloff_freq, long sample_rate, long cutoff_freq = 0 );
	
private:
	double treble;
	long rolloff_freq;
	long sample_rate;
	long cutoff_freq;
	void generate( float* out, int count ) const;
	friend class Blip_Synth_;
};

int const blip_sample_bits = 30;

// Dummy Blip_Buffer to direct sound output to, for easy muting without
// having to stop sound code.
class Silent_Blip_Buffer : public Blip_Buffer {
	buf_t_ buf [blip_buffer_extra_ + 1];
public:
	// The following cannot be used (an assertion will fail if attempted):
	blargg_err_t set_sample_rate( long samples_per_sec, int msec_length );
	blip_time_t count_clocks( long count ) const;
	void mix_samples( blip_sample_t const* buf, long count );
	
	Silent_Blip_Buffer();
};

	#if defined (__GNUC__) || _MSC_VER >= 1100
		#define BLIP_RESTRICT __restrict
	#else
		#define BLIP_RESTRICT
	#endif

// Optimized reading from Blip_Buffer, for use in custom sample output

// Begin reading from buffer. Name should be unique to the current block.
#define BLIP_READER_BEGIN( name, blip_buffer ) \
	const Blip_Buffer::buf_t_* BLIP_RESTRICT name##_reader_buf = (blip_buffer).buffer_;\
	blip_long name##_reader_accum = (blip_buffer).reader_accum_

// Get value to pass to BLIP_READER_NEXT()
#define BLIP_READER_BASS( blip_buffer ) ((blip_buffer).bass_shift_)

// Constant value to use instead of BLIP_READER_BASS(), for slightly more optimal
// code at the cost of having no bass control
int const blip_reader_default_bass = 9;

// Current sample
#define BLIP_READER_READ( name )        (name##_reader_accum >> (blip_sample_bits - 16))

// Current raw sample in full internal resolution
#define BLIP_READER_READ_RAW( name )    (name##_reader_accum)

// Advance to next sample
#define BLIP_READER_NEXT( name, bass ) \
	(void) (name##_reader_accum += *name##_reader_buf++ - (name##_reader_accum >> (bass)))

// End reading samples from buffer. The number of samples read must now be removed
// using Blip_Buffer::remove_samples().
#define BLIP_READER_END( name, blip_buffer ) \
	(void) ((blip_buffer).reader_accum_ = name##_reader_accum)


// Compatibility with older version
const long blip_unscaled = 65535;
const int blip_low_quality  = blip_med_quality;
const int blip_best_quality = blip_high_quality;

// Deprecated; use BLIP_READER macros as follows:
// Blip_Reader r; r.begin( buf ); -> BLIP_READER_BEGIN( r, buf );
// int bass = r.begin( buf )      -> BLIP_READER_BEGIN( r, buf ); int bass = BLIP_READER_BASS( buf );
// r.read()                       -> BLIP_READER_READ( r )
// r.read_raw()                   -> BLIP_READER_READ_RAW( r )
// r.next( bass )                 -> BLIP_READER_NEXT( r, bass )
// r.next()                       -> BLIP_READER_NEXT( r, blip_reader_default_bass )
// r.end( buf )                   -> BLIP_READER_END( r, buf )
class Blip_Reader {
public:
	int begin( Blip_Buffer& );
	blip_long read() const          { return accum >> (blip_sample_bits - 16); }
	blip_long read_raw() const      { return accum; }
	void next( int bass_shift = 9 )         { accum += *buf++ - (accum >> bass_shift); }
	void end( Blip_Buffer& b )              { b.reader_accum_ = accum; }
	
private:
	const Blip_Buffer::buf_t_* buf;
	blip_long accum;
};

// End of public interface

#include <assert.h>

template<int quality,int range>
inline void Blip_Synth<quality,range>::offset_resampled( blip_resampled_time_t time,
		int delta, Blip_Buffer* blip_buf ) const
{
	// Fails if time is beyond end of Blip_Buffer, due to a bug in caller code or the
	// need for a longer buffer as set by set_sample_rate().
	assert( (blip_long) (time >> BLIP_BUFFER_ACCURACY) < blip_buf->buffer_size_ );
	delta *= impl.delta_factor;
	blip_long* BLIP_RESTRICT buf = blip_buf->buffer_ + (time >> BLIP_BUFFER_ACCURACY);
	int phase = (int) (time >> (BLIP_BUFFER_ACCURACY - BLIP_PHASE_BITS) & (blip_res - 1));

#if BLIP_BUFFER_FAST
	blip_long left = buf [0] + delta;
	
	// Kind of crappy, but doing shift after multiply results in overflow.
	// Alternate way of delaying multiply by delta_factor results in worse
	// sub-sample resolution.
	blip_long right = (delta >> BLIP_PHASE_BITS) * phase;
	left  -= right;
	right += buf [1];
	
	buf [0] = left;
	buf [1] = right;
#else

	int const fwd = (blip_widest_impulse_ - quality) / 2;
	int const rev = fwd + quality - 2;
	int const mid = quality / 2 - 1;
	
	imp_t const* BLIP_RESTRICT imp = impulses + blip_res - phase;
	
	#if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \
			defined (__x86_64__) || defined (__ia64__) || defined (__i386__)
	
	// straight forward implementation resulted in better code on GCC for x86
	
	#define ADD_IMP( out, in ) \
		buf [out] += (blip_long) imp [blip_res * (in)] * delta
	
	#define BLIP_FWD( i ) {\
		ADD_IMP( fwd     + i, i     );\
		ADD_IMP( fwd + 1 + i, i + 1 );\
	}
	#define BLIP_REV( r ) {\
		ADD_IMP( rev     - r, r + 1 );\
		ADD_IMP( rev + 1 - r, r     );\
	}

		BLIP_FWD( 0 )
		if ( quality > 8  ) BLIP_FWD( 2 )
		if ( quality > 12 ) BLIP_FWD( 4 )
		{
			ADD_IMP( fwd + mid - 1, mid - 1 );
			ADD_IMP( fwd + mid    , mid     );
			imp = impulses + phase;
		}
		if ( quality > 12 ) BLIP_REV( 6 )
		if ( quality > 8  ) BLIP_REV( 4 )
		BLIP_REV( 2 )
		
		ADD_IMP( rev    , 1 );
		ADD_IMP( rev + 1, 0 );
		
	#else
	
	// for RISC processors, help compiler by reading ahead of writes
	
	#define BLIP_FWD( i ) {\
		blip_long t0 =                       i0 * delta + buf [fwd     + i];\
		blip_long t1 = imp [blip_res * (i + 1)] * delta + buf [fwd + 1 + i];\
		i0 =           imp [blip_res * (i + 2)];\
		buf [fwd     + i] = t0;\
		buf [fwd + 1 + i] = t1;\
	}
	#define BLIP_REV( r ) {\
		blip_long t0 =                 i0 * delta + buf [rev     - r];\
		blip_long t1 = imp [blip_res * r] * delta + buf [rev + 1 - r];\
		i0 =           imp [blip_res * (r - 1)];\
		buf [rev     - r] = t0;\
		buf [rev + 1 - r] = t1;\
	}
		
		blip_long i0 = *imp;
		BLIP_FWD( 0 )
		if ( quality > 8  ) BLIP_FWD( 2 )
		if ( quality > 12 ) BLIP_FWD( 4 )
		{
			blip_long t0 =                   i0 * delta + buf [fwd + mid - 1];
			blip_long t1 = imp [blip_res * mid] * delta + buf [fwd + mid    ];
			imp = impulses + phase;
			i0 = imp [blip_res * mid];
			buf [fwd + mid - 1] = t0;
			buf [fwd + mid    ] = t1;
		}
		if ( quality > 12 ) BLIP_REV( 6 )
		if ( quality > 8  ) BLIP_REV( 4 )
		BLIP_REV( 2 )
		
		blip_long t0 =   i0 * delta + buf [rev    ];
		blip_long t1 = *imp * delta + buf [rev + 1];
		buf [rev    ] = t0;
		buf [rev + 1] = t1;
	#endif
	
#endif
}

#undef BLIP_FWD
#undef BLIP_REV

template<int quality,int range>
#if BLIP_BUFFER_FAST
	inline
#endif
void Blip_Synth<quality,range>::offset( blip_time_t t, int delta, Blip_Buffer* buf ) const
{
	offset_resampled( t * buf->factor_ + buf->offset_, delta, buf );
}

template<int quality,int range>
#if BLIP_BUFFER_FAST
	inline
#endif
void Blip_Synth<quality,range>::update( blip_time_t t, int amp )
{
	int delta = amp - impl.last_amp;
	impl.last_amp = amp;
	offset_resampled( t * impl.buf->factor_ + impl.buf->offset_, delta, impl.buf );
}

inline blip_eq_t::blip_eq_t( double t ) :
		treble( t ), rolloff_freq( 0 ), sample_rate( 44100 ), cutoff_freq( 0 ) { }
inline blip_eq_t::blip_eq_t( double t, long rf, long sr, long cf ) :
		treble( t ), rolloff_freq( rf ), sample_rate( sr ), cutoff_freq( cf ) { }

inline int  Blip_Buffer::length() const         { return length_; }
inline long Blip_Buffer::samples_avail() const  { return (long) (offset_ >> BLIP_BUFFER_ACCURACY); }
inline long Blip_Buffer::sample_rate() const    { return sample_rate_; }
inline int  Blip_Buffer::output_latency() const { return blip_widest_impulse_ / 2; }
inline long Blip_Buffer::clock_rate() const     { return clock_rate_; }
inline void Blip_Buffer::clock_rate( long cps ) { factor_ = clock_rate_factor( clock_rate_ = cps ); }

inline int Blip_Reader::begin( Blip_Buffer& blip_buf )
{
	buf = blip_buf.buffer_;
	accum = blip_buf.reader_accum_;
	return blip_buf.bass_shift_;
}

int const blip_max_length = 0;
int const blip_default_length = 250;

#endif