[Scummvm-cvs-logs] SF.net SVN: scummvm: [30849] scummvm/trunk/engines/scumm

Kirben at users.sourceforge.net Kirben at users.sourceforge.net
Tue Feb 12 04:26:06 CET 2008


Revision: 30849
          http://scummvm.svn.sourceforge.net/scummvm/?rev=30849&view=rev
Author:   Kirben
Date:     2008-02-11 19:26:05 -0800 (Mon, 11 Feb 2008)

Log Message:
-----------
Add patch #1891606 - Improved sound playback for Amiga SCUMM V2/V3 games.

Modified Paths:
--------------
    scummvm/trunk/engines/scumm/player_mod.cpp
    scummvm/trunk/engines/scumm/player_mod.h

Modified: scummvm/trunk/engines/scumm/player_mod.cpp
===================================================================
--- scummvm/trunk/engines/scumm/player_mod.cpp	2008-02-11 13:51:04 UTC (rev 30848)
+++ scummvm/trunk/engines/scumm/player_mod.cpp	2008-02-12 03:26:05 UTC (rev 30849)
@@ -41,8 +41,9 @@
 		_channels[i].id = 0;
 		_channels[i].vol = 0;
 		_channels[i].freq = 0;
-		_channels[i].converter = NULL;
 		_channels[i].input = NULL;
+		_channels[i].ctr = 0;
+		_channels[i].pos = 0;
 	}
 
 	_playproc = NULL;
@@ -56,7 +57,6 @@
 	for (int i = 0; i < MOD_MAXCHANS; i++) {
 		if (!_channels[i].id)
 			continue;
-		delete _channels[i].converter;
 		delete _channels[i].input;
 	}
 }
@@ -93,8 +93,10 @@
 	_channels[i].vol = vol;
 	_channels[i].pan = pan;
 	_channels[i].freq = rate;
+	_channels[i].ctr = 0;
 	_channels[i].input = Audio::makeLinearInputStream((const byte*)data, size, rate, Audio::Mixer::FLAG_AUTOFREE | (loopStart != loopEnd ? Audio::Mixer::FLAG_LOOP : 0), loopStart, loopEnd);
-	_channels[i].converter = Audio::makeRateConverter(rate, _mixer->getOutputRate(), false, false);
+	// read the first sample
+	_channels[i].input->readBuffer(&_channels[i].pos, 1);
 }
 
 void Player_MOD::stopChannel(int id) {
@@ -102,13 +104,13 @@
 		error("player_mod - attempted to stop channel id 0");
 	for (int i = 0; i < MOD_MAXCHANS; i++) {
 		if (_channels[i].id == id) {
-			delete _channels[i].converter;
-			_channels[i].converter = NULL;
 			delete _channels[i].input;
 			_channels[i].input = NULL;
 			_channels[i].id = 0;
 			_channels[i].vol = 0;
 			_channels[i].freq = 0;
+			_channels[i].ctr = 0;
+			_channels[i].pos = 0;
 		}
 	}
 }
@@ -139,9 +141,9 @@
 		error("player_mod - attempted to set frequency for channel id 0");
 	for (int i = 0; i < MOD_MAXCHANS; i++) {
 		if (_channels[i].id == id) {
+			if (freq > 31400)	// this is about as high as WinUAE goes
+				freq = 31400;	// can't easily verify on my own Amiga
 			_channels[i].freq = freq;
-			delete _channels[i].converter;
-			_channels[i].converter = Audio::makeRateConverter(freq, _mixer->getOutputRate(), false, false);
 			break;
 		}
 	}
@@ -170,11 +172,51 @@
 			len = 0;
 		}
 		for (i = 0; i < MOD_MAXCHANS; i++)
+		{
 			if (_channels[i].id) {
 				Audio::st_volume_t vol_l = (127 - _channels[i].pan) * _channels[i].vol / 127;
 				Audio::st_volume_t vol_r = (127 + _channels[i].pan) * _channels[i].vol / 127;
-				_channels[i].converter->flow(*_channels[i].input, &data[dpos*2], dlen, vol_l, vol_r);
+				for (uint j = 0; j < dlen; j++)
+				{
+					// simple linear resample, unbuffered
+					int delta = (uint32)(_channels[i].freq * 0x10000) / _samplerate;
+					uint16 cfrac = ~_channels[i].ctr & 0xFFFF;
+					if (_channels[i].ctr + delta < 0x10000)
+						cfrac = delta;
+					_channels[i].ctr += delta;
+					int32 cpos = _channels[i].pos * cfrac / 0x10000;
+					while (_channels[i].ctr >= 0x10000)
+					{
+						if (_channels[i].input->readBuffer(&_channels[i].pos, 1) != 1)
+						{	// out of data
+							stopChannel(_channels[i].id);
+							goto skipchan;	// exit 2 loops at once
+						}
+						_channels[i].ctr -= 0x10000;
+						if (_channels[i].ctr > 0x10000)
+							cpos += _channels[i].pos;
+						else	cpos += (int32)(_channels[i].pos * (_channels[i].ctr & 0xFFFF)) / 0x10000;
+					}
+					int16 pos = 0;
+					// if too many samples play in a row, the calculation below will overflow and clip
+					// so try and split it up into pieces it can manage comfortably
+					while (cpos < -0x8000)
+					{
+						pos -= 0x80000000 / delta;
+						cpos += 0x8000;
+					}
+					while (cpos > 0x7FFF)
+					{
+						pos += 0x7FFF0000 / delta;
+						cpos -= 0x7FFF;
+					}
+					pos += cpos * 0x10000 / delta;
+					Audio::clampedAdd(data[(dpos + j) * 2 + 0], pos * vol_l / Audio::Mixer::kMaxMixerVolume);
+					Audio::clampedAdd(data[(dpos + j) * 2 + 1], pos * vol_r / Audio::Mixer::kMaxMixerVolume);
+				}
 			}
+skipchan:		;	// channel ran out of data
+		}
 		dpos += dlen;
 	}
 }

Modified: scummvm/trunk/engines/scumm/player_mod.h
===================================================================
--- scummvm/trunk/engines/scumm/player_mod.h	2008-02-11 13:51:04 UTC (rev 30848)
+++ scummvm/trunk/engines/scumm/player_mod.h	2008-02-12 03:26:05 UTC (rev 30849)
@@ -75,7 +75,9 @@
 		uint8 vol;
 		int8 pan;
 		uint16 freq;
-		Audio::RateConverter *converter;
+
+		uint32 ctr;
+		int16 pos;
 		Audio::AudioStream *input;
 	};
 


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