diff options
Diffstat (limited to 'engines/zvision/scripting/effects/music_effect.cpp')
-rw-r--r-- | engines/zvision/scripting/effects/music_effect.cpp | 296 |
1 files changed, 296 insertions, 0 deletions
diff --git a/engines/zvision/scripting/effects/music_effect.cpp b/engines/zvision/scripting/effects/music_effect.cpp new file mode 100644 index 0000000000..e3fdc96dba --- /dev/null +++ b/engines/zvision/scripting/effects/music_effect.cpp @@ -0,0 +1,296 @@ +/* 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 "common/scummsys.h" + +#include "zvision/scripting/effects/music_effect.h" + +#include "zvision/zvision.h" +#include "zvision/scripting/script_manager.h" +#include "zvision/graphics/render_manager.h" +#include "zvision/sound/midi.h" +#include "zvision/sound/zork_raw.h" + +#include "common/stream.h" +#include "common/file.h" +#include "audio/decoders/wave.h" + +namespace ZVision { + +static const uint8 dbMapLinear[256] = +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, +2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, +4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, +8, 8, 8, 9, 9, 9, 10, 10, 11, 11, 11, 12, 12, 13, 13, 14, +14, 15, 15, 16, 16, 17, 18, 18, 19, 20, 21, 21, 22, 23, 24, 25, +26, 27, 28, 29, 30, 31, 32, 33, 34, 36, 37, 38, 40, 41, 43, 45, +46, 48, 50, 52, 53, 55, 57, 60, 62, 64, 67, 69, 72, 74, 77, 80, +83, 86, 89, 92, 96, 99, 103, 107, 111, 115, 119, 123, 128, 133, 137, 143, +148, 153, 159, 165, 171, 177, 184, 191, 198, 205, 212, 220, 228, 237, 245, 255}; + +MusicNode::MusicNode(ZVision *engine, uint32 key, Common::String &filename, bool loop, uint8 volume) + : MusicNodeBASE(engine, key, SCRIPTING_EFFECT_AUDIO) { + _loop = loop; + _volume = volume; + _deltaVolume = 0; + _balance = 0; + _crossfade = false; + _crossfadeTarget = 0; + _crossfadeTime = 0; + _sub = NULL; + _stereo = false; + _loaded = false; + + Audio::RewindableAudioStream *audioStream = NULL; + + if (filename.contains(".wav")) { + Common::File *file = new Common::File(); + if (_engine->getSearchManager()->openFile(*file, filename)) { + audioStream = Audio::makeWAVStream(file, DisposeAfterUse::YES); + } + } else { + audioStream = makeRawZorkStream(filename, _engine); + } + + if (audioStream) { + _stereo = audioStream->isStereo(); + + if (_loop) { + Audio::LoopingAudioStream *loopingAudioStream = new Audio::LoopingAudioStream(audioStream, 0, DisposeAfterUse::YES); + _engine->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_handle, loopingAudioStream, -1, dbMapLinear[_volume]); + } else { + _engine->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_handle, audioStream, -1, dbMapLinear[_volume]); + } + + if (_key != StateKey_NotSet) + _engine->getScriptManager()->setStateValue(_key, 1); + + // Change filename.raw into filename.sub + Common::String subname = filename; + subname.setChar('s', subname.size() - 3); + subname.setChar('u', subname.size() - 2); + subname.setChar('b', subname.size() - 1); + + if (_engine->getSearchManager()->hasFile(subname)) + _sub = new Subtitle(_engine, subname); + + _loaded = true; + } +} + +MusicNode::~MusicNode() { + if (_loaded) + _engine->_mixer->stopHandle(_handle); + if (_key != StateKey_NotSet) + _engine->getScriptManager()->setStateValue(_key, 2); + if (_sub) + delete _sub; + debug(1, "MusicNode: %d destroyed", _key); +} + +void MusicNode::setDeltaVolume(uint8 volume) { + _deltaVolume = volume; + setVolume(_volume); +} + +void MusicNode::setBalance(int8 balance) { + _balance = balance; + _engine->_mixer->setChannelBalance(_handle, _balance); +} + +void MusicNode::setFade(int32 time, uint8 target) { + _crossfadeTarget = target; + _crossfadeTime = time; + _crossfade = true; +} + +bool MusicNode::process(uint32 deltaTimeInMillis) { + if (!_loaded || ! _engine->_mixer->isSoundHandleActive(_handle)) + return stop(); + else { + uint8 _newvol = _volume; + + if (_crossfade) { + if (_crossfadeTime > 0) { + if ((int32)deltaTimeInMillis > _crossfadeTime) + deltaTimeInMillis = _crossfadeTime; + _newvol += (int)(floor(((float)(_crossfadeTarget - _newvol) / (float)_crossfadeTime)) * (float)deltaTimeInMillis); + _crossfadeTime -= deltaTimeInMillis; + } else { + _crossfade = false; + _newvol = _crossfadeTarget; + } + } + + if (_volume != _newvol) + setVolume(_newvol); + + if (_sub && _engine->getScriptManager()->getStateValue(StateKey_Subtitles) == 1) + _sub->process(_engine->_mixer->getSoundElapsedTime(_handle) / 100); + } + return false; +} + +void MusicNode::setVolume(uint8 newVolume) { + if (!_loaded) + return; + + _volume = newVolume; + + if (_deltaVolume >= _volume) + _engine->_mixer->setChannelVolume(_handle, 0); + else + _engine->_mixer->setChannelVolume(_handle, dbMapLinear[_volume - _deltaVolume]); +} + +uint8 MusicNode::getVolume() { + return _volume; +} + +PanTrackNode::PanTrackNode(ZVision *engine, uint32 key, uint32 slot, int16 pos) + : ScriptingEffect(engine, key, SCRIPTING_EFFECT_PANTRACK) { + _slot = slot; + _position = pos; + + // Try to set pan value for music node immediately + process(0); +} + +PanTrackNode::~PanTrackNode() { +} + +bool PanTrackNode::process(uint32 deltaTimeInMillis) { + ScriptManager * scriptManager = _engine->getScriptManager(); + ScriptingEffect *fx = scriptManager->getSideFX(_slot); + if (fx && fx->getType() == SCRIPTING_EFFECT_AUDIO) { + MusicNodeBASE *mus = (MusicNodeBASE *)fx; + + int curPos = scriptManager->getStateValue(StateKey_ViewPos); + int16 _width = _engine->getRenderManager()->getBkgSize().x; + int16 _halfWidth = _width / 2; + int16 _quarterWidth = _width / 4; + + int tmp = 0; + if (curPos <= _position) + tmp = _position - curPos; + else + tmp = _position - curPos + _width; + + int balance = 0; + + if (tmp > _halfWidth) + tmp -= _width; + + if (tmp > _quarterWidth) { + balance = 1; + tmp = _halfWidth - tmp; + } else if (tmp < -_quarterWidth) { + balance = -1; + tmp = -_halfWidth - tmp; + } + + // Originally it's value -90...90 but we use -127...127 and therefore 360 replaced by 508 + mus->setBalance( (508 * tmp) / _width ); + + tmp = (360 * tmp) / _width; + + int deltaVol = balance; + + // This value sets how fast volume goes off than sound source back of you + // By this value we can hack some "bugs" have place in originall game engine like beat sound in ZGI-dc10 + int volumeCorrection = 2; + + if (_engine->getGameId() == GID_GRANDINQUISITOR) { + if (scriptManager->getCurrentLocation() == "dc10") + volumeCorrection = 5; + } + + if (deltaVol != 0) + deltaVol = (mus->getVolume() * volumeCorrection) * (90 - tmp * balance) / 90; + if (deltaVol > 255) + deltaVol = 255; + + mus->setDeltaVolume(deltaVol); + } + return false; +} + +MusicMidiNode::MusicMidiNode(ZVision *engine, uint32 key, int8 program, int8 note, int8 volume) + : MusicNodeBASE(engine, key, SCRIPTING_EFFECT_AUDIO) { + _volume = volume; + _prog = program; + _noteNumber = note; + _pan = 0; + + _chan = _engine->getMidiManager()->getFreeChannel(); + + if (_chan >= 0) { + _engine->getMidiManager()->setVolume(_chan, _volume); + _engine->getMidiManager()->setPan(_chan, _pan); + _engine->getMidiManager()->setProgram(_chan, _prog); + _engine->getMidiManager()->noteOn(_chan, _noteNumber, _volume); + } + + if (_key != StateKey_NotSet) + _engine->getScriptManager()->setStateValue(_key, 1); +} + +MusicMidiNode::~MusicMidiNode() { + if (_chan >= 0) { + _engine->getMidiManager()->noteOff(_chan); + } + if (_key != StateKey_NotSet) + _engine->getScriptManager()->setStateValue(_key, 2); +} + +void MusicMidiNode::setDeltaVolume(uint8 volume) { +} + +void MusicMidiNode::setBalance(int8 balance) { +} + +void MusicMidiNode::setFade(int32 time, uint8 target) { +} + +bool MusicMidiNode::process(uint32 deltaTimeInMillis) { + return false; +} + +void MusicMidiNode::setVolume(uint8 newVolume) { + if (_chan >= 0) { + _engine->getMidiManager()->setVolume(_chan, newVolume); + } + _volume = newVolume; +} + +uint8 MusicMidiNode::getVolume() { + return _volume; +} + +} // End of namespace ZVision |