mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-22 01:39:57 +00:00
507 lines
16 KiB
C++
507 lines
16 KiB
C++
/* 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.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* This file is based on WME Lite.
|
|
* http://dead-code.org/redir.php?target=wmelite
|
|
* Copyright (c) 2011 Jan Nedoma
|
|
*/
|
|
|
|
#include "engines/wintermute/base/base_game_music.h"
|
|
#include "engines/wintermute/base/base_engine.h"
|
|
#include "engines/wintermute/base/base_game.h"
|
|
#include "engines/wintermute/base/base_persistence_manager.h"
|
|
#include "engines/wintermute/base/scriptables/script_stack.h"
|
|
#include "engines/wintermute/base/scriptables/script_value.h"
|
|
#include "engines/wintermute/base/scriptables/script.h"
|
|
#include "engines/wintermute/base/sound/base_sound.h"
|
|
|
|
namespace Wintermute {
|
|
|
|
BaseGameMusic::BaseGameMusic(BaseGame *gameRef) : _gameRef(gameRef) {
|
|
for (int i = 0; i < NUM_MUSIC_CHANNELS; i++) {
|
|
_music[i] = NULL;
|
|
_musicStartTime[i] = 0;
|
|
}
|
|
|
|
_musicCrossfadeRunning = false;
|
|
_musicCrossfadeStartTime = 0;
|
|
_musicCrossfadeLength = 0;
|
|
_musicCrossfadeChannel1 = -1;
|
|
_musicCrossfadeChannel2 = -1;
|
|
_musicCrossfadeSwap = false;
|
|
}
|
|
|
|
void BaseGameMusic::cleanup() {
|
|
for (int i = 0; i < NUM_MUSIC_CHANNELS; i++) {
|
|
delete _music[i];
|
|
_music[i] = NULL;
|
|
_musicStartTime[i] = 0;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGameMusic::playMusic(int channel, const char *filename, bool looping, uint32 loopStart) {
|
|
if (channel >= NUM_MUSIC_CHANNELS) {
|
|
BaseEngine::LOG(0, "**Error** Attempting to use music channel %d (max num channels: %d)", channel, NUM_MUSIC_CHANNELS);
|
|
return STATUS_FAILED;
|
|
}
|
|
|
|
delete _music[channel];
|
|
_music[channel] = NULL;
|
|
|
|
_music[channel] = new BaseSound(_gameRef);
|
|
if (_music[channel] && DID_SUCCEED(_music[channel]->setSound(filename, Audio::Mixer::kMusicSoundType, true))) {
|
|
if (_musicStartTime[channel]) {
|
|
_music[channel]->setPositionTime(_musicStartTime[channel]);
|
|
_musicStartTime[channel] = 0;
|
|
}
|
|
if (loopStart) {
|
|
_music[channel]->setLoopStart(loopStart);
|
|
}
|
|
return _music[channel]->play(looping);
|
|
} else {
|
|
delete _music[channel];
|
|
_music[channel] = NULL;
|
|
return STATUS_FAILED;
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGameMusic::stopMusic(int channel) {
|
|
if (channel >= NUM_MUSIC_CHANNELS) {
|
|
BaseEngine::LOG(0, "**Error** Attempting to use music channel %d (max num channels: %d)", channel, NUM_MUSIC_CHANNELS);
|
|
return STATUS_FAILED;
|
|
}
|
|
|
|
if (_music[channel]) {
|
|
_music[channel]->stop();
|
|
delete _music[channel];
|
|
_music[channel] = NULL;
|
|
return STATUS_OK;
|
|
} else {
|
|
return STATUS_FAILED;
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGameMusic::pauseMusic(int channel) {
|
|
if (channel >= NUM_MUSIC_CHANNELS) {
|
|
BaseEngine::LOG(0, "**Error** Attempting to use music channel %d (max num channels: %d)", channel, NUM_MUSIC_CHANNELS);
|
|
return STATUS_FAILED;
|
|
}
|
|
|
|
if (_music[channel]) {
|
|
return _music[channel]->pause();
|
|
} else {
|
|
return STATUS_FAILED;
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGameMusic::resumeMusic(int channel) {
|
|
if (channel >= NUM_MUSIC_CHANNELS) {
|
|
BaseEngine::LOG(0, "**Error** Attempting to use music channel %d (max num channels: %d)", channel, NUM_MUSIC_CHANNELS);
|
|
return STATUS_FAILED;
|
|
}
|
|
|
|
if (_music[channel]) {
|
|
return _music[channel]->resume();
|
|
} else {
|
|
return STATUS_FAILED;
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGameMusic::setMusicStartTime(int channel, uint32 time) {
|
|
if (channel >= NUM_MUSIC_CHANNELS) {
|
|
BaseEngine::LOG(0, "**Error** Attempting to use music channel %d (max num channels: %d)", channel, NUM_MUSIC_CHANNELS);
|
|
return STATUS_FAILED;
|
|
}
|
|
|
|
_musicStartTime[channel] = time;
|
|
if (_music[channel] && _music[channel]->isPlaying()) {
|
|
return _music[channel]->setPositionTime(time);
|
|
} else {
|
|
return STATUS_OK;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGameMusic::updateMusicCrossfade() {
|
|
/* byte globMusicVol = _soundMgr->getVolumePercent(SOUND_MUSIC); */
|
|
|
|
if (!_musicCrossfadeRunning) {
|
|
return STATUS_OK;
|
|
}
|
|
if (_gameRef->_state == GAME_FROZEN) {
|
|
return STATUS_OK;
|
|
}
|
|
|
|
if (_musicCrossfadeChannel1 < 0 || _musicCrossfadeChannel1 >= NUM_MUSIC_CHANNELS || !_music[_musicCrossfadeChannel1]) {
|
|
_musicCrossfadeRunning = false;
|
|
return STATUS_OK;
|
|
}
|
|
if (_musicCrossfadeChannel2 < 0 || _musicCrossfadeChannel2 >= NUM_MUSIC_CHANNELS || !_music[_musicCrossfadeChannel2]) {
|
|
_musicCrossfadeRunning = false;
|
|
return STATUS_OK;
|
|
}
|
|
|
|
if (!_music[_musicCrossfadeChannel1]->isPlaying()) {
|
|
_music[_musicCrossfadeChannel1]->play();
|
|
}
|
|
if (!_music[_musicCrossfadeChannel2]->isPlaying()) {
|
|
_music[_musicCrossfadeChannel2]->play();
|
|
}
|
|
|
|
uint32 currentTime = _gameRef->_liveTimer - _musicCrossfadeStartTime;
|
|
|
|
if (currentTime >= _musicCrossfadeLength) {
|
|
_musicCrossfadeRunning = false;
|
|
//_music[_musicCrossfadeChannel2]->setVolume(GlobMusicVol);
|
|
_music[_musicCrossfadeChannel2]->setVolumePercent(100);
|
|
|
|
_music[_musicCrossfadeChannel1]->stop();
|
|
//_music[_musicCrossfadeChannel1]->setVolume(GlobMusicVol);
|
|
_music[_musicCrossfadeChannel1]->setVolumePercent(100);
|
|
|
|
|
|
if (_musicCrossfadeSwap) {
|
|
// swap channels
|
|
BaseSound *dummy = _music[_musicCrossfadeChannel1];
|
|
int dummyInt = _musicStartTime[_musicCrossfadeChannel1];
|
|
|
|
_music[_musicCrossfadeChannel1] = _music[_musicCrossfadeChannel2];
|
|
_musicStartTime[_musicCrossfadeChannel1] = _musicStartTime[_musicCrossfadeChannel2];
|
|
|
|
_music[_musicCrossfadeChannel2] = dummy;
|
|
_musicStartTime[_musicCrossfadeChannel2] = dummyInt;
|
|
}
|
|
} else {
|
|
//_music[_musicCrossfadeChannel1]->setVolume(GlobMusicVol - (float)CurrentTime / (float)_musicCrossfadeLength * GlobMusicVol);
|
|
//_music[_musicCrossfadeChannel2]->setVolume((float)CurrentTime / (float)_musicCrossfadeLength * GlobMusicVol);
|
|
_music[_musicCrossfadeChannel1]->setVolumePercent((int)(100.0f - (float)currentTime / (float)_musicCrossfadeLength * 100.0f));
|
|
_music[_musicCrossfadeChannel2]->setVolumePercent((int)((float)currentTime / (float)_musicCrossfadeLength * 100.0f));
|
|
|
|
//_gameRef->QuickMessageForm("%d %d", _music[_musicCrossfadeChannel1]->GetVolume(), _music[_musicCrossfadeChannel2]->GetVolume());
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
bool BaseGameMusic::persistChannels(BasePersistenceManager *persistMgr) {
|
|
for (int i = 0; i < NUM_MUSIC_CHANNELS; i++) {
|
|
persistMgr->transfer(TMEMBER(_music[i]));
|
|
persistMgr->transfer(TMEMBER(_musicStartTime[i]));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool BaseGameMusic::persistCrossfadeSettings(BasePersistenceManager *persistMgr) {
|
|
persistMgr->transfer(TMEMBER(_musicCrossfadeRunning));
|
|
persistMgr->transfer(TMEMBER(_musicCrossfadeStartTime));
|
|
persistMgr->transfer(TMEMBER(_musicCrossfadeLength));
|
|
persistMgr->transfer(TMEMBER(_musicCrossfadeChannel1));
|
|
persistMgr->transfer(TMEMBER(_musicCrossfadeChannel2));
|
|
persistMgr->transfer(TMEMBER(_musicCrossfadeSwap));
|
|
return true;
|
|
}
|
|
|
|
bool BaseGameMusic::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) {
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// PlayMusic / PlayMusicChannel
|
|
//////////////////////////////////////////////////////////////////////////
|
|
if (strcmp(name, "PlayMusic") == 0 || strcmp(name, "PlayMusicChannel") == 0) {
|
|
int channel = 0;
|
|
if (strcmp(name, "PlayMusic") == 0) {
|
|
stack->correctParams(3);
|
|
} else {
|
|
stack->correctParams(4);
|
|
channel = stack->pop()->getInt();
|
|
}
|
|
|
|
const char *filename = stack->pop()->getString();
|
|
ScValue *valLooping = stack->pop();
|
|
bool looping = valLooping->isNULL() ? true : valLooping->getBool();
|
|
|
|
ScValue *valLoopStart = stack->pop();
|
|
uint32 loopStart = (uint32)(valLoopStart->isNULL() ? 0 : valLoopStart->getInt());
|
|
|
|
|
|
if (DID_FAIL(playMusic(channel, filename, looping, loopStart))) {
|
|
stack->pushBool(false);
|
|
} else {
|
|
stack->pushBool(true);
|
|
}
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// StopMusic / StopMusicChannel
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "StopMusic") == 0 || strcmp(name, "StopMusicChannel") == 0) {
|
|
int channel = 0;
|
|
|
|
if (strcmp(name, "StopMusic") == 0) {
|
|
stack->correctParams(0);
|
|
} else {
|
|
stack->correctParams(1);
|
|
channel = stack->pop()->getInt();
|
|
}
|
|
|
|
if (DID_FAIL(stopMusic(channel))) {
|
|
stack->pushBool(false);
|
|
} else {
|
|
stack->pushBool(true);
|
|
}
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// PauseMusic / PauseMusicChannel
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "PauseMusic") == 0 || strcmp(name, "PauseMusicChannel") == 0) {
|
|
int channel = 0;
|
|
|
|
if (strcmp(name, "PauseMusic") == 0) {
|
|
stack->correctParams(0);
|
|
} else {
|
|
stack->correctParams(1);
|
|
channel = stack->pop()->getInt();
|
|
}
|
|
|
|
if (DID_FAIL(pauseMusic(channel))) {
|
|
stack->pushBool(false);
|
|
} else {
|
|
stack->pushBool(true);
|
|
}
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// ResumeMusic / ResumeMusicChannel
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "ResumeMusic") == 0 || strcmp(name, "ResumeMusicChannel") == 0) {
|
|
int channel = 0;
|
|
if (strcmp(name, "ResumeMusic") == 0) {
|
|
stack->correctParams(0);
|
|
} else {
|
|
stack->correctParams(1);
|
|
channel = stack->pop()->getInt();
|
|
}
|
|
|
|
if (DID_FAIL(resumeMusic(channel))) {
|
|
stack->pushBool(false);
|
|
} else {
|
|
stack->pushBool(true);
|
|
}
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// GetMusic / GetMusicChannel
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "GetMusic") == 0 || strcmp(name, "GetMusicChannel") == 0) {
|
|
int channel = 0;
|
|
if (strcmp(name, "GetMusic") == 0) {
|
|
stack->correctParams(0);
|
|
} else {
|
|
stack->correctParams(1);
|
|
channel = stack->pop()->getInt();
|
|
}
|
|
if (channel < 0 || channel >= NUM_MUSIC_CHANNELS) {
|
|
stack->pushNULL();
|
|
} else {
|
|
if (!_music[channel] || !_music[channel]->getFilename()) {
|
|
stack->pushNULL();
|
|
} else {
|
|
stack->pushString(_music[channel]->getFilename());
|
|
}
|
|
}
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SetMusicPosition / SetMusicChannelPosition
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "SetMusicPosition") == 0 || strcmp(name, "SetMusicChannelPosition") == 0 || strcmp(name, "SetMusicPositionChannel") == 0) {
|
|
int channel = 0;
|
|
if (strcmp(name, "SetMusicPosition") == 0) {
|
|
stack->correctParams(1);
|
|
} else {
|
|
stack->correctParams(2);
|
|
channel = stack->pop()->getInt();
|
|
}
|
|
|
|
uint32 time = stack->pop()->getInt();
|
|
|
|
if (DID_FAIL(setMusicStartTime(channel, time))) {
|
|
stack->pushBool(false);
|
|
} else {
|
|
stack->pushBool(true);
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// GetMusicPosition / GetMusicChannelPosition
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "GetMusicPosition") == 0 || strcmp(name, "GetMusicChannelPosition") == 0) {
|
|
int channel = 0;
|
|
if (strcmp(name, "GetMusicPosition") == 0) {
|
|
stack->correctParams(0);
|
|
} else {
|
|
stack->correctParams(1);
|
|
channel = stack->pop()->getInt();
|
|
}
|
|
|
|
if (channel < 0 || channel >= NUM_MUSIC_CHANNELS || !_music[channel]) {
|
|
stack->pushInt(0);
|
|
} else {
|
|
stack->pushInt(_music[channel]->getPositionTime());
|
|
}
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// IsMusicPlaying / IsMusicChannelPlaying
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "IsMusicPlaying") == 0 || strcmp(name, "IsMusicChannelPlaying") == 0) {
|
|
int channel = 0;
|
|
if (strcmp(name, "IsMusicPlaying") == 0) {
|
|
stack->correctParams(0);
|
|
} else {
|
|
stack->correctParams(1);
|
|
channel = stack->pop()->getInt();
|
|
}
|
|
|
|
if (channel < 0 || channel >= NUM_MUSIC_CHANNELS || !_music[channel]) {
|
|
stack->pushBool(false);
|
|
} else {
|
|
stack->pushBool(_music[channel]->isPlaying());
|
|
}
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SetMusicVolume / SetMusicChannelVolume
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "SetMusicVolume") == 0 || strcmp(name, "SetMusicChannelVolume") == 0) {
|
|
int channel = 0;
|
|
if (strcmp(name, "SetMusicVolume") == 0) {
|
|
stack->correctParams(1);
|
|
} else {
|
|
stack->correctParams(2);
|
|
channel = stack->pop()->getInt();
|
|
}
|
|
|
|
int volume = stack->pop()->getInt();
|
|
if (channel < 0 || channel >= NUM_MUSIC_CHANNELS || !_music[channel]) {
|
|
stack->pushBool(false);
|
|
} else {
|
|
if (DID_FAIL(_music[channel]->setVolumePercent(volume))) {
|
|
stack->pushBool(false);
|
|
} else {
|
|
stack->pushBool(true);
|
|
}
|
|
}
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// GetMusicVolume / GetMusicChannelVolume
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "GetMusicVolume") == 0 || strcmp(name, "GetMusicChannelVolume") == 0) {
|
|
int channel = 0;
|
|
if (strcmp(name, "GetMusicVolume") == 0) {
|
|
stack->correctParams(0);
|
|
} else {
|
|
stack->correctParams(1);
|
|
channel = stack->pop()->getInt();
|
|
}
|
|
|
|
if (channel < 0 || channel >= NUM_MUSIC_CHANNELS || !_music[channel]) {
|
|
stack->pushInt(0);
|
|
} else {
|
|
stack->pushInt(_music[channel]->getVolumePercent());
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// MusicCrossfade
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "MusicCrossfade") == 0) {
|
|
stack->correctParams(4);
|
|
int channel1 = stack->pop()->getInt(0);
|
|
int channel2 = stack->pop()->getInt(0);
|
|
uint32 fadeLength = (uint32)stack->pop()->getInt(0);
|
|
bool swap = stack->pop()->getBool(true);
|
|
|
|
if (_musicCrossfadeRunning) {
|
|
script->runtimeError("Game.MusicCrossfade: Music crossfade is already in progress.");
|
|
stack->pushBool(false);
|
|
return STATUS_OK;
|
|
}
|
|
|
|
_musicCrossfadeStartTime = _gameRef->_liveTimer;
|
|
_musicCrossfadeChannel1 = channel1;
|
|
_musicCrossfadeChannel2 = channel2;
|
|
_musicCrossfadeLength = fadeLength;
|
|
_musicCrossfadeSwap = swap;
|
|
|
|
_musicCrossfadeRunning = true;
|
|
|
|
stack->pushBool(true);
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// GetSoundLength
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "GetSoundLength") == 0) {
|
|
stack->correctParams(1);
|
|
|
|
int length = 0;
|
|
const char *filename = stack->pop()->getString();
|
|
|
|
BaseSound *sound = new BaseSound(_gameRef);
|
|
if (sound && DID_SUCCEED(sound->setSound(filename, Audio::Mixer::kMusicSoundType, true))) {
|
|
length = sound->getLength();
|
|
delete sound;
|
|
sound = NULL;
|
|
}
|
|
stack->pushInt(length);
|
|
return STATUS_OK;
|
|
} else {
|
|
return STATUS_FAILED;
|
|
}
|
|
}
|
|
|
|
} // end of namespace Wintermute
|