aboutsummaryrefslogtreecommitdiff
path: root/engines/scumm
diff options
context:
space:
mode:
authorTravis Howell2008-02-12 03:26:05 +0000
committerTravis Howell2008-02-12 03:26:05 +0000
commitba717bc5155c896b0376d23c374d4dc801794dac (patch)
tree2944d63fe30507877e6a7b3557252b05236e7788 /engines/scumm
parentacf50bac9d48632c39ad0a0cb812800714a1076d (diff)
downloadscummvm-rg350-ba717bc5155c896b0376d23c374d4dc801794dac.tar.gz
scummvm-rg350-ba717bc5155c896b0376d23c374d4dc801794dac.tar.bz2
scummvm-rg350-ba717bc5155c896b0376d23c374d4dc801794dac.zip
Add patch #1891606 - Improved sound playback for Amiga SCUMM V2/V3 games.
svn-id: r30849
Diffstat (limited to 'engines/scumm')
-rw-r--r--engines/scumm/player_mod.cpp58
-rw-r--r--engines/scumm/player_mod.h4
2 files changed, 53 insertions, 9 deletions
diff --git a/engines/scumm/player_mod.cpp b/engines/scumm/player_mod.cpp
index 71842d74b0..e50e116c83 100644
--- a/engines/scumm/player_mod.cpp
+++ b/engines/scumm/player_mod.cpp
@@ -41,8 +41,9 @@ Player_MOD::Player_MOD(Audio::Mixer *mixer) {
_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 @@ Player_MOD::~Player_MOD() {
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 @@ void Player_MOD::startChannel(int id, void *data, int size, int rate, uint8 vol,
_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 @@ void Player_MOD::stopChannel(int id) {
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 @@ void Player_MOD::setChannelFreq(int id, int freq) {
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 @@ void Player_MOD::do_mix(int16 *data, uint len) {
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;
}
}
diff --git a/engines/scumm/player_mod.h b/engines/scumm/player_mod.h
index 5756916ae0..ba709e2430 100644
--- a/engines/scumm/player_mod.h
+++ b/engines/scumm/player_mod.h
@@ -75,7 +75,9 @@ private:
uint8 vol;
int8 pan;
uint16 freq;
- Audio::RateConverter *converter;
+
+ uint32 ctr;
+ int16 pos;
Audio::AudioStream *input;
};