[Scummvm-cvs-logs] SF.net SVN: scummvm: [27767] scummvm/trunk

fingolfin at users.sourceforge.net fingolfin at users.sourceforge.net
Fri Jun 29 00:21:35 CEST 2007


Revision: 27767
          http://scummvm.svn.sourceforge.net/scummvm/?rev=27767&view=rev
Author:   fingolfin
Date:     2007-06-28 15:21:32 -0700 (Thu, 28 Jun 2007)

Log Message:
-----------
Switched Paula (Amiga MOD) code to use fixed point math instead of doubles (caveat: this only works for samples < 32k right now; if this ever turns out to be a problem, I can fix it, though)

Modified Paths:
--------------
    scummvm/trunk/common/frac.h
    scummvm/trunk/sound/mods/paula.cpp
    scummvm/trunk/sound/mods/paula.h
    scummvm/trunk/sound/mods/protracker.cpp

Modified: scummvm/trunk/common/frac.h
===================================================================
--- scummvm/trunk/common/frac.h	2007-06-28 20:21:16 UTC (rev 27766)
+++ scummvm/trunk/common/frac.h	2007-06-28 22:21:32 UTC (rev 27767)
@@ -46,6 +46,9 @@
  */
 typedef int32 frac_t;
 
+inline frac_t doubleToFrac(double value) { return (frac_t)(value * FRAC_ONE); }
+inline double fracToDouble(frac_t value) { return ((double)value) / FRAC_ONE; }
+
 inline frac_t intToFrac(int16 value) { return value << FRAC_BITS; }
 inline int16 fracToInt(frac_t value) { return value >> FRAC_BITS; }
 

Modified: scummvm/trunk/sound/mods/paula.cpp
===================================================================
--- scummvm/trunk/sound/mods/paula.cpp	2007-06-28 20:21:16 UTC (rev 27766)
+++ scummvm/trunk/sound/mods/paula.cpp	2007-06-28 22:21:32 UTC (rev 27767)
@@ -75,14 +75,9 @@
 
 
 template<bool stereo>
-inline void mixBuffer(int16 *&buf, const int8 *data, double &offset, double rate, int end, byte volume, byte panning) {
+inline void mixBuffer(int16 *&buf, const int8 *data, frac_t &offset, frac_t rate, int end, byte volume, byte panning) {
 	for (int i = 0; i < end; i++) {
-		// FIXME: We should avoid using floating point arithmetic here, since
-		// FP calculations and int<->FP conversions are very expensive on many
-		// architectures.
-		// So consider replacing offset and rate with fixed point values...
-
-		const int32 tmp = ((int32) data[(int)offset]) * volume;
+		const int32 tmp = ((int32) data[fracToInt(offset)]) * volume;
 		if (stereo) {
 			*buf++ += (tmp * (255 - panning)) >> 7;
 			*buf++ += (tmp * (panning)) >> 7;
@@ -110,50 +105,46 @@
 			if (!_voice[voice].data || (_voice[voice].period <= 0))
 				continue;
 
-			double frequency = (7093789.2 / 2.0) / _voice[voice].period;
-			double rate = frequency / _rate;
-			double offset = _voice[voice].offset;
+			const double frequency = (7093789.2 / 2.0) / _voice[voice].period;
+			frac_t rate = doubleToFrac(frequency / _rate);
+			frac_t offset = _voice[voice].offset;
+			frac_t sLen = intToFrac(_voice[voice].length);
 
-			int sLen = _voice[voice].length;
 			const int8 *data = _voice[voice].data;
 			int16 *p = buffer;
 			int end = 0;
 
-
 			_voice[voice].volume = MIN((byte) 0x40, _voice[voice].volume);
 			// If looping has been enabled and we see that we will have to loop
 			// to generate enough samples, then use the "loop" branch.
 			if ((_voice[voice].lengthRepeat > 2) &&
-					((int)(offset + nSamples * rate) >= sLen)) {
+					(offset + nSamples * rate >= sLen)) {
 				int neededSamples = nSamples;
 
 				while (neededSamples > 0) {
-					end = MIN(neededSamples, (int)((sLen - offset) / rate));
-					
-					if (end == 0) {
+					if (sLen - offset < rate) {
 						// This means that "rate" is too high, bigger than the sample size.
 						// So we scale it down according to the euclidean algorithm.
-						while (rate > (sLen - offset))
-							rate -= (sLen - offset);
-
-						end = MIN(neededSamples, (int)((sLen - offset) / rate));
+						rate %= sLen - offset;
 					}
 
+					end = MIN(neededSamples, (sLen - offset) / rate);
 					mixBuffer<stereo>(p, data, offset, rate, end, _voice[voice].volume, _voice[voice].panning);
 					_voice[voice].offset = offset;
 					neededSamples -= end;
 
 					// If we read beyond the sample end, loop back to the start.
-					if (ceil(_voice[voice].offset) >= sLen) {
+					// TODO: Shouldn't we wrap around here?
+					if (_voice[voice].offset + FRAC_ONE > sLen) {
 						_voice[voice].data = data = _voice[voice].dataRepeat;
-						_voice[voice].length = sLen = _voice[voice].lengthRepeat;
+						_voice[voice].length = _voice[voice].lengthRepeat;
 						_voice[voice].offset = offset = 0;
+						sLen = intToFrac(_voice[voice].length);
 					}
 				}
 			} else {
 				if (offset < sLen) {	// Sample data left?
-					end = MIN(nSamples, (int)((sLen - offset) / rate));
-
+					end = MIN(nSamples, (sLen - offset) / rate);
 					mixBuffer<stereo>(p, data, offset, rate, end, _voice[voice].volume, _voice[voice].panning);
 					_voice[voice].offset = offset;
 				}

Modified: scummvm/trunk/sound/mods/paula.h
===================================================================
--- scummvm/trunk/sound/mods/paula.h	2007-06-28 20:21:16 UTC (rev 27766)
+++ scummvm/trunk/sound/mods/paula.h	2007-06-28 22:21:32 UTC (rev 27767)
@@ -27,6 +27,7 @@
 #define SOUND_MODS_PAULA_H
 
 #include "sound/audiostream.h"
+#include "common/frac.h"
 #include "common/mutex.h"
 
 namespace Audio {
@@ -65,7 +66,7 @@
 		uint32 lengthRepeat;
 		int16 period;
 		byte volume;
-		double offset;	// FIXME: Avoid floating point at all cost!!!
+		frac_t offset;
 		byte panning; // For stereo mixing: 0 = far left, 255 = far right
 	};
 
@@ -99,22 +100,30 @@
 		_voice[channel].volume = volume;
 	}
 
-	void setChannelData(uint8 channel, const int8 *data, const int8 *dataRepeat, uint32 length, uint32 lengthRepeat, double offset = 0.0) {
+	void setChannelData(uint8 channel, const int8 *data, const int8 *dataRepeat, uint32 length, uint32 lengthRepeat, int32 offset = 0) {
 		assert(channel < NUM_VOICES);
+
+		// For now, we only support 32k samples, as we use 16bit fixed point arithmetics.
+		// If this ever turns out to be a problem, we can still enhance this code.
+		assert(0 <= offset && offset < 32768);
+		assert(length < 32768);
+		assert(lengthRepeat < 32768);
+
 		Channel &ch = _voice[channel];
 		ch.data = data;
 		ch.dataRepeat = dataRepeat;
 		ch.length = length;
 		ch.lengthRepeat = lengthRepeat;
-		ch.offset = offset;
+		ch.offset = intToFrac(offset);
 	}
 
-	void setChannelOffset(byte channel, double offset) {
+	void setChannelOffset(byte channel, frac_t offset) {
 		assert(channel < NUM_VOICES);
+		assert(0 <= offset);
 		_voice[channel].offset = offset;
 	}
 
-	double getChannelOffset(byte channel) {
+	frac_t getChannelOffset(byte channel) {
 		assert(channel < NUM_VOICES);
 		return _voice[channel].offset;
 	}

Modified: scummvm/trunk/sound/mods/protracker.cpp
===================================================================
--- scummvm/trunk/sound/mods/protracker.cpp	2007-06-28 20:21:16 UTC (rev 27766)
+++ scummvm/trunk/sound/mods/protracker.cpp	2007-06-28 22:21:32 UTC (rev 27767)
@@ -65,7 +65,7 @@
 	struct {
 		byte sample;
 		uint16 period;
-		double offset;
+		frac_t offset;
 
 		byte vol;
 		byte finetune;
@@ -197,13 +197,13 @@
 					_track[track].period = _module.noteToPeriod(note.note, _track[track].finetune);
 				else
 					_track[track].period = note.period;
-				_track[track].offset = 0.0;
+				_track[track].offset = 0;
 			}
 		}
 
-		const int exy = note.effect & 0xff;
-		const int ex = (note.effect >> 4) & 0xf;
-		const int ey = note.effect & 0xf;
+		const byte exy = note.effect & 0xff;
+		const byte ex = (note.effect >> 4) & 0xf;
+		const byte ey = note.effect & 0xf;
 
 		int vol;
 		switch (effect) {
@@ -243,7 +243,7 @@
 			break;
 		case 0x9: // Set sample offset
 			if (exy) {
-				_track[track].offset = exy * 256;
+				_track[track].offset = intToFrac(exy * 256);
 				setChannelOffset(track, _track[track].offset);
 			}
 			break;
@@ -384,12 +384,12 @@
 				break;	// Pattern loop
 			case 0x9:	// Retrigger note
 				if (ey && (_tick % ey) == 0)
-					_track[track].offset = 0.0;
+					_track[track].offset = 0;
 				break;
 			case 0xD: // Delay sample
 				if (_tick == _track[track].delaySampleTick) {
 					_track[track].sample = _track[track].delaySample;
-					_track[track].offset = 0.0;
+					_track[track].offset = 0;
 					if (_track[track].sample)
 						_track[track].vol = _module.sample[_track[track].sample - 1].vol;
 				}


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