scummvm/sword2/sound.cpp

273 lines
6.5 KiB
C++
Raw Normal View History

/* Copyright (C) 1994-1998 Revolution Software Ltd.
* Copyright (C) 2003-2005 The ScummVM project
2003-07-28 01:44:38 +00:00
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Header$
*/
2003-09-20 12:43:52 +00:00
// ---------------------------------------------------------------------------
2003-07-28 01:44:38 +00:00
// BROKEN SWORD 2
//
2003-09-20 12:43:52 +00:00
// SOUND.CPP Contains the sound engine, fx & music functions
// Some very 'sound' code in here ;)
2003-07-28 01:44:38 +00:00
//
// (16Dec96 JEL)
//
2003-09-20 12:43:52 +00:00
// ---------------------------------------------------------------------------
2003-07-28 01:44:38 +00:00
#include "common/stdafx.h"
#include "common/file.h"
#include "common/system.h"
2003-10-28 19:51:30 +00:00
#include "sword2/sword2.h"
#include "sword2/defs.h"
#include "sword2/logic.h"
#include "sword2/resman.h"
2004-11-14 15:00:01 +00:00
#include "sword2/sound.h"
#include "sound/wave.h"
2003-07-28 01:44:38 +00:00
2003-10-04 00:52:27 +00:00
namespace Sword2 {
Sound::Sound(Sword2Engine *vm) {
int i;
_vm = vm;
for (i = 0; i < FXQ_LENGTH; i++)
_fxQueue[i].resource = 0;
for (i = 0; i < MAXMUS; i++)
_music[i] = NULL;
2003-07-28 01:44:38 +00:00
_speechPaused = false;
_musicPaused = false;
_fxPaused = false;
_speechMuted = false;
_musicMuted = false;
_fxMuted = false;
_mixBuffer = NULL;
_mixBufferLen = 0;
_vm->_mixer->setupPremix(this, SoundMixer::kMusicAudioDataType);
}
Sound::~Sound() {
_vm->_mixer->setupPremix(0);
clearFxQueue();
stopMusic();
stopSpeech();
for (int i = 0; i < MAXMUS; i++)
delete _music[i];
free(_mixBuffer);
}
/**
* Stop all sounds, close their resources and clear the FX queue.
*/
void Sound::clearFxQueue() {
for (int i = 0; i < FXQ_LENGTH; i++) {
if (_fxQueue[i].resource) {
stopFx(i);
}
}
2003-07-28 01:44:38 +00:00
}
/**
* Process the FX queue. This function is called once every game cycle.
*/
2003-07-28 01:44:38 +00:00
void Sound::processFxQueue() {
for (int i = 0; i < FXQ_LENGTH; i++) {
if (!_fxQueue[i].resource)
2003-09-20 12:43:52 +00:00
continue;
2003-07-28 01:44:38 +00:00
switch (_fxQueue[i].type) {
case FX_RANDOM:
// 1 in 'delay' chance of this fx occurring
if (_vm->_rnd.getRandomNumber(_fxQueue[i].delay) == 0)
playFx(&_fxQueue[i]);
break;
case FX_SPOT:
if (_fxQueue[i].delay)
_fxQueue[i].delay--;
else {
playFx(&_fxQueue[i]);
_fxQueue[i].type = FX_SPOT2;
}
break;
case FX_LOOP:
playFx(&_fxQueue[i]);
_fxQueue[i].type = FX_LOOPING;
break;
case FX_SPOT2:
// Once the FX has finished remove it from the queue.
if (!_fxQueue[i].handle.isActive()) {
_vm->_resman->closeResource(_fxQueue[i].resource);
_fxQueue[i].resource = 0;
}
break;
case FX_LOOPING:
// Once the looped FX has started we can ignore it,
// but we can't close it since the WAV data is in use.
break;
2003-07-28 01:44:38 +00:00
}
}
}
/**
* Queue a sound effect for playing later.
* @param res the sound resource number
* @param type the type of sound effect
* @param delay when to play the sound effect
* @param volume the sound effect volume (0 through 16)
* @param pan the sound effect panning (-16 through 16)
*/
2003-09-20 12:43:52 +00:00
void Sound::queueFx(int32 res, int32 type, int32 delay, int32 volume, int32 pan) {
if (_vm->_wantSfxDebug) {
const char *typeStr;
switch (type) {
case FX_SPOT:
typeStr = "SPOT";
break;
case FX_LOOP:
typeStr = "LOOPED";
break;
case FX_RANDOM:
typeStr = "RANDOM";
break;
default:
typeStr = "INVALID";
break;
2003-07-28 01:44:38 +00:00
}
byte buf[NAME_LEN];
debug(0, "SFX (sample=\"%s\", vol=%d, pan=%d, delay=%d, type=%s)", _vm->fetchObjectName(res, buf), volume, pan, delay, typeStr);
}
2003-07-28 01:44:38 +00:00
for (int i = 0; i < FXQ_LENGTH; i++) {
if (!_fxQueue[i].resource) {
byte *data = _vm->_resman->openResource(res);
StandardHeader *header = (StandardHeader *) data;
2003-09-20 12:43:52 +00:00
assert(header->fileType == WAV_FILE);
2003-07-28 01:44:38 +00:00
uint32 len = _vm->_resman->fetchLen(res) - sizeof(StandardHeader);
2003-07-28 01:44:38 +00:00
if (type == FX_RANDOM) {
// For spot effects and loops the delay is the
// number of frames to wait. For random
// effects, however, it's the average number of
// seconds between playing the sound, so we
// have to multiply by the frame rate.
delay *= 12;
}
2003-07-28 01:44:38 +00:00
volume = (volume * SoundMixer::kMaxChannelVolume) / 16;
pan = (pan * 127) / 16;
2003-07-28 01:44:38 +00:00
_fxQueue[i].resource = res;
_fxQueue[i].data = data + sizeof(StandardHeader);
_fxQueue[i].len = len;
_fxQueue[i].delay = delay;
_fxQueue[i].volume = volume;
_fxQueue[i].pan = pan;
_fxQueue[i].type = type;
2003-07-28 01:44:38 +00:00
// Keep track of the index in the loop so that
// fnStopFx() can be used later to kill this sound.
// Mainly for FX_LOOP and FX_RANDOM.
2003-07-28 01:44:38 +00:00
Logic::_scriptVars[RESULT] = i;
return;
}
}
2003-09-20 12:43:52 +00:00
warning("No free slot in FX queue");
2003-07-28 01:44:38 +00:00
}
int32 Sound::playFx(FxQueueEntry *fx) {
return playFx(&fx->handle, fx->data, fx->len, fx->volume, fx->pan, (fx->type == FX_LOOP), SoundMixer::kSFXAudioDataType);
2003-07-28 01:44:38 +00:00
}
2003-09-20 12:43:52 +00:00
int32 Sound::playFx(PlayingSoundHandle *handle, byte *data, uint32 len, uint8 vol, int8 pan, bool loop, SoundMixer::SoundType soundType) {
if (_fxMuted)
return RD_OK;
2003-07-28 01:44:38 +00:00
if (handle->isActive())
return RDERR_FXALREADYOPEN;
2003-07-28 01:44:38 +00:00
Common::MemoryReadStream stream(data, len);
int rate, size;
byte flags;
2003-07-28 01:44:38 +00:00
if (!loadWAVFromStream(stream, size, rate, flags)) {
warning("playFX: Not a valid WAV file");
return RDERR_INVALIDWAV;
2003-07-28 01:44:38 +00:00
}
if (isReverseStereo())
flags |= SoundMixer::FLAG_REVERSE_STEREO;
if (loop)
flags |= SoundMixer::FLAG_LOOP;
2003-07-28 01:44:38 +00:00
_vm->_mixer->playRaw(handle, data + stream.pos(), size, rate, flags, -1, vol, pan, 0, 0, soundType);
return RD_OK;
2003-07-28 01:44:38 +00:00
}
/**
* This function closes a sound effect which has been previously opened for
* playing. Sound effects must be closed when they are finished with, otherwise
* you will run out of sound effect buffers.
* @param i the index of the sound to close
*/
2003-07-28 01:44:38 +00:00
int32 Sound::stopFx(int32 i) {
if (!_fxQueue[i].resource)
return RDERR_FXNOTOPEN;
2003-09-20 12:43:52 +00:00
if (_fxQueue[i].handle.isActive())
_vm->_mixer->stopHandle(_fxQueue[i].handle);
2003-07-28 01:44:38 +00:00
_vm->_resman->closeResource(_fxQueue[i].resource);
_fxQueue[i].resource = 0;
return RD_OK;
2003-07-28 01:44:38 +00:00
}
void Sound::pauseAllSound() {
pauseMusic();
pauseSpeech();
pauseFx();
2003-07-28 01:44:38 +00:00
}
void Sound::unpauseAllSound() {
unpauseMusic();
unpauseSpeech();
unpauseFx();
2003-07-28 01:44:38 +00:00
}
2003-09-20 12:43:52 +00:00
2003-10-04 00:52:27 +00:00
} // End of namespace Sword2