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

dogmatixman at users.sourceforge.net dogmatixman at users.sourceforge.net
Sun Jul 29 13:37:28 CEST 2007


Revision: 28287
          http://scummvm.svn.sourceforge.net/scummvm/?rev=28287&view=rev
Author:   dogmatixman
Date:     2007-07-29 04:37:27 -0700 (Sun, 29 Jul 2007)

Log Message:
-----------
Added dithering to the filtering resampler, and better separated the mono and stereo cases.

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

Modified: scummvm/branches/gsoc2007-mixer/sound/rate.cpp
===================================================================
--- scummvm/branches/gsoc2007-mixer/sound/rate.cpp	2007-07-29 11:21:12 UTC (rev 28286)
+++ scummvm/branches/gsoc2007-mixer/sound/rate.cpp	2007-07-29 11:37:27 UTC (rev 28287)
@@ -319,12 +319,16 @@
 	
 	/* The maximum DC gain across all subfilters */
 	double filtGain;
+	
+	/* Random number source for getting dither values */
+	Common::RandomSource *rand;
 
 public:
 	FilteringRateConverter(st_rate_t inrate, st_rate_t outrate);
 	~FilteringRateConverter() {
 		delete filt;
 		free(inBuf);
+		delete rand;
 	}
 	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);
@@ -395,6 +399,8 @@
 	inBuf = (st_sample_t *)calloc(numChan * subLen, sizeof(st_sample_t));
 	
 	inPos = 0;
+	
+	rand = new Common::RandomSource();
 }
 
 template<bool stereo, bool reverseStereo>
@@ -448,39 +454,71 @@
 		 * ensure that there can be no clipping at all, the volume is far
 		 * softer than the other resamplers produce)
 		 */
-		double out0 = kFudgeFactor * accum0 / filtGain;
-		double out1 = kFudgeFactor * (stereo ? accum1 : accum0) / filtGain;
+		accum0 *= kFudgeFactor / filtGain;
 		
-		/* Check for clipping and clamp values in these cases */
-		if (fmax(out0, out1) > ST_SAMPLE_MAX) {
-			debug(1, "Clipping: sample value is %g (should be maximally %g)", fmax(out0, out1), (double)ST_SAMPLE_MAX);
-			
-			if (out0 > ST_SAMPLE_MAX) {
-				out0 = ST_SAMPLE_MAX;
-			}
-			if (out1 > ST_SAMPLE_MAX) {
-				out1 = ST_SAMPLE_MAX;
-			}
+		/* Scale down according to the volume settings. */
+		accum0 *= vol_l / Audio::Mixer::kMaxMixerVolume;
+		
+		/*
+		 * The overall effect of the following code is to add dithering of up
+		 * to +/- 0.5, using a triangular distribution centred at 0 (central
+		 * limit theorem), then rounding to the nearest integer; however, due
+		 * to the fact that the floating point -> integer cast will round
+		 * towards 0, the implementation uses a triangular distribution
+		 * centred at 0.5 (spreading out to 0 and 1) and then checks the sign
+		 * of the sample to determine if the dither value should be added or
+		 * subtracted (to give the desired overall effect of rounding to the
+		 * nearest integer).
+		 */
+		
+		/* RandomSource hiccups if you use -1U here, since it adds 1 to this */
+		static const uint kRandMax = -2U; 
+		
+		double dither0 = ((accum0 >= 0) ? 1 : -1) * 
+				( (double)(rand->getRandomNumber(kRandMax)) + 
+				  (double)(rand->getRandomNumber(kRandMax)) )
+				/ (2.0 * kRandMax);
+		
+		accum0 += dither0;
+		
+		/* Check for clipping and clamp values if necessary */
+		if (accum0 > ST_SAMPLE_MAX) {
+			debug(1, "Clipping: sample value is %g (should be maximally %g)", accum0, (double)ST_SAMPLE_MAX);
+			accum0 = ST_SAMPLE_MAX;
+		} else	if (accum0 < ST_SAMPLE_MIN) {
+			debug(1, "Clipping: sample value is %g (should be minimally %g)", accum0, (double)ST_SAMPLE_MIN);
+			accum0 = ST_SAMPLE_MIN;
 		}
 		
-		if (fmin(out0, out1) < ST_SAMPLE_MIN) {
-			debug(1, "Clipping: sample value is %g (should be minimally %g)", fmin(out0, out1), (double)ST_SAMPLE_MIN);
-			if (out0 < ST_SAMPLE_MIN) {
-				out0 = ST_SAMPLE_MIN;
+		/* Perform the same steps for the second channel if neccesary */
+		if (stereo || vol_l != vol_r) {
+			accum1 *= kFudgeFactor / filtGain;
+			
+			accum1 *= vol_r / Audio::Mixer::kMaxMixerVolume;
+			
+			double dither1 = ((accum1 >= 0) ? 1 : -1) * 
+					( (double)(rand->getRandomNumber(kRandMax)) + 
+					(double)(rand->getRandomNumber(kRandMax)) )
+					/ (2.0 * kRandMax);
+			
+			accum1 += dither1;
+			
+			if (accum1 > ST_SAMPLE_MAX) {
+				debug(1, "Clipping: sample value is %g (should be maximally %g)", accum1, (double)ST_SAMPLE_MAX);
+				accum1 = ST_SAMPLE_MAX;
+			} else	if (accum1 < ST_SAMPLE_MIN) {
+				debug(1, "Clipping: sample value is %g (should be minimally %g)", accum1, (double)ST_SAMPLE_MIN);
+				accum1 = ST_SAMPLE_MIN;
 			}
-			if (out1 < ST_SAMPLE_MIN) {
-				out1 = ST_SAMPLE_MIN;
-			}
+		} else {
+			accum1 = accum0;
 		}
 		
-		assert(fmax(out0, out1) <= ST_SAMPLE_MAX);
-		assert(fmin(out0, out1) >= ST_SAMPLE_MIN);
+		/* Output left channel */
+		clampedAdd(obuf[reverseStereo    ], (int)accum0);
 		
-		/* Output left channel */
-		clampedAdd(obuf[reverseStereo    ], ((st_sample_t)out0 * (int)vol_l) / Audio::Mixer::kMaxMixerVolume);
-
 		/* output right channel */
-		clampedAdd(obuf[reverseStereo ^ 1], ((st_sample_t)out1 * (int)vol_r) / Audio::Mixer::kMaxMixerVolume);
+		clampedAdd(obuf[reverseStereo ^ 1], (int)accum1);
 		
 		obuf += 2;
 		
@@ -494,7 +532,8 @@
 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;
+	
+	return ST_EOF;
 }
 
 


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