diff options
Diffstat (limited to 'engines/parallaction')
-rw-r--r-- | engines/parallaction/callables.cpp | 5 | ||||
-rw-r--r-- | engines/parallaction/disk.cpp | 166 | ||||
-rw-r--r-- | engines/parallaction/disk.h | 7 | ||||
-rw-r--r-- | engines/parallaction/location.cpp | 11 | ||||
-rw-r--r-- | engines/parallaction/music.cpp | 49 | ||||
-rw-r--r-- | engines/parallaction/music.h | 20 | ||||
-rw-r--r-- | engines/parallaction/zone.cpp | 7 | ||||
-rw-r--r-- | engines/parallaction/zone.h | 4 |
8 files changed, 160 insertions, 109 deletions
diff --git a/engines/parallaction/callables.cpp b/engines/parallaction/callables.cpp index 1946737488..1c81534ed6 100644 --- a/engines/parallaction/callables.cpp +++ b/engines/parallaction/callables.cpp @@ -449,7 +449,10 @@ void _c_testResult(void *parm) { } void _c_offSound(void*) { - // TODO: to be implemented + _vm->_soundMan->stopSfx(0); + _vm->_soundMan->stopSfx(1); + _vm->_soundMan->stopSfx(2); + _vm->_soundMan->stopSfx(3); } void _c_startMusic(void*) { diff --git a/engines/parallaction/disk.cpp b/engines/parallaction/disk.cpp index cbedb17e85..d1f237773a 100644 --- a/engines/parallaction/disk.cpp +++ b/engines/parallaction/disk.cpp @@ -22,101 +22,19 @@ #include "common/stdafx.h" +#include "graphics/iff.h" + #include "parallaction/defs.h" #include "parallaction/graphics.h" #include "parallaction/parallaction.h" #include "parallaction/disk.h" #include "parallaction/walk.h" -#include "graphics/ilbm.h" - -namespace Parallaction { - -class RLEStream : public Common::ReadStream { - - Common::ReadStream *_input; - - byte _rembuf[257]; - int32 _wpos; - int32 _rpos; - - int32 _toBeRead; - byte* _dst; - int32 _read; - - void store(byte b) { - if (_toBeRead > 0) { - *_dst++ = b; - _read++; - _wpos = 0; - _rpos = 0; - } else { - assert(_wpos < 257); - _rembuf[_wpos++] = b; - _rpos = 0; - } - - _toBeRead--; - } - - void feed() { - int32 len = MIN(_wpos - _rpos, _toBeRead); - if (len == 0) return; - - memcpy(_dst, _rembuf + _rpos, len); - - _rpos += len; - _read += len; - _toBeRead -= len; - } - - void unpack() { - byte byteRun; - byte idx; - - uint32 i, j; - - while (_toBeRead > 0 && !_input->eos()) { - byteRun = _input->readByte(); - if (byteRun <= 127) { - i = byteRun + 1; - for (j = 0; j < i; j++) { - idx = _input->readByte(); - store(idx); - } - } else if (byteRun != 128) { - i = (256 - byteRun) + 1; - idx = _input->readByte(); - for (j = 0; j < i; j++) { - store(idx); - } - } - } - - } - -public: - RLEStream(Common::ReadStream *input) : _input(input), _wpos(0), _rpos(0) { - } - - ~RLEStream() { - } - - bool eos() const { - return _input->eos() & (_rpos == _wpos); - } - - uint32 read(void *dataPtr, uint32 dataSize) { - _toBeRead = (int32)dataSize; - _dst = (byte*)dataPtr; - _read = 0; - feed(); - unpack(); - return _read; - } - -}; +namespace Audio { + AudioStream *make8SVXStream(Common::ReadStream &input); +} +namespace Parallaction { /* This stream class is just a wrapper around Archive, so @@ -290,7 +208,7 @@ Cnv* DosDisk::loadCnv(const char *filename) { uint32 decsize = numFrames * width * height; byte *data = (byte*)malloc(decsize); - RLEStream decoder(&_resArchive); + Graphics::PackBitsReadStream decoder(_resArchive); decoder.read(data, decsize); return new Cnv(numFrames, width, height, data); @@ -416,7 +334,7 @@ StaticCnv* DosDisk::loadStatic(const char* name) { uint16 size = cnv->_width*cnv->_height; cnv->_data0 = (byte*)malloc(size); - RLEStream decoder(&_resArchive); + Graphics::PackBitsReadStream decoder(_resArchive); decoder.read(cnv->_data0, size); return cnv; @@ -489,7 +407,7 @@ void DosDisk::loadBackground(const char *filename) { byte *path = (byte*)calloc(1, SCREENPATH_WIDTH*SCREEN_HEIGHT); - RLEStream stream(&_resArchive); + Graphics::PackBitsReadStream stream(_resArchive); unpackBackground(&stream, bg, mask, path); _vm->_gfx->setBackground(bg); @@ -580,6 +498,16 @@ Common::ReadStream* DosDisk::loadMusic(const char* name) { return stream; } + +Common::ReadStream* DosDisk::loadSound(const char* name) { + return NULL; +} + + + + + + #pragma mark - @@ -746,7 +674,6 @@ public: - AmigaDisk::AmigaDisk(Parallaction *vm) : Disk(vm) { } @@ -1020,18 +947,42 @@ class BackgroundDecoder : public Graphics::ILBMDecoder { uint32 _i; protected: - void readCRNG() { - _range[_i]._timer = _chunk.readUint16(); - _range[_i]._step = _chunk.readUint16(); - _range[_i]._flags = _chunk.readUint16(); - _range[_i]._first = _chunk.readByte(); - _range[_i]._last = _chunk.readByte(); + void readCRNG(Common::IFFChunk &chunk) { + _range[_i]._timer = chunk.readUint16BE(); + _range[_i]._step = chunk.readUint16BE(); + _range[_i]._flags = chunk.readUint16BE(); + _range[_i]._first = chunk.readByte(); + _range[_i]._last = chunk.readByte(); _i++; } public: - BackgroundDecoder(Common::ReadStream &input, PaletteFxRange *range) : ILBMDecoder(input), _range(range), _i(0) { + BackgroundDecoder(Common::ReadStream &input, Graphics::Surface &surface, byte *&colors, PaletteFxRange *range) : + Graphics::ILBMDecoder(input, surface, colors), _range(range), _i(0) { + } + + void decode() { + Common::IFFChunk *chunk; + while ((chunk = nextChunk()) != 0) { + switch (chunk->id) { + case ID_BMHD: + readBMHD(*chunk); + break; + + case ID_CMAP: + readCMAP(*chunk); + break; + + case ID_BODY: + readBODY(*chunk); + break; + + case ID_CRNG: + readCRNG(*chunk); + break; + } + } } uint32 getNumRanges() { @@ -1043,12 +994,12 @@ public: void AmigaDisk::loadBackground(const char *name) { Common::SeekableReadStream *s = openArchivedFile(name, true); - BackgroundDecoder decoder(*s, _vm->_gfx->_palettefx); Graphics::Surface surf; byte *pal; + BackgroundDecoder decoder(*s, surf, pal, _vm->_gfx->_palettefx); + decoder.decode(); - decoder.decode(surf, pal); for (uint32 i = 0; i < BASE_PALETTE_COLORS * 3; i++) _vm->_gfx->_palette[i] = pal[i] >> 2; free(pal); @@ -1082,7 +1033,7 @@ void AmigaDisk::loadMask(const char *name) { s->seek(0x126, SEEK_SET); // HACK: skipping IFF/ILBM header should be done by analysis, not magic - RLEStream stream(s); + Graphics::PackBitsReadStream stream(*s); byte *buf = (byte*)malloc(SCREENMASK_WIDTH*SCREEN_HEIGHT); stream.read(buf, SCREENMASK_WIDTH*SCREEN_HEIGHT); @@ -1106,7 +1057,7 @@ void AmigaDisk::loadPath(const char *name) { s->seek(0x120, SEEK_SET); // HACK: skipping IFF/ILBM header should be done by analysis, not magic - RLEStream stream(s); + Graphics::PackBitsReadStream stream(*s); byte *buf = (byte*)malloc(SCREENPATH_WIDTH*SCREEN_HEIGHT); stream.read(buf, SCREENPATH_WIDTH*SCREEN_HEIGHT); setPath(buf); @@ -1171,5 +1122,14 @@ Common::ReadStream* AmigaDisk::loadMusic(const char* name) { return openArchivedFile(name); } +Common::ReadStream* AmigaDisk::loadSound(const char* name) { + char path[PATH_LEN]; + sprintf(path, "%s.snd", name); + + openArchivedFile(path); + + return new DummyArchiveStream(_resArchive); +} + } // namespace Parallaction diff --git a/engines/parallaction/disk.h b/engines/parallaction/disk.h index ea3ad6523f..14c671b02b 100644 --- a/engines/parallaction/disk.h +++ b/engines/parallaction/disk.h @@ -26,6 +26,10 @@ #include "parallaction/defs.h" #include "common/file.h" +namespace Audio { + class AudioStream; +} + namespace Parallaction { //------------------------------------------------------ @@ -112,6 +116,7 @@ public: virtual void loadScenery(const char* background, const char* mask) = 0; virtual Table* loadTable(const char* name) = 0; virtual Common::ReadStream* loadMusic(const char* name) = 0; + virtual Common::ReadStream* loadSound(const char* name) = 0; }; class DosDisk : public Disk { @@ -147,6 +152,7 @@ public: void loadScenery(const char* background, const char* mask); Table* loadTable(const char* name); Common::ReadStream* loadMusic(const char* name); + Common::ReadStream* loadSound(const char* name); }; class AmigaDisk : public Disk { @@ -178,6 +184,7 @@ public: void loadScenery(const char* background, const char* mask); Table* loadTable(const char* name); Common::ReadStream* loadMusic(const char* name); + Common::ReadStream* loadSound(const char* name); }; } // namespace Parallaction diff --git a/engines/parallaction/location.cpp b/engines/parallaction/location.cpp index c0c2d8cad5..3c76021097 100644 --- a/engines/parallaction/location.cpp +++ b/engines/parallaction/location.cpp @@ -154,6 +154,10 @@ void Parallaction::parseLocation(const char *filename) { if (getPlatform() == Common::kPlatformAmiga) _soundMan->setMusicFile(_tokens[1]); } + if (!scumm_stricmp(_tokens[0], "SOUND")) { +// if (getPlatform() == Common::kPlatformAmiga) +// _soundMan->loadSfx(_tokens[1], atoi(_tokens[2])); + } fillBuffers(*_locationScript, true); } @@ -181,6 +185,11 @@ void Parallaction::resolveLocationForwards() { void Parallaction::freeLocation() { debugC(7, kDebugLocation, "freeLocation"); + _soundMan->stopSfx(0); + _soundMan->stopSfx(1); + _soundMan->stopSfx(2); + _soundMan->stopSfx(3); + if (_localFlagNames) delete _localFlagNames; _localFlagNames = new Table(120); @@ -413,6 +422,8 @@ void Parallaction::changeLocation(char *location) { debugC(1, kDebugLocation, "changeLocation: location acommands run"); } +// _soundMan->playSfx(0); + debugC(1, kDebugLocation, "changeLocation completed"); return; diff --git a/engines/parallaction/music.cpp b/engines/parallaction/music.cpp index e637e84569..8398bd7729 100644 --- a/engines/parallaction/music.cpp +++ b/engines/parallaction/music.cpp @@ -307,6 +307,53 @@ AmigaSoundMan::~AmigaSoundMan() { stopMusic(); } +void AmigaSoundMan::playSfx(const char *filename, uint channel, bool looping, int volume, int rate) { + if (channel < 0 || channel >= NUM_AMIGA_CHANNELS) { + warning("unknown sfx channel"); + return; + } + + Channel *ch = &_channels[channel]; + Common::ReadStream *stream = _vm->_disk->loadSound(filename); + Audio::A8SVXDecoder decoder(*stream, ch->header, ch->data, ch->dataSize); + decoder.decode(); + delete stream; + + uint32 loopStart, loopEnd, flags; + if (looping) { + // the standard way to loop 8SVX audio implies use of the oneShotHiSamples and + // repeatHiSamples fields, but Nippon Safes handles loops according to flags + // set in its location scripts and always operates on the whole data. + loopStart = 0; + loopEnd = ch->header.oneShotHiSamples + ch->header.repeatHiSamples; + flags = Audio::Mixer::FLAG_LOOP; + } else { + loopStart = loopEnd = 0; + flags = 0; + } + + if (volume == -1) { + volume = ch->header.volume; + } + + if (rate == -1) { + rate = ch->header.samplesPerSec; + } + + _mixer->playRaw(Audio::Mixer::kSFXSoundType, &ch->handle, ch->data, ch->dataSize, rate, flags, -1, volume, 0, loopStart, loopEnd); +} + +void AmigaSoundMan::stopSfx(uint channel) { + if (channel < 0 || channel >= NUM_AMIGA_CHANNELS) { + warning("unknown sfx channel"); + return; + } + + _mixer->stopHandle(_channels[channel].handle); + free(_channels[channel].data); + _channels[channel].data = 0; +} + void AmigaSoundMan::playMusic() { stopMusic(); @@ -314,7 +361,7 @@ void AmigaSoundMan::playMusic() { _musicStream = Audio::makeProtrackerStream(stream); delete stream; - _mixer->playInputStream(Audio::Mixer::kMusicSoundType, &_musicHandle, _musicStream, -1, 255, 0, false, true); + _mixer->playInputStream(Audio::Mixer::kMusicSoundType, &_musicHandle, _musicStream, -1, 255, 0, false, false); } void AmigaSoundMan::stopMusic() { diff --git a/engines/parallaction/music.h b/engines/parallaction/music.h index bfb74fa38f..ae2f9c8716 100644 --- a/engines/parallaction/music.h +++ b/engines/parallaction/music.h @@ -27,6 +27,7 @@ #include "common/mutex.h" #include "sound/audiostream.h" +#include "sound/iff.h" #include "sound/mixer.h" #include "sound/mididrv.h" @@ -50,14 +51,14 @@ public: SoundMan(Parallaction *vm); virtual ~SoundMan() {} - void setMusicFile(const char *filename); + virtual void playSfx(const char *filename, uint channel, bool looping, int volume = -1, int rate = -1) { } + virtual void stopSfx(uint channel) { } + void setMusicFile(const char *filename); virtual void playMusic() = 0; virtual void stopMusic() = 0; - virtual void playCharacterMusic(const char *character) = 0; virtual void playLocationMusic(const char *location) = 0; - void setMusicVolume(int value); }; @@ -76,17 +77,30 @@ public: void playLocationMusic(const char *location); }; +#define NUM_AMIGA_CHANNELS 4 + class AmigaSoundMan : public SoundMan { Audio::AudioStream *_musicStream; Audio::SoundHandle _musicHandle; + struct Channel { + Audio::Voice8Header header; + byte *data; + uint32 dataSize; + Audio::SoundHandle handle; + uint32 flags; + } _channels[NUM_AMIGA_CHANNELS]; + public: AmigaSoundMan(Parallaction *vm); ~AmigaSoundMan(); void playMusic(); void stopMusic(); + void playSfx(const char *filename, uint channel, bool looping, int volume, int rate); + void stopSfx(uint channel); + void playCharacterMusic(const char *character); void playLocationMusic(const char *location); }; diff --git a/engines/parallaction/zone.cpp b/engines/parallaction/zone.cpp index f3cb12f7ca..03ac70fe7d 100644 --- a/engines/parallaction/zone.cpp +++ b/engines/parallaction/zone.cpp @@ -26,6 +26,7 @@ #include "parallaction/graphics.h" #include "parallaction/inventory.h" #include "parallaction/zone.h" +#include "parallaction/music.h" namespace Parallaction { @@ -271,6 +272,10 @@ void Parallaction::parseZoneTypeBlock(Script &script, Zone *z) { case kZoneHear: // hear Zone init if (!scumm_stricmp(_tokens[0], "sound")) { strcpy(u->hear->_name, _tokens[1]); + z->u.hear->_channel = atoi(_tokens[2]); + } + if (!scumm_stricmp(_tokens[0], "freq")) { + z->u.hear->_freq = atoi(_tokens[1]); } break; @@ -400,7 +405,7 @@ uint16 Parallaction::runZone(Zone *z) { break; case kZoneHear: - strcpy(_soundFile, z->u.hear->_name); + _soundMan->playSfx(z->u.hear->_name, z->u.hear->_channel, (z->_flags & kFlagsLooping) == kFlagsLooping, 60); break; case kZoneSpeak: diff --git a/engines/parallaction/zone.h b/engines/parallaction/zone.h index 559eedb0fe..707f24f7f2 100644 --- a/engines/parallaction/zone.h +++ b/engines/parallaction/zone.h @@ -147,8 +147,12 @@ struct DoorData { // size = 28 }; struct HearData { // size = 20 char _name[20]; + int _channel; + int _freq; HearData() { + _channel = -1; + _freq = -1; _name[0] = '\0'; } }; |