scummvm/engines/mohawk/myst_sound.cpp

240 lines
6.9 KiB
C++
Raw Normal View History

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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.
*
*/
#include "mohawk/myst_sound.h"
#include "mohawk/myst.h"
#include "mohawk/resource.h"
#include "common/debug.h"
#include "audio/audiostream.h"
#include "audio/decoders/wave.h"
namespace Mohawk {
MystSound::MystSound(MohawkEngine_Myst *vm) :
_vm(vm) {
_mystBackgroundSound.type = kFreeHandle;
}
MystSound::~MystSound() {
stopSound();
stopBackgroundMyst();
}
Audio::RewindableAudioStream *MystSound::makeAudioStream(uint16 id, CueList *cueList) {
if (_vm->getFeatures() & GF_ME)
return Audio::makeWAVStream(_vm->getResource(ID_MSND, convertMystID(id)), DisposeAfterUse::YES);
else
return makeMohawkWaveStream(_vm->getResource(ID_MSND, id), cueList);
}
Audio::SoundHandle *MystSound::playSound(uint16 id, byte volume, bool loop, CueList *cueList) {
debug (0, "Playing sound %d", id);
Audio::RewindableAudioStream *rewindStream = makeAudioStream(id, cueList);
if (rewindStream) {
SndHandle *handle = getHandle();
handle->type = kUsedHandle;
handle->id = id;
handle->samplesPerSecond = rewindStream->getRate();
// Set the stream to loop here if it's requested
Audio::AudioStream *audStream = rewindStream;
if (loop)
audStream = Audio::makeLoopingAudioStream(rewindStream, 0);
_vm->_mixer->playStream(Audio::Mixer::kPlainSoundType, &handle->handle, audStream, -1, volume);
return &handle->handle;
}
return nullptr;
}
Audio::SoundHandle *MystSound::replaceSoundMyst(uint16 id, byte volume, bool loop) {
debug (0, "Replacing sound %d", id);
// The original engine also forces looping for those sounds
switch (id) {
case 2205:
case 2207:
case 5378:
case 7220:
case 9119: // Elevator engine sound in mechanical age is looping.
case 9120:
case 9327:
loop = true;
break;
}
stopSound();
return playSound(id, volume, loop);
}
SndHandle *MystSound::getHandle() {
for (uint32 i = 0; i < _handles.size(); i++) {
if (_handles[i].type == kFreeHandle)
return &_handles[i];
if (!_vm->_mixer->isSoundHandleActive(_handles[i].handle)) {
_handles[i].type = kFreeHandle;
_handles[i].id = 0;
return &_handles[i];
}
}
// Let's add a new sound handle!
SndHandle handle;
handle.handle = Audio::SoundHandle();
handle.type = kFreeHandle;
handle.id = 0;
_handles.push_back(handle);
return &_handles[_handles.size() - 1];
}
void MystSound::stopSound() {
for (uint32 i = 0; i < _handles.size(); i++)
if (_handles[i].type == kUsedHandle) {
_vm->_mixer->stopHandle(_handles[i].handle);
_handles[i].type = kFreeHandle;
_handles[i].id = 0;
}
}
void MystSound::stopSound(uint16 id) {
for (uint32 i = 0; i < _handles.size(); i++)
if (_handles[i].type == kUsedHandle && _handles[i].id == id) {
_vm->_mixer->stopHandle(_handles[i].handle);
_handles[i].type = kFreeHandle;
_handles[i].id = 0;
}
}
bool MystSound::isPlaying(uint16 id) {
for (uint32 i = 0; i < _handles.size(); i++)
if (_handles[i].type == kUsedHandle && _handles[i].id == id)
return _vm->_mixer->isSoundHandleActive(_handles[i].handle);
return false;
}
bool MystSound::isPlaying() {
for (uint32 i = 0; i < _handles.size(); i++)
if (_handles[i].type == kUsedHandle)
if (_vm->_mixer->isSoundHandleActive(_handles[i].handle))
return true;
return false;
}
uint MystSound::getNumSamplesPlayed(uint16 id) {
for (uint32 i = 0; i < _handles.size(); i++)
if (_handles[i].type == kUsedHandle && _handles[i].id == id) {
return (_vm->_mixer->getSoundElapsedTime(_handles[i].handle) * _handles[i].samplesPerSecond) / 1000;
}
return 0;
}
uint16 MystSound::convertMystID(uint16 id) {
// Myst ME is a bit more efficient with sound storage than Myst
// Myst has lots of sounds repeated. To overcome this, Myst ME
// has MJMP resources which provide a link to the actual MSND
// resource we're looking for. This saves a lot of space from
// repeated data.
if (_vm->hasResource(ID_MJMP, id)) {
Common::SeekableReadStream *mjmpStream = _vm->getResource(ID_MJMP, id);
id = mjmpStream->readUint16LE();
delete mjmpStream;
}
return id;
}
void MystSound::replaceBackgroundMyst(uint16 id, uint16 volume) {
debug(0, "Replacing background sound with %d", id);
// TODO: The original engine does fading
Common::String name = _vm->getResourceName(ID_MSND, convertMystID(id));
// Only the first eight characters need to be the same to have a match
Common::String prefix;
if (name.size() >= 8)
prefix = Common::String(name.c_str(), name.c_str() + 8);
else
prefix = name;
// Check if sound is already playing
if (_mystBackgroundSound.type == kUsedHandle && _vm->_mixer->isSoundHandleActive(_mystBackgroundSound.handle)
&& _vm->getResourceName(ID_MSND, convertMystID(_mystBackgroundSound.id)).hasPrefix(prefix)) {
// The sound is already playing, just change the volume
changeBackgroundVolumeMyst(volume);
return;
}
// Stop old background sound
stopBackgroundMyst();
// Play new sound
Audio::RewindableAudioStream *rewindStream = makeAudioStream(id);
if (rewindStream) {
_mystBackgroundSound.type = kUsedHandle;
_mystBackgroundSound.id = id;
_mystBackgroundSound.samplesPerSecond = rewindStream->getRate();
// Set the stream to loop
Audio::AudioStream *audStream = Audio::makeLoopingAudioStream(rewindStream, 0);
_vm->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_mystBackgroundSound.handle, audStream, -1, volume >> 8);
}
}
void MystSound::stopBackgroundMyst() {
if (_mystBackgroundSound.type == kUsedHandle) {
_vm->_mixer->stopHandle(_mystBackgroundSound.handle);
_mystBackgroundSound.type = kFreeHandle;
_mystBackgroundSound.id = 0;
}
}
void MystSound::pauseBackgroundMyst() {
if (_mystBackgroundSound.type == kUsedHandle)
_vm->_mixer->pauseHandle(_mystBackgroundSound.handle, true);
}
void MystSound::resumeBackgroundMyst() {
if (_mystBackgroundSound.type == kUsedHandle)
_vm->_mixer->pauseHandle(_mystBackgroundSound.handle, false);
}
void MystSound::changeBackgroundVolumeMyst(uint16 vol) {
if (_mystBackgroundSound.type == kUsedHandle)
_vm->_mixer->setChannelVolume(_mystBackgroundSound.handle, vol >> 8);
}
} // End of namespace Mohawk