diff options
| author | Max Horn | 2007-06-28 22:21:32 +0000 | 
|---|---|---|
| committer | Max Horn | 2007-06-28 22:21:32 +0000 | 
| commit | f058edf860b33086f473720dc790280c563bebcb (patch) | |
| tree | 8c577a80555a4cdf130ff58f91e2481660d66d55 | |
| parent | 1a3724b59b4c89411c748fd3b645a627b4f599cd (diff) | |
| download | scummvm-rg350-f058edf860b33086f473720dc790280c563bebcb.tar.gz scummvm-rg350-f058edf860b33086f473720dc790280c563bebcb.tar.bz2 scummvm-rg350-f058edf860b33086f473720dc790280c563bebcb.zip | |
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)
svn-id: r27767
| -rw-r--r-- | common/frac.h | 3 | ||||
| -rw-r--r-- | sound/mods/paula.cpp | 39 | ||||
| -rw-r--r-- | sound/mods/paula.h | 19 | ||||
| -rw-r--r-- | sound/mods/protracker.cpp | 16 | 
4 files changed, 40 insertions, 37 deletions
| diff --git a/common/frac.h b/common/frac.h index 1c2c622a2c..b1e6c518d1 100644 --- a/common/frac.h +++ b/common/frac.h @@ -46,6 +46,9 @@ enum {   */  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; } diff --git a/sound/mods/paula.cpp b/sound/mods/paula.cpp index 9061891c35..b4f7018343 100644 --- a/sound/mods/paula.cpp +++ b/sound/mods/paula.cpp @@ -75,14 +75,9 @@ int Paula::readBuffer(int16 *buffer, const int numSamples) {  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 @@ int Paula::readBufferIntern(int16 *buffer, const int numSamples) {  			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;  				} diff --git a/sound/mods/paula.h b/sound/mods/paula.h index 1e196daf40..e86c05b7f8 100644 --- a/sound/mods/paula.h +++ b/sound/mods/paula.h @@ -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 @@ protected:  		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 @@ protected:  		_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;  	} diff --git a/sound/mods/protracker.cpp b/sound/mods/protracker.cpp index 102c265ce9..46ee3aabf7 100644 --- a/sound/mods/protracker.cpp +++ b/sound/mods/protracker.cpp @@ -65,7 +65,7 @@ private:  	struct {  		byte sample;  		uint16 period; -		double offset; +		frac_t offset;  		byte vol;  		byte finetune; @@ -197,13 +197,13 @@ void ProtrackerStream::updateRow() {  					_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 @@ void ProtrackerStream::updateRow() {  			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 @@ void ProtrackerStream::updateEffects() {  				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;  				} | 
