/* ScummVM - Scumm Interpreter * Copyright (C) 2006 The ScummVM project * * cinE Engine is (C) 2004-2005 by CinE Team * * 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. * * $URL$ * $Id$ * */ #include "common/stdafx.h" #include "common/endian.h" #include "common/system.h" #include "cine/cine.h" #include "cine/sfx_player.h" #include "cine/sound_driver.h" #include "cine/unpack.h" #include "cine/various.h" namespace Cine { SfxPlayer::SfxPlayer(SoundDriver *driver) : _playing(false), _driver(driver) { memset(_instrumentsData, 0, sizeof(_instrumentsData)); _sfxData = NULL; _fadeOutCounter = 0; _driver->setUpdateCallback(updateCallback, this); } SfxPlayer::~SfxPlayer() { _driver->setUpdateCallback(NULL, NULL); if (_playing) { stop(); } } bool SfxPlayer::load(const char *song) { debug(9, "SfxPlayer::load('%s')", song); /* stop (w/ fade out) the previous song */ while (_fadeOutCounter != 0 && _fadeOutCounter < 100) { g_system->delayMillis(50); } _fadeOutCounter = 0; if (_playing) { stop(); } /* like the original PC version, skip introduction song (file doesn't exist) */ if (gameType == Cine::GID_OS && strncmp(song, "INTRO", 5) == 0) { return 0; } _sfxData = snd_loadBasesonEntry(song); if (!_sfxData) { warning("Unable to load soundfx module '%s'", song); return 0; } for (int i = 0; i < NUM_INSTRUMENTS; ++i) { _instrumentsData[i] = NULL; char instrument[13]; memcpy(instrument, _sfxData + 20 + i * 30, 12); instrument[12] = '\0'; if (strlen(instrument) != 0) { char *dot = strrchr(instrument, '.'); if (dot) { *dot = '\0'; } strcat(instrument, _driver->getInstrumentExtension()); _instrumentsData[i] = snd_loadBasesonEntry(instrument); if (!_instrumentsData[i]) { warning("Unable to load soundfx instrument '%s'", instrument); } } } return 1; } void SfxPlayer::play() { debug(9, "SfxPlayer::play()"); if (_sfxData) { for (int i = 0; i < NUM_CHANNELS; ++i) { _instrumentsChannelTable[i] = -1; } _currentPos = 0; _currentOrder = 0; _numOrders = _sfxData[470]; _eventsDelay = (252 - _sfxData[471]) * 50 / 1060; _updateTicksCounter = 0; _playing = true; } } void SfxPlayer::stop() { _fadeOutCounter = 0; _playing = false; for (int i = 0; i < NUM_CHANNELS; ++i) { _driver->stopChannel(i); } _driver->stopSound(); unload(); } void SfxPlayer::fadeOut() { if (_playing) { _fadeOutCounter = 1; _playing = false; } } void SfxPlayer::updateCallback(void *ref) { ((SfxPlayer *)ref)->update(); } void SfxPlayer::update() { if (_playing || (_fadeOutCounter != 0 && _fadeOutCounter < 100)) { ++_updateTicksCounter; if (_updateTicksCounter > _eventsDelay) { handleEvents(); _updateTicksCounter = 0; } } } void SfxPlayer::handleEvents() { const byte *patternData = _sfxData + 600; const byte *orderTable = _sfxData + 472; uint16 patternNum = orderTable[_currentOrder] * 1024; for (int i = 0; i < 4; ++i) { handlePattern(i, patternData + patternNum + _currentPos); patternData += 4; } if (_fadeOutCounter != 0 && _fadeOutCounter < 100) { _fadeOutCounter += 2; } _currentPos += 16; if (_currentPos >= 1024) { _currentPos = 0; ++_currentOrder; if (_currentOrder == _numOrders) { _currentOrder = 0; } } debug(7, "_currentOrder=%d/%d _currentPos=%d", _currentOrder, _numOrders, _currentPos); } void SfxPlayer::handlePattern(int channel, const byte *patternData) { int instrument = patternData[2] >> 4; if (instrument != 0) { --instrument; if (_instrumentsChannelTable[channel] != instrument || _fadeOutCounter != 0) { _instrumentsChannelTable[channel] = instrument; const int volume = _sfxData[instrument] - _fadeOutCounter; _driver->setupChannel(channel, _instrumentsData[instrument], instrument, volume); } } int16 freq = (int16)READ_BE_UINT16(patternData); if (freq > 0) { _driver->stopChannel(channel); _driver->setChannelFrequency(channel, freq); } } void SfxPlayer::unload() { for (int i = 0; i < NUM_INSTRUMENTS; ++i) { free(_instrumentsData[i]); _instrumentsData[i] = NULL; } free(_sfxData); _sfxData = NULL; } } // End of namespace Cine