aboutsummaryrefslogtreecommitdiff
path: root/scumm/player_v3a.cpp
diff options
context:
space:
mode:
authorTravis Howell2003-09-24 06:56:30 +0000
committerTravis Howell2003-09-24 06:56:30 +0000
commit4a62eb3e3b75944bca5af3bbab9e05dfecd77dcd (patch)
treefcd1210b4b896122ade69adf498a7054e23cd8d4 /scumm/player_v3a.cpp
parent09a01e4cbeada86167d83608cd0dcd77d7a0168f (diff)
downloadscummvm-rg350-4a62eb3e3b75944bca5af3bbab9e05dfecd77dcd.tar.gz
scummvm-rg350-4a62eb3e3b75944bca5af3bbab9e05dfecd77dcd.tar.bz2
scummvm-rg350-4a62eb3e3b75944bca5af3bbab9e05dfecd77dcd.zip
More Amiga V2/V3 sound updates from _Q_:
1. A Player_MOD class, basically acts as a simplified mixer that mixes at 60Hz intervals (or whatever interval you specify), this gives smooth music playback in player_v3a 2. Some changes to player_v3a as a result of #1, including reduced music volume 3. player_v2a, and the necessary additions to scummvm.cpp/scumm.h svn-id: r10392
Diffstat (limited to 'scumm/player_v3a.cpp')
-rw-r--r--scumm/player_v3a.cpp203
1 files changed, 103 insertions, 100 deletions
diff --git a/scumm/player_v3a.cpp b/scumm/player_v3a.cpp
index a7efa37ec5..bebc98cf6b 100644
--- a/scumm/player_v3a.cpp
+++ b/scumm/player_v3a.cpp
@@ -24,8 +24,6 @@
#include "base/engine.h"
#include "player_v3a.h"
#include "scumm.h"
-#include "sound/mixer.h"
-#include "common/timer.h"
static const uint16 note_freqs[4][12] = {
{0x06B0,0x0650,0x05F4,0x05A0,0x054C,0x0500,0x04B8,0x0474,0x0434,0x03F8,0x03C0,0x0388},
@@ -44,13 +42,14 @@ Player_V3A::Player_V3A(Scumm *scumm) {
int i;
_scumm = scumm;
_system = scumm->_system;
- _mixer = scumm->_mixer;
-
- for (i = 0; i < V3A_MAXSFX; i++)
- _sfx[i].id = _sfx[i].dur = 0;
-
- for (i = 0; i < V3A_MAXMUS; i++)
- _mus[i].id = _mus[i].dur = 0;
+ for (i = 0; i < V3A_MAXMUS; i++) {
+ _mus[i].id = 0;
+ _mus[i].dur = 0;
+ }
+ for (i = 0; i < V3A_MAXSFX; i++) {
+ _sfx[i].id = 0;
+ _sfx[i].dur = 0;
+ }
_curSong = 0;
_songData = NULL;
@@ -59,36 +58,63 @@ Player_V3A::Player_V3A(Scumm *scumm) {
_music_timer = 0;
- _maxvol = 255;
-
- scumm->_timer->installProcedure(timerHandler, 16666, this);
-
_isinit = false;
+
+ _mod = new Player_MOD(scumm);
+ _mod->setUpdateProc(update_proc, this, 60);
}
Player_V3A::~Player_V3A() {
- _scumm->_timer->releaseProcedure(timerHandler);
- if (!_isinit)
- return;
- for (int i = 0; _wavetable[i] != NULL; i++) {
- for (int j = 0; j < 6; j++) {
- free(_wavetable[i]->_idat[j]);
- free(_wavetable[i]->_ldat[j]);
+ int i;
+ delete _mod;
+ if (_isinit) {
+ for (i = 0; _wavetable[i] != NULL; i++) {
+ for (int j = 0; j < 6; j++) {
+ free(_wavetable[i]->_idat[j]);
+ free(_wavetable[i]->_ldat[j]);
+ }
+ free(_wavetable[i]);
}
- free(_wavetable[i]);
+ free(_wavetable);
}
- free(_wavetable);
}
void Player_V3A::setMasterVolume (int vol) {
- _maxvol = vol;
+ _mod->setMasterVolume(vol);
+}
+
+int Player_V3A::getMusChan (int id) const {
+ int i;
+ for (i = 0; i < V3A_MAXMUS; i++) {
+ if (_mus[i].id == id)
+ break;
+ }
+ if (i == V3A_MAXMUS) {
+ if (id == 0)
+ warning("player_v3a - out of music channels");
+ return -1;
+ }
+ return i;
+}
+int Player_V3A::getSfxChan (int id) const {
+ int i;
+ for (i = 0; i < V3A_MAXSFX; i++) {
+ if (_sfx[i].id == id)
+ break;
+ }
+ if (i == V3A_MAXSFX) {
+ if (id == 0)
+ warning("player_v3a - out of sfx channels");
+ return -1;
+ }
+ return i;
}
void Player_V3A::stopAllSounds() {
int i;
for (i = 0; i < V3A_MAXMUS; i++) {
if (_mus[i].id)
- _mixer->stopID(V3A_MUS_BASEID + i);
+ _mod->stopChannel(_mus[i].id);
_mus[i].id = 0;
_mus[i].dur = 0;
}
@@ -98,7 +124,7 @@ void Player_V3A::stopAllSounds() {
_songData = NULL;
for (i = 0; i < V3A_MAXSFX; i++) {
if (_sfx[i].id)
- _mixer->stopID(V3A_SFX_BASEID + i);
+ _mod->stopChannel(_sfx[i].id | 0x100);
_sfx[i].id = 0;
_sfx[i].dur = 0;
}
@@ -106,10 +132,14 @@ void Player_V3A::stopAllSounds() {
void Player_V3A::stopSound(int nr) {
int i;
+ if (nr == 0) { // Amiga Loom does this near the end, when Chaos casts SILENCE on Hetchel
+ stopAllSounds();
+ return;
+ }
if (nr == _curSong) {
for (i = 0; i < V3A_MAXMUS; i++) {
if (_mus[i].id)
- _mixer->stopID(V3A_MUS_BASEID + i);
+ _mod->stopChannel(_mus[i].id);
_mus[i].id = 0;
_mus[i].dur = 0;
}
@@ -118,59 +148,21 @@ void Player_V3A::stopSound(int nr) {
_songDelay = 0;
_songData = NULL;
} else {
- for (i = 0; i < V3A_MAXSFX; i++) {
- if (_sfx[i].id == nr) {
- _mixer->stopID(V3A_SFX_BASEID + i);
- _sfx[i].id = 0;
- _sfx[i].dur = 0;
- break;
- }
+ i = getSfxChan(nr);
+ if (i != -1) {
+ _mod->stopChannel(nr | 0x100);
+ _sfx[i].id = 0;
+ _sfx[i].dur = 0;
}
}
}
-void Player_V3A::playSoundSFX (int nr, char *data, int size, int rate, int vol, int tl, bool looped, int loopStart, int loopEnd) {
- int i;
- for (i = 0; i < V3A_MAXSFX; i++) {
- if (!_sfx[i].id)
- break;
- }
- if (i == V3A_MAXSFX) {
- warning("player_v3a - too many sound effects playing (%i max)",V3A_MAXSFX);
- return;
- }
- _sfx[i].id = nr;
- _sfx[i].dur = tl;
-
- vol = (vol * _maxvol) / 255;
- _mixer->playRaw(NULL, data, size, rate, SoundMixer::FLAG_AUTOFREE | (looped ? SoundMixer::FLAG_LOOP : 0),
- V3A_SFX_BASEID + i, vol, 0, loopStart, loopEnd);
-}
-
-void Player_V3A::playSoundMUS (char *data, int size, int rate, int vol, int tl, bool looped, int loopStart, int loopEnd) {
- int i;
- for (i = 0; i < V3A_MAXMUS; i++) {
- if (!_mus[i].id)
- break;
- }
- if (i == V3A_MAXMUS) {
- warning("player_v3a - too many music channels playing (%i max)",V3A_MAXMUS);
- return;
- }
- _mus[i].id = i + 1;
- _mus[i].dur = tl;
-
- vol = (vol * _maxvol) / 255;
- _mixer->playRaw(NULL, data, size, rate, SoundMixer::FLAG_AUTOFREE | (looped ? SoundMixer::FLAG_LOOP : 0),
- V3A_MUS_BASEID + i, vol, 0, loopStart, loopEnd);
-}
-
void Player_V3A::startSound(int nr) {
assert(_scumm);
byte *data = _scumm->getResourceAddress(rtSound, nr);
assert(data);
- if (_scumm->_gameId != GID_INDY3 && _scumm->_gameId != GID_LOOM)
+ if ((_scumm->_gameId != GID_INDY3) && (_scumm->_gameId != GID_LOOM))
error("player_v3a - unknown game!");
if (!_isinit) {
@@ -223,6 +215,8 @@ void Player_V3A::startSound(int nr) {
stopSound(nr); // if a sound is playing, restart it
if (data[26]) {
+ if (_curSong)
+ stopSound(_curSong);
_curSong = nr;
_songData = data;
_songPtr = 0x1C;
@@ -232,43 +226,49 @@ void Player_V3A::startSound(int nr) {
int size = READ_BE_UINT16(data + 12);
int rate = 3579545 / READ_BE_UINT16(data + 20);
char *sound = (char *)malloc(size);
- int vol = (data[24] << 2) | (data[24] >> 4);
+ int vol = (data[24] << 1) | (data[24] >> 5); // if I boost this to 0-255, it gets too loud and starts to clip
memcpy(sound,data + READ_BE_UINT16(data + 8),size);
+ int loopStart = 0, loopEnd = 0;
+ bool looped = false;
if ((READ_BE_UINT16(data + 16) || READ_BE_UINT16(data + 6))) {
- // the first check is for complex (pitch-bending) looped sounds
- // the second check is for simple looped sounds
- int loopStart = READ_BE_UINT16(data + 10) - READ_BE_UINT16(data + 8);
- int loopEnd = READ_BE_UINT16(data + 14);
- int tl = -1;
- if ((_scumm->_gameId == GID_INDY3) && (nr == 60))
- tl = 240; // the "airplane dive" sound needs to end on its own - the game won't stop it
- playSoundSFX(nr, sound, size, rate, vol, tl, true, loopStart, loopEnd);
- } else {
- int tl = 1 + 60 * size / rate;
- playSoundSFX(nr, sound, size, rate, vol, tl, false);
+ loopStart = READ_BE_UINT16(data + 10) - READ_BE_UINT16(data + 8);
+ loopEnd = READ_BE_UINT16(data + 14);
+ looped = true;
}
+ int i = getSfxChan();
+ _sfx[i].id = nr;
+ _sfx[i].dur = looped ? -1 : (1 + 60 * size / rate);
+ if ((_scumm->_gameId == GID_INDY3) && (nr == 60))
+ _sfx[i].dur = 240;
+ _mod->startChannel(nr | 0x100, sound, size, rate, vol, loopStart, loopEnd);
}
}
-void Player_V3A::timerHandler(void *refCon) {
- Player_V3A *player = (Player_V3A *)refCon;
- assert(player);
- player->playMusic();
+void Player_V3A::update_proc(void *param) {
+ ((Player_V3A *)param)->playMusic();
}
void Player_V3A::playMusic() {
int i;
- for (i = 0; i < V3A_MAXSFX; i++) {
- if ((_sfx[i].dur) && (!--_sfx[i].dur))
- stopSound(_sfx[i].id);
- }
for (i = 0; i < V3A_MAXMUS; i++) {
- if ((_mus[i].dur) && (!--_mus[i].dur)) {
- _scumm->_mixer->stopID(V3A_MUS_BASEID + i);
+ if (_mus[i].id) {
+ _mus[i].dur--;
+ if (_mus[i].dur)
+ continue;
+ _mod->stopChannel(_mus[i].id);
_mus[i].id = 0;
- _mus[i].dur = 0;
}
}
+ for (i = 0; i < V3A_MAXSFX; i++) {
+ if (_sfx[i].id) {
+ _sfx[i].dur--;
+ if (_sfx[i].dur)
+ continue;
+ _mod->stopChannel(_sfx[i].id | 0x100);
+ _sfx[i].id = 0;
+ }
+ }
+
_music_timer++;
if (!_curSong)
return;
@@ -295,8 +295,7 @@ void Player_V3A::playMusic() {
}
inst &= 0xF;
pit = _songData[_songPtr++];
- vol = _songData[_songPtr++] & 0x7F;
- vol = (vol << 1) | (vol >> 7); // 7-bit volume (Amiga drops the bottom bit), convert to 8-bit
+ vol = _songData[_songPtr++] & 0x7F; // if I boost this to 0-255, it gets too loud and starts to clip
dur = _songData[_songPtr++];
if (pit == 0) {
_songDelay = dur;
@@ -309,13 +308,18 @@ void Player_V3A::playMusic() {
oct = 0;
if (oct > 5)
oct = 5;
+ int rate = 3579545 / note_freqs[_wavetable[inst]->_oct[oct]][pit];
char *data = (char *)malloc(_wavetable[inst]->_ilen[oct] + _wavetable[inst]->_llen[oct]);
if (_wavetable[inst]->_idat[oct])
memcpy(data, _wavetable[inst]->_idat[oct], _wavetable[inst]->_ilen[oct]);
if (_wavetable[inst]->_ldat[oct])
memcpy(data + _wavetable[inst]->_ilen[oct], _wavetable[inst]->_ldat[oct], _wavetable[inst]->_llen[oct]);
- playSoundMUS(data, _wavetable[inst]->_ilen[oct] + _wavetable[inst]->_llen[oct], 3579545 / note_freqs[_wavetable[inst]->_oct[oct]][pit], vol, dur,
- (_wavetable[inst]->_ldat[oct] != NULL), _wavetable[inst]->_ilen[oct], _wavetable[inst]->_ilen[oct] + _wavetable[inst]->_llen[oct]);
+
+ i = getMusChan();
+ _mus[i].id = i + 1;
+ _mus[i].dur = dur;
+ _mod->startChannel(_mus[i].id, data, _wavetable[inst]->_ilen[oct] + _wavetable[inst]->_llen[oct], rate, vol,
+ _wavetable[inst]->_ilen[oct], _wavetable[inst]->_ilen[oct] + _wavetable[inst]->_llen[oct]);
}
}
@@ -326,8 +330,7 @@ int Player_V3A::getMusicTimer() const {
int Player_V3A::getSoundStatus(int nr) const {
if (nr == _curSong)
return 1;
- for (int i = 0; i < V3A_MAXSFX; i++)
- if (_sfx[i].id == nr)
- return 1;
+ if (getSfxChan(nr) != -1)
+ return 1;
return 0;
}