cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

Blip_Buffer.h (18126B)


      1// Band-limited sound synthesis buffer
      2
      3// Blip_Buffer 0.4.1
      4#ifndef BLIP_BUFFER_H
      5#define BLIP_BUFFER_H
      6
      7	// internal
      8	#include <limits.h>
      9	#if INT_MAX < 0x7FFFFFFF || LONG_MAX == 0x7FFFFFFF
     10		typedef long blip_long;
     11		typedef unsigned long blip_ulong;
     12	#else
     13		typedef int blip_long;
     14		typedef unsigned blip_ulong;
     15	#endif
     16
     17// Time unit at source clock rate
     18typedef blip_long blip_time_t;
     19
     20// Output samples are 16-bit signed, with a range of -32768 to 32767
     21typedef short blip_sample_t;
     22enum { blip_sample_max = 32767 };
     23
     24struct blip_buffer_state_t;
     25
     26class Blip_Buffer {
     27public:
     28	typedef const char* blargg_err_t;
     29
     30	// Sets output sample rate and buffer length in milliseconds (1/1000 sec, defaults
     31	// to 1/4 second) and clears buffer. If there isn't enough memory, leaves buffer
     32	// untouched and returns "Out of memory", otherwise returns NULL.
     33	blargg_err_t set_sample_rate( long samples_per_sec, int msec_length = 1000 / 4 );
     34
     35	// Sets number of source time units per second
     36	void clock_rate( long clocks_per_sec );
     37
     38	// Ends current time frame of specified duration and makes its samples available
     39	// (along with any still-unread samples) for reading with read_samples(). Begins
     40	// a new time frame at the end of the current frame.
     41	void end_frame( blip_time_t time );
     42
     43	// Reads at most 'max_samples' out of buffer into 'dest', removing them from
     44	// the buffer. Returns number of samples actually read and removed. If stereo is
     45	// true, increments 'dest' one extra time after writing each sample, to allow
     46	// easy interleving of two channels into a stereo output buffer.
     47	long read_samples( blip_sample_t* dest, long max_samples, int stereo = 0 );
     48
     49// Additional features
     50
     51	// Removes all available samples and clear buffer to silence. If 'entire_buffer' is
     52	// false, just clears out any samples waiting rather than the entire buffer.
     53	void clear( int entire_buffer = 1 );
     54
     55	// Number of samples available for reading with read_samples()
     56	long samples_avail() const;
     57
     58	// Removes 'count' samples from those waiting to be read
     59	void remove_samples( long count );
     60
     61	// Sets frequency high-pass filter frequency, where higher values reduce bass more
     62	void bass_freq( int frequency );
     63
     64	// Current output sample rate
     65	long sample_rate() const;
     66
     67	// Length of buffer in milliseconds
     68	int length() const;
     69
     70	// Number of source time units per second
     71	long clock_rate() const;
     72
     73// Experimental features
     74
     75	// Saves state, including high-pass filter and tails of last deltas.
     76	// All samples must have been read from buffer before calling this.
     77	void save_state( blip_buffer_state_t* out );
     78
     79	// Loads state. State must have been saved from Blip_Buffer with same
     80	// settings during same run of program. States can NOT be stored on disk.
     81	// Clears buffer before loading state.
     82	void load_state( blip_buffer_state_t const& in );
     83
     84	// Number of samples delay from synthesis to samples read out
     85	int output_latency() const;
     86
     87	// Counts number of clocks needed until 'count' samples will be available.
     88	// If buffer can't even hold 'count' samples, returns number of clocks until
     89	// buffer becomes full.
     90	blip_time_t count_clocks( long count ) const;
     91
     92	// Number of raw samples that can be mixed within frame of specified duration.
     93	long count_samples( blip_time_t duration ) const;
     94
     95	// Mixes in 'count' samples from 'buf_in'
     96	void mix_samples( blip_sample_t const* buf_in, long count );
     97
     98
     99	// Signals that sound has been added to buffer. Could be done automatically in
    100	// Blip_Synth, but that would affect performance more, as you can arrange that
    101	// this is called only once per time frame rather than for every delta.
    102	void set_modified() { modified_ = this; }
    103
    104	// not documented yet
    105	blip_ulong unsettled() const;
    106	Blip_Buffer* clear_modified() { Blip_Buffer* b = modified_; modified_ = 0; return b; }
    107	void remove_silence( long count );
    108	typedef blip_ulong blip_resampled_time_t;
    109	blip_resampled_time_t resampled_duration( int t ) const     { return t * factor_; }
    110	blip_resampled_time_t resampled_time( blip_time_t t ) const { return t * factor_ + offset_; }
    111	blip_resampled_time_t clock_rate_factor( long clock_rate ) const;
    112public:
    113	Blip_Buffer();
    114	~Blip_Buffer();
    115
    116	// Deprecated
    117	typedef blip_resampled_time_t resampled_time_t;
    118	blargg_err_t sample_rate( long r ) { return set_sample_rate( r ); }
    119	blargg_err_t sample_rate( long r, int msec ) { return set_sample_rate( r, msec ); }
    120private:
    121	// noncopyable
    122	Blip_Buffer( const Blip_Buffer& );
    123	Blip_Buffer& operator = ( const Blip_Buffer& );
    124public:
    125	typedef blip_long buf_t_;
    126	blip_ulong factor_;
    127	blip_resampled_time_t offset_;
    128	buf_t_* buffer_;
    129	blip_long buffer_size_;
    130	blip_long reader_accum_;
    131	int bass_shift_;
    132private:
    133	long sample_rate_;
    134	long clock_rate_;
    135	int bass_freq_;
    136	int length_;
    137	Blip_Buffer* modified_; // non-zero = true (more optimal than using bool, heh)
    138	friend class Blip_Reader;
    139};
    140
    141#ifdef HAVE_CONFIG_H
    142	#include "config.h"
    143#endif
    144
    145// Number of bits in resample ratio fraction. Higher values give a more accurate ratio
    146// but reduce maximum buffer size.
    147#ifndef BLIP_BUFFER_ACCURACY
    148	#define BLIP_BUFFER_ACCURACY 16
    149#endif
    150
    151// Number bits in phase offset. Fewer than 6 bits (64 phase offsets) results in
    152// noticeable broadband noise when synthesizing high frequency square waves.
    153// Affects size of Blip_Synth objects since they store the waveform directly.
    154#ifndef BLIP_PHASE_BITS
    155	#if BLIP_BUFFER_FAST
    156		#define BLIP_PHASE_BITS 8
    157	#else
    158		#define BLIP_PHASE_BITS 6
    159	#endif
    160#endif
    161
    162	// Internal
    163	typedef blip_ulong blip_resampled_time_t;
    164	int const blip_widest_impulse_ = 16;
    165	int const blip_buffer_extra_ = blip_widest_impulse_ + 2;
    166	int const blip_res = 1 << BLIP_PHASE_BITS;
    167	class blip_eq_t;
    168
    169	class Blip_Synth_Fast_ {
    170	public:
    171		Blip_Buffer* buf;
    172		int last_amp;
    173		int delta_factor;
    174
    175		void volume_unit( double );
    176		Blip_Synth_Fast_();
    177		void treble_eq( blip_eq_t const& ) { }
    178	};
    179
    180	class Blip_Synth_ {
    181	public:
    182		Blip_Buffer* buf;
    183		int last_amp;
    184		int delta_factor;
    185
    186		void volume_unit( double );
    187		Blip_Synth_( short* impulses, int width );
    188		void treble_eq( blip_eq_t const& );
    189	private:
    190		double volume_unit_;
    191		short* const impulses;
    192		int const width;
    193		blip_long kernel_unit;
    194		int impulses_size() const { return blip_res / 2 * width + 1; }
    195		void adjust_impulse();
    196	};
    197
    198// Quality level, better = slower. In general, use blip_good_quality.
    199const int blip_med_quality  = 8;
    200const int blip_good_quality = 12;
    201const int blip_high_quality = 16;
    202
    203// Range specifies the greatest expected change in amplitude. Calculate it
    204// by finding the difference between the maximum and minimum expected
    205// amplitudes (max - min).
    206template<int quality,int range>
    207class Blip_Synth {
    208public:
    209	// Sets overall volume of waveform
    210	void volume( double v ) { impl.volume_unit( v * (1.0 / (range < 0 ? -range : range)) ); }
    211
    212	// Configures low-pass filter (see blip_buffer.txt)
    213	void treble_eq( blip_eq_t const& eq )       { impl.treble_eq( eq ); }
    214
    215	// Gets/sets Blip_Buffer used for output
    216	Blip_Buffer* output() const                 { return impl.buf; }
    217	void output( Blip_Buffer* b )               { impl.buf = b; impl.last_amp = 0; }
    218
    219	// Updates amplitude of waveform at given time. Using this requires a separate
    220	// Blip_Synth for each waveform.
    221	void update( blip_time_t time, int amplitude );
    222
    223// Low-level interface
    224
    225	// Adds an amplitude transition of specified delta, optionally into specified buffer
    226	// rather than the one set with output(). Delta can be positive or negative.
    227	// The actual change in amplitude is delta * (volume / range)
    228	void offset( blip_time_t, int delta, Blip_Buffer* ) const;
    229	void offset( blip_time_t t, int delta ) const { offset( t, delta, impl.buf ); }
    230
    231	// Works directly in terms of fractional output samples. Contact author for more info.
    232	void offset_resampled( blip_resampled_time_t, int delta, Blip_Buffer* ) const;
    233
    234	// Same as offset(), except code is inlined for higher performance
    235	void offset_inline( blip_time_t t, int delta, Blip_Buffer* buf ) const {
    236		offset_resampled( t * buf->factor_ + buf->offset_, delta, buf );
    237	}
    238	void offset_inline( blip_time_t t, int delta ) const {
    239		offset_resampled( t * impl.buf->factor_ + impl.buf->offset_, delta, impl.buf );
    240	}
    241
    242private:
    243#if BLIP_BUFFER_FAST
    244	Blip_Synth_Fast_ impl;
    245#else
    246	Blip_Synth_ impl;
    247	typedef short imp_t;
    248	imp_t impulses [blip_res * (quality / 2) + 1];
    249public:
    250	Blip_Synth() : impl( impulses, quality ) { }
    251#endif
    252};
    253
    254// Low-pass equalization parameters
    255class blip_eq_t {
    256public:
    257	// Logarithmic rolloff to treble dB at half sampling rate. Negative values reduce
    258	// treble, small positive values (0 to 5.0) increase treble.
    259	blip_eq_t( double treble_db = 0 );
    260
    261	// See blip_buffer.txt
    262	blip_eq_t( double treble, long rolloff_freq, long sample_rate, long cutoff_freq = 0 );
    263
    264private:
    265	double treble;
    266	long rolloff_freq;
    267	long sample_rate;
    268	long cutoff_freq;
    269	void generate( float* out, int count ) const;
    270	friend class Blip_Synth_;
    271};
    272
    273int const blip_sample_bits = 30;
    274
    275// Dummy Blip_Buffer to direct sound output to, for easy muting without
    276// having to stop sound code.
    277class Silent_Blip_Buffer : public Blip_Buffer {
    278	buf_t_ buf [blip_buffer_extra_ + 1];
    279public:
    280	// The following cannot be used (an assertion will fail if attempted):
    281	blargg_err_t set_sample_rate( long samples_per_sec, int msec_length );
    282	blip_time_t count_clocks( long count ) const;
    283	void mix_samples( blip_sample_t const* buf, long count );
    284
    285	Silent_Blip_Buffer();
    286};
    287
    288	#if __GNUC__ >= 3 || _MSC_VER >= 1100
    289		#define BLIP_RESTRICT __restrict
    290	#else
    291		#define BLIP_RESTRICT
    292	#endif
    293
    294// Optimized reading from Blip_Buffer, for use in custom sample output
    295
    296// Begins reading from buffer. Name should be unique to the current block.
    297#define BLIP_READER_BEGIN( name, blip_buffer ) \
    298	const Blip_Buffer::buf_t_* BLIP_RESTRICT name##_reader_buf = (blip_buffer).buffer_;\
    299	blip_long name##_reader_accum = (blip_buffer).reader_accum_
    300
    301// Gets value to pass to BLIP_READER_NEXT()
    302#define BLIP_READER_BASS( blip_buffer ) ((blip_buffer).bass_shift_)
    303
    304// Constant value to use instead of BLIP_READER_BASS(), for slightly more optimal
    305// code at the cost of having no bass control
    306int const blip_reader_default_bass = 9;
    307
    308// Current sample
    309#define BLIP_READER_READ( name )        (name##_reader_accum >> (blip_sample_bits - 16))
    310
    311// Current raw sample in full internal resolution
    312#define BLIP_READER_READ_RAW( name )    (name##_reader_accum)
    313
    314// Advances to next sample
    315#define BLIP_READER_NEXT( name, bass ) \
    316	(void) (name##_reader_accum += *name##_reader_buf++ - (name##_reader_accum >> (bass)))
    317
    318// Ends reading samples from buffer. The number of samples read must now be removed
    319// using Blip_Buffer::remove_samples().
    320#define BLIP_READER_END( name, blip_buffer ) \
    321	(void) ((blip_buffer).reader_accum_ = name##_reader_accum)
    322
    323
    324// experimental
    325#define BLIP_READER_ADJ_( name, offset ) (name##_reader_buf += offset)
    326
    327blip_long const blip_reader_idx_factor = sizeof (Blip_Buffer::buf_t_);
    328
    329#define BLIP_READER_NEXT_IDX_( name, bass, idx ) {\
    330	name##_reader_accum -= name##_reader_accum >> (bass);\
    331	name##_reader_accum += name##_reader_buf [(idx)];\
    332}
    333
    334#define BLIP_READER_NEXT_RAW_IDX_( name, bass, idx ) {\
    335	name##_reader_accum -= name##_reader_accum >> (bass);\
    336	name##_reader_accum +=\
    337			*(Blip_Buffer::buf_t_ const*) ((char const*) name##_reader_buf + (idx));\
    338}
    339
    340// Compatibility with older version
    341const long blip_unscaled = 65535;
    342const int blip_low_quality  = blip_med_quality;
    343const int blip_best_quality = blip_high_quality;
    344
    345// Deprecated; use BLIP_READER macros as follows:
    346// Blip_Reader r; r.begin( buf ); -> BLIP_READER_BEGIN( r, buf );
    347// int bass = r.begin( buf )      -> BLIP_READER_BEGIN( r, buf ); int bass = BLIP_READER_BASS( buf );
    348// r.read()                       -> BLIP_READER_READ( r )
    349// r.read_raw()                   -> BLIP_READER_READ_RAW( r )
    350// r.next( bass )                 -> BLIP_READER_NEXT( r, bass )
    351// r.next()                       -> BLIP_READER_NEXT( r, blip_reader_default_bass )
    352// r.end( buf )                   -> BLIP_READER_END( r, buf )
    353class Blip_Reader {
    354public:
    355	int begin( Blip_Buffer& );
    356	blip_long read() const          { return accum >> (blip_sample_bits - 16); }
    357	blip_long read_raw() const      { return accum; }
    358	void next( int bass_shift = 9 ) { accum += *buf++ - (accum >> bass_shift); }
    359	void end( Blip_Buffer& b )      { b.reader_accum_ = accum; }
    360private:
    361	const Blip_Buffer::buf_t_* buf;
    362	blip_long accum;
    363};
    364
    365#if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \
    366		defined (__x86_64__) || defined (__ia64__) || defined (__i386__)
    367	#define BLIP_CLAMP_( in ) in < -0x8000 || 0x7FFF < in
    368#else
    369	#define BLIP_CLAMP_( in ) (blip_sample_t) in != in
    370#endif
    371
    372// Clamp sample to blip_sample_t range
    373#define BLIP_CLAMP( sample, out )\
    374	{ if ( BLIP_CLAMP_( (sample) ) ) (out) = ((sample) >> 24) ^ 0x7FFF; }
    375
    376struct blip_buffer_state_t
    377{
    378	blip_resampled_time_t offset_;
    379	blip_long reader_accum_;
    380	blip_long buf [blip_buffer_extra_];
    381};
    382
    383// End of public interface
    384
    385#ifndef assert
    386	#include <assert.h>
    387#endif
    388
    389template<int quality,int range>
    390inline void Blip_Synth<quality,range>::offset_resampled( blip_resampled_time_t time,
    391		int delta, Blip_Buffer* blip_buf ) const
    392{
    393	// If this assertion fails, it means that an attempt was made to add a delta
    394	// at a negative time or past the end of the buffer.
    395	assert( (blip_long) (time >> BLIP_BUFFER_ACCURACY) < blip_buf->buffer_size_ );
    396
    397	delta *= impl.delta_factor;
    398	blip_long* BLIP_RESTRICT buf = blip_buf->buffer_ + (time >> BLIP_BUFFER_ACCURACY);
    399	int phase = (int) (time >> (BLIP_BUFFER_ACCURACY - BLIP_PHASE_BITS) & (blip_res - 1));
    400
    401#if BLIP_BUFFER_FAST
    402	blip_long left = buf [0] + delta;
    403
    404	// Kind of crappy, but doing shift after multiply results in overflow.
    405	// Alternate way of delaying multiply by delta_factor results in worse
    406	// sub-sample resolution.
    407	blip_long right = (delta >> BLIP_PHASE_BITS) * phase;
    408	left  -= right;
    409	right += buf [1];
    410
    411	buf [0] = left;
    412	buf [1] = right;
    413#else
    414
    415	int const fwd = (blip_widest_impulse_ - quality) / 2;
    416	int const rev = fwd + quality - 2;
    417	int const mid = quality / 2 - 1;
    418
    419	imp_t const* BLIP_RESTRICT imp = impulses + blip_res - phase;
    420
    421	#if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \
    422			defined (__x86_64__) || defined (__ia64__) || defined (__i386__)
    423
    424	// this straight forward version gave in better code on GCC for x86
    425
    426	#define ADD_IMP( out, in ) \
    427		buf [out] += (blip_long) imp [blip_res * (in)] * delta
    428
    429	#define BLIP_FWD( i ) {\
    430		ADD_IMP( fwd     + i, i     );\
    431		ADD_IMP( fwd + 1 + i, i + 1 );\
    432	}
    433	#define BLIP_REV( r ) {\
    434		ADD_IMP( rev     - r, r + 1 );\
    435		ADD_IMP( rev + 1 - r, r     );\
    436	}
    437
    438		BLIP_FWD( 0 )
    439		if ( quality > 8  ) BLIP_FWD( 2 )
    440		if ( quality > 12 ) BLIP_FWD( 4 )
    441		{
    442			ADD_IMP( fwd + mid - 1, mid - 1 );
    443			ADD_IMP( fwd + mid    , mid     );
    444			imp = impulses + phase;
    445		}
    446		if ( quality > 12 ) BLIP_REV( 6 )
    447		if ( quality > 8  ) BLIP_REV( 4 )
    448		BLIP_REV( 2 )
    449
    450		ADD_IMP( rev    , 1 );
    451		ADD_IMP( rev + 1, 0 );
    452
    453	#undef ADD_IMP
    454
    455	#else
    456
    457	// for RISC processors, help compiler by reading ahead of writes
    458
    459	#define BLIP_FWD( i ) {\
    460		blip_long t0 =                       i0 * delta + buf [fwd     + i];\
    461		blip_long t1 = imp [blip_res * (i + 1)] * delta + buf [fwd + 1 + i];\
    462		i0 =           imp [blip_res * (i + 2)];\
    463		buf [fwd     + i] = t0;\
    464		buf [fwd + 1 + i] = t1;\
    465	}
    466	#define BLIP_REV( r ) {\
    467		blip_long t0 =                 i0 * delta + buf [rev     - r];\
    468		blip_long t1 = imp [blip_res * r] * delta + buf [rev + 1 - r];\
    469		i0 =           imp [blip_res * (r - 1)];\
    470		buf [rev     - r] = t0;\
    471		buf [rev + 1 - r] = t1;\
    472	}
    473
    474		blip_long i0 = *imp;
    475		BLIP_FWD( 0 )
    476		if ( quality > 8  ) BLIP_FWD( 2 )
    477		if ( quality > 12 ) BLIP_FWD( 4 )
    478		{
    479			blip_long t0 =                   i0 * delta + buf [fwd + mid - 1];
    480			blip_long t1 = imp [blip_res * mid] * delta + buf [fwd + mid    ];
    481			imp = impulses + phase;
    482			i0 = imp [blip_res * mid];
    483			buf [fwd + mid - 1] = t0;
    484			buf [fwd + mid    ] = t1;
    485		}
    486		if ( quality > 12 ) BLIP_REV( 6 )
    487		if ( quality > 8  ) BLIP_REV( 4 )
    488		BLIP_REV( 2 )
    489
    490		blip_long t0 =   i0 * delta + buf [rev    ];
    491		blip_long t1 = *imp * delta + buf [rev + 1];
    492		buf [rev    ] = t0;
    493		buf [rev + 1] = t1;
    494	#endif
    495
    496#endif
    497}
    498
    499#undef BLIP_FWD
    500#undef BLIP_REV
    501
    502template<int quality,int range>
    503#if BLIP_BUFFER_FAST
    504	inline
    505#endif
    506void Blip_Synth<quality,range>::offset( blip_time_t t, int delta, Blip_Buffer* buf ) const
    507{
    508	offset_resampled( t * buf->factor_ + buf->offset_, delta, buf );
    509}
    510
    511template<int quality,int range>
    512#if BLIP_BUFFER_FAST
    513	inline
    514#endif
    515void Blip_Synth<quality,range>::update( blip_time_t t, int amp )
    516{
    517	int delta = amp - impl.last_amp;
    518	impl.last_amp = amp;
    519	offset_resampled( t * impl.buf->factor_ + impl.buf->offset_, delta, impl.buf );
    520}
    521
    522inline blip_eq_t::blip_eq_t( double t ) :
    523		treble( t ), rolloff_freq( 0 ), sample_rate( 44100 ), cutoff_freq( 0 ) { }
    524inline blip_eq_t::blip_eq_t( double t, long rf, long sr, long cf ) :
    525		treble( t ), rolloff_freq( rf ), sample_rate( sr ), cutoff_freq( cf ) { }
    526
    527inline int  Blip_Buffer::length() const         { return length_; }
    528inline long Blip_Buffer::samples_avail() const  { return (long) (offset_ >> BLIP_BUFFER_ACCURACY); }
    529inline long Blip_Buffer::sample_rate() const    { return sample_rate_; }
    530inline int  Blip_Buffer::output_latency() const { return blip_widest_impulse_ / 2; }
    531inline long Blip_Buffer::clock_rate() const     { return clock_rate_; }
    532inline void Blip_Buffer::clock_rate( long cps ) { factor_ = clock_rate_factor( clock_rate_ = cps ); }
    533
    534inline int Blip_Reader::begin( Blip_Buffer& blip_buf )
    535{
    536	buf   = blip_buf.buffer_;
    537	accum = blip_buf.reader_accum_;
    538	return blip_buf.bass_shift_;
    539}
    540
    541inline void Blip_Buffer::remove_silence( long count )
    542{
    543	// fails if you try to remove more samples than available
    544	assert( count <= samples_avail() );
    545	offset_ -= (blip_resampled_time_t) count << BLIP_BUFFER_ACCURACY;
    546}
    547
    548inline blip_ulong Blip_Buffer::unsettled() const
    549{
    550	return reader_accum_ >> (blip_sample_bits - 16);
    551}
    552
    553int const blip_max_length = 0;
    554int const blip_default_length = 250; // 1/4 second
    555
    556#endif