diff options
-rw-r--r-- | engines/chewy/graphics.cpp | 2 | ||||
-rw-r--r-- | engines/chewy/sound.cpp | 113 | ||||
-rw-r--r-- | engines/chewy/sound.h | 29 | ||||
-rw-r--r-- | engines/chewy/video/cfo_decoder.cpp | 65 | ||||
-rw-r--r-- | engines/chewy/video/cfo_decoder.h | 16 |
5 files changed, 168 insertions, 57 deletions
diff --git a/engines/chewy/graphics.cpp b/engines/chewy/graphics.cpp index de95b11440..5db2a76398 100644 --- a/engines/chewy/graphics.cpp +++ b/engines/chewy/graphics.cpp @@ -115,7 +115,7 @@ void Graphics::drawText(Common::String text, uint x, uint y) { } void Graphics::playVideo(uint num) { - CfoDecoder *cfoDecoder = new CfoDecoder(_vm->_mixer); + CfoDecoder *cfoDecoder = new CfoDecoder(_vm->_sound); VideoResource *videoResource = new VideoResource("cut.tap"); Common::SeekableReadStream *videoStream = videoResource->getVideoStream(num); diff --git a/engines/chewy/sound.cpp b/engines/chewy/sound.cpp index e0e84e2101..5e519f47f9 100644 --- a/engines/chewy/sound.cpp +++ b/engines/chewy/sound.cpp @@ -41,41 +41,112 @@ Sound::~Sound() { delete _speechRes; } -void Sound::playSound(int num, bool loop) { +void Sound::playSound(int num, bool loop, uint channel) { SoundChunk *sound = _soundRes->getSound(num); byte *data = (byte *)malloc(sound->size); memcpy(data, sound->data, sound->size); + playSound(data, sound->size, loop, channel); + + delete[] sound->data; + delete sound; +} + +void Sound::playSound(byte *data, uint32 size, bool loop, uint channel, DisposeAfterUse::Flag dispose) { Audio::AudioStream *stream = Audio::makeLoopingAudioStream( Audio::makeRawStream(data, - sound->size, 22050, Audio::FLAG_UNSIGNED, - DisposeAfterUse::YES), + size, 22050, Audio::FLAG_UNSIGNED, + dispose), loop ? 0 : 1); - _mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundHandle, stream); + _mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundHandle[channel], stream); +} - delete[] sound->data; - delete sound; +void Sound::pauseSound(uint channel) { + assert(channel < MAX_SOUND_EFFECTS); + _mixer->pauseHandle(_soundHandle[channel], true); +} + +void Sound::resumeSound(uint channel) { + assert(channel < MAX_SOUND_EFFECTS); + _mixer->pauseHandle(_soundHandle[channel], false); +} + +void Sound::stopSound(uint channel) { + assert(channel < MAX_SOUND_EFFECTS); + _mixer->stopHandle(_soundHandle[channel]); +} + +bool Sound::isSoundActive(uint channel) { + assert(channel < MAX_SOUND_EFFECTS); + return _mixer->isSoundHandleActive(_soundHandle[channel]); +} + +void Sound::setSoundVolume(uint volume) { + _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, volume); +} + +void Sound::setSoundChannelVolume(uint channel, uint volume) { + assert(channel < MAX_SOUND_EFFECTS); + _mixer->setChannelVolume(_soundHandle[channel], volume); +} + +void Sound::setSoundChannelBalance(uint channel, uint balance) { + assert(channel < MAX_SOUND_EFFECTS); + _mixer->setChannelBalance(_soundHandle[channel], balance); } void Sound::playMusic(int num, bool loop) { uint32 musicNum = _soundRes->getChunkCount() - 1 - num; Chunk *chunk = _soundRes->getChunk(musicNum); byte *data = _soundRes->getChunkData(musicNum); + + playMusic(data, chunk->size, loop); + + delete[] data; + delete chunk; +} + +void Sound::playMusic(byte *data, uint32 size, bool loop, DisposeAfterUse::Flag dispose) { + byte *modData = nullptr; + uint32 modSize; // TODO: TMF music files are similar to MOD files. With the following // incorrect implementation, the PCM parts of these files can be played warning("The current music playing implementation is wrong"); + modSize = size; + modData = (byte *)malloc(modSize); + memcpy(modData, data, size); Audio::AudioStream *stream = Audio::makeLoopingAudioStream( - Audio::makeRawStream(data, - chunk->size, 22050, Audio::FLAG_UNSIGNED, - DisposeAfterUse::YES), + Audio::makeRawStream(modData, + modSize, 22050, Audio::FLAG_UNSIGNED, + dispose), loop ? 0 : 1); _mixer->playStream(Audio::Mixer::kMusicSoundType, &_musicHandle, stream); } +void Sound::pauseMusic() { + _mixer->pauseHandle(_musicHandle, true); +} + +void Sound::resumeMusic() { + _mixer->pauseHandle(_musicHandle, false); +} + +void Sound::stopMusic() { + _mixer->stopHandle(_musicHandle); +} + +bool Sound::isMusicActive() { + return _mixer->isSoundHandleActive(_musicHandle); +} + +void Sound::setMusicVolume(uint volume) { + _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, volume); +} + void Sound::playSpeech(int num) { SoundChunk *sound = _speechRes->getSound(num); byte *data = (byte *)malloc(sound->size); @@ -93,4 +164,28 @@ void Sound::playSpeech(int num) { delete sound; } +void Sound::pauseSpeech() { + _mixer->pauseHandle(_speechHandle, true); +} + +void Sound::resumeSpeech() { + _mixer->pauseHandle(_speechHandle, false); +} + +void Sound::stopSpeech() { + _mixer->stopHandle(_speechHandle); +} + +bool Sound::isSpeechActive() { + return _mixer->isSoundHandleActive(_speechHandle); +} + +void Sound::setSpeechVolume(uint volume) { + _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, volume); +} + +void Sound::stopAll() { + _mixer->stopAll(); +} + } // End of namespace Chewy diff --git a/engines/chewy/sound.h b/engines/chewy/sound.h index 7884eadb63..9b7acab59f 100644 --- a/engines/chewy/sound.h +++ b/engines/chewy/sound.h @@ -30,18 +30,43 @@ namespace Chewy { class SoundResource; +#define MAX_SOUND_EFFECTS 14 + class Sound { public: Sound(Audio::Mixer *mixer); virtual ~Sound(); - void playSound(int num, bool loop = false); + void playSound(int num, bool loop = false, uint channel = 0); + void playSound(byte *data, uint32 size, bool loop = false, uint channel = 0, DisposeAfterUse::Flag dispose = DisposeAfterUse::YES); + void pauseSound(uint channel); + void resumeSound(uint channel); + void stopSound(uint channel); + bool isSoundActive(uint channel); + void setSoundVolume(uint volume); + void setSoundChannelVolume(uint channel, uint volume); + void setSoundChannelBalance(uint channel, uint balance); + void playMusic(int num, bool loop = false); + void playMusic(byte *data, uint32 size, bool loop = false, DisposeAfterUse::Flag dispose = DisposeAfterUse::YES); + void pauseMusic(); + void resumeMusic(); + void stopMusic(); + bool isMusicActive(); + void setMusicVolume(uint volume); + void playSpeech(int num); + void pauseSpeech(); + void resumeSpeech(); + void stopSpeech(); + bool isSpeechActive(); + void setSpeechVolume(uint volume); + + void stopAll(); private: Audio::Mixer *_mixer; - Audio::SoundHandle _soundHandle; + Audio::SoundHandle _soundHandle[MAX_SOUND_EFFECTS]; Audio::SoundHandle _musicHandle; Audio::SoundHandle _speechHandle; diff --git a/engines/chewy/video/cfo_decoder.cpp b/engines/chewy/video/cfo_decoder.cpp index 94363dc1be..30f48d27cd 100644 --- a/engines/chewy/video/cfo_decoder.cpp +++ b/engines/chewy/video/cfo_decoder.cpp @@ -20,15 +20,12 @@ * */ -#include "audio/audiostream.h" -#include "audio/mixer.h" -#include "audio/decoders/raw.h" #include "common/events.h" -#include "common/stream.h" #include "common/system.h" #include "engines/engine.h" #include "video/flic_decoder.h" +#include "chewy/sound.h" #include "chewy/video/cfo_decoder.h" namespace Chewy { @@ -70,12 +67,12 @@ bool CfoDecoder::loadStream(Common::SeekableReadStream *stream) { uint16 width = stream->readUint16LE(); uint16 height = stream->readUint16LE(); - addTrack(new CfoVideoTrack(stream, frameCount, width, height, _mixer)); + addTrack(new CfoVideoTrack(stream, frameCount, width, height, _sound)); return true; } -CfoDecoder::CfoVideoTrack::CfoVideoTrack(Common::SeekableReadStream *stream, uint16 frameCount, uint16 width, uint16 height, Audio::Mixer *mixer) : - Video::FlicDecoder::FlicVideoTrack(stream, frameCount, width, height, true) { +CfoDecoder::CfoVideoTrack::CfoVideoTrack(Common::SeekableReadStream *stream, uint16 frameCount, uint16 width, uint16 height, Sound *sound) : + Video::FlicDecoder::FlicVideoTrack(stream, frameCount, width, height, true), _sound(sound) { readHeader(); for (int i = 0; i < MAX_SOUND_EFFECTS; i++) { @@ -83,15 +80,18 @@ CfoDecoder::CfoVideoTrack::CfoVideoTrack(Common::SeekableReadStream *stream, uin _soundEffectSize[i] = 0; } - _mixer = mixer; + _musicData = nullptr; + _musicSize = 0; } CfoDecoder::CfoVideoTrack::~CfoVideoTrack() { - _mixer->stopAll(); + _sound->stopAll(); for (int i = 0; i < MAX_SOUND_EFFECTS; i++) { delete[] _soundEffects[i]; } + + delete[] _musicData; } void CfoDecoder::CfoVideoTrack::readHeader() { @@ -105,7 +105,7 @@ void CfoDecoder::CfoVideoTrack::readHeader() { #define FRAME_TYPE 0xF1FA #define CUSTOM_FRAME_TYPE 0xFAF1 -const Graphics::Surface *CfoDecoder::CfoVideoTrack::decodeNextFrame() { +const ::Graphics::Surface *CfoDecoder::CfoVideoTrack::decodeNextFrame() { uint16 frameType; // Read chunk @@ -164,7 +164,7 @@ void CfoDecoder::CfoVideoTrack::handleFrame() { /* PSTAMP - skip for now */ break; default: - error("FlicDecoder::decodeNextFrame(): unknown subchunk type (type = 0x%02X)", frameType); + error("CfoDecoder::decodeNextFrame(): unknown subchunk type (type = 0x%02X)", frameType); break; } @@ -176,7 +176,6 @@ void CfoDecoder::CfoVideoTrack::handleCustomFrame() { uint16 chunkCount = _fileStream->readUint16LE(); uint16 delay, number, channel, volume, repeat, balance; - Audio::AudioStream *stream; // Read subchunks for (uint32 i = 0; i < chunkCount; ++i) { @@ -196,9 +195,9 @@ void CfoDecoder::CfoVideoTrack::handleCustomFrame() { break; case kChunkLoadMusic: // Used in videos 0, 18, 34, 71 - warning("kChunkLoadMusic"); - // TODO - _fileStream->skip(frameSize); + _musicSize = frameSize; + _musicData = new byte[frameSize]; + _fileStream->read(_musicData, frameSize); break; case kChunkLoadRaw: error("Unused chunk kChunkLoadRaw found"); @@ -214,9 +213,7 @@ void CfoDecoder::CfoVideoTrack::handleCustomFrame() { break; case kChunkPlayMusic: // Used in videos 0, 18, 34, 71 - warning("kChunkPlayMusic"); - // TODO - _fileStream->skip(frameSize); + _sound->playMusic(_musicData, _musicSize, false, DisposeAfterUse::NO); break; case kChunkPlaySeq: error("Unused chunk kChunkPlaySeq found"); @@ -225,7 +222,11 @@ void CfoDecoder::CfoVideoTrack::handleCustomFrame() { error("Unused chunk kChunkPlayPattern found"); break; case kChunkStopMusic: - _mixer->stopHandle(_musicHandle); + _sound->stopMusic(); + + // Game videos do not restart music after stopping it + delete[] _musicData; + _musicSize = 0; break; case kChunkWaitMusicEnd: do { @@ -233,12 +234,11 @@ void CfoDecoder::CfoVideoTrack::handleCustomFrame() { while (g_system->getEventManager()->pollEvent(event)) {} // ignore events g_system->updateScreen(); g_system->delayMillis(10); - } while (_mixer->isSoundHandleActive(_musicHandle)); + } while (_sound->isMusicActive()); break; case kChunkSetMusicVolume: volume = _fileStream->readUint16LE() * Audio::Mixer::kMaxChannelVolume / 63; - - _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, volume); + _sound->setMusicVolume(volume); break; case kChunkSetLoopMode: error("Unused chunk kChunkSetLoopMode found"); @@ -252,28 +252,19 @@ void CfoDecoder::CfoVideoTrack::handleCustomFrame() { volume = _fileStream->readUint16LE() * Audio::Mixer::kMaxChannelVolume / 63; repeat = _fileStream->readUint16LE(); assert(number < MAX_SOUND_EFFECTS); - assert(channel < MAX_SOUND_EFFECTS); - - stream = Audio::makeLoopingAudioStream( - Audio::makeRawStream(_soundEffects[number], - _soundEffectSize[number], 22050, Audio::FLAG_UNSIGNED, - DisposeAfterUse::NO), - (repeat == 0) ? 1 : repeat); - _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, volume); - _mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundHandle[channel], stream); + _sound->setSoundVolume(volume); + _sound->playSound(_soundEffects[number], _soundEffectSize[number], repeat, channel, DisposeAfterUse::NO); break; case kChunkSetSoundVolume: volume = _fileStream->readUint16LE() * Audio::Mixer::kMaxChannelVolume / 63; - - _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, volume); + _sound->setSoundVolume(volume); break; case kChunkSetChannelVolume: channel = _fileStream->readUint16LE(); volume = _fileStream->readUint16LE() * Audio::Mixer::kMaxChannelVolume / 63; - assert(channel < MAX_SOUND_EFFECTS); - _mixer->setChannelVolume(_soundHandle[channel], volume); + _sound->setSoundChannelVolume(channel, volume); break; case kChunkFreeSoundEffect: number = _fileStream->readUint16LE(); @@ -294,9 +285,7 @@ void CfoDecoder::CfoVideoTrack::handleCustomFrame() { case kChunkSetBalance: channel = _fileStream->readUint16LE(); balance = (_fileStream->readUint16LE() * 2) - 127; - assert(channel < MAX_SOUND_EFFECTS); - - _mixer->setChannelBalance(_soundHandle[channel], balance); + _sound->setSoundChannelBalance(channel, balance); break; case kChunkSetSpeed: error("Unused chunk kChunkSetSpeed found"); diff --git a/engines/chewy/video/cfo_decoder.h b/engines/chewy/video/cfo_decoder.h index b15b00e0b2..26b97ec4ff 100644 --- a/engines/chewy/video/cfo_decoder.h +++ b/engines/chewy/video/cfo_decoder.h @@ -23,7 +23,6 @@ #ifndef CHEWY_VIDEO_CFO_DECODER_H #define CHEWY_VIDEO_CFO_DECODER_H -#include "audio/mixer.h" #include "graphics/surface.h" #include "video/flic_decoder.h" @@ -31,20 +30,22 @@ namespace Chewy { #define MAX_SOUND_EFFECTS 14 +class Sound; + // A FLIC decoder, with a modified header and additional custom frames class CfoDecoder : public Video::FlicDecoder { public: - CfoDecoder(Audio::Mixer *mixer) : Video::FlicDecoder() { _mixer = mixer; } + CfoDecoder(Sound *sound) : Video::FlicDecoder(), _sound(sound) {} virtual ~CfoDecoder() {} bool loadStream(Common::SeekableReadStream *stream); private: - Audio::Mixer *_mixer; + Sound *_sound; class CfoVideoTrack : public Video::FlicDecoder::FlicVideoTrack { public: - CfoVideoTrack(Common::SeekableReadStream *stream, uint16 frameCount, uint16 width, uint16 height, Audio::Mixer *mixer); + CfoVideoTrack(Common::SeekableReadStream *stream, uint16 frameCount, uint16 width, uint16 height, Sound *sound); virtual ~CfoVideoTrack(); void readHeader(); @@ -58,11 +59,12 @@ private: void handleFrame(); void handleCustomFrame(); - Audio::Mixer *_mixer; - Audio::SoundHandle _musicHandle; - Audio::SoundHandle _soundHandle[MAX_SOUND_EFFECTS]; + Sound *_sound; + byte *_soundEffects[MAX_SOUND_EFFECTS]; uint32 _soundEffectSize[MAX_SOUND_EFFECTS]; + byte *_musicData; + uint32 _musicSize; }; }; |