diff options
author | Nicola Mettifogo | 2007-05-01 15:39:40 +0000 |
---|---|---|
committer | Nicola Mettifogo | 2007-05-01 15:39:40 +0000 |
commit | 008042ac2538bebfce013cb0ec4efa4a5600e4bb (patch) | |
tree | 3c1107a6a9323641201a6ebb11960214891c3cc9 /engines | |
parent | d520bdfcb8f70e8fd4448ea404d9e5fa993f23ca (diff) | |
download | scummvm-rg350-008042ac2538bebfce013cb0ec4efa4a5600e4bb.tar.gz scummvm-rg350-008042ac2538bebfce013cb0ec4efa4a5600e4bb.tar.bz2 scummvm-rg350-008042ac2538bebfce013cb0ec4efa4a5600e4bb.zip |
Implemented a IFF (Interchange File Format) parser and added subclasses to parse graphics (ILBM, PBM) and audio (8SVX), thus replacing old decoding routines. SAGA and Parallaction have been adjusted to work with the new code.
svn-id: r26719
Diffstat (limited to 'engines')
-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 | ||||
-rw-r--r-- | engines/saga/scene.cpp | 10 |
9 files changed, 165 insertions, 114 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'; } }; diff --git a/engines/saga/scene.cpp b/engines/saga/scene.cpp index 8311308018..bbe6b92c2b 100644 --- a/engines/saga/scene.cpp +++ b/engines/saga/scene.cpp @@ -45,7 +45,7 @@ #include "saga/rscfile.h" #include "saga/sagaresnames.h" -#include "graphics/ilbm.h" +#include "graphics/iff.h" #include "common/util.h" namespace Saga { @@ -594,7 +594,7 @@ void Scene::loadScene(LoadSceneParams *loadSceneParams) { Event event; Event *q_event; static PalEntry current_pal[PAL_ENTRIES]; - + if ((_vm->getGameType() == GType_IHNM) && (loadSceneParams->chapter != NO_CHAPTER_CHANGE)) { if (loadSceneParams->loadFlag != kLoadBySceneNumber) { error("loadScene wrong usage"); @@ -680,7 +680,7 @@ void Scene::loadScene(LoadSceneParams *loadSceneParams) { _vm->_resource->loadResource(_sceneContext, _resourceList[i].resourceId, _resourceList[i].buffer, _resourceList[i].size); - + if (_resourceList[i].size >= 6) { if (!memcmp(_resourceList[i].buffer, "DUMMY!", 6)) { _resourceList[i].invalid = true; @@ -897,7 +897,7 @@ void Scene::loadScene(LoadSceneParams *loadSceneParams) { void Scene::loadSceneDescriptor(uint32 resourceId) { byte *sceneDescriptorData; size_t sceneDescriptorDataLength; - + memset(&_sceneDescription, 0, sizeof(_sceneDescription)); if (resourceId == 0) { @@ -970,7 +970,7 @@ void Scene::processSceneResources() { SAGAResourceTypes resType; getResourceTypes(types, typesCount); - + // Process the scene resource list for (i = 0; i < _resourceListCount; i++) { if (_resourceList[i].invalid) { |