[Scummvm-cvs-logs] SF.net SVN: scummvm: [28612] scummvm/branches/gsoc2007-mixer/sound
dogmatixman at users.sourceforge.net
dogmatixman at users.sourceforge.net
Tue Aug 14 14:42:56 CEST 2007
Revision: 28612
http://scummvm.svn.sourceforge.net/scummvm/?rev=28612&view=rev
Author: dogmatixman
Date: 2007-08-14 05:42:56 -0700 (Tue, 14 Aug 2007)
Log Message:
-----------
Allows rational resampling factors, and chooses a "nice" filter length (that divides neatly into subfilters). Filter generation delays need improving.
Modified Paths:
--------------
scummvm/branches/gsoc2007-mixer/sound/filter.cpp
scummvm/branches/gsoc2007-mixer/sound/filter.h
scummvm/branches/gsoc2007-mixer/sound/rate.cpp
Modified: scummvm/branches/gsoc2007-mixer/sound/filter.cpp
===================================================================
--- scummvm/branches/gsoc2007-mixer/sound/filter.cpp 2007-08-14 08:49:20 UTC (rev 28611)
+++ scummvm/branches/gsoc2007-mixer/sound/filter.cpp 2007-08-14 12:42:56 UTC (rev 28612)
@@ -78,25 +78,31 @@
/*
* Estimated window length using the Kaiser design formula.
- * Assumption: window length <= 65535 taps.
*/
-inline uint16 FIRFilter::windowLength(
+inline uint32 FIRFilter::windowLength(
double ripple,
double transitionBW,
- uint16 samplingFreq) {
- double length = (samplingFreq * (-ripple - 7.95)) / (14.36 * transitionBW);
+ uint32 samplingFreq,
+ uint16 upFactor) {
+ double idealLength = (samplingFreq * (-ripple - 7.95)) / (14.36 * transitionBW);
- assert(length > 0);
+ assert(idealLength > 0);
- return (uint16)(length + 1);
+ /* Round length up to a multiple of the upsampling rate */
+ uint32 length = (uint32)(idealLength + 1);
+ if (length % upFactor) {
+ length += upFactor - (length % upFactor);
+ }
+
+ return length;
}
/*
* Derives the coefficients for a Kaiser window of the given properties, using
* standard Kaiser design formulae.
*/
-void FIRFilter::windowDesign(double *coeffs, uint16 length, double ripple) {
- uint16 i;
+void FIRFilter::windowDesign(double *coeffs, uint32 length, double ripple) {
+ uint32 i;
double alpha = -ripple;
double beta;
@@ -110,7 +116,7 @@
}
for (i = 0; i <= (length - 1) / 2; i++) {
- double n = i - (length - 1) / 2 - ((length % 2) ? 0 : 0.5);
+ double n = (int32)(i - (length - 1) / 2) - ((length % 2) ? 0 : 0.5);
/*
* Both this window and the later filter are even symmetric, so we
@@ -137,14 +143,14 @@
*/
void FIRFilter::LPDesign(
double *coeffs,
- uint16 length,
+ uint32 length,
double passbandEdge,
double stopbandEdge,
- uint16 samplingFreq) {
- uint16 i;
+ uint32 samplingFreq) {
+ uint32 i;
for (i = 0; i <= (length - 1) / 2; i++) {
- double n = i - (length - 1) / 2 - ((length % 2) ? 0 : 0.5);
+ double n = (int32)(i - (length - 1) / 2) - ((length % 2) ? 0 : 0.5);
/*
* Use an ideal transition halfway between the passband and stopband
@@ -162,17 +168,19 @@
/* Generates lowpass filter coefficients using the parameters provided */
FIRFilter::FIRFilter(double passbandEdge, double stopbandEdge,
double dBPassbandRipple, double dBStopbandAtten,
- uint16 samplingFreq)
+ uint32 samplingFreq, uint16 upFactor)
: _passbandEdge(passbandEdge), _stopbandEdge(stopbandEdge),
_dBPassbandRipple(dBPassbandRipple),
_dBStopbandAtten(dBStopbandAtten),
- _samplingFreq(samplingFreq), _ripple(0), _length(0), _coeffs(0) {
+ _samplingFreq(samplingFreq),
+ _upFactor(upFactor), _ripple(0), _length(0), _coeffs(0) {
/* Find the amount of ripple that the filter will produce */
_ripple = equiripple(_dBPassbandRipple, _dBStopbandAtten);
/* Find the number of coefficients in the window */
_length =
- windowLength(_ripple, _stopbandEdge - _passbandEdge, _samplingFreq);
+ windowLength(_ripple, _stopbandEdge - _passbandEdge, _samplingFreq,
+ _upFactor);
/* Calculate the window coefficients */
_coeffs = (double *)malloc(_length * sizeof(double));
Modified: scummvm/branches/gsoc2007-mixer/sound/filter.h
===================================================================
--- scummvm/branches/gsoc2007-mixer/sound/filter.h 2007-08-14 08:49:20 UTC (rev 28611)
+++ scummvm/branches/gsoc2007-mixer/sound/filter.h 2007-08-14 12:42:56 UTC (rev 28612)
@@ -37,10 +37,11 @@
double _stopbandEdge;
double _dBPassbandRipple;
double _dBStopbandAtten;
- uint16 _samplingFreq;
+ uint32 _samplingFreq;
+ uint16 _upFactor;
double _ripple;
- uint16 _length;
+ uint32 _length;
double *_coeffs;
public:
@@ -50,11 +51,12 @@
double stopbandEdge,
double dBPassbandRipple,
double dBStopbandAtten,
- uint16 samplingFreq);
+ uint32 samplingFreq,
+ uint16 upFactor);
~FIRFilter() { free(_coeffs); }
- uint16 getLength() { return _length; }
+ uint32 getLength() { return _length; }
double *getCoeffs() { return _coeffs; }
@@ -63,21 +65,22 @@
double dBPassbandRipple,
double dBStopbandAtten);
- uint16 windowLength(
+ uint32 windowLength(
double ripple,
double transitionBW,
- uint16 samplingFreq);
+ uint32 samplingFreq,
+ uint16 upFactor);
- void windowDesign(double *coeffs, uint16 length, double ripple);
+ void windowDesign(double *coeffs, uint32 length, double ripple);
double sinc(double arg);
void LPDesign(
double *coeffs,
- uint16 length,
+ uint32 length,
double passbandEdge,
double stopbandEdge,
- uint16 samplingFreq);
+ uint32 samplingFreq);
};
Modified: scummvm/branches/gsoc2007-mixer/sound/rate.cpp
===================================================================
--- scummvm/branches/gsoc2007-mixer/sound/rate.cpp 2007-08-14 08:49:20 UTC (rev 28611)
+++ scummvm/branches/gsoc2007-mixer/sound/rate.cpp 2007-08-14 12:42:56 UTC (rev 28612)
@@ -51,6 +51,7 @@
*/
#define INTERMEDIATE_BUFFER_SIZE 512
+static st_rate_t gcd(st_rate_t a, st_rate_t b);
/**
* Audio rate converter based on simple resampling. Used when no
@@ -277,11 +278,8 @@
* 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.
+ * TODO: Optimise filter creation -- too slow for large upsampling factors
*/
-
template<bool stereo, bool reverseStereo>
class FilteringRateConverter : public RateConverter {
protected:
@@ -291,16 +289,22 @@
st_sample_t *inBuf;
/* Offset into the circular buffer of the most recent input sample */
- uint32 inPos;
+ uint16 inPos;
+ /*
+ * The number of samples we need to fetch into the input buffer from the
+ * AudioStream
+ */
+ uint16 toFetch;
+
/*
* 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;
+ /* Upsampling and downsampling factors */
+ uint16 upFactor, downFactor;
/* Subfilter length */
uint16 subLen;
@@ -339,36 +343,45 @@
*/
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");
- }
+ /*
+ * Note: we'll first upsample the audio by upFactor and filter it, and
+ * then downsample it by downFactor. This means we'll use upFactor
+ * different filter banks and only calculate one in every downFactor
+ * outputs.
+ */
+ upFactor = outrate / gcd(inrate, outrate);
+ downFactor = inrate / gcd(inrate, outrate);
- currBank = 0;
+ /* Initially we'll need to put some samples in the input buffer */
+ toFetch = 1 + (downFactor - 1) / upFactor;
- numBanks = outrate / inrate;
+ /* We'll be ignoring the first downFactor - 1 samples */
+ currBank = (downFactor - 1) % upFactor;
// TODO: Make an editable way to set this value
/* This sets the point in the input signal where attenuation will begin */
lowpassBW = 0.925;
+ /* We'll want to lowpass based on the most restrictive frequency */
+ st_rate_t stopband = (outrate < inrate) ? outrate : inrate;
+
// 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);
+ filt = new FIRFilter(lowpassBW * stopband / 2.0, stopband / 2.0,
+ -40, 80, (uint32)inrate * upFactor, upFactor);
- uint16 len = filt->getLength();
+ uint32 len = filt->getLength();
- subLen = (len + (numBanks - 1)) / numBanks;
+ subLen = (len + (upFactor - 1)) / upFactor;
- /* TODO: Fix this. */
- /* At this point I don't have any code appending 0s in this case */
+ /* Want to be able to divide the filter perfectly into subfilters */
assert((len % subLen) == 0);
/* Find the DC gain of each subfilter */
- double *gain = (double *)calloc(numBanks, sizeof(double));
+ double *gain = (double *)calloc(upFactor, sizeof(double));
- uint16 i;
+ uint32 i;
for (i = 0; i < len; i++) {
/*
* Using the commented-out line and setting kFudgeFactor to 1 will
@@ -376,14 +389,14 @@
* softer than those of other resamplers using otherwise equal
* options.
*/
- //gain[i % numBanks] += fabs((filt->getCoeffs())[i]);
- gain[i % numBanks] += (filt->getCoeffs())[i];
+ //gain[i % upFactor] += fabs((filt->getCoeffs())[i]);
+ gain[i % upFactor] += (filt->getCoeffs())[i];
}
/* Find the maximum of these subfilter gains */
filtGain = 0;
- for (i = 0; i < numBanks; i++) {
+ for (i = 0; i < upFactor; i++) {
if (gain[i] > filtGain) {
filtGain = gain[i];
}
@@ -408,7 +421,7 @@
st_sample_t *oend = obuf + osamp * 2;
while (obuf < oend) {
- if (currBank == 0) {
+ while (toFetch--) {
/*
* 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
@@ -442,10 +455,10 @@
*/
for (i = 0; i < subLen; i++) {
accum0 += (double)inBuf[(inPos + numChan * i) % subLen]
- * (filt->getCoeffs())[currBank + i*numBanks];
+ * (filt->getCoeffs())[currBank + i*upFactor];
if (stereo) {
accum1 += (double)inBuf[(inPos + numChan * i + 1) % subLen]
- * (filt->getCoeffs())[currBank + i*numBanks];
+ * (filt->getCoeffs())[currBank + i*upFactor];
}
}
@@ -522,8 +535,11 @@
obuf += 2;
- /* Circularly increment currBank */
- currBank = (currBank + 1) % numBanks;
+ /* Find out how many more input samples are needed next time */
+ toFetch = (currBank + downFactor) / upFactor;
+
+ /* Circularly increment currBank by downFactor */
+ currBank = (currBank + downFactor) % upFactor;
}
return ST_SUCCESS;
@@ -597,13 +613,22 @@
#pragma mark -
+static inline st_rate_t gcd(st_rate_t a, st_rate_t b) {
+ while (b) {
+ int temp = b;
+ b = a % b;
+ a = temp;
+ }
+
+ return a;
+}
+
// 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)) {
+ if (outrate != inrate) {
return new FilteringRateConverter<stereo, reverseStereo>(inrate, outrate);
}
}
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