diff options
Diffstat (limited to 'scumm')
-rw-r--r-- | scumm/debugger.cpp | 2 | ||||
-rw-r--r-- | scumm/module.mk | 8 | ||||
-rw-r--r-- | scumm/player_mod.cpp | 188 | ||||
-rw-r--r-- | scumm/player_mod.h | 77 | ||||
-rw-r--r-- | scumm/player_v2a.cpp | 1307 | ||||
-rw-r--r-- | scumm/player_v2a.h | 66 | ||||
-rw-r--r-- | scumm/player_v3a.cpp | 203 | ||||
-rw-r--r-- | scumm/player_v3a.h | 38 | ||||
-rw-r--r-- | scumm/scumm.h | 2 | ||||
-rw-r--r-- | scumm/scummvm.cpp | 6 | ||||
-rw-r--r-- | scumm/sound.cpp | 24 |
11 files changed, 1774 insertions, 147 deletions
diff --git a/scumm/debugger.cpp b/scumm/debugger.cpp index ea35395804..62c5200493 100644 --- a/scumm/debugger.cpp +++ b/scumm/debugger.cpp @@ -361,7 +361,7 @@ bool ScummDebugger::Cmd_Restart(int argc, const char **argv) { } bool ScummDebugger::Cmd_IMuse(int argc, const char **argv) { - if (!_s->_imuse && !_s->_playerV2) { + if (!_s->_imuse && !_s->_musicEngine) { Debug_Printf("No iMuse engine is active.\n"); return true; } diff --git a/scumm/module.mk b/scumm/module.mk index 9aaafe5b84..dd9d9f0676 100644 --- a/scumm/module.mk +++ b/scumm/module.mk @@ -22,9 +22,11 @@ MODULE_OBJS := \ scumm/midiparser_eup.o \ scumm/nut_renderer.o \ scumm/object.o \ - scumm/player_v1.o\ - scumm/player_v2.o\ - scumm/player_v3a.o\ + scumm/player_mod.o \ + scumm/player_v1.o \ + scumm/player_v2.o \ + scumm/player_v2a.o \ + scumm/player_v3a.o \ scumm/resource.o \ scumm/resource_v2.o \ scumm/resource_v3.o \ diff --git a/scumm/player_mod.cpp b/scumm/player_mod.cpp new file mode 100644 index 0000000000..828fc3ae7a --- /dev/null +++ b/scumm/player_mod.cpp @@ -0,0 +1,188 @@ +/* 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. + * + * $Header$ + * + */ + +#include "player_mod.h" + +//////////////////////////////////////// +// +// Generic Amiga MOD mixer - provides a 60Hz 'update' routine. +// +//////////////////////////////////////// + +Player_MOD::Player_MOD(Scumm *scumm) { + int i; + _mixer = scumm->_mixer; + _samplerate = scumm->_system->property(OSystem::PROP_GET_SAMPLE_RATE, 0); + _mixamt = 0; + _mixpos = 0; + + for (i = 0; i < MOD_MAXCHANS; i++) { + _channels[i].id = 0; + _channels[i].vol = 0; + _channels[i].freq = 0; + _channels[i].ptr = NULL; + _channels[i].converter = NULL; + _channels[i].input = NULL; + } + + _playproc = NULL; + _playparam = NULL; + + _mixer->setupPremix(premix_proc, this); +} + +Player_MOD::~Player_MOD() { + // Detach the premix callback handler + _mixer->setupPremix(0, 0); + for (int i = 0; i < MOD_MAXCHANS; i++) { + if (!_channels[i].id) + continue; + delete _channels[i].ptr; + delete _channels[i].converter; + delete _channels[i].input; + } +} + +void Player_MOD::setMasterVolume (int vol) { + _maxvol = vol; +} + +void Player_MOD::setUpdateProc(ModUpdateProc *proc, void *param, int freq) { + _playproc = proc; + _playparam = param; + _mixamt = _samplerate / freq; +} +void Player_MOD::clearUpdateProc() { + _playproc = NULL; + _playparam = NULL; + _mixamt = 0; +} + +void Player_MOD::startChannel (int id, const char *data, int size, int rate, uint8 vol, int loopStart, int loopEnd, int8 pan) { + int i; + if (id == 0) + error("player_mod - attempted to start channel id 0"); + + for (i = 0; i < MOD_MAXCHANS; i++) { + if (!_channels[i].id) + break; + } + if (i == MOD_MAXCHANS) { + warning("player_mod - too many music channels playing (%i max)",MOD_MAXCHANS); + return; + } + _channels[i].id = id; + _channels[i].vol = vol; + _channels[i].pan = pan; + _channels[i].ptr = (byte *)data; + _channels[i].freq = rate; + _channels[i].input = makeLinearInputStream(SoundMixer::FLAG_AUTOFREE | (loopStart != loopEnd ? SoundMixer::FLAG_LOOP : 0), (byte *)data, size, loopStart, loopEnd - loopStart); + _channels[i].converter = makeRateConverter(rate, _mixer->getOutputRate(), false, false); +} + +void Player_MOD::stopChannel(int id) { + if (id == 0) + 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].ptr; + _channels[i].ptr = NULL; + 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; + } + } +} +void Player_MOD::setChannelVol(int id, uint8 vol) { + if (id == 0) + error("player_mod - attempted to set volume for channel id 0"); + for (int i = 0; i < MOD_MAXCHANS; i++) { + if (_channels[i].id == id) { + _channels[i].vol = vol; + break; + } + } +} + +void Player_MOD::setChannelPan(int id, int8 pan) { + if (id == 0) + error("player_mod - attempted to set pan for channel id 0"); + for (int i = 0; i < MOD_MAXCHANS; i++) { + if (_channels[i].id == id) { + _channels[i].pan = pan; + break; + } + } +} + +void Player_MOD::setChannelFreq(int id, int freq) { + if (id == 0) + error("player_mod - attempted to set frequency for channel id 0"); + for (int i = 0; i < MOD_MAXCHANS; i++) { + if (_channels[i].id == id) { + _channels[i].freq = freq; + delete _channels[i].converter; + _channels[i].converter = makeRateConverter(freq, _mixer->getOutputRate(), false, false); + break; + } + } +} + +void Player_MOD::premix_proc(void *param, int16 *buf, uint len) { + ((Player_MOD *) param)->do_mix(buf, len); +} + +void Player_MOD::do_mix (int16 *data, uint len) { + int i; + int dpos = 0; + uint dlen = 0; + memset(data, 0, 2 * len * sizeof(int16)); + while (len) { + if (_playproc) { + dlen = _mixamt - _mixpos; + if (!_mixpos) + _playproc(_playparam); + if (dlen <= len) { + _mixpos = 0; + len -= dlen; + } else { + _mixpos = _mixamt - len; + dlen = len; + len = 0; + } + } else { + dlen = len; + len = 0; + } + for (i = 0; i < MOD_MAXCHANS; i++) + if (_channels[i].id) { + st_volume_t vol_l = (127 - _channels[i].pan) * _channels[i].vol / 127; + 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); + } + dpos += dlen; + } +} diff --git a/scumm/player_mod.h b/scumm/player_mod.h new file mode 100644 index 0000000000..4310d16f3e --- /dev/null +++ b/scumm/player_mod.h @@ -0,0 +1,77 @@ +/* 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. + * + * $Header$ + * + */ + +#ifndef PLAYER_MOD_H +#define PLAYER_MOD_H + +#include "scumm.h" +#include "sound/mixer.h" +#include "sound/audiostream.h" +#include "sound/rate.h" + +#define MOD_MAXCHANS 16 + +class Player_MOD { +public: + Player_MOD(Scumm *scumm); + virtual ~Player_MOD(); + virtual void setMasterVolume(int vol); + + virtual void startChannel(int id, const char *data, int size, int rate, uint8 vol, int loopStart = 0, int loopEnd = 0, int8 pan = 0); + virtual void stopChannel(int id); + virtual void setChannelVol(int id, uint8 vol); + virtual void setChannelPan(int id, int8 pan); + virtual void setChannelFreq(int id, int freq); + + typedef void ModUpdateProc(void *param); + + virtual void setUpdateProc(ModUpdateProc *proc, void *param, int freq); + virtual void clearUpdateProc(); + +private: + SoundMixer *_mixer; + + uint32 _mixamt; + uint32 _mixpos; + int _samplerate; + + struct soundChan + { + int id; + uint8 vol; + int8 pan; + uint16 freq; + byte *ptr; + RateConverter *converter; + AudioInputStream *input; + } _channels[MOD_MAXCHANS]; + + uint8 _maxvol; + + static void premix_proc(void *param, int16 *buf, uint len); + virtual void do_mix(int16 *buf, uint len); + + ModUpdateProc *_playproc; + void *_playparam; +}; + +#endif diff --git a/scumm/player_v2a.cpp b/scumm/player_v2a.cpp new file mode 100644 index 0000000000..844917d903 --- /dev/null +++ b/scumm/player_v2a.cpp @@ -0,0 +1,1307 @@ +/* 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. + * + * $Header$ + * + */ + +#include "stdafx.h" +#include "base/engine.h" +#include "player_v2a.h" +#include "scumm.h" + +//////////////////////////////////////// +// +// V2 Amiga sound/music driver +// +//////////////////////////////////////// + +static uint32 CRCtable[256]; +static void InitCRC (void) +{ + const uint32 poly = 0xEDB88320; + int i, j; + uint32 n; + for (i = 0; i < 256; i++) + { + n = i; + for (j = 0; j < 8; j++) + n = (n & 1) ? ((n >> 1) ^ poly) : (n >> 1); + CRCtable[i] = n; + } +} +static uint32 GetCRC (byte *data, int len) +{ + uint32 CRC = 0xFFFFFFFF; + int i; + for (i = 0; i < len; i++) + CRC = (CRC >> 8) ^ CRCtable[(CRC ^ data[i]) & 0xFF]; + return CRC ^ 0xFFFFFFFF; +} + +class V2A_Sound { +public: + V2A_Sound() : _id(0), _mod(NULL) { } + virtual void start(Player_MOD *mod, int id, const byte *data) { + warning("player_v2a - sound %i not supported yet", id); + } + virtual bool update() { return false; } + virtual void stop() { } +protected: + int _id; + Player_MOD *_mod; +}; + +class V2A_Sound_Music : public V2A_Sound { // TODO - finish support (use the 'unk' data appropriately) +public: + V2A_Sound_Music(uint16 instoff, uint16 unkoff, uint16 chan1off, uint16 chan2off, uint16 chan3off, uint16 chan4off, uint16 sampoff) : + _instoff(instoff), _unkoff(unkoff), _chan1off(chan1off), _chan2off(chan2off), _chan3off(chan3off), _chan4off(chan4off), _sampoff(sampoff) { } + virtual void start(Player_MOD *mod, int id, const byte *data) { + _mod = mod; + _id = id; + + _data = (char *)malloc(READ_LE_UINT16(data)); + memcpy(_data,data,READ_LE_UINT16(data)); + + _ptr[0] = _chan1off; + _ptr[1] = _chan2off; + _ptr[2] = _chan3off; + _ptr[3] = _chan4off; + _dur[0] = _dur[1] = _dur[2] = _dur[3] = 0; + _ticks = 0; + update(); + } + virtual bool update() { + assert(_id); + int i, j = 0; + for (i = 0; i < 4; i++) { + if ((_dur[i]) && (!--_dur[i])) + _mod->stopChannel(_id | (_chan[i] << 8)); + if (!_ptr[i]) { + j++; + continue; + } + if (READ_BE_UINT16(_data + _ptr[i]) == _ticks) { + if (READ_BE_UINT16(_data + _ptr[i] + 2) == 0xFFFF) { + _ptr[i] = 0; + j++; + continue; + } + int freq = 3579545 / READ_BE_UINT16(_data + _ptr[i] + 2); + _dur[i] = READ_BE_UINT16(_data + _ptr[i] + 4); + _chan[i] = READ_BE_UINT16(_data + _ptr[i] + 6) & 0x3; + int inst = READ_BE_UINT16(_data + _ptr[i] + 8); + _ptr[i] += 16; + int pan; + if ((_chan[i] == 0) || (_chan[i] == 3)) + pan = -127; + else pan = 127; + int size = READ_BE_UINT16(_data + _instoff + (inst << 5) + 0x18); + char *data = (char *)malloc(size); + memcpy(data, _data + _sampoff + READ_BE_UINT16(_data + _instoff + (inst << 5) + 0x14), size); + _mod->startChannel(_id | (_chan[i] << 8), data, size, freq, 0x3F, 0, 0, pan); + } + } + _ticks++; + if (j == 4) + return false; + return true; + } + virtual void stop() { + assert(_id); + for (int i = 0; i < 4; i++) { + if (_dur[i]) + _mod->stopChannel(_id | (_chan[i] << 8)); + } + free(_data); + _id = 0; + } +private: + const uint16 _instoff; + const uint16 _unkoff; + const uint16 _chan1off; + const uint16 _chan2off; + const uint16 _chan3off; + const uint16 _chan4off; + const uint16 _sampoff; + + char *_data; + uint16 _ptr[4]; + uint16 _chan[4]; + uint16 _dur[4]; + int _ticks; +}; + +class V2A_Sound_Single : public V2A_Sound { +public: + V2A_Sound_Single(uint16 offset, uint16 size, uint16 freq, uint8 vol) : + _offset(offset), _size(size), _freq(freq), _vol(vol) { } + virtual void start(Player_MOD *mod, int id, const byte *data) { + _mod = mod; + _id = id; + char *_data = (char *)malloc(_size); + memcpy(_data, data + _offset, _size); + int vol = (_vol << 2) | (_vol >> 4); + _ticks = 1 + (60 * _size * _freq) / 3579545; + _mod->startChannel(_id, _data, _size, 3579545 / _freq, vol, 0, 0); + } + virtual bool update() { + assert(_id); + _ticks--; + if (!_ticks) { + return false; + } + return true; + } + virtual void stop() { + assert(_id); + _mod->stopChannel(_id); + _id = 0; + } +private: + const uint16 _offset; + const uint16 _size; + const uint16 _freq; + const uint8 _vol; + + int _ticks; +}; +class V2A_Sound_SingleLooped : public V2A_Sound { +public: + V2A_Sound_SingleLooped(uint16 offset, uint16 size, uint16 freq, uint8 vol) : + _offset(offset), _size(size), _freq(freq), _vol(vol) { } + virtual void start(Player_MOD *mod, int id, const byte *data) { + _mod = mod; + _id = id; + char *_data = (char *)malloc(_size); + memcpy(_data, data + _offset, _size); + int vol = (_vol << 2) | (_vol >> 4); + _mod->startChannel(_id, _data, _size, 3579545 / _freq, vol, 0, _size); + } + virtual bool update() { + assert(_id); + return true; + } + virtual void stop() { + assert(_id); + _mod->stopChannel(_id); + _id = 0; + } +private: + const uint16 _offset; + const uint16 _size; + const uint16 _freq; + const uint8 _vol; +}; +class V2A_Sound_SingleLoopedIntro : public V2A_Sound { +public: + V2A_Sound_SingleLoopedIntro(uint16 offset, uint16 size, uint16 loopoffset, uint16 loopsize, uint16 freq, uint8 vol) : + _offset(offset), _size(size), _loopoffset(loopoffset), _loopsize(loopsize), _freq(freq), _vol(vol) { } + virtual void start(Player_MOD *mod, int id, const byte *data) { + _mod = mod; + _id = id; + char *_data = (char *)malloc(_size); + memcpy(_data, data + _offset, _size); + int vol = (_vol << 2) | (_vol >> 4); + _mod->startChannel(_id, _data, _size, 3579545 / _freq, vol, _loopoffset, _loopoffset + _loopsize); + } + virtual bool update() { + assert(_id); + return true; + } + virtual void stop() { + assert(_id); + _mod->stopChannel(_id); + _id = 0; + } +private: + const uint16 _offset; + const uint16 _size; + const uint16 _loopoffset; + const uint16 _loopsize; + const uint16 _freq; + const uint8 _vol; +}; +class V2A_Sound_MultiLooped : public V2A_Sound { +public: + V2A_Sound_MultiLooped(uint16 offset, uint16 size, uint16 freq1, uint8 vol1, uint16 freq2, uint8 vol2) : + _offset(offset), _size(size), _freq1(freq1), _vol1(vol1), _freq2(freq2), _vol2(vol2) { } + virtual void start(Player_MOD *mod, int id, const byte *data) { + _mod = mod; + _id = id; + char *_data1 = (char *)malloc(_size); + char *_data2 = (char *)malloc(_size); + memcpy(_data1, data + _offset, _size); + memcpy(_data2, data + _offset, _size); + int vol1 = (_vol1 << 1) | (_vol1 >> 5); + int vol2 = (_vol2 << 1) | (_vol2 >> 5); + _mod->startChannel(_id | 0x000, _data1, _size, 3579545 / _freq1, vol1, 0, _size, -127); + _mod->startChannel(_id | 0x100, _data2, _size, 3579545 / _freq2, vol2, 0, _size, 127); + } + virtual bool update() { + assert(_id); + return true; + } + virtual void stop() { + assert(_id); + _mod->stopChannel(_id | 0x000); + _mod->stopChannel(_id | 0x100); + _id = 0; + } +private: + const uint16 _offset; + const uint16 _size; + const uint16 _freq1; + const uint8 _vol1; + const uint16 _freq2; + const uint8 _vol2; +}; +class V2A_Sound_MultiLoopedDuration : public V2A_Sound { +public: + V2A_Sound_MultiLoopedDuration(uint16 offset, uint16 size, uint16 freq1, uint8 vol1, uint16 freq2, uint8 vol2, uint16 numframes) : + _offset(offset), _size(size), _freq1(freq1), _vol1(vol1), _freq2(freq2), _vol2(vol2), _duration(numframes) { } + virtual void start(Player_MOD *mod, int id, const byte *data) { + _mod = mod; + _id = id; + char *_data1 = (char *)malloc(_size); + char *_data2 = (char *)malloc(_size); + memcpy(_data1, data + _offset, _size); + memcpy(_data2, data + _offset, _size); + int vol1 = (_vol1 << 1) | (_vol1 >> 5); + int vol2 = (_vol2 << 1) | (_vol2 >> 5); + _mod->startChannel(_id | 0x000, _data1, _size, 3579545 / _freq1, vol1, 0, _size, -127); + _mod->startChannel(_id | 0x100, _data2, _size, 3579545 / _freq2, vol2, 0, _size, 127); + _ticks = 0; + } + virtual bool update() { + assert(_id); + _ticks++; + if (_ticks == _duration) + return false; + return true; + } + virtual void stop() { + assert(_id); + _mod->stopChannel(_id | 0x000); + _mod->stopChannel(_id | 0x100); + _id = 0; + } +private: + const uint16 _offset; + const uint16 _size; + const uint16 _freq1; + const uint8 _vol1; + const uint16 _freq2; + const uint8 _vol2; + const uint16 _duration; + + int _ticks; +}; +class V2A_Sound_SingleLoopedPitchbend : public V2A_Sound { +public: + V2A_Sound_SingleLoopedPitchbend(uint16 offset, uint16 size, uint16 freq1, uint16 freq2, uint8 vol, uint8 step) : + _offset(offset), _size(size), _freq1(freq1), _freq2(freq2), _vol(vol), _step(step) { } + virtual void start(Player_MOD *mod, int id, const byte *data) { + _mod = mod; + _id = id; + char *_data = (char *)malloc(_size); + memcpy(_data, data + _offset, _size); + int vol = (_vol << 2) | (_vol >> 4); + _curfreq = _freq1; + _mod->startChannel(_id, _data, _size, 3579545 / _curfreq, vol, 0, _size); + } + virtual bool update() { + assert(_id); + if (_freq1 < _freq2) { + _curfreq += _step; + if (_curfreq > _freq2) + _curfreq = _freq2; + else + _mod->setChannelFreq(_id, 3579545 / _curfreq); + } else { + _curfreq -= _step; + if (_curfreq < _freq2) + _curfreq = _freq2; + else + _mod->setChannelFreq(_id, 3579545 / _curfreq); + } + return true; + } + virtual void stop() { + assert(_id); + _mod->stopChannel(_id); + _id = 0; + } +private: + const uint16 _offset; + const uint16 _size; + const uint16 _freq1; + const uint16 _freq2; + const uint8 _vol; + const uint16 _step; + + uint16 _curfreq; +}; +class V2A_Sound_Special_FastPitchbendDownAndFadeout : public V2A_Sound { +public: + V2A_Sound_Special_FastPitchbendDownAndFadeout(uint16 offset, uint16 size, uint16 freq, uint8 vol) : + _offset(offset), _size(size), _freq(freq), _vol(vol) { } + virtual void start(Player_MOD *mod, int id, const byte *data) { + _mod = mod; + _id = id; + char *_data = (char *)malloc(_size); + memcpy(_data, data + _offset, _size); + _curvol = (_vol << 3) | (_vol >> 3); + _curfreq = _freq; + _mod->startChannel(_id, _data, _size, 3579545 / _curfreq, _curvol, 0, _size); + } + virtual bool update() { + assert(_id); + _curfreq += 2; + _mod->setChannelFreq(_id, 3579545 / _curfreq); + _curvol--; + if (_curvol == 0) + return false; + _mod->setChannelVol(_id, _curvol >> 1); + return true; + } + virtual void stop() { + assert(_id); + _mod->stopChannel(_id); + _id = 0; + } +private: + const uint16 _offset; + const uint16 _size; + const uint16 _freq; + const uint8 _vol; + + uint16 _curfreq; + uint16 _curvol; +}; + +class V2A_Sound_Special_LoopedFadeinFadeout : public V2A_Sound { +public: + V2A_Sound_Special_LoopedFadeinFadeout(uint16 offset, uint16 size, uint16 freq, uint8 fadeinrate, uint8 fadeoutrate) : + _offset(offset), _size(size), _freq(freq), _fade1(fadeinrate), _fade2(fadeoutrate) { } + virtual void start(Player_MOD *mod, int id, const byte *data) { + _mod = mod; + _id = id; + char *_data = (char *)malloc(_size); + memcpy(_data, data + _offset, _size); + _curvol = 1; + _dir = 0; + _mod->startChannel(_id, _data, _size, 3579545 / _freq, 1, 0, _size); + } + virtual bool update() { + assert(_id); + if (_dir == 0) { + _curvol += _fade1; + if (_curvol > 0x3F) { + _curvol = 0x3F; + _dir = 1; + } + } else { + _curvol -= _fade2; + if (_curvol < 1) + return false; + } + _mod->setChannelVol(_id, (_curvol << 2) | (_curvol >> 4)); + return true; + } + virtual void stop() { + assert(_id); + _mod->stopChannel(_id); + _id = 0; + } +private: + const uint16 _offset; + const uint16 _size; + const uint16 _freq; + const uint16 _fade1; + const uint16 _fade2; + + int _curvol; + int _dir; +}; + +class V2A_Sound_Special_MultiLoopedFadeinFadeout : public V2A_Sound { +public: + V2A_Sound_Special_MultiLoopedFadeinFadeout(uint16 offset, uint16 size, uint16 freq1, uint16 freq2, uint8 fadeinrate, uint8 fadeoutrate) : + _offset(offset), _size(size), _freq1(freq1), _freq2(freq2), _fade1(fadeinrate), _fade2(fadeoutrate) { } + virtual void start(Player_MOD *mod, int id, const byte *data) { + _mod = mod; + _id = id; + char *_data1 = (char *)malloc(_size); + char *_data2 = (char *)malloc(_size); + memcpy(_data1, data + _offset, _size); + memcpy(_data2, data + _offset, _size); + _curvol = 1; + _dir = 0; + _mod->startChannel(_id | 0x000, _data1, _size, 3579545 / _freq1, 1, 0, _size, -127); + _mod->startChannel(_id | 0x100, _data2, _size, 3579545 / _freq2, 1, 0, _size, 127); + } + virtual bool update() { + assert(_id); + if (_dir == 0) { + _curvol += _fade1; + if (_curvol > 0x3F) { + _curvol = 0x3F; + _dir = 1; + } + } else { + _curvol -= _fade2; + if (_curvol < 1) + return false; + } + _mod->setChannelVol(_id | 0x000, (_curvol << 1) | (_curvol >> 5)); + _mod->setChannelVol(_id | 0x100, (_curvol << 1) | (_curvol >> 5)); + return true; + } + virtual void stop() { + assert(_id); + _mod->stopChannel(_id | 0x000); + _mod->stopChannel(_id | 0x100); + _id = 0; + } +private: + const uint16 _offset; + const uint16 _size; + const uint16 _freq1; + const uint16 _freq2; + const uint16 _fade1; + const uint16 _fade2; + + int _curvol; + int _dir; +}; + +class V2A_Sound_Special_PitchbendDownThenFadeout : public V2A_Sound { +public: + V2A_Sound_Special_PitchbendDownThenFadeout(uint16 offset, uint16 size, uint16 freq1, uint16 freq2, uint16 step) : + _offset(offset), _size(size), _freq1(freq1), _freq2(freq2), _step(step) { } + virtual void start(Player_MOD *mod, int id, const byte *data) { + _mod = mod; + _id = id; + char *_data = (char *)malloc(_size); + memcpy(_data, data + _offset, _size); + _curfreq = _freq1; + _curvol = 0x3F; + _mod->startChannel(_id, _data, _size, 3579545 / _curfreq, (_curvol << 2) | (_curvol >> 4), 0, _size); + } + virtual bool update() { + assert(_id); + if (_curfreq > _freq2) + _curvol = 0x3F + _freq2 - _curfreq; + if (_curvol < 1) + return false; + _curfreq += _step; + _mod->setChannelFreq(_id, 3579545 / _curfreq); + _mod->setChannelVol(_id, (_curvol << 2) | (_curvol >> 4)); + return true; + } + virtual void stop() { + assert(_id); + _mod->stopChannel(_id); + _id = 0; + } +private: + const uint16 _offset; + const uint16 _size; + const uint16 _freq1; + const uint16 _freq2; + const uint16 _step; + + uint16 _curfreq; + int _curvol; + int _ticks; +}; + +class V2A_Sound_Special_PitchbendDownAndBackUp : public V2A_Sound { +public: + V2A_Sound_Special_PitchbendDownAndBackUp(uint16 offset, uint16 size, uint16 freq1, uint16 freq2, uint16 step, uint8 vol) : + _offset(offset), _size(size), _freq1(freq1), _freq2(freq2), _step(step), _vol(vol) { } + virtual void start(Player_MOD *mod, int id, const byte *data) { + _mod = mod; + _id = id; + char *_data = (char *)malloc(_size); + memcpy(_data, data + _offset, _size); + int vol = (_vol << 2) | (_vol >> 4); + _curfreq = _freq1; + _dir = 2; + _mod->startChannel(_id, _data, _size, 3579545 / _curfreq, vol, 0, _size); + } + virtual bool update() { + assert(_id); + if (_dir == 2) { + _curfreq += _step; + if (_curfreq > _freq2) { + _curfreq = _freq2; + _dir = 1; + } + _mod->setChannelFreq(_id, 3579545 / _curfreq); + } else if (_dir == 1) { + _curfreq -= _step; + if (_curfreq < _freq1) { + _curfreq = _freq1; + _dir = 0; + } + _mod->setChannelFreq(_id, 3579545 / _curfreq); + } + return true; + } + virtual void stop() { + assert(_id); + _mod->stopChannel(_id); + _id = 0; + } +private: + const uint16 _offset; + const uint16 _size; + const uint16 _freq1; + const uint16 _freq2; + const uint16 _step; + const uint8 _vol; + + uint16 _curfreq; + int _dir; +}; + +class V2A_Sound_Special_SlowPitchbendDownAndFadeout : public V2A_Sound { +public: + V2A_Sound_Special_SlowPitchbendDownAndFadeout(uint16 offset, uint16 size, uint16 freq1, uint16 freq2) : + _offset(offset), _size(size), _freq1(freq1), _freq2(freq2) { } + virtual void start(Player_MOD *mod, int id, const byte *data) { + _mod = mod; + _id = id; + char *_data = (char *)malloc(_size); + memcpy(_data, data + _offset, _size); + _curvol = 0x3F; + _curfreq = _freq1; + _mod->startChannel(_id, _data, _size, 3579545 / _curfreq, (_curvol << 2) | (_curvol >> 4), 0, _size); + } + virtual bool update() { + assert(_id); + _curfreq++; + if (!(_curfreq & 3)) + _curvol--; + if ((_curfreq == _freq2) || (_curvol == 0)) + return false; + _mod->setChannelFreq(_id, 3579545 / _curfreq); + _mod->setChannelVol(_id, (_curvol << 2) | (_curvol >> 4)); + return true; + } + virtual void stop() { + assert(_id); + _mod->stopChannel(_id); + _id = 0; + } +private: + const uint16 _offset; + const uint16 _size; + const uint16 _freq1; + const uint16 _freq2; + + uint16 _curfreq; + uint8 _curvol; +}; + +class V2A_Sound_Special_MultiLoopedDurationMulti : public V2A_Sound { +public: + V2A_Sound_Special_MultiLoopedDurationMulti(uint16 offset, uint16 size, uint16 freq1, uint8 vol1, uint16 freq2, uint8 vol2, uint16 numframes, uint8 playwidth, uint8 loopwidth) : + _offset(offset), _size(size), _freq1(freq1), _vol1(vol1), _freq2(freq2), _vol2(vol2), _duration(numframes), _playwidth(playwidth), _loopwidth(loopwidth) { } + virtual void start(Player_MOD *mod, int id, const byte *data) { + _mod = mod; + _id = id; + _data = (char *)malloc(READ_LE_UINT16(data)); + memcpy(_data,data,READ_LE_UINT16(data)); + soundon(); + _ticks = 0; + _loop = 0; + } + virtual bool update() { + assert(_id); + if (_loop == _playwidth) + soundoff(); + if (_loop == _loopwidth) { + _loop = 0; + soundon(); + } + _loop++; + _ticks++; + if (_ticks == _duration) + return false; + return true; + } + virtual void stop() { + assert(_id); + soundoff(); + free(_data); + _id = 0; + } +private: + const uint16 _offset; + const uint16 _size; + const uint16 _freq1; + const uint8 _vol1; + const uint16 _freq2; + const uint8 _vol2; + const uint16 _duration; + const uint8 _playwidth; + const uint8 _loopwidth; + + char *_data; + + int _ticks; + int _loop; + + void soundon() { + char *_data1 = (char *)malloc(_size); + char *_data2 = (char *)malloc(_size); + memcpy(_data1, _data + _offset, _size); + memcpy(_data2, _data + _offset, _size); + int vol1 = (_vol1 << 1) | (_vol1 >> 5); + int vol2 = (_vol2 << 1) | (_vol2 >> 5); + _mod->startChannel(_id | 0x000, _data1, _size, 3579545 / _freq1, vol1, 0, _size, -127); + _mod->startChannel(_id | 0x100, _data2, _size, 3579545 / _freq2, vol2, 0, _size, 127); + } + void soundoff() { + _mod->stopChannel(_id | 0x000); + _mod->stopChannel(_id | 0x100); + } +}; + +class V2A_Sound_Special_SingleDurationMulti : public V2A_Sound { +public: + V2A_Sound_Special_SingleDurationMulti(uint16 offset, uint16 size, uint16 freq, uint8 vol, uint8 loopwidth, uint8 numloops) : + _offset(offset), _size(size), _freq(freq), _vol(vol), _loopwidth(loopwidth), _numloops(numloops) { } + virtual void start(Player_MOD *mod, int id, const byte *data) { + _mod = mod; + _id = id; + _data = (char *)malloc(READ_LE_UINT16(data)); + memcpy(_data,data,READ_LE_UINT16(data)); + soundon(); + _loop = 0; + _loopctr = 0; + } + virtual bool update() { + assert(_id); + _loop++; + if (_loop == _loopwidth) { + _loop = 0; + _loopctr++; + if (_loopctr == _numloops) + return false; + soundoff(); + soundon(); + } + return true; + } + virtual void stop() { + assert(_id); + soundoff(); + free(_data); + _id = 0; + } +private: + const uint16 _offset; + const uint16 _size; + const uint16 _freq; + const uint8 _vol; + const uint8 _loopwidth; + const uint8 _numloops; + + char *_data; + + int _ticks; + int _loop; + int _loopctr; + + void soundon() { + char *_data1 = (char *)malloc(_size); + memcpy(_data1, _data + _offset, _size); + _mod->startChannel(_id, _data1, _size, 3579545 / _freq, (_vol << 2) | (_vol >> 4), 0, 0); + } + void soundoff() { + _mod->stopChannel(_id); + } +}; + +class V2A_Sound_Special_SingleDurationMultiDurations : public V2A_Sound { +public: + V2A_Sound_Special_SingleDurationMultiDurations(uint16 offset, uint16 size, uint16 freq, uint8 vol, uint8 numdurs, uint8 *durations) : + _offset(offset), _size(size), _freq(freq), _vol(vol), _numdurs(numdurs), _durations(durations) { } + virtual void start(Player_MOD *mod, int id, const byte *data) { + _mod = mod; + _id = id; + _data = (char *)malloc(READ_LE_UINT16(data)); + memcpy(_data,data,READ_LE_UINT16(data)); + soundon(); + _curdur = 0; + _ticks = _durations[_curdur]; + } + virtual bool update() { + assert(_id); + _ticks--; + if (!_ticks) { + soundoff(); + soundon(); + _ticks = _durations[_curdur++]; + if (_curdur == _numdurs) + _curdur = 0; + } + return true; + } + virtual void stop() { + assert(_id); + soundoff(); + free(_data); + _id = 0; + } +private: + const uint16 _offset; + const uint16 _size; + const uint16 _freq; + const uint8 _vol; + const uint8 _numdurs; + const uint8 *_durations; + + char *_data; + + int _ticks; + int _curdur; + + void soundon() { + char *_data1 = (char *)malloc(_size); + memcpy(_data1, _data + _offset, _size); + _mod->startChannel(_id, _data1, _size, 3579545 / _freq, (_vol << 2) | (_vol >> 4), 0, 0); + } + void soundoff() { + _mod->stopChannel(_id); + } +}; + +class V2A_Sound_Special_QuadSiren : public V2A_Sound { +public: + V2A_Sound_Special_QuadSiren(uint16 offset1, uint16 size1, uint16 offset2, uint16 size2, uint8 vol) : + _offset1(offset1), _size1(size1), _offset2(offset2), _size2(size2), _vol(vol) { } + virtual void start(Player_MOD *mod, int id, const byte *data) { + _mod = mod; + _id = id; + char *_data1 = (char *)malloc(_size1); + char *_data2 = (char *)malloc(_size2); + char *_data3 = (char *)malloc(_size1); + char *_data4 = (char *)malloc(_size2); + memcpy(_data1, data + _offset1, _size1); + memcpy(_data2, data + _offset2, _size2); + memcpy(_data3, data + _offset1, _size1); + memcpy(_data4, data + _offset2, _size2); + + _freq1 = 0x02D0; + _step1 = -0x000A; + _freq2 = 0x0122; + _step2 = 0x000A; + _freq3 = 0x02BC; + _step3 = -0x0005; + _freq4 = 0x010E; + _step4 = 0x0007; + + _mod->startChannel(_id | 0x000, _data1, _size1, 3579545 / _freq1, _vol, 0, _size1, -127); + _mod->startChannel(_id | 0x100, _data2, _size2, 3579545 / _freq2, _vol, 0, _size2, 127); + _mod->startChannel(_id | 0x200, _data3, _size1, 3579545 / _freq3, _vol, 0, _size1, 127); + _mod->startChannel(_id | 0x300, _data4, _size2, 3579545 / _freq4, _vol, 0, _size2, -127); + } + virtual bool update() { + assert(_id); + updatefreq(_freq1,_step1,0x00AA,0x00FA); + updatefreq(_freq2,_step2,0x019A,0x03B6); + updatefreq(_freq3,_step3,0x00AA,0x00FA); + updatefreq(_freq4,_step4,0x019A,0x03B6); + _mod->setChannelFreq(_id | 0x000, 3579545 / _freq1); + _mod->setChannelFreq(_id | 0x100, 3579545 / _freq2); + _mod->setChannelFreq(_id | 0x200, 3579545 / _freq3); + _mod->setChannelFreq(_id | 0x300, 3579545 / _freq4); + return true; + } + virtual void stop() { + assert(_id); + _mod->stopChannel(_id | 0x000); + _mod->stopChannel(_id | 0x100); + _mod->stopChannel(_id | 0x200); + _mod->stopChannel(_id | 0x300); + _id = 0; + } +private: + const uint16 _offset1; + const uint16 _size1; + const uint16 _offset2; + const uint16 _size2; + const uint8 _vol; + + uint16 _freq1; + int16 _step1; + uint16 _freq2; + int16 _step2; + uint16 _freq3; + int16 _step3; + uint16 _freq4; + int16 _step4; + + void updatefreq (uint16 &freq, int16 &step, uint16 min, uint16 max) { + freq += step; + if (freq <= min) { + freq = min; + step = -step; + } + if (freq >= max) { + freq = max; + step = -step; + } + } +}; + +class V2A_Sound_Special_TwinSirenMulti : public V2A_Sound { +public: + V2A_Sound_Special_TwinSirenMulti(uint16 offset1, uint16 size1, uint16 offset2, uint16 size2, uint16 freq1, uint16 freq2, uint8 vol) : + _offset1(offset1), _size1(size1), _offset2(offset2), _size2(size2), _freq1(freq1), _freq2(freq2), _vol(vol) { } + virtual void start(Player_MOD *mod, int id, const byte *data) { + _mod = mod; + _id = id; + + _data = (char *)malloc(READ_LE_UINT16(data)); + memcpy(_data,data,READ_LE_UINT16(data)); + + char *_data1 = (char *)malloc(_size1); + char *_data2 = (char *)malloc(_size1); + memcpy(_data1, _data + _offset1, _size1); + memcpy(_data2, _data + _offset1, _size1); + + _loopnum = 1; + _step = 2; + _curfreq = _freq1; + + int vol = (_vol << 1) | (_vol >> 5); + _mod->startChannel(_id | 0x000, _data1, _size1, 3579545 / _curfreq, vol, 0, _size1, -127); + _mod->startChannel(_id | 0x100, _data2, _size1, 3579545 / (_curfreq + 3), vol, 0, _size1, 127); + } + virtual bool update() { + assert(_id); + _mod->setChannelFreq(_id | 0x000, 3579545 / _curfreq); + _mod->setChannelFreq(_id | 0x100, 3579545 / (_curfreq + 3)); + _curfreq -= _step; + if (_loopnum == 7) { + if ((3579545 / _curfreq) >= 65536) + return false; + else + return true; + } + if (_curfreq >= _freq2) + return true; + const char steps[8] = {0,2,2,3,4,8,15,2}; + _curfreq = _freq1; + _step = steps[++_loopnum]; + if (_loopnum == 7) { + _mod->stopChannel(_id | 0x000); + _mod->stopChannel(_id | 0x100); + char *_data1 = (char *)malloc(_size2); + char *_data2 = (char *)malloc(_size2); + memcpy(_data1, _data + _offset2, _size2); + memcpy(_data2, _data + _offset2, _size2); + int vol = (_vol << 1) | (_vol >> 5); + _mod->startChannel(_id | 0x000, _data1, _size2, 3579545 / _curfreq, vol, 0, _size2, -127); + _mod->startChannel(_id | 0x100, _data2, _size2, 3579545 / (_curfreq + 3), vol, 0, _size2, 127); + } + return true; + } + virtual void stop() { + assert(_id); + _mod->stopChannel(_id | 0x000); + _mod->stopChannel(_id | 0x100); + free(_data); + _id = 0; + } +private: + const uint16 _offset1; + const uint16 _size1; + const uint16 _offset2; + const uint16 _size2; + const uint16 _freq1; + const uint16 _freq2; + const uint8 _vol; + + char *_data; + int _curfreq; + uint16 _loopnum; + uint16 _step; +}; + +class V2A_Sound_Special_QuadFreqLooped : public V2A_Sound { +public: + V2A_Sound_Special_QuadFreqLooped(uint16 offset, uint16 size, uint16 freq1, uint16 freq2, uint16 freq3, uint16 freq4, uint8 vol) : + _offset(offset), _size(size), _freq1(freq1), _freq2(freq2), _freq3(freq3), _freq4(freq4), _vol(vol) { } + virtual void start(Player_MOD *mod, int id, const byte *data) { + _mod = mod; + _id = id; + char *_data1 = (char *)malloc(_size); + char *_data2 = (char *)malloc(_size); + char *_data3 = (char *)malloc(_size); + char *_data4 = (char *)malloc(_size); + memcpy(_data1, data + _offset, _size); + memcpy(_data2, data + _offset, _size); + memcpy(_data3, data + _offset, _size); + memcpy(_data4, data + _offset, _size); + _mod->startChannel(_id | 0x000, _data1, _size, 3579545 / _freq1, _vol, 0, _size, -127); + _mod->startChannel(_id | 0x100, _data2, _size, 3579545 / _freq2, _vol, 0, _size, 127); + _mod->startChannel(_id | 0x200, _data3, _size, 3579545 / _freq3, _vol, 0, _size, 127); + _mod->startChannel(_id | 0x300, _data4, _size, 3579545 / _freq4, _vol, 0, _size, -127); + } + virtual bool update() { + assert(_id); + return true; + } + virtual void stop() { + assert(_id); + _mod->stopChannel(_id | 0x000); + _mod->stopChannel(_id | 0x100); + _mod->stopChannel(_id | 0x200); + _mod->stopChannel(_id | 0x300); + _id = 0; + } +private: + const uint16 _offset; + const uint16 _size; + const uint16 _freq1; + const uint16 _freq2; + const uint16 _freq3; + const uint16 _freq4; + const uint8 _vol; +}; + +class V2A_Sound_Special_QuadFreqFadeout : public V2A_Sound { +public: + V2A_Sound_Special_QuadFreqFadeout(uint16 offset, uint16 size, uint16 freq1, uint16 freq2, uint16 freq3, uint16 freq4, uint8 vol, uint16 dur) : + _offset(offset), _size(size), _freq1(freq1), _freq2(freq2), _freq3(freq3), _freq4(freq4), _vol(vol), _dur(dur) { } + virtual void start(Player_MOD *mod, int id, const byte *data) { + _mod = mod; + _id = id; + char *_data1 = (char *)malloc(_size); + char *_data2 = (char *)malloc(_size); + char *_data3 = (char *)malloc(_size); + char *_data4 = (char *)malloc(_size); + memcpy(_data1, data + _offset, _size); + memcpy(_data2, data + _offset, _size); + memcpy(_data3, data + _offset, _size); + memcpy(_data4, data + _offset, _size); + _mod->startChannel(_id | 0x000, _data1, _size, 3579545 / _freq1, _vol, 0, _size, -127); + _mod->startChannel(_id | 0x100, _data2, _size, 3579545 / _freq2, _vol, 0, _size, 127); + _mod->startChannel(_id | 0x200, _data3, _size, 3579545 / _freq3, _vol, 0, _size, 127); + _mod->startChannel(_id | 0x300, _data4, _size, 3579545 / _freq4, _vol, 0, _size, -127); + _ticks = _dur; + } + virtual bool update() { + assert(_id); + if (!--_ticks) + return false; + if (_ticks < _vol) { + _mod->setChannelVol(_id | 0x000, _ticks); + _mod->setChannelVol(_id | 0x100, _ticks); + _mod->setChannelVol(_id | 0x200, _ticks); + _mod->setChannelVol(_id | 0x300, _ticks); + } + return true; + } + virtual void stop() { + assert(_id); + _mod->stopChannel(_id | 0x000); + _mod->stopChannel(_id | 0x100); + _mod->stopChannel(_id | 0x200); + _mod->stopChannel(_id | 0x300); + } +private: + const uint16 _offset; + const uint16 _size; + const uint16 _freq1; + const uint16 _freq2; + const uint16 _freq3; + const uint16 _freq4; + const uint8 _vol; + const uint16 _dur; + + int _ticks; +}; + +class V2A_Sound_Special_SingleFadeout : public V2A_Sound { +public: + V2A_Sound_Special_SingleFadeout(uint16 offset, uint16 size, uint16 freq, uint8 vol) : + _offset(offset), _size(size), _freq(freq), _vol(vol) { } + virtual void start(Player_MOD *mod, int id, const byte *data) { + _mod = mod; + _id = id; + char *_data = (char *)malloc(_size); + memcpy(_data, data + _offset, _size); + _curvol = _vol << 2; + _mod->startChannel(_id, _data, _size, 3579545 / _freq, (_curvol << 2) | (_curvol >> 4), 0, _size); + } + virtual bool update() { + assert(_id); + if (!--_curvol) + return false; + _mod->setChannelVol(_id, _curvol); + return true; + } + virtual void stop() { + assert(_id); + _mod->stopChannel(_id); + _id = 0; + } +private: + const uint16 _offset; + const uint16 _size; + const uint16 _freq; + const uint8 _vol; + + int _curvol; +}; + +struct soundObj { + ~soundObj() { delete sound; } + uint32 crc; + V2A_Sound *sound; +} sndobjs[] = { + {0x8FAB08C4,new V2A_Sound_SingleLooped(0x006C,0x2B58,0x016E,0x3F)}, // Maniac 17 + {0xB673160A,new V2A_Sound_SingleLooped(0x006C,0x1E78,0x01C2,0x1E)}, // Maniac 38 + {0x4DB1D0B2,new V2A_Sound_MultiLooped(0x0072,0x1BC8,0x023D,0x3F,0x0224,0x3F)}, // Maniac 20 + {0x754D75EF,new V2A_Sound_Single(0x0076,0x0738,0x01FC,0x3F)}, // Maniac 10 + {0x6E3454AF,new V2A_Sound_Single(0x0076,0x050A,0x017C,0x3F)}, // Maniac 12 + {0x92F0BBB6,new V2A_Sound_Single(0x0076,0x3288,0x012E,0x3F)}, // Maniac 41 + {0xE1B13982,new V2A_Sound_MultiLoopedDuration(0x0078,0x0040,0x007C,0x3F,0x007B,0x3F,0x001E)}, // Maniac 21 + {0x288B16CF,new V2A_Sound_MultiLoopedDuration(0x007A,0x0040,0x007C,0x3F,0x007B,0x3F,0x000A)}, // Maniac 11 + {0xA7565268,new V2A_Sound_MultiLoopedDuration(0x007A,0x0040,0x00F8,0x3F,0x00F7,0x3F,0x000A)}, // Maniac 19 + {0x7D419BFC,new V2A_Sound_MultiLoopedDuration(0x007E,0x0040,0x012C,0x3F,0x0149,0x3F,0x001E)}, // Maniac 22 + {0x1B52280C,new V2A_Sound_Single(0x0098,0x0A58,0x007F,0x32)}, // Maniac 6 + {0x38D4A810,new V2A_Sound_Single(0x0098,0x2F3C,0x0258,0x32)}, // Maniac 7 + {0x09F98FC2,new V2A_Sound_Single(0x0098,0x0A56,0x012C,0x32)}, // Maniac 16 + {0x90440A65,new V2A_Sound_Single(0x0098,0x0208,0x0078,0x28)}, // Maniac 28 + {0x985C76EF,new V2A_Sound_Single(0x0098,0x0D6E,0x00C8,0x32)}, // Maniac 30 + {0x76156137,new V2A_Sound_Single(0x0098,0x2610,0x017C,0x39)}, // Maniac 39 + {0x5D95F88C,new V2A_Sound_Single(0x0098,0x0A58,0x007F,0x1E)}, // Maniac 65 + {0x92D704EA,new V2A_Sound_SingleLoopedIntro(0x009C,0x29BC,0x1BD4,0x0DE8,0x012C,0x3F)}, // Maniac 15 + {0x92F5513C,new V2A_Sound_Single(0x009E,0x0DD4,0x01F4,0x3F)}, // Maniac 13 + {0xCC2F3B5A,new V2A_Sound_Single(0x009E,0x00DE,0x01AC,0x3F)}, // Maniac 43 + {0x153207D3,new V2A_Sound_Single(0x009E,0x0E06,0x02A8,0x3F)}, // Maniac 67 + {0xC4F370CE,new V2A_Sound_Single(0x00AE,0x0330,0x01AC,0x3F)}, // Maniac 8 + {0x928C4BAC,new V2A_Sound_Single(0x00AE,0x08D6,0x01AC,0x3F)}, // Maniac 9 + {0x62D5B11F,new V2A_Sound_Single(0x00AE,0x165C,0x01CB,0x3F)}, // Maniac 27 + {0x3AB22CB5,new V2A_Sound_Single(0x00AE,0x294E,0x012A,0x3F)}, // Maniac 62 + {0x2D70BBE9,new V2A_Sound_SingleLoopedPitchbend(0x00B4,0x1702,0x03E8,0x0190,0x3F,5)}, // Maniac 64 + {0xFA4C1B1C,new V2A_Sound_Special_FastPitchbendDownAndFadeout(0x00B2,0x1702,0x0190,0x3F)}, // Maniac 69 + {0x19D50D67,new V2A_Sound_Special_LoopedFadeinFadeout(0x00B6,0x0020,0x00C8,16,2)}, // Maniac 14 + {0x3E6FBE15,new V2A_Sound_Special_PitchbendDownThenFadeout(0x00B2,0x0010,0x007C,0x016D,1)}, // Maniac 25 + {0x5305753C,new V2A_Sound_Special_PitchbendDownThenFadeout(0x00B2,0x0010,0x007C,0x016D,7)}, // Maniac 36 + {0x28895106,new V2A_Sound_Special_PitchbendDownAndBackUp(0x00C0,0x00FE,0x00E9,0x0111,4,0x0A)}, // Maniac 59 + {0xB641ACF6,new V2A_Sound_Special_SlowPitchbendDownAndFadeout(0x00C8,0x0100,0x00C8,0x01C2)}, // Maniac 61 + {0xE1A91583,new V2A_Sound_Special_MultiLoopedDurationMulti(0x00D0,0x0040,0x007C,0x3F,0x007B,0x3F,0x3C,5,6)}, // Maniac 23 + {0x64816ED5,new V2A_Sound_Special_MultiLoopedDurationMulti(0x00D0,0x0040,0x00BE,0x37,0x00BD,0x37,0x3C,5,6)}, // Maniac 24 + {0x639D72C2,new V2A_Sound_Special_SingleDurationMulti(0x00D0,0x10A4,0x0080,0x3F,0x28,3)}, // Maniac 46 + {0xE8826D92,new V2A_Sound_Special_SingleDurationMultiDurations(0x00EC,0x025A,0x023C,0x3F,8,(uint8 *)"\x20\x41\x04\x21\x08\x10\x13\x07")}, // Maniac 45 + {0xEDFF3D41,new V2A_Sound_Single(0x00F8,0x2ADE,0x01F8,0x3F)}, // Maniac 42 (this should echo, but it's barely noticeable and I don't feel like doing it) + {0x15606D06,new V2A_Sound_Special_QuadSiren(0x0148,0x0020,0x0168,0x0020,0x3F)}, // Maniac 32 + {0x753EAFE3,new V2A_Sound_Special_TwinSirenMulti(0x017C,0x0010,0x018C,0x0020,0x00C8,0x0080,0x3F)}, // Maniac 44 + {0xB1AB065C,new V2A_Sound_Music(0x0032,0x00B2,0x08B2,0x1222,0x1A52,0x23C2,0x3094)}, // Maniac 50 + {0x091F5D9C,new V2A_Sound_Music(0x0032,0x0132,0x0932,0x1802,0x23D2,0x3EA2,0x4F24)}, // Maniac 58 + + {0x8E2C8AB3,new V2A_Sound_SingleLooped(0x005C,0x0F26,0x0168,0x3C)}, // Zak 41 + {0x3792071F,new V2A_Sound_SingleLooped(0x0060,0x1A18,0x06A4,0x3F)}, // Zak 88 + {0xF192EDE9,new V2A_Sound_SingleLooped(0x0062,0x0054,0x01FC,0x1E)}, // Zak 68 + {0xC43B0245,new V2A_Sound_Special_QuadFreqLooped(0x006C,0x166E,0x00C8,0x0190,0x0320,0x0640,0x32)}, // Zak 70 + {0xCEB51670,new V2A_Sound_SingleLooped(0x00AC,0x26DC,0x012C,0x3F)}, // Zak 42 + {0x10347B51,new V2A_Sound_SingleLooped(0x006C,0x00E0,0x0594,0x3F)}, // Zak 18 + {0x9D2FADC0,new V2A_Sound_MultiLooped(0x0072,0x1FC8,0x016A,0x3F,0x01CE,0x3F)}, // Zak 80 + {0xFAD2C676,new V2A_Sound_MultiLooped(0x0076,0x0010,0x0080,0x3F,0x0090,0x3B)}, // Zak 40 + {0x01508B48,new V2A_Sound_Single(0x0076,0x0D8C,0x017C,0x3F)}, // Zak 90 + {0x9C18DC46,new V2A_Sound_Single(0x0076,0x0D8C,0x015E,0x3F)}, // Zak 91 + {0xF98F7EAC,new V2A_Sound_Single(0x0076,0x0D8C,0x0140,0x3F)}, // Zak 92 + {0xC925FBEF,new V2A_Sound_MultiLoopedDuration(0x0080,0x0010,0x0080,0x3F,0x0090,0x3B,0x0168)}, // Zak 53 + {0xCAB35257,new V2A_Sound_Special_QuadFreqFadeout(0x00DA,0x425C,0x023C,0x08F0,0x0640,0x0478,0x3F,0x012C)}, // Zak 101 + {0xA31FE4FD,new V2A_Sound_Single(0x0094,0x036A,0x00E1,0x3F)}, // Zak 97 + {0x0A1AE0F5,new V2A_Sound_Single(0x009E,0x0876,0x0168,0x3F)}, // Zak 5 + {0xD01A66CB,new V2A_Sound_Single(0x009E,0x04A8,0x0168,0x3F)}, // Zak 47 + {0x5497B912,new V2A_Sound_Single(0x009E,0x0198,0x01F4,0x3F)}, // Zak 39 + {0x2B50362F,new V2A_Sound_Single(0x009E,0x09B6,0x023D,0x3F)}, // Zak 67 + {0x7BFB6E72,new V2A_Sound_Single(0x009E,0x0D14,0x0078,0x3F)}, // Zak 69 + {0xB803A792,new V2A_Sound_Single(0x009E,0x2302,0x02BC,0x3F)}, // Zak 78 + {0x7AB82E39,new V2A_Sound_SingleLoopedIntro(0x00A0,0x2A3C,0x1018,0x1A24,0x016E,0x3F)}, // Zak 100 + {0x28057CEC,new V2A_Sound_Single(0x0098,0x0FEC,0x0140,0x32)}, // Zak 63 + {0x1180A2FC,new V2A_Sound_Single(0x0098,0x0F06,0x0190,0x32)}, // Zak 64 + {0x12616755,new V2A_Sound_Single(0x0098,0x14C8,0x023C,0x14)}, // Zak 9 + {0x642723AA,new V2A_Sound_Special_SingleFadeout(0x00A2,0x1702,0x01F4,0x3F)}, // Zak 37 + {0xDEE56848,new V2A_Sound_Single(0x009A,0x0F86,0x0100,0x3F)}, // Zak 93 + {0xF9BE27B8,new V2A_Sound_Special_SingleFadeout(0x011C,0x1704,0x0228,0x3F)}, // Zak 113 + {0xC73487B2,new V2A_Sound_Single(0x00B0,0x18BA,0x0478,0x3F)}, // Zak 81 + {0x32D8F925,new V2A_Sound_Single(0x00B0,0x2E46,0x00F0,0x3F)}, // Zak 94 + {0x988C83A5,new V2A_Sound_Single(0x00B0,0x0DE0,0x025B,0x3F)}, // Zak 106 + {0x8F1E3B3D,new V2A_Sound_Single(0x00B0,0x05FE,0x04E2,0x3F)}, // Zak 107 + {0x0A2A7646,new V2A_Sound_Single(0x00B0,0x36FE,0x016E,0x3F)}, // Zak 43 + {0x6F1FC435,new V2A_Sound_Single(0x00B0,0x2808,0x044C,0x3F)}, // Zak 108 + {0x870EFC29,new V2A_Sound()}, // Zak 55 + {0xED773699,new V2A_Sound_Special_LoopedFadeinFadeout(0x00B4,0x0020,0x012C,8,4)}, // Zak 3 + {0x0BF59774,new V2A_Sound_Special_MultiLoopedFadeinFadeout(0x00BE,0x0020,0x00F8,0x00F7,8,1)}, // Zak 72 + {0x656FFEDE,new V2A_Sound_Special_MultiLoopedFadeinFadeout(0x00BE,0x0020,0x00C4,0x00C3,8,1)}, // Zak 73 + {0xFC4D41E5,new V2A_Sound_Special_MultiLoopedFadeinFadeout(0x00BE,0x0020,0x00A5,0x00A4,8,1)}, // Zak 74 + {0xC0DD2089,new V2A_Sound_Special_MultiLoopedFadeinFadeout(0x00BE,0x0020,0x009C,0x009B,8,1)}, // Zak 75 + {0x627DFD92,new V2A_Sound_Special_MultiLoopedFadeinFadeout(0x00BE,0x0020,0x008B,0x008A,8,1)}, // Zak 76 + {0x703E05C1,new V2A_Sound_Special_MultiLoopedFadeinFadeout(0x00BE,0x0020,0x007C,0x007B,8,1)}, // Zak 77 + {0xB0F77006,new V2A_Sound()}, // Zak 52 + {0x5AE9D6A7,new V2A_Sound()}, // Zak 109 + {0xABE0D3B0,new V2A_Sound()}, // Zak 105 + {0x788CC749,new V2A_Sound()}, // Zak 71 + {0x2E2AB1FA,new V2A_Sound()}, // Zak 99 + {0x1304CF20,new V2A_Sound()}, // Zak 79 + {0xAE68ED91,new V2A_Sound()}, // Zak 54 + {0xA4F40F97,new V2A_Sound()}, // Zak 61 + {0x348F85CE,new V2A_Sound()}, // Zak 62 + {0xD473AB86,new V2A_Sound()}, // Zak 46 + {0x84A0BA90,new V2A_Sound()}, // Zak 110 + {0x92680D9F,new V2A_Sound()}, // Zak 32 + {0xABFFDB02,new V2A_Sound()}, // Zak 86 + {0x41045447,new V2A_Sound()}, // Zak 98 + {0xC8EEBD34,new V2A_Sound()}, // Zak 82 + {0x42F9469F,new V2A_Sound_Music(0x05F6,0x0636,0x0456,0x0516,0x05D6,0x05E6,0x0A36)}, // Zak 96 + {0x038BBD78,new V2A_Sound_Music(0x054E,0x05CE,0x044E,0x04BE,0x052E,0x053E,0x0BCE)}, // Zak 85 + {0x06FFADC5,new V2A_Sound_Music(0x0626,0x0686,0x0466,0x04F6,0x0606,0x0616,0x0C86)}, // Zak 87 + {0xCE20ECF0,new V2A_Sound_Music(0x0636,0x0696,0x0446,0x0576,0x0616,0x0626,0x0E96)}, // Zak 114 + {0xBDA01BB6,new V2A_Sound_Music(0x0678,0x06B8,0x0458,0x0648,0x0658,0x0668,0x0EB8)}, // Zak 33 + {0x59976529,new V2A_Sound_Music(0x088E,0x092E,0x048E,0x05EE,0x074E,0x07EE,0x112E)}, // Zak 49 + {0xED1EED02,new V2A_Sound_Music(0x08D0,0x0950,0x0440,0x07E0,0x08B0,0x08C0,0x1350)}, // Zak 112 + {0x5A16C037,new V2A_Sound_Music(0x634A,0x64CA,0x049A,0x18FA,0x398A,0x511A,0x6CCA)}, // Zak 95 + {0x00000000,NULL} +}; + +static V2A_Sound *findSound (unsigned long crc) { + for (int i = 0; sndobjs[i].crc != 0; i++) { + if (sndobjs[i].crc == crc) + return sndobjs[i].sound; + } + return NULL; +} + +Player_V2A::Player_V2A(Scumm *scumm) { + int i; + _scumm = scumm; + _system = scumm->_system; + + InitCRC(); + + for (i = 0; i < V2A_MAXSLOTS; i++) { + _slot[i].id = 0; + _slot[i].sound = NULL; + } + + _mod = new Player_MOD(scumm); + _mod->setUpdateProc(update_proc, this, 60); +} + +Player_V2A::~Player_V2A() { + delete _mod; +} + +void Player_V2A::setMasterVolume (int vol) { + _mod->setMasterVolume(vol); +} + +int Player_V2A::getSoundSlot (int id) const { + int i; + for (i = 0; i < V2A_MAXSLOTS; i++) { + if (_slot[i].id == id) + break; + } + if (i == V2A_MAXSLOTS) { + if (id == 0) + warning("player_v2a - out of sound slots"); + return -1; + } + return i; +} + +void Player_V2A::stopAllSounds() { + for (int i = 0; i < V2A_MAXSLOTS; i++) { + if (!_slot[i].id) + continue; + _slot[i].sound->stop(); + _slot[i].sound = NULL; + _slot[i].id = 0; + } +} + +void Player_V2A::stopSound(int nr) { + int i; + if (nr == 0) + return; + i = getSoundSlot(nr); + if (i == -1) + return; + _slot[i].sound->stop(); + _slot[i].sound = NULL; + _slot[i].id = 0; +} + +void Player_V2A::startSound(int nr) { + assert(_scumm); + byte *data = _scumm->getResourceAddress(rtSound, nr); + assert(data); + uint32 crc = GetCRC(data + 0x0A,READ_BE_UINT16(data + 0x08)); + V2A_Sound *snd = findSound(crc); + if (snd == NULL) { + warning("player_v2a - sound %i not recognized yet (crc %08X)",nr,crc); + return; + } + stopSound(nr); + int i = getSoundSlot(); + if (i == -1) + return; + _slot[i].id = nr; + _slot[i].sound = snd; + _slot[i].sound->start(_mod,nr,data); +} + +void Player_V2A::update_proc(void *param) { + ((Player_V2A *)param)->updateSound(); +} + +void Player_V2A::updateSound() { + int i; + for (i = 0; i < V2A_MAXSLOTS; i++) { + if ((_slot[i].id) && (!_slot[i].sound->update())) { + _slot[i].sound->stop(); + _slot[i].sound = NULL; + _slot[i].id = 0; + } + } +} + +int Player_V2A::getMusicTimer() const { + return 0; // FIXME - need to keep track of playing music resources +} + +int Player_V2A::getSoundStatus(int nr) const { + for (int i = 0; i < V2A_MAXSLOTS; i++) { + if (_slot[i].id == nr) + return 1; + } + return 0; +} diff --git a/scumm/player_v2a.h b/scumm/player_v2a.h new file mode 100644 index 0000000000..128899683b --- /dev/null +++ b/scumm/player_v2a.h @@ -0,0 +1,66 @@ +/* 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. + * + * $Header$ + * + */ + +#ifndef PLAYER_V2A_H +#define PLAYER_V2A_H + +#include "common/scummsys.h" +#include "common/system.h" +#include "scumm/music.h" +#include "scumm/player_mod.h" + +#define V2A_MAXSLOTS 8 + +class Scumm; +class SoundMixer; + +class V2A_Sound; + +class Player_V2A : public MusicEngine { +public: + Player_V2A(Scumm *scumm); + virtual ~Player_V2A(); + + virtual void setMasterVolume(int vol); + virtual void startSound(int nr); + virtual void stopSound(int nr); + virtual void stopAllSounds(); + virtual int getMusicTimer() const; + virtual int getSoundStatus(int nr) const; + +private: + OSystem *_system; + Scumm *_scumm; + Player_MOD *_mod; + + struct soundSlot + { + int id; + V2A_Sound *sound; + } _slot[V2A_MAXSLOTS]; + int getSoundSlot (int id = 0) const; + + static void update_proc(void *param); + void updateSound(); +}; + +#endif 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; } diff --git a/scumm/player_v3a.h b/scumm/player_v3a.h index e9f2d050d0..020036a2c0 100644 --- a/scumm/player_v3a.h +++ b/scumm/player_v3a.h @@ -26,12 +26,10 @@ #include "common/scummsys.h" #include "common/system.h" #include "scumm/music.h" +#include "scumm/player_mod.h" -#define V3A_MAXMUS 8 -#define V3A_MAXSFX 8 - -#define V3A_MUS_BASEID (1) -#define V3A_SFX_BASEID (V3A_MUS_BASEID + V3A_MAXMUS) +#define V3A_MAXMUS 8 +#define V3A_MAXSFX 8 class Scumm; class SoundMixer; @@ -42,26 +40,31 @@ public: virtual ~Player_V3A(); virtual void setMasterVolume(int vol); - virtual void startSound(int nr); virtual void stopSound(int nr); virtual void stopAllSounds(); virtual int getMusicTimer() const; - virtual int getSoundStatus(int nr) const; -protected: - SoundMixer *_mixer; +private: OSystem *_system; Scumm *_scumm; + Player_MOD *_mod; - struct soundChan + struct musChan { - uint16 id; - uint16 dur; - } _mus[V3A_MAXMUS], _sfx[V3A_MAXSFX]; - - uint8 _maxvol; + int id; + int dur; + } _mus[V3A_MAXMUS]; + int getMusChan (int id = 0) const; + + struct sfxChan + { + int id; + int dur; + // SFX will eventually have pitch bends + } _sfx[V3A_MAXSFX]; + int getSfxChan (int id = 0) const; int _curSong; uint8 *_songData; @@ -80,11 +83,8 @@ protected: int16 _pitadjust; } **_wavetable; - void playSoundSFX (int nr, char *data, int size, int rate, int vol, int tl, bool looped, int loopStart = 0, int loopEnd = 0); - void playSoundMUS (char *data, int size, int rate, int vol, int tl, bool looped, int loopStart = 0, int loopEnd = 0); - + static void update_proc(void *param); void playMusic(); - static void timerHandler(void *engine); }; #endif diff --git a/scumm/scumm.h b/scumm/scumm.h index 2474d81cd4..39932839e2 100644 --- a/scumm/scumm.h +++ b/scumm/scumm.h @@ -43,6 +43,7 @@ class IMuseDigital; class MusicEngine; class NewGui; class Player_V2; +class Player_V2A; class Player_V3A; class Scumm; class ScummDebugger; @@ -260,6 +261,7 @@ public: IMuse *_imuse; IMuseDigital *_imuseDigital; Player_V2 *_playerV2; + Player_V2A *_playerV2A; Player_V3A *_playerV3A; MusicEngine *_musicEngine; Sound *_sound; diff --git a/scumm/scummvm.cpp b/scumm/scummvm.cpp index 4831260dce..6ca8325896 100644 --- a/scumm/scummvm.cpp +++ b/scumm/scummvm.cpp @@ -44,6 +44,7 @@ #include "scumm/object.h" #include "scumm/player_v1.h" #include "scumm/player_v2.h" +#include "scumm/player_v2a.h" #include "scumm/player_v3a.h" #include "scumm/resource.h" #include "scumm/scumm.h" @@ -719,10 +720,13 @@ Scumm::Scumm (GameDetector *detector, OSystem *syst) _imuse = NULL; _imuseDigital = NULL; _playerV2 = NULL; + _playerV2A = NULL; _playerV3A = NULL; _musicEngine = NULL; if (_features & GF_DIGI_IMUSE) { _musicEngine = _imuseDigital = new IMuseDigital(this); + } else if ((_features & GF_AMIGA) && (_version == 2)) { + _musicEngine = _playerV2A = new Player_V2A(this); } else if ((_features & GF_AMIGA) && (_version == 3)) { _musicEngine = _playerV3A = new Player_V3A(this); } else if ((_features & GF_AMIGA) && (_version < 5)) { @@ -1329,6 +1333,8 @@ int Scumm::scummLoop(int delta) { // Covered automatically by the Sound class } else if (_playerV2) { VAR(VAR_MUSIC_TIMER) = _playerV2->getMusicTimer(); + } else if (_playerV2A) { + VAR(VAR_MUSIC_TIMER) = _playerV2A->getMusicTimer(); } else if (_playerV3A) { VAR(VAR_MUSIC_TIMER) = _playerV3A->getMusicTimer(); } else if (_imuse) { diff --git a/scumm/sound.cpp b/scumm/sound.cpp index ef6219e20a..df82552470 100644 --- a/scumm/sound.cpp +++ b/scumm/sound.cpp @@ -25,8 +25,6 @@ #include "bundle.h" #include "imuse.h" #include "imuse_digi.h" -#include "player_v2.h" -#include "player_v3a.h" #include "scumm.h" #include "sound.h" @@ -439,28 +437,6 @@ void Sound::playSound(int soundID) { memcpy(sound,ptr + READ_BE_UINT16(ptr + 8), size); _scumm->_mixer->playRaw(NULL, sound, size, rate, SoundMixer::FLAG_AUTOFREE, soundID, vol, 0); } - else if ((_scumm->_features & GF_AMIGA) && (_scumm->_version <= 2) && READ_BE_UINT16(ptr + 14) == 0x0880) { - size = READ_BE_UINT16(ptr + 6); - int start = READ_BE_UINT16(ptr + 8); - start += 10; - rate = 11000; - int vol = 255; - int i = 0; - - while (i < start) { - if ((READ_BE_UINT16(ptr) == 0x357c) && (READ_BE_UINT16(ptr + 4) == 6)) - rate = 3579545 / READ_BE_UINT16(ptr + 2); - - if ((READ_BE_UINT16(ptr) == 0x357c) && (READ_BE_UINT16(ptr + 4) == 8)) - vol = READ_BE_UINT16(ptr + 2) * 4; - ptr += 2; - i += 2; - } - - sound = (char *)malloc(size); - memcpy(sound, ptr, size); - _scumm->_mixer->playRaw(NULL, sound, size, rate, SoundMixer::FLAG_AUTOFREE, soundID, vol, 0); - } else { if (_scumm->_gameId == GID_MONKEY_VGA || _scumm->_gameId == GID_MONKEY_EGA) { |