PageRenderTime 19ms CodeModel.GetById 2ms app.highlight 13ms RepoModel.GetById 2ms app.codeStats 0ms

/gme/Fir_Resampler.h

http://game-music-emu.googlecode.com/
C++ Header | 171 lines | 109 code | 39 blank | 23 comment | 7 complexity | 84a08a6b58c942f85fd77ba0ba4bc2a3 MD5 | raw file
  1// Finite impulse response (FIR) resampler with adjustable FIR size
  2
  3// Game_Music_Emu 0.5.5
  4#ifndef FIR_RESAMPLER_H
  5#define FIR_RESAMPLER_H
  6
  7#include "blargg_common.h"
  8#include <string.h>
  9
 10class Fir_Resampler_ {
 11public:
 12	
 13	// Use Fir_Resampler<width> (below)
 14	
 15	// Set input/output resampling ratio and optionally low-pass rolloff and gain.
 16	// Returns actual ratio used (rounded to internal precision).
 17	double time_ratio( double factor, double rolloff = 0.999, double gain = 1.0 );
 18	
 19	// Current input/output ratio
 20	double ratio() const { return ratio_; }
 21	
 22// Input
 23	
 24	typedef short sample_t;
 25	
 26	// Resize and clear input buffer
 27	blargg_err_t buffer_size( int );
 28	
 29	// Clear input buffer. At least two output samples will be available after
 30	// two input samples are written.
 31	void clear();
 32	
 33	// Number of input samples that can be written
 34	int max_write() const { return buf.end() - write_pos; }
 35	
 36	// Pointer to place to write input samples
 37	sample_t* buffer() { return write_pos; }
 38	
 39	// Notify resampler that 'count' input samples have been written
 40	void write( long count );
 41	
 42	// Number of input samples in buffer
 43	int written() const { return write_pos - &buf [write_offset]; }
 44	
 45	// Skip 'count' input samples. Returns number of samples actually skipped.
 46	int skip_input( long count );
 47	
 48// Output
 49	
 50	// Number of extra input samples needed until 'count' output samples are available
 51	int input_needed( blargg_long count ) const;
 52	
 53	// Number of output samples available
 54	int avail() const { return avail_( write_pos - &buf [width_ * stereo] ); }
 55	
 56public:
 57	~Fir_Resampler_();
 58protected:
 59	enum { stereo = 2 };
 60	enum { max_res = 32 };
 61	blargg_vector<sample_t> buf;
 62	sample_t* write_pos;
 63	int res;
 64	int imp_phase;
 65	int const width_;
 66	int const write_offset;
 67	blargg_ulong skip_bits;
 68	int step;
 69	int input_per_cycle;
 70	double ratio_;
 71	sample_t* impulses;
 72	
 73	Fir_Resampler_( int width, sample_t* );
 74	int avail_( blargg_long input_count ) const;
 75};
 76
 77// Width is number of points in FIR. Must be even and 4 or more. More points give
 78// better quality and rolloff effectiveness, and take longer to calculate.
 79template<int width>
 80class Fir_Resampler : public Fir_Resampler_ {
 81	BOOST_STATIC_ASSERT( width >= 4 && width % 2 == 0 );
 82	short impulses [max_res] [width];
 83public:
 84	Fir_Resampler() : Fir_Resampler_( width, impulses [0] ) { }
 85	
 86	// Read at most 'count' samples. Returns number of samples actually read.
 87	typedef short sample_t;
 88	int read( sample_t* out, blargg_long count );
 89};
 90
 91// End of public interface
 92
 93inline void Fir_Resampler_::write( long count )
 94{
 95	write_pos += count;
 96	assert( write_pos <= buf.end() );
 97}
 98
 99template<int width>
100int Fir_Resampler<width>::read( sample_t* out_begin, blargg_long count )
101{
102	sample_t* out = out_begin;
103	const sample_t* in = buf.begin();
104	sample_t* end_pos = write_pos;
105	blargg_ulong skip = skip_bits >> imp_phase;
106	sample_t const* imp = impulses [imp_phase];
107	int remain = res - imp_phase;
108	int const step = this->step;
109	
110	count >>= 1;
111	
112	if ( end_pos - in >= width * stereo )
113	{
114		end_pos -= width * stereo;
115		do
116		{
117			count--;
118			
119			// accumulate in extended precision
120			blargg_long l = 0;
121			blargg_long r = 0;
122			
123			const sample_t* i = in;
124			if ( count < 0 )
125				break;
126			
127			for ( int n = width / 2; n; --n )
128			{
129				int pt0 = imp [0];
130				l += pt0 * i [0];
131				r += pt0 * i [1];
132				int pt1 = imp [1];
133				imp += 2;
134				l += pt1 * i [2];
135				r += pt1 * i [3];
136				i += 4;
137			}
138			
139			remain--;
140			
141			l >>= 15;
142			r >>= 15;
143			
144			in += (skip * stereo) & stereo;
145			skip >>= 1;
146			in += step;
147			
148			if ( !remain )
149			{
150				imp = impulses [0];
151				skip = skip_bits;
152				remain = res;
153			}
154			
155			out [0] = (sample_t) l;
156			out [1] = (sample_t) r;
157			out += 2;
158		}
159		while ( in <= end_pos );
160	}
161	
162	imp_phase = res - remain;
163	
164	int left = write_pos - in;
165	write_pos = &buf [left];
166	memmove( buf.begin(), in, left * sizeof *in );
167	
168	return out - out_begin;
169}
170
171#endif