diff options
author | Max Horn | 2006-02-11 22:45:04 +0000 |
---|---|---|
committer | Max Horn | 2006-02-11 22:45:04 +0000 |
commit | 26ee630756ebdd7c96bccede0881a8c8b98e8f2b (patch) | |
tree | 26e378d5cf990a2b81c2c96e9e683a7f333b62e8 /engines/scumm/imuse_digi/dimuse.cpp | |
parent | 2a9a0d4211b1ea5723f1409d91cb95de8984429e (diff) | |
download | scummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.tar.gz scummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.tar.bz2 scummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.zip |
Moved engines to the new engines/ directory
svn-id: r20582
Diffstat (limited to 'engines/scumm/imuse_digi/dimuse.cpp')
-rw-r--r-- | engines/scumm/imuse_digi/dimuse.cpp | 412 |
1 files changed, 412 insertions, 0 deletions
diff --git a/engines/scumm/imuse_digi/dimuse.cpp b/engines/scumm/imuse_digi/dimuse.cpp new file mode 100644 index 0000000000..c057cc8d85 --- /dev/null +++ b/engines/scumm/imuse_digi/dimuse.cpp @@ -0,0 +1,412 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + */ + +#include "common/stdafx.h" +#include "common/system.h" +#include "common/timer.h" + +#include "scumm/actor.h" +#include "scumm/saveload.h" +#include "scumm/scumm.h" +#include "scumm/sound.h" +#include "scumm/imuse_digi/dimuse.h" +#include "scumm/imuse_digi/dimuse_bndmgr.h" + +#include "sound/audiostream.h" +#include "sound/mixer.h" + +namespace Scumm { + +IMuseDigital::Track::Track() + : soundId(-1), used(false), stream(NULL), stream2(NULL) { +} + +void IMuseDigital::timer_handler(void *refCon) { + IMuseDigital *imuseDigital = (IMuseDigital *)refCon; + imuseDigital->callback(); +} + +IMuseDigital::IMuseDigital(ScummEngine *scumm, int fps) + : _vm(scumm) { + _pause = false; + _sound = new ImuseDigiSndMgr(_vm); + _callbackFps = fps; + resetState(); + for (int l = 0; l < MAX_DIGITAL_TRACKS + MAX_DIGITAL_FADETRACKS; l++) { + _track[l] = new Track; + _track[l]->trackId = l; + _track[l]->used = false; + } + _vm->_timer->installTimerProc(timer_handler, 1000000 / _callbackFps, this); + + _audioNames = NULL; + _numAudioNames = 0; +} + +IMuseDigital::~IMuseDigital() { + stopAllSounds(); + _vm->_timer->removeTimerProc(timer_handler); + for (int l = 0; l < MAX_DIGITAL_TRACKS + MAX_DIGITAL_FADETRACKS; l++) { + delete _track[l]; + } + delete _sound; + free(_audioNames); +} + +void IMuseDigital::resetState() { + _curMusicState = 0; + _curMusicSeq = 0; + _curMusicCue = 0; + memset(_attributes, 0, sizeof(_attributes)); + _nextSeqToPlay = 0; +} + +void IMuseDigital::saveOrLoad(Serializer *ser) { + Common::StackLock lock(_mutex, "IMuseDigital::saveOrLoad()"); + + const SaveLoadEntry mainEntries[] = { + MK_OBSOLETE(IMuseDigital, _volVoice, sleInt32, VER(31), VER(42)), + MK_OBSOLETE(IMuseDigital, _volSfx, sleInt32, VER(31), VER(42)), + MK_OBSOLETE(IMuseDigital, _volMusic, sleInt32, VER(31), VER(42)), + MKLINE(IMuseDigital, _curMusicState, sleInt32, VER(31)), + MKLINE(IMuseDigital, _curMusicSeq, sleInt32, VER(31)), + MKLINE(IMuseDigital, _curMusicCue, sleInt32, VER(31)), + MKLINE(IMuseDigital, _nextSeqToPlay, sleInt32, VER(31)), + MKARRAY(IMuseDigital, _attributes[0], sleInt32, 188, VER(31)), + MKEND() + }; + + const SaveLoadEntry trackEntries[] = { + MKLINE(Track, pan, sleInt8, VER(31)), + MKLINE(Track, vol, sleInt32, VER(31)), + MKLINE(Track, volFadeDest, sleInt32, VER(31)), + MKLINE(Track, volFadeStep, sleInt32, VER(31)), + MKLINE(Track, volFadeDelay, sleInt32, VER(31)), + MKLINE(Track, volFadeUsed, sleByte, VER(31)), + MKLINE(Track, soundId, sleInt32, VER(31)), + MKARRAY(Track, soundName[0], sleByte, 15, VER(31)), + MKLINE(Track, used, sleByte, VER(31)), + MKLINE(Track, toBeRemoved, sleByte, VER(31)), + MKLINE(Track, souStream, sleByte, VER(31)), + MKLINE(Track, started, sleByte, VER(31)), + MKLINE(Track, priority, sleInt32, VER(31)), + MKLINE(Track, regionOffset, sleInt32, VER(31)), + MK_OBSOLETE(Track, trackOffset, sleInt32, VER(31), VER(31)), + MKLINE(Track, dataOffset, sleInt32, VER(31)), + MKLINE(Track, curRegion, sleInt32, VER(31)), + MKLINE(Track, curHookId, sleInt32, VER(31)), + MKLINE(Track, volGroupId, sleInt32, VER(31)), + MKLINE(Track, soundType, sleInt32, VER(31)), + MKLINE(Track, iteration, sleInt32, VER(31)), + MKLINE(Track, mod, sleInt32, VER(31)), + MKLINE(Track, mixerFlags, sleInt32, VER(31)), + MK_OBSOLETE(Track, mixerVol, sleInt32, VER(31), VER(42)), + MK_OBSOLETE(Track, mixerPan, sleInt32, VER(31), VER(42)), + MKLINE(Track, compressed, sleByte, VER(45)), + MKEND() + }; + + ser->saveLoadEntries(this, mainEntries); + + for (int l = 0; l < MAX_DIGITAL_TRACKS + MAX_DIGITAL_FADETRACKS; l++) { + Track *track = _track[l]; + if (!ser->isSaving()) { + track->compressed = false; + } + ser->saveLoadEntries(track, trackEntries); + if (!ser->isSaving()) { + if (!track->used) + continue; + track->readyToRemove = false; + if ((track->toBeRemoved) || (track->souStream) || (track->curRegion == -1)) { + track->stream2 = NULL; + track->stream = NULL; + track->used = false; + continue; + } + + track->soundHandle = _sound->openSound(track->soundId, + track->soundName, track->soundType, + track->volGroupId, -1); + if (!track->soundHandle) { + warning("IMuseDigital::saveOrLoad: Can't open sound so will not be resumed, propably on diffrent CD"); + track->stream2 = NULL; + track->stream = NULL; + track->used = false; + continue; + } + + if (track->compressed) { + track->regionOffset = 0; + } + track->compressed = _sound->isCompressed(track->soundHandle); + if (track->compressed) { + track->regionOffset = 0; + } + track->dataOffset = _sound->getRegionOffset(track->soundHandle, track->curRegion); + int bits = _sound->getBits(track->soundHandle); + int channels = _sound->getChannels(track->soundHandle); + int freq = _sound->getFreq(track->soundHandle); + track->iteration = freq * channels; + track->mixerFlags = 0; + if (channels == 2) + track->mixerFlags = Audio::Mixer::FLAG_STEREO | Audio::Mixer::FLAG_REVERSE_STEREO; + + if ((bits == 12) || (bits == 16)) { + track->mixerFlags |= Audio::Mixer::FLAG_16BITS; + track->iteration *= 2; + } else if (bits == 8) { + track->mixerFlags |= Audio::Mixer::FLAG_UNSIGNED; + } else + error("IMuseDigital::saveOrLoad(): Can't handle %d bit samples", bits); + +#ifdef SCUMM_LITTLE_ENDIAN + if (track->compressed) + track->mixerFlags |= Audio::Mixer::FLAG_LITTLE_ENDIAN; +#endif + + int32 streamBufferSize = track->iteration; + track->stream2 = NULL; + track->stream = makeAppendableAudioStream(freq, track->mixerFlags, streamBufferSize); + + const int pan = (track->pan != 64) ? 2 * track->pan - 127 : 0; + const int vol = track->vol / 1000; + Audio::Mixer::SoundType type = Audio::Mixer::kPlainSoundType; + + if (track->volGroupId == 1) + type = Audio::Mixer::kSpeechSoundType; + if (track->volGroupId == 2) + type = Audio::Mixer::kSFXSoundType; + if (track->volGroupId == 3) + type = Audio::Mixer::kMusicSoundType; + + _vm->_mixer->playInputStream(type, &track->handle, track->stream, -1, vol, pan, false); + } + } +} + +void IMuseDigital::callback() { + Common::StackLock lock(_mutex, "IMuseDigital::callback()"); + + for (int l = 0; l < MAX_DIGITAL_TRACKS + MAX_DIGITAL_FADETRACKS; l++) { + Track *track = _track[l]; + if (track->used && !track->readyToRemove) { + if (track->toBeRemoved) { + track->readyToRemove = true; + continue; + } + + if (_pause || !_vm) + return; + + if (track->volFadeUsed) { + if (track->volFadeStep < 0) { + if (track->vol > track->volFadeDest) { + track->vol += track->volFadeStep; + if (track->vol < track->volFadeDest) { + track->vol = track->volFadeDest; + track->volFadeUsed = false; + } + if (track->vol == 0) { + track->toBeRemoved = true; + } + } + } else if (track->volFadeStep > 0) { + if (track->vol < track->volFadeDest) { + track->vol += track->volFadeStep; + if (track->vol > track->volFadeDest) { + track->vol = track->volFadeDest; + track->volFadeUsed = false; + } + } + } + debug(5, "Fade: sound(%d), Vol(%d)", track->soundId, track->vol / 1000); + } + + const int pan = (track->pan != 64) ? 2 * track->pan - 127 : 0; + const int vol = track->vol / 1000; + Audio::Mixer::SoundType type = Audio::Mixer::kPlainSoundType; + + if (track->volGroupId == 1) + type = Audio::Mixer::kSpeechSoundType; + if (track->volGroupId == 2) + type = Audio::Mixer::kSFXSoundType; + if (track->volGroupId == 3) + type = Audio::Mixer::kMusicSoundType; + + if (track->stream) { + byte *data = NULL; + int32 result = 0; + + if (track->curRegion == -1) { + switchToNextRegion(track); + if (track->toBeRemoved) + continue; + } + + int bits = _sound->getBits(track->soundHandle); + int channels = _sound->getChannels(track->soundHandle); + + int32 mixer_size = track->iteration / _callbackFps; + + if (track->stream->endOfData()) { + mixer_size *= 2; + } + + if ((bits == 12) || (bits == 16)) { + if (channels == 1) + mixer_size &= ~1; + if (channels == 2) + mixer_size &= ~3; + } else { + if (channels == 2) + mixer_size &= ~1; + } + + if (mixer_size == 0) + continue; + + do { + if (bits == 12) { + byte *ptr = NULL; + + mixer_size += track->mod; + int mixer_size_12 = (mixer_size * 3) / 4; + int length = (mixer_size_12 / 3) * 4; + track->mod = mixer_size - length; + + int32 offset = (track->regionOffset * 3) / 4; + int result2 = _sound->getDataFromRegion(track->soundHandle, track->curRegion, &ptr, offset, mixer_size_12); + result = BundleCodecs::decode12BitsSample(ptr, &data, result2); + + free(ptr); + } else if (bits == 16) { + result = _sound->getDataFromRegion(track->soundHandle, track->curRegion, &data, track->regionOffset, mixer_size); + if (channels == 1) { + result &= ~1; + } + if (channels == 2) { + result &= ~3; + } + } else if (bits == 8) { + result = _sound->getDataFromRegion(track->soundHandle, track->curRegion, &data, track->regionOffset, mixer_size); + if (channels == 2) { + result &= ~1; + } + } + + if (result > mixer_size) + result = mixer_size; + + if (_vm->_mixer->isReady()) { + _vm->_mixer->setChannelVolume(track->handle, vol); + _vm->_mixer->setChannelBalance(track->handle, pan); + track->stream->append(data, result); + track->regionOffset += result; + } + free(data); + + if (_sound->isEndOfRegion(track->soundHandle, track->curRegion)) { + switchToNextRegion(track); + if (track->toBeRemoved) + break; + } + mixer_size -= result; + assert(mixer_size >= 0); + } while (mixer_size != 0); + } else if (track->stream2) { + if (_vm->_mixer->isReady()) { + if (!track->started) { + track->started = true; + _vm->_mixer->playInputStream(type, &track->handle, track->stream2, -1, vol, pan, false); + } else { + _vm->_mixer->setChannelVolume(track->handle, vol); + _vm->_mixer->setChannelBalance(track->handle, pan); + } + } + } + } + } +} + +void IMuseDigital::switchToNextRegion(Track *track) { + assert(track); + debug(5, "switchToNextRegion(track:%d)", track->trackId); + + if (track->trackId >= MAX_DIGITAL_TRACKS) { + track->toBeRemoved = true; + debug(5, "exit (fadetrack can't go next region) switchToNextRegion(trackId:%d)", track->trackId); + return; + } + + int num_regions = _sound->getNumRegions(track->soundHandle); + + if (++track->curRegion == num_regions) { + track->toBeRemoved = true; + debug(5, "exit (end of regions) switchToNextRegion(track:%d)", track->trackId); + return; + } + + ImuseDigiSndMgr::soundStruct *soundHandle = track->soundHandle; + int jumpId = _sound->getJumpIdByRegionAndHookId(soundHandle, track->curRegion, track->curHookId); + if (jumpId == -1) + jumpId = _sound->getJumpIdByRegionAndHookId(soundHandle, track->curRegion, 0); + if (jumpId != -1) { + int region = _sound->getRegionIdByJumpId(soundHandle, jumpId); + assert(region != -1); + int sampleHookId = _sound->getJumpHookId(soundHandle, jumpId); + assert(sampleHookId != -1); + int fadeDelay = (60 * _sound->getJumpFade(soundHandle, jumpId)) / 1000; + if (sampleHookId != 0) { + if (track->curHookId == sampleHookId) { + if (fadeDelay != 0) { + Track *fadeTrack = cloneToFadeOutTrack(track, fadeDelay); + if (fadeTrack) { + fadeTrack->dataOffset = _sound->getRegionOffset(fadeTrack->soundHandle, fadeTrack->curRegion); + fadeTrack->regionOffset = 0; + debug(5, "switchToNextRegion-sound(%d) select region %d, curHookId: %d", fadeTrack->soundId, fadeTrack->curRegion, fadeTrack->curHookId); + fadeTrack->curHookId = 0; + } + } + track->curRegion = region; + debug(5, "switchToNextRegion-sound(%d) jump to region %d, curHookId: %d", track->soundId, track->curRegion, track->curHookId); + track->curHookId = 0; + } + } else { + if (fadeDelay != 0) { + Track *fadeTrack = cloneToFadeOutTrack(track, fadeDelay); + if (fadeTrack) { + fadeTrack->dataOffset = _sound->getRegionOffset(fadeTrack->soundHandle, fadeTrack->curRegion); + fadeTrack->regionOffset = 0; + debug(5, "switchToNextRegion-sound(%d) select region %d, curHookId: %d", fadeTrack->soundId, fadeTrack->curRegion, fadeTrack->curHookId); + } + } + track->curRegion = region; + debug(5, "switchToNextRegion-sound(%d) jump to region %d, curHookId: %d", track->soundId, track->curRegion, track->curHookId); + } + } + + debug(5, "switchToNextRegion-sound(%d) select region %d, curHookId: %d", track->soundId, track->curRegion, track->curHookId); + track->dataOffset = _sound->getRegionOffset(soundHandle, track->curRegion); + track->regionOffset = 0; +} + +} // End of namespace Scumm |