ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

stark/resources/sound.cpp

Go to the documentation of this file.
00001 /* ResidualVM - A 3D game interpreter
00002  *
00003  * ResidualVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the AUTHORS
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "engines/stark/resources/sound.h"
00024 
00025 #include "audio/decoders/vorbis.h"
00026 
00027 #include "common/system.h"
00028 
00029 #include "engines/stark/formats/iss.h"
00030 #include "engines/stark/formats/xrc.h"
00031 #include "engines/stark/resources/location.h"
00032 #include "engines/stark/services/archiveloader.h"
00033 #include "engines/stark/services/global.h"
00034 #include "engines/stark/services/services.h"
00035 #include "engines/stark/services/stateprovider.h"
00036 
00037 namespace Stark {
00038 namespace Resources {
00039 
00040 Sound::~Sound() {
00041 }
00042 
00043 Sound::Sound(Object *parent, byte subType, uint16 index, const Common::String &name) :
00044         Object(parent, subType, index, name),
00045         _enabled(0),
00046         _looping(false),
00047         _field_64(0),
00048         _loopIndefinitely(false),
00049         _loadFromFile(true),
00050         _maxDuration(0),
00051         _stockSoundType(0),
00052         _field_6C(0),
00053         _soundType(0),
00054         _pan(0),
00055         _volume(0),
00056         _fadeDurationRemaining(0),
00057         _fadeTargetVolume(0.0),
00058         _fadeTargetPan(0.0),
00059         _shouldStopOnDestroy(true) {
00060     _type = TYPE;
00061 }
00062 
00063 Audio::RewindableAudioStream *Sound::makeAudioStream() {
00064     Common::SeekableReadStream *stream = nullptr;
00065     Audio::RewindableAudioStream *audioStream = nullptr;
00066 
00067     // First try the .iss / isn files
00068     if (_loadFromFile) {
00069         stream = StarkArchiveLoader->getExternalFile(_filename, _archiveName);
00070     } else {
00071         stream = StarkArchiveLoader->getFile(_filename, _archiveName);
00072     }
00073 
00074     if (stream) {
00075         audioStream = Formats::makeISSStream(stream, DisposeAfterUse::YES);
00076     }
00077 
00078     if (!audioStream) {
00079         // The 2 CD version uses Ogg Vorbis
00080         Common::String filename = _filename;
00081         if (_filename.hasSuffix(".iss") || _filename.hasSuffix(".isn")) {
00082             filename = Common::String(_filename.c_str(), _filename.size() - 4) + ".ovs";
00083         }
00084 
00085         stream = StarkArchiveLoader->getExternalFile(filename, _archiveName);
00086         if (stream) {
00087 #ifdef USE_VORBIS
00088             audioStream = Audio::makeVorbisStream(stream, DisposeAfterUse::YES);
00089 #else
00090             warning("Cannot decode sound '%s', Vorbis support is not compiled in", filename.c_str());
00091             delete stream;
00092 #endif
00093         }
00094     }
00095 
00096     if (!audioStream) {
00097         warning("Unable to load sound '%s'", _filename.c_str());
00098     }
00099 
00100     return audioStream;
00101 }
00102 
00103 Audio::Mixer::SoundType Sound::getMixerSoundType() {
00104     switch (_soundType) {
00105     case kSoundTypeVoice:
00106         return Audio::Mixer::kSpeechSoundType;
00107     case kSoundTypeEffect:
00108         return Audio::Mixer::kSFXSoundType;
00109     case kSoundTypeMusic:
00110         return Audio::Mixer::kMusicSoundType;
00111     default:
00112         error("Unknown sound type '%d'", _soundType);
00113     }
00114 }
00115 
00116 void Sound::play() {
00117     Audio::RewindableAudioStream *rewindableStream = makeAudioStream();
00118 
00119     if (!rewindableStream) {
00120         return;
00121     }
00122 
00123     Audio::AudioStream *playStream;
00124     if (_looping) {
00125         playStream = Audio::makeLoopingAudioStream(rewindableStream, 0);
00126     } else {
00127         playStream = rewindableStream;
00128     }
00129 
00130     g_system->getMixer()->playStream(getMixerSoundType(), &_handle, playStream, -1,
00131                                      _volume * Audio::Mixer::kMaxChannelVolume, _pan * 127);
00132 }
00133 
00134 bool Sound::isPlaying() {
00135     return g_system->getMixer()->isSoundHandleActive(_handle);
00136 }
00137 
00138 void Sound::stop() {
00139     g_system->getMixer()->stopHandle(_handle);
00140     _handle = Audio::SoundHandle();
00141 }
00142 
00143 void Sound::onPreDestroy() {
00144     Object::onPreDestroy();
00145 
00146     if (_shouldStopOnDestroy) {
00147         stop();
00148     }
00149 }
00150 
00151 void Sound::readData(Formats::XRCReadStream *stream) {
00152     _filename = stream->readString();
00153     _enabled = stream->readUint32LE();
00154     _looping = stream->readBool();
00155     _field_64 = stream->readUint32LE();
00156     _loopIndefinitely = stream->readBool();
00157     _maxDuration = stream->readUint32LE();
00158     _loadFromFile = stream->readBool(); // Used only in the 4CD version
00159     _stockSoundType = stream->readUint32LE();
00160     _soundName = stream->readString();
00161     _field_6C = stream->readUint32LE();
00162     _soundType = stream->readUint32LE();
00163     _pan = stream->readFloatLE();
00164     _volume = stream->readFloatLE();
00165     _archiveName = stream->getArchiveName();
00166 }
00167 
00168 void Sound::printData() {
00169     debug("filename: %s", _filename.c_str());
00170     debug("enabled: %d", _enabled);
00171     debug("looping: %d", _looping);
00172     debug("field_64: %d", _field_64);
00173     debug("loopIndefinitely: %d", _loopIndefinitely);
00174     debug("maxDuration: %d", _maxDuration);
00175     debug("loadFromFile: %d", _loadFromFile);
00176     debug("stockSoundType: %d", _stockSoundType);
00177     debug("soundName: %s", _soundName.c_str());
00178     debug("field_6C: %d", _field_6C);
00179     debug("soundType: %d", _soundType);
00180     debug("pan: %f", _pan);
00181     debug("volume: %f", _volume);
00182 }
00183 
00184 void Sound::onGameLoop() {
00185     Object::onGameLoop();
00186 
00187     if (_subType == kSoundBackground && !isPlaying()) {
00188         Location *location = StarkGlobal->getCurrent()->getLocation();
00189         if (location->getName() != "Amongst Stalls" || StarkGlobal->getCurrentChapter() < 100) {
00190             play();
00191         }
00192     }
00193 
00194     if (_looping && !_loopIndefinitely) {
00195         // Automatically stop after the maximum run time has been reached
00196         uint32 elapsedTime = g_system->getMixer()->getSoundElapsedTime(_handle);
00197         if (elapsedTime > _maxDuration) {
00198             stop();
00199         }
00200     }
00201 
00202     if (_fadeDurationRemaining > 0 && isPlaying()) {
00203         _volume += (_fadeTargetVolume - _volume) * StarkGlobal->getMillisecondsPerGameloop() / (float) _fadeDurationRemaining;
00204         _pan += (_fadeTargetPan - _pan) * StarkGlobal->getMillisecondsPerGameloop() / (float) _fadeDurationRemaining;
00205 
00206         _fadeDurationRemaining -= StarkGlobal->getMillisecondsPerGameloop();
00207 
00208         if (_fadeDurationRemaining <= 0) {
00209             _fadeDurationRemaining = 0;
00210 
00211             _volume = _fadeTargetVolume;
00212             _pan = _fadeTargetPan;
00213         }
00214 
00215         g_system->getMixer()->setChannelVolume(_handle, _volume * Audio::Mixer::kMaxChannelVolume);
00216         g_system->getMixer()->setChannelBalance(_handle, _pan * 127);
00217     }
00218 }
00219 
00220 uint32 Sound::getStockSoundType() const {
00221     return _stockSoundType;
00222 }
00223 
00224 void Sound::changeVolumePan(int32 volume, int32 pan, int32 duration) {
00225     if (isPlaying()) {
00226         _fadeDurationRemaining = duration;
00227 
00228         if (_fadeDurationRemaining > 0) {
00229             _fadeTargetVolume = volume / 100.0f;
00230             _fadeTargetPan = pan / 100.0f;
00231         } else {
00232             _volume = volume / 100.0f;
00233             _pan = pan / 100.0f;
00234 
00235             g_system->getMixer()->setChannelVolume(_handle, _volume * Audio::Mixer::kMaxChannelVolume);
00236             g_system->getMixer()->setChannelBalance(_handle, _pan * 127);
00237         }
00238     } else {
00239         if (_fadeDurationRemaining == 0) {
00240             _volume = volume / 100.0f;
00241             _pan = pan / 100.0f;
00242         }
00243     }
00244 }
00245 
00246 void Sound::saveLoadCurrent(ResourceSerializer *serializer) {
00247     bool playing = isPlaying();
00248     serializer->syncAsUint32LE(playing);
00249 
00250     if (_subType != kSoundBackground && playing) {
00251         uint32 elapsed = g_system->getMixer()->getSoundElapsedTime(_handle);
00252         serializer->syncAsUint32LE(elapsed);
00253         serializer->syncAsFloat(_volume);
00254         serializer->syncAsFloat(_pan);
00255         serializer->syncAsUint32LE(_fadeDurationRemaining);
00256         serializer->syncAsFloat(_fadeTargetVolume);
00257         serializer->syncAsFloat(_fadeTargetPan);
00258 
00259         if (serializer->isLoading()) {
00260             play();
00261             // TODO: Seek to the "elapsed" position
00262         }
00263     }
00264 }
00265 
00266 void Sound::onEnginePause(bool pause) {
00267     g_system->getMixer()->pauseHandle(_handle, pause);
00268 }
00269 
00270 void Sound::setStopOnDestroy(bool stopOnDestroy) {
00271     _shouldStopOnDestroy = stopOnDestroy;
00272 }
00273 
00274 } // End of namespace Resources
00275 } // End of namespace Stark


Generated on Sat May 25 2019 05:00:54 for ResidualVM by doxygen 1.7.1
curved edge   curved edge