[Scummvm-cvs-logs] SF.net SVN: scummvm: [27992] scummvm/branches/gsoc2007-mixer/sound

dogmatixman at users.sourceforge.net dogmatixman at users.sourceforge.net
Mon Jul 9 19:30:51 CEST 2007


Revision: 27992
          http://scummvm.svn.sourceforge.net/scummvm/?rev=27992&view=rev
Author:   dogmatixman
Date:     2007-07-09 10:30:50 -0700 (Mon, 09 Jul 2007)

Log Message:
-----------
Added a floating point filtering rate converter -- it only handles integer upsampling rates at this point.  Changed drain() prototype.

Modified Paths:
--------------
    scummvm/branches/gsoc2007-mixer/sound/rate.cpp
    scummvm/branches/gsoc2007-mixer/sound/rate.h

Modified: scummvm/branches/gsoc2007-mixer/sound/rate.cpp
===================================================================
--- scummvm/branches/gsoc2007-mixer/sound/rate.cpp	2007-07-09 17:05:44 UTC (rev 27991)
+++ scummvm/branches/gsoc2007-mixer/sound/rate.cpp	2007-07-09 17:30:50 UTC (rev 27992)
@@ -35,8 +35,10 @@
 #include "sound/audiostream.h"
 #include "sound/rate.h"
 #include "sound/mixer.h"
+#include "sound/filter.h"
 #include "common/frac.h"
 #include "common/util.h"
+#include "common/config-manager.h"
 
 namespace Audio {
 
@@ -73,7 +75,7 @@
 public:
 	SimpleRateConverter(st_rate_t inrate, st_rate_t outrate);
 	int flow(AudioStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r);
-	int drain(st_sample_t *obuf, st_size_t osamp, st_volume_t vol) {
+	int drain(st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r) {
 		return ST_SUCCESS;
 	}
 };
@@ -179,7 +181,7 @@
 public:
 	LinearRateConverter(st_rate_t inrate, st_rate_t outrate);
 	int flow(AudioStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r);
-	int drain(st_sample_t *obuf, st_size_t osamp, st_volume_t vol) {
+	int drain(st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r) {
 		return ST_SUCCESS;
 	}
 };
@@ -269,7 +271,168 @@
 
 #pragma mark -
 
+/**
+ * Audio rate converter that uses filtering techniques.
+ *
+ * This currently allows us to upsample by an integer factor with very little
+ * spectral distortion.
+ *
+ * TODO: Make this a rational factor rather than an integer factor
+ *
+ * Limited to sampling frequency <= 65535 Hz.
+ */
 
+template<bool stereo, bool reverseStereo>
+class FilteringRateConverter : public RateConverter {
+protected:
+	FIRFilter *filt;
+	
+	/* Circular buffers for inputs which are currently in the filter */
+	st_sample_t *inBuf;
+	
+	/* Offset into the circular buffer of the most recent input sample */
+	uint32 inPos;
+	
+	/*
+     * Fraction of the input frequency which should be used as passband for
+	 * the filter design.
+	 */
+	double lowpassBW;
+	
+	/* Number of filter banks to use for the multirate filter */
+	uint16 numBanks;
+	
+	/* Subfilter length */
+	uint16 subLen;
+	
+	/* The current bank that we're up to (for output samples) */
+	uint16 currBank;
+	
+	/* The number of channels of audio */
+	uint8 numChan;
+
+public:
+	FilteringRateConverter(st_rate_t inrate, st_rate_t outrate);
+	~FilteringRateConverter() {
+		delete filt;
+		free(inBuf);
+	}
+	int flow(AudioStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r);
+	int drain(st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r);
+};
+
+/*
+ * Prepare processing.
+ */
+template<bool stereo, bool reverseStereo>
+FilteringRateConverter<stereo, reverseStereo>::FilteringRateConverter(st_rate_t inrate, st_rate_t outrate) {
+	if (inrate >= 65536 || outrate >= 65536) {
+		error("rate effect can only handle rates < 65536");
+	}
+	
+	currBank = 0;
+	
+	numBanks = outrate / inrate;
+	
+	// TODO: Make an editable way to set this value
+	/* This sets the point in the input signal where attenuation will begin */
+	lowpassBW = 0.925;
+	
+	// TODO: Make it so that this filter data can be reused by other
+	//       converters. 
+	/* Generate the filter coefficients */
+	filt = new FIRFilter(lowpassBW * inrate / 2.0, inrate / 2.0,
+						-40, 80, (uint16)outrate);
+	
+	uint16 len = filt->getLength();
+	
+	subLen = (len + (numBanks - 1)) / numBanks;
+	
+	/* TODO: Fix this. */
+	/* At this point I don't have any code appending 0s in this case */
+	assert((len % subLen) == 0); 
+	
+	numChan = (stereo ? 2 : 1);
+	
+	/* Two channel of audio */
+	inBuf = (st_sample_t *)calloc(numChan * subLen, sizeof(st_sample_t));
+	
+	inPos = 0;
+}
+
+template<bool stereo, bool reverseStereo>
+int FilteringRateConverter<stereo, reverseStereo>::flow(AudioStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r) {
+	st_sample_t *oend = obuf + osamp * 2;
+	
+	while (obuf < oend) {
+		if (currBank == 0) {
+			/*
+			 * We need to fetch a new input sample (two if this is a stereo
+			 * stream).  We'll want to replace the oldest sample(s) in the
+			 * circular buffer.  Since inPos points to the newest sample(s) in
+			 * the buffer, the oldest sample(s) can be found directly before
+			 * inPos.
+			 */
+			 
+			/* Circularly decrement inPos by numChan */
+			inPos = (inPos + (subLen - numChan)) % subLen;
+			
+			uint8 inLen;
+			
+			inLen = input.readBuffer(&inBuf[inPos], numChan);
+			if (inLen == 0) {
+				/* No more input samples */
+				return this->drain(obuf, (oend - obuf) / 2, vol_l, vol_r);
+			}
+			
+			assert(inLen == numChan);
+		}
+		
+		double accum0 = 0;
+		double accum1 = 0;
+		
+		uint16 i;
+		
+		/*
+		 * Convolve the input samples with the filter to get the next
+		 * outputs
+		 */
+		for (i = 0; i < subLen; i++) {
+			accum0 += (double)inBuf[(inPos + numChan * i) % subLen] /// ST_SAMPLE_MAX
+						* (filt->getCoeffs())[currBank + i*numBanks];
+			if (stereo) {
+				accum1 += (double)inBuf[(inPos + numChan * i + 1) % subLen] /// ST_SAMPLE_MAX
+						* (filt->getCoeffs())[currBank + i*numBanks];
+			}
+		}
+		
+		st_sample_t out0 = (st_sample_t)(accum0); //* ST_SAMPLE_MAX);
+		st_sample_t out1 = (st_sample_t)(stereo ? accum1 : accum0);//* ST_SAMPLE_MAX : accum0 * ST_SAMPLE_MAX);
+		
+		/* Output left channel */
+		clampedAdd(obuf[reverseStereo    ], (out0 * (int)vol_l) / Audio::Mixer::kMaxMixerVolume);
+
+		/* output right channel */
+		clampedAdd(obuf[reverseStereo ^ 1], (out1 * (int)vol_r) / Audio::Mixer::kMaxMixerVolume);
+		
+		obuf += 2;
+		
+		/* Circularly increment currBank */
+		currBank = (currBank + 1) % numBanks;
+	}
+	
+	return ST_SUCCESS;
+}
+
+template<bool stereo, bool reverseStereo>
+int FilteringRateConverter<stereo, reverseStereo>::drain(st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r) {
+	// TODO: implement this
+	return ST_SUCCESS;
+}
+
+
+#pragma mark -
+
 /**
  * Simple audio rate converter for the case that the inrate equals the outrate.
  */
@@ -320,7 +483,7 @@
 		return ST_SUCCESS;
 	}
 
-	virtual int drain(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_l, st_volume_t vol_r) {
 		return ST_SUCCESS;
 	}
 };
@@ -328,8 +491,17 @@
 
 #pragma mark -
 
+// TODO: Add options checking for filtering rate converters.
 template<bool stereo, bool reverseStereo>
 RateConverter *makeRateConverter(st_rate_t inrate, st_rate_t outrate) {
+	if (ConfMan.hasKey("rate_converter")
+			&& (ConfMan.getInt("rate_converter") == kFilteringType)) {
+		/* Only handling integer upsampling rates at this point */
+		if (((outrate % inrate) == 0) && (outrate != inrate)) {
+			return new FilteringRateConverter<stereo, reverseStereo>(inrate, outrate);
+		}
+	}
+	
 	if (inrate != outrate) {
 		if ((inrate % outrate) == 0) {
 			return new SimpleRateConverter<stereo, reverseStereo>(inrate, outrate);

Modified: scummvm/branches/gsoc2007-mixer/sound/rate.h
===================================================================
--- scummvm/branches/gsoc2007-mixer/sound/rate.h	2007-07-09 17:05:44 UTC (rev 27991)
+++ scummvm/branches/gsoc2007-mixer/sound/rate.h	2007-07-09 17:30:50 UTC (rev 27992)
@@ -50,6 +50,13 @@
 	ST_SUCCESS = 0
 };
 
+/* This relates to the ConfMan rate_converter key. */
+enum RateConverterType {
+	kLinearType = 0,
+	kFilteringType = 1
+};
+	
+
 static inline void clampedAdd(int16& a, int b) {
 	register int val;
 #ifdef OUTPUT_UNSIGNED_AUDIO
@@ -75,7 +82,7 @@
 	RateConverter() {}
 	virtual ~RateConverter() {}
 	virtual int flow(AudioStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r) = 0;
-	virtual int drain(st_sample_t *obuf, st_size_t osamp, st_volume_t vol) = 0;
+	virtual int drain(st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r) = 0;
 };
 
 RateConverter *makeRateConverter(st_rate_t inrate, st_rate_t outrate, bool stereo, bool reverseStereo = false);


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list