/* 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] = nullptr; _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] = nullptr; _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] = nullptr; _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] = nullptr; 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] = nullptr; 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->getLiveTimer()->getTime() - _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->transferPtr(TMEMBER_PTR(_music[i])); persistMgr->transferUint32(TMEMBER(_musicStartTime[i])); } return true; } bool BaseGameMusic::persistCrossfadeSettings(BasePersistenceManager *persistMgr) { persistMgr->transferBool(TMEMBER(_musicCrossfadeRunning)); persistMgr->transferUint32(TMEMBER(_musicCrossfadeStartTime)); persistMgr->transferUint32(TMEMBER(_musicCrossfadeLength)); persistMgr->transferSint32(TMEMBER(_musicCrossfadeChannel1)); persistMgr->transferSint32(TMEMBER(_musicCrossfadeChannel2)); persistMgr->transferBool(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->getLiveTimer()->getTime(); _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 = nullptr; } stack->pushInt(length); return STATUS_OK; } else { return STATUS_FAILED; } } } // End of namespace Wintermute