diff options
| -rw-r--r-- | sound/audiostream.cpp | 64 | ||||
| -rw-r--r-- | sound/audiostream.h | 10 | ||||
| -rw-r--r-- | sound/rate.cpp | 86 | ||||
| -rw-r--r-- | sound/rate.h | 48 | ||||
| -rw-r--r-- | sound/resample.cpp | 54 | 
5 files changed, 174 insertions, 88 deletions
diff --git a/sound/audiostream.cpp b/sound/audiostream.cpp index 7b796b8d50..1690d58fff 100644 --- a/sound/audiostream.cpp +++ b/sound/audiostream.cpp @@ -23,47 +23,79 @@  #include "mixer.h"  template<int channels, int sampleSize> -class MemoryAudioInputStream : public AudioInputStream { +class LinearMemoryStream : public AudioInputStream {  protected:  	const byte *_ptr;  	const byte *_end; -	void advance() { _ptr += channels * sampleSize; } +	void advance() { _ptr += sampleSize; }  public: -	MemoryAudioInputStream(const byte *ptr, uint len) : _ptr(ptr), _end(ptr+len) { } -	virtual int size() { return (_end - _ptr) / (channels * sampleSize); } +	LinearMemoryStream(const byte *ptr, uint len) : _ptr(ptr), _end(ptr+len) { } +	virtual int size() const { return (_end - _ptr) / sampleSize; } +	virtual bool isStereo() const { return channels == 2; }  }; +#if 0 +TODO: Implement a wrapped memory stream, to be used by the ChannelStream class +(and possibly others?) -template<int channels> -class Input8bitSignedStream : public MemoryAudioInputStream<channels, 1> { +template<int channels, int sampleSize> +class WrappedMemoryStream : public AudioInputStream { +protected: +	byte *_bufferStart; +	byte *_bufferEnd; +	byte *_pos; +	byte *_end; +	 +	void advance() { +		_ptr += channels * sampleSize; +		.. TODO: wrap +	} +public: +	WrappedMemoryStream(const byte *ptr, uint len) : _bufferStart(ptr), _bufferEnd(ptr+len) { } +	virtual int size() const { +		int size = _end - _pos; +		if (size < 0) +			size += _bufferEnd - _bufferStart +		return size / (channels * sampleSize); +	} +	 +	void append(const byte *ptr, uint len) { +		... +	} +}; +#endif + + +template<int channels, class T = class LinearMemoryStream<channels, 1> > +class Input8bitSignedStream : public T {  protected:  	int16 readIntern() { int8 v = (int8)*_ptr; return v << 8; }  public: -	Input8bitSignedStream(const byte *ptr, int len) : MemoryAudioInputStream<channels, 1>(ptr, len) { } +	Input8bitSignedStream(const byte *ptr, int len) : T(ptr, len) { }  }; -template<int channels> -class Input8bitUnsignedStream : public MemoryAudioInputStream<channels, 1> { +template<int channels, class T = class LinearMemoryStream<channels, 1> > +class Input8bitUnsignedStream : public T {  protected:  	int16 readIntern() { int8 v = (int8)(*_ptr ^ 0x80); return v << 8; }  public: -	Input8bitUnsignedStream(const byte *ptr, int len) : MemoryAudioInputStream<channels, 1>(ptr, len) { } +	Input8bitUnsignedStream(const byte *ptr, int len) : T(ptr, len) { }  }; -template<int channels> -class Input16bitSignedStream : public MemoryAudioInputStream<channels, 2> { +template<int channels, class T = class LinearMemoryStream<channels, 2> > +class Input16bitSignedStream : public T {  protected:  	int16 readIntern() { return (int16)READ_BE_UINT16(_ptr); }  public: -	Input16bitSignedStream(const byte *ptr, int len) : MemoryAudioInputStream<channels, 2>(ptr, len) { } +	Input16bitSignedStream(const byte *ptr, int len) : T(ptr, len) { }  }; -template<int channels> -class Input16bitUnsignedStream : public MemoryAudioInputStream<channels, 2> { +template<int channels, class T = class LinearMemoryStream<channels, 2> > +class Input16bitUnsignedStream : public T {  protected:  	int16 readIntern() { return (int16)(READ_BE_UINT16(_ptr) ^ 0x8000); }  public: -	Input16bitUnsignedStream(const byte *ptr, int len) : MemoryAudioInputStream<channels, 2>(ptr, len) { } +	Input16bitUnsignedStream(const byte *ptr, int len) : T(ptr, len) { }  }; diff --git a/sound/audiostream.h b/sound/audiostream.h index 1eca349967..cb4e986124 100644 --- a/sound/audiostream.h +++ b/sound/audiostream.h @@ -40,9 +40,10 @@ protected:  	virtual void advance() = 0;  public:  	int16 read() { assert(size() > 0); int16 val = readIntern(); advance(); return val; } -	int16 peek() { assert(size() > 0); return readIntern(); } -	virtual int size() = 0; -	bool eof() { return size() <= 0; } +//	int16 peek() { assert(size() > 0); return readIntern(); } +	virtual int size() const = 0; +	bool eof() const { return size() <= 0; } +	virtual bool isStereo() const = 0;  };  class ZeroInputStream : public AudioInputStream { @@ -52,7 +53,8 @@ protected:  	void advance() { _len--; }  public:  	ZeroInputStream(uint len) : _len(len) { } -	virtual int size() { return _len; } +	virtual int size() const { return _len; } +	virtual bool isStereo() const { return false; }  };  AudioInputStream *makeInputStream(byte _flags, const byte *ptr, uint32 len); diff --git a/sound/rate.cpp b/sound/rate.cpp index c056b85a9a..5d6faaeee3 100644 --- a/sound/rate.cpp +++ b/sound/rate.cpp @@ -51,7 +51,7 @@ typedef struct ratestuff  	unsigned long ipos;	 /* position in the input stream (integer) */ -	st_sample_t ilast; /* last sample in the input stream */ +	st_sample_t ilast[2]; /* last sample(s) in the input stream (left/right channel) */  } *rate_t;  /* @@ -83,7 +83,8 @@ int st_rate_start(eff_t effp, st_rate_t inrate, st_rate_t outrate)  	rate->ipos = 0; -	rate->ilast = 0; +	rate->ilast[0] = 0; +	rate->ilast[1] = 0;  	return (ST_SUCCESS);  } @@ -91,23 +92,29 @@ int st_rate_start(eff_t effp, st_rate_t inrate, st_rate_t outrate)   * Processed signed long samples from ibuf to obuf.   * Return number of samples processed.   */ +template<int channels>  int st_rate_flow(eff_t effp, AudioInputStream &input, st_sample_t *obuf, st_size_t *osamp, st_volume_t vol)  {  	rate_t rate = (rate_t) effp->priv;  	st_sample_t *ostart, *oend; -	st_sample_t ilast, icur, out; +	st_sample_t ilast[2], icur[2], out;  	unsigned long tmp; +	int i; -	ilast = rate->ilast; +	assert(channels == 1 || channels == 2); + +	for (i = 0; i < channels; i++) +		ilast[i] = rate->ilast[i];  	ostart = obuf;  	oend = obuf + *osamp;  	while (obuf < oend && !input.eof()) { -		/* read as many input samples so that ipos > opos */ +		/* read enough input samples so that ipos > opos */  		while (rate->ipos <= rate->opos) { -			ilast = input.read(); +			for (i = 0; i < channels; i++) +				ilast[i] = input.read();  			rate->ipos++;  			/* See if we finished the input buffer yet */ @@ -115,25 +122,64 @@ int st_rate_flow(eff_t effp, AudioInputStream &input, st_sample_t *obuf, st_size  				goto the_end;  		} -		icur = input.peek(); - -		/* interpolate */ -		out = ilast + (((icur - ilast) * rate->opos_frac + (1UL << (FRAC_BITS-1))) >> FRAC_BITS); +		// read the input sample(s) +		icur[0] = input.read(); +		if (channels == 2) { +			if (input.eof()) +				goto the_end;	// Shouldn't happen if data comes pair-wise +			icur[1] = input.read(); +		} -		/* output sample & increment position */ -		out = out * vol / 256; -		clampedAdd(*obuf++, out); -		#if 1	// FIXME: Hack to generate stereo output -		clampedAdd(*obuf++, out); -		#endif +		while (rate->ipos > rate->opos) { +			for (i = 0; i < channels; i++) { +				// interpolate +				out = ilast[i] + (((icur[i] - ilast[i]) * rate->opos_frac + (1UL << (FRAC_BITS-1))) >> FRAC_BITS); +		 +				// adjust volume +				out = out * vol / 256; +		 +				// output left channel sample +				clampedAdd(*obuf++, out); +			} +	 +			// For mono input, repeat the sample to produce stereo output +			if (channels == 1) +				clampedAdd(*obuf++, out); +	 +			// Increment output position +			tmp = rate->opos_frac + rate->opos_inc_frac; +			rate->opos = rate->opos + rate->opos_inc + (tmp >> FRAC_BITS); +			rate->opos_frac = tmp & ((1UL << FRAC_BITS) - 1); +		} -		tmp = rate->opos_frac + rate->opos_inc_frac; -		rate->opos = rate->opos + rate->opos_inc + (tmp >> FRAC_BITS); -		rate->opos_frac = tmp & ((1UL << FRAC_BITS) - 1); +		// Increment input position again (for the sample we read now) +		rate->ipos++; +		for (i = 0; i < channels; i++) +			ilast[i] = icur[i];  	}  the_end:  	*osamp = obuf - ostart; -	rate->ilast = ilast; +	for (i = 0; i < channels; i++) +		rate->ilast[i] = ilast[i]; +	return (ST_SUCCESS); +} + + +#pragma mark - + + +LinearRateConverter::LinearRateConverter(st_rate_t inrate, st_rate_t outrate) { +	st_rate_start(&effp, inrate, outrate); +} + +int LinearRateConverter::flow(AudioInputStream &input, st_sample_t *obuf, st_size_t *osamp, st_volume_t vol) { +	if (input.isStereo()) +		return st_rate_flow<2>(&effp, input, obuf, osamp, vol); +	else +		return st_rate_flow<1>(&effp, input, obuf, osamp, vol); +} + +int LinearRateConverter::drain(st_sample_t *obuf, st_size_t *osamp, st_volume_t vol) {  	return (ST_SUCCESS);  } diff --git a/sound/rate.h b/sound/rate.h index c84e33a2ad..080107c831 100644 --- a/sound/rate.h +++ b/sound/rate.h @@ -56,17 +56,6 @@ static inline void clampedAdd(int16& a, int b) {  #define st_fail error -// Resample (high quality) -int st_resample_getopts(eff_t effp, int n, const char **argv); -int st_resample_start(eff_t effp, st_rate_t inrate, st_rate_t outrate); -int st_resample_flow(eff_t effp, AudioInputStream &input, st_sample_t *obuf, st_size_t *osamp, st_volume_t vol); -int st_resample_drain(eff_t effp, st_sample_t *obuf, st_size_t *osamp, st_volume_t vol); -int st_resample_stop(eff_t effp); - -// Rate (linear filter, low quality) -int st_rate_start(eff_t effp, st_rate_t inrate, st_rate_t outrate); -int st_rate_flow(eff_t effp, AudioInputStream &input, st_sample_t *obuf, st_size_t *osamp, st_volume_t vol); -  class RateConverter {  protected:  	eff_struct effp; @@ -79,40 +68,17 @@ public:  class LinearRateConverter : public RateConverter {  public: -	LinearRateConverter(st_rate_t inrate, st_rate_t outrate) { -		st_rate_start(&effp, inrate, outrate); -	} -	virtual int flow(AudioInputStream &input, st_sample_t *obuf, st_size_t *osamp, st_volume_t vol) { -		return st_rate_flow(&effp, input, obuf, osamp, vol); -	} -	virtual int drain(st_sample_t *obuf, st_size_t *osamp, st_volume_t vol) { -		return (ST_SUCCESS); -	} +	LinearRateConverter(st_rate_t inrate, st_rate_t outrate); +	virtual int flow(AudioInputStream &input, st_sample_t *obuf, st_size_t *osamp, st_volume_t vol); +	virtual int drain(st_sample_t *obuf, st_size_t *osamp, st_volume_t vol);  };  class ResampleRateConverter : public RateConverter {  public: -	ResampleRateConverter(st_rate_t inrate, st_rate_t outrate, int quality) { -		// FIXME: quality is for now a nasty hack. -		// Valid values are 0,1,2,3 (everything else is treated like 0 for now) -		const char *arg = 0; -		switch (quality) { -		case 1: arg = "-qs"; break; -		case 2: arg = "-q"; break; -		case 3: arg = "-ql"; break; -		} -		st_resample_getopts(&effp, arg ? 1 : 0, &arg); -		st_resample_start(&effp, inrate, outrate); -	} -	~ResampleRateConverter() { -		st_resample_stop(&effp); -	} -	virtual int flow(AudioInputStream &input, st_sample_t *obuf, st_size_t *osamp, st_volume_t vol) { -		return st_resample_flow(&effp, input, obuf, osamp, vol); -	} -	virtual int drain(st_sample_t *obuf, st_size_t *osamp, st_volume_t vol) { -		return st_resample_drain(&effp, obuf, osamp, vol); -	} +	ResampleRateConverter(st_rate_t inrate, st_rate_t outrate, int quality); +	~ResampleRateConverter(); +	virtual int flow(AudioInputStream &input, st_sample_t *obuf, st_size_t *osamp, st_volume_t vol); +	virtual int drain(st_sample_t *obuf, st_size_t *osamp, st_volume_t vol);  };  #endif diff --git a/sound/resample.cpp b/sound/resample.cpp index 3bbd3d18ca..a621d89213 100644 --- a/sound/resample.cpp +++ b/sound/resample.cpp @@ -274,6 +274,16 @@ int st_resample_flow(eff_t effp, AudioInputStream &input, st_sample_t *obuf, st_  	const long obufSize = *osamp;  #endif +TODO: adjust for the changes made to AudioInputStream; add support for stereo +initially, could just average the left/right channel -> bad for quality of course, +but easiest to implement and would get this going again. +Next step is to duplicate the X/Y buffers... a lot of computations don't care about +how many channels there are anyway, they could just be ran twice, e.g. SrcEX and SrcUD. +But better for efficiency would be to rewrite those to deal with 2 channels, too. +Because esp in SrcEX/SrcUD, only very few computations depend on the input data, +and dealing with both channels in parallel should only be a little slower than dealing +with them alone +  	// Constrain amount we actually process  	//fprintf(stderr,"Xp %d, Xread %d\n",r->Xp, r->Xread); @@ -313,7 +323,6 @@ int st_resample_flow(eff_t effp, AudioInputStream &input, st_sample_t *obuf, st_  	// Finally compute the effective number of bytes to process  	Nproc = last - r->Xoff - r->Xp; -printf("FOO(3) Nproc %ld\n", Nproc);  	if (Nproc <= 0) {  		/* fill in starting here next time */ @@ -356,7 +365,7 @@ printf("FOO(3) Nproc %ld\n", Nproc);  	/* Copy back portion of input signal that must be re-used */  	k = r->Xp - r->Xoff; -	fprintf(stderr,"k %d, last %d\n",k,last); +	//fprintf(stderr,"k %d, last %d\n",k,last);  	for (i = 0; i < last - k; i++)  		r->X[i] = r->X[i + k]; @@ -370,7 +379,8 @@ printf("osamp = %ld, Nout = %ld\n", obufSize, Nout);  		int sample = (int)(r->Y[i] * vol / 256);  		clampedAdd(*obuf++, sample);  #if 1	// FIXME: Hack to generate stereo output -		clampedAdd(*obuf++, sample); +//		clampedAdd(*obuf++, sample); +		*obuf++;  #endif  	} @@ -514,12 +524,12 @@ static long SrcUD(resample_t r, long Nx) {  	Factor = r->Factor;  	time = r->Time;  	dt = 1.0 / Factor;	   /* Output sampling period */ -	fprintf(stderr,"Factor %f, dt %f, ",Factor,dt); -	fprintf(stderr,"Time %f, ",r->Time); +	//fprintf(stderr,"Factor %f, dt %f, ",Factor,dt); +	//fprintf(stderr,"Time %f, ",r->Time);  	/* (Xh * dhb)>>La is max index into Imp[] */  	/*fprintf(stderr,"ct=%d\n",ct);*/ -	fprintf(stderr,"ct=%.2f %d\n",(double)r->Nwing*Na/r->dhb, r->Xh); -	fprintf(stderr,"ct=%ld, T=%.6f, dhb=%6f, dt=%.6f\n", r->Xh, time-floor(time),(double)r->dhb/Na,dt); +	//fprintf(stderr,"ct=%.2f %d\n",(double)r->Nwing*Na/r->dhb, r->Xh); +	//fprintf(stderr,"ct=%ld, T=%.6f, dhb=%6f, dt=%.6f\n", r->Xh, time-floor(time),(double)r->dhb/Na,dt);  	Ystart = Y = r->Y + r->Yposition;  	n = (int)ceil((double)Nx / dt);  	while (n--) { @@ -722,3 +732,33 @@ static void LpFilter(double *c, long N, double frq, double Beta, long Num) {  		}  	}  } + + +#pragma mark - + + +ResampleRateConverter::ResampleRateConverter(st_rate_t inrate, st_rate_t outrate, int quality) { +	// FIXME: quality is for now a nasty hack. +	// Valid values are 0,1,2,3 (everything else is treated like 0 for now) +	const char *arg = 0; +	switch (quality) { +	case 1: arg = "-qs"; break; +	case 2: arg = "-q"; break; +	case 3: arg = "-ql"; break; +	} +	st_resample_getopts(&effp, arg ? 1 : 0, &arg); +	st_resample_start(&effp, inrate, outrate); +} + +ResampleRateConverter::~ResampleRateConverter() { +	st_resample_stop(&effp); +} + +int ResampleRateConverter::flow(AudioInputStream &input, st_sample_t *obuf, st_size_t *osamp, st_volume_t vol) { +	return st_resample_flow(&effp, input, obuf, osamp, vol); +} + +int ResampleRateConverter::drain(st_sample_t *obuf, st_size_t *osamp, st_volume_t vol) { +	return st_resample_drain(&effp, obuf, osamp, vol); +} +  | 
