scummvm/engines/cine/sfx_player.cpp
Eugene Sandulenko 95749148cf Add proper game detection to CinE engine.
svn-id: r24320
2006-10-15 01:06:44 +00:00

195 lines
4.7 KiB
C++

/* 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 (g_cine->getGameType() == Cine::GType_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