diff Plugins/Input/console/Blip_Buffer.h @ 493:c04dff121e1d trunk

[svn] hostile merge, phase 2: reimport based on new plugin code
author nenolod
date Tue, 24 Jan 2006 20:19:01 -0800
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/console/Blip_Buffer.h	Tue Jan 24 20:19:01 2006 -0800
@@ -0,0 +1,354 @@
+
+// Band-limited sound synthesis and buffering
+
+// Blip_Buffer 0.4.0
+
+#ifndef BLIP_BUFFER_H
+#define BLIP_BUFFER_H
+
+// Time unit at source clock rate
+typedef 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
+	
+	// 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 );
+	
+	// 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;
+	
+	// not documented yet
+	typedef unsigned long 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 long buf_t_;
+	unsigned long factor_;
+	blip_resampled_time_t offset_;
+	buf_t_* buffer_;
+	long buffer_size_;
+private:
+	long reader_accum;
+	int bass_shift;
+	long sample_rate_;
+	long clock_rate_;
+	int bass_freq_;
+	int length_;
+	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
+	#define BLIP_PHASE_BITS 6
+#endif
+
+	// Internal
+	typedef unsigned long blip_resampled_time_t;
+	int const blip_widest_impulse_ = 16;
+	int const blip_res = 1 << BLIP_PHASE_BITS;
+	class blip_eq_t;
+	
+	class Blip_Synth_ {
+		double volume_unit_;
+		short* const impulses;
+		int const width;
+		long kernel_unit;
+		int impulses_size() const { return blip_res / 2 * width + 1; }
+		void adjust_impulse();
+	public:
+		Blip_Buffer* buf;
+		int last_amp;
+		int delta_factor;
+		
+		Blip_Synth_( short* impulses, int width );
+		void treble_eq( blip_eq_t const& );
+		void volume_unit( double );
+	};
+
+// 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 notes.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.
+	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 );
+	}
+	
+public:
+	Blip_Synth() : impl( impulses, quality ) { }
+private:
+	typedef short imp_t;
+	imp_t impulses [blip_res * (quality / 2) + 1];
+	Blip_Synth_ impl;
+};
+
+// 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 notes.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;
+
+// Optimized inline sample reader for custom sample formats and mixing of Blip_Buffer samples
+class Blip_Reader {
+public:
+	// Begin reading samples from buffer. Returns value to pass to next() (can
+	// be ignored if default bass_freq is acceptable).
+	int begin( Blip_Buffer& );
+	
+	// Current sample
+	long read() const               { return accum >> (blip_sample_bits - 16); }
+	
+	// Current raw sample in full internal resolution
+	long read_raw() const           { return accum; }
+	
+	// Advance to next sample
+	void next( int bass_shift = 9 )         { accum += *buf++ - (accum >> bass_shift); }
+	
+	// End reading samples from buffer. The number of samples read must now be removed
+	// using Blip_Buffer::remove_samples().
+	void end( Blip_Buffer& b )              { b.reader_accum = accum; }
+	
+private:
+	const Blip_Buffer::buf_t_* buf;
+	long accum;
+};
+
+
+// End of public interface
+
+
+#include <assert.h>
+
+// 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;
+
+#define BLIP_FWD( i ) {                     \
+	long t0 = i0 * delta + buf [fwd + i];   \
+	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 ) {                     \
+	long t0 = i0 * delta + buf [rev - r];   \
+	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; }
+
+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( (long) (time >> BLIP_BUFFER_ACCURACY) < blip_buf->buffer_size_ );
+	delta *= impl.delta_factor;
+	int phase = (int) (time >> (BLIP_BUFFER_ACCURACY - BLIP_PHASE_BITS) & (blip_res - 1));
+	imp_t const* imp = impulses + blip_res - phase;
+	long* buf = blip_buf->buffer_ + (time >> BLIP_BUFFER_ACCURACY);
+	long i0 = *imp;
+	
+	int const fwd = (blip_widest_impulse_ - quality) / 2;
+	int const rev = fwd + quality - 2;
+	
+	BLIP_FWD( 0 )
+	if ( quality > 8  ) BLIP_FWD( 2 )
+	if ( quality > 12 ) BLIP_FWD( 4 )
+	{
+		int const mid = quality / 2 - 1;
+		long t0 = i0 * delta + buf [fwd + mid - 1];
+		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 )
+	
+	long t0 = i0 * delta + buf [rev];
+	long t1 = *imp * delta + buf [rev + 1];
+	buf [rev] = t0;
+	buf [rev + 1] = t1;
+}
+
+#undef BLIP_FWD
+#undef BLIP_REV
+
+template<int quality,int range>
+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>
+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
+