diff options
-rw-r--r-- | scumm/player_v3a.cpp | 301 | ||||
-rw-r--r-- | scumm/player_v3a.h | 78 |
2 files changed, 379 insertions, 0 deletions
diff --git a/scumm/player_v3a.cpp b/scumm/player_v3a.cpp new file mode 100644 index 0000000000..1bf41f2646 --- /dev/null +++ b/scumm/player_v3a.cpp @@ -0,0 +1,301 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001-2003 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * /scummvm/scumm/player_v3a.cpp + */ + +#include "stdafx.h" +#include "common/engine.h" +#include "player_v3a.h" +#include "scumm.h" +#include "sound/mixer.h" + +unsigned short _notefreqs[4][12] = { + {0x06B0,0x0650,0x05F4,0x05A0,0x054C,0x0500,0x04B8,0x0474,0x0434,0x03F8,0x03C0,0x0388}, + {0x0358,0x0328,0x02FA,0x02D0,0x02A6,0x0280,0x025C,0x023A,0x021A,0x01FC,0x01E0,0x01C4}, + {0x01AC,0x0194,0x017D,0x0168,0x0153,0x0140,0x012E,0x011D,0x010D,0x00FE,0x00F0,0x00E2}, + {0x00D6,0x00CA,0x00BE,0x00B4,0x00A9,0x00A0,0x0097,0x008E,0x0086,0x007F,0x00F0,0x00E2} +}; + +//////////////////////////////////////// +// +// V3 Amiga sound/music driver +// +//////////////////////////////////////// + +Player_V3A::Player_V3A(Scumm *scumm) { + int i; + _scumm = scumm; + _system = scumm->_system; + _mixer = scumm->_mixer; + + for (i = 0; i < V3A_MAXCHANS; i++) + _soundID[i] = _timeleft[i] = 0; + + _curSong = 0; + _songData = NULL; + _songPtr = 0; + _songDelay = 0; + + _music_timer = 0; + + _maxvol = 255; + + _isinit = false; +} + +Player_V3A::~Player_V3A() { + 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]); + } + free(_wavetable[i]); + } + free(_wavetable); +} + +void Player_V3A::set_master_volume (int vol) { + _maxvol = vol; +} + +void Player_V3A::stopAllSounds() { + _curSong = 0; + _songData = NULL; + _songPtr = 0; + _songDelay = 0; + for (int i = 0; i < V3A_MAXCHANS; i++) + if (_soundID[i]) { + _mixer->stopID(_soundID[i]); + _soundID[i] = 0; + _timeleft[i] = 0; + } +} + +void Player_V3A::stopSound(int nr) { + int i; + if (nr == _curSong) { + _curSong = 0; + _songData = NULL; + _songPtr = 0; + _songDelay = 0; + for (i = 0; i < V3A_MAXCHANS; i++) + if ((_soundID[i] >> 8) == nr) + stopSound(_soundID[i--]); + return; + } + for (i = 0; i < V3A_MAXCHANS; i++) { + if (_soundID[i] == nr) + break; + } + if (i == V3A_MAXCHANS) + return; + _mixer->stopID(_soundID[i]); + for (i++; i < V3A_MAXCHANS; i++) + { + _soundID[i - 1] = _soundID[i]; + _timeleft[i - 1] = _timeleft[i]; + } + _soundID[V3A_MAXCHANS - 1] = 0; + _timeleft[V3A_MAXCHANS - 1] = 0; +} + +void Player_V3A::playSound (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_MAXCHANS; i++) + if (!_soundID[i]) + break; + if (i == V3A_MAXCHANS) + { + warning("player_v3a - out of sound channels!"); + return; + } + _soundID[i] = nr; + _timeleft[i] = tl; + + vol = (vol * _maxvol) / 255; + if (looped) + _mixer->playRaw(NULL, data, size, rate, SoundMixer::FLAG_AUTOFREE | SoundMixer::FLAG_LOOP, nr, vol, 0, loopStart, loopEnd); + else _mixer->playRaw(NULL, data, size, rate, SoundMixer::FLAG_AUTOFREE, nr, vol, 0); +} + +void Player_V3A::startSound(int nr, byte *data) { + if (!_isinit) { + int i; + if (_scumm->_gameId == GID_INDY3) { + unsigned char *ptr = _scumm->getResourceAddress(rtSound,83); + int offset = 4; + _wavetable = (instData **)malloc(13 * sizeof(void *)); + for (i = 0; i < 12; i++) { + _wavetable[i] = (instData *)malloc(sizeof(instData)); + for (int j = 0; j < 6; j++) { + int off, len; + off = READ_BE_UINT16(ptr + offset + 0); + _wavetable[i]->_ilen[j] = len = READ_BE_UINT16(ptr + offset + 2); + if (len) { + _wavetable[i]->_idat[j] = (char *)malloc(len); + memcpy(_wavetable[i]->_idat[j],ptr + off,len); + } else _wavetable[i]->_idat[j] = NULL; + off = READ_BE_UINT16(ptr + offset + 4); + _wavetable[i]->_llen[j] = len = READ_BE_UINT16(ptr + offset + 6); + if (len) { + _wavetable[i]->_ldat[j] = (char *)malloc(len); + memcpy(_wavetable[i]->_ldat[j],ptr + off,len); + } else _wavetable[i]->_ldat[j] = NULL; + _wavetable[i]->_oct[j] = READ_BE_UINT16(ptr + offset + 8); + offset += 10; + } + offset += 2; + } + _wavetable[i] = NULL; + } + else if (_scumm->_gameId == GID_LOOM) { + unsigned char *ptr = _scumm->getResourceAddress(rtSound,79); + int offset = 4; + _wavetable = (instData **)malloc(10 * sizeof(void *)); + for (i = 0; i < 9; i++) { + _wavetable[i] = (instData *)malloc(sizeof(instData)); + for (int j = 0; j < 6; j++) { + int off, len; + off = READ_BE_UINT16(ptr + offset + 0); + _wavetable[i]->_ilen[j] = len = READ_BE_UINT16(ptr + offset + 2); + if (len) { + _wavetable[i]->_idat[j] = (char *)malloc(len); + memcpy(_wavetable[i]->_idat[j],ptr + off,len); + } else _wavetable[i]->_idat[j] = NULL; + off = READ_BE_UINT16(ptr + offset + 4); + _wavetable[i]->_llen[j] = len = READ_BE_UINT16(ptr + offset + 6); + if (len) { + _wavetable[i]->_ldat[j] = (char *)malloc(len); + memcpy(_wavetable[i]->_ldat[j],ptr + off,len); + } else _wavetable[i]->_ldat[j] = NULL; + _wavetable[i]->_oct[j] = READ_BE_UINT16(ptr + offset + 8); + offset += 10; + } + offset += 4; + } + _wavetable[i] = NULL; + } + else error("player_v3a - unknown game!"); + _isinit = true; + } + + + if (data[26]) { + stopAllSounds(); + _curSong = nr; + _songData = data; + _songPtr = 0x1C; + _songDelay = 1; + _music_timer = 0; + } else { + if (_curSong) + return; // don't play music and SFX at the same time + if (getSoundStatus(nr)) + stopSound(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); + memcpy(sound,data + READ_BE_UINT16(data + 8),size); + 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; + playSound(nr, sound, size, rate, vol, tl, true, loopStart, loopEnd); + } else { + int tl = 1 + 60 * size / rate; + playSound(nr, sound, size, rate, vol, tl, false); + } + } +} + +void Player_V3A::playMusic() { + int i; + for (i = 0; i < V3A_MAXCHANS; i++) + if ((_timeleft[i]) && (!--_timeleft[i])) + stopSound(_soundID[i--]); + _music_timer++; + if (_songDelay && --_songDelay) + return; + if (!_curSong) + return; + while (1) { + uint8 inst = _songData[_songPtr++]; + if ((inst == 0) || (inst == 0xFC)) { + for (i = 0; i < V3A_MAXCHANS; i++) + if ((_soundID[i] >> 8) == _curSong) + if (_songDelay < _timeleft[i]) + _songDelay = _timeleft[i]; + _curSong = 0; + break; + } + else if (inst == 0xFB) { + _songPtr = 0x1C; + for (i = 0; i < V3A_MAXCHANS; i++) + if ((_soundID[i] >> 8) == _curSong) + if (_songDelay < _timeleft[i]) + _songDelay = _timeleft[i]; + break; + } + uint8 pitch = _songData[_songPtr++]; + uint8 unk = _songData[_songPtr++]; + uint8 dur = _songData[_songPtr++]; + if ((inst == 0x80) && (pitch == 0) && (unk == 0)) { + _songDelay = dur; + break; + } + if (_scumm->_gameId == GID_INDY3) + pitch -= 24; + else if (_scumm->_gameId == GID_LOOM) // Loom music still has a lot of problems + pitch -= 21; // but this adjustment seems to get it mostly right + if (pitch < 0) + pitch = 0; + int pit = pitch % 12; + int oct = (pitch / 12); + if (oct > 5) + oct = 5; + inst &= 0x7F; + 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]); + if (!_lastSample) + _lastSample++; + int id = (_curSong << 8) | _lastSample++; + playSound(id,data,_wavetable[inst]->_ilen[oct] + _wavetable[inst]->_llen[oct],3579545 / _notefreqs[_wavetable[inst]->_oct[oct]][pit],255,dur,(_wavetable[inst]->_ldat[oct] != NULL),_wavetable[inst]->_ilen[oct],_wavetable[inst]->_ilen[oct] + _wavetable[inst]->_llen[oct]); + } +} + +int Player_V3A::getMusicTimer() const { + return _music_timer / 30; +} + +bool Player_V3A::getSoundStatus(int nr) const { + if (nr == _curSong) + return true; + for (int i = 0; i < V3A_MAXCHANS; i++) + if (_soundID[i] == nr) + return true; + return false; +} diff --git a/scumm/player_v3a.h b/scumm/player_v3a.h new file mode 100644 index 0000000000..29bb6faa8b --- /dev/null +++ b/scumm/player_v3a.h @@ -0,0 +1,78 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2003 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * /scummvm/scummvm/scumm/player_v3a.h + * + */ + +#ifndef PLAYER_V3A_H +#define PLAYER_V3A_H + +#include "common/scummsys.h" +#include "common/system.h" + +#define V3A_MAXCHANS 8 + +class Scumm; +class SoundMixer; + +class Player_V3A { +public: + Player_V3A(Scumm *scumm); + virtual ~Player_V3A(); + + virtual void set_master_volume(int vol); + + virtual void startSound(int nr, byte *data); + virtual void stopSound(int nr); + virtual void stopAllSounds(); + virtual int getMusicTimer() const; + + virtual void playMusic(); + virtual bool getSoundStatus(int nr) const; + +protected: + SoundMixer *_mixer; + OSystem *_system; + Scumm *_scumm; + + uint16 _soundID[V3A_MAXCHANS]; + uint16 _timeleft[V3A_MAXCHANS]; + uint8 _maxvol; + + int _curSong; + unsigned char *_songData; + uint16 _songPtr; + uint16 _songDelay; + uint8 _lastSample; + int _music_timer; + bool _isinit; + + struct instData + { + char *_idat[6]; + uint16 _ilen[6]; + char *_ldat[6]; + uint16 _llen[6]; + uint16 _oct[6]; + } **_wavetable; + + void playSound (int nr, char *data, int size, int rate, int vol, int tl, bool looped, int loopStart = 0, int loopEnd = 0); +}; + +#endif |