Logo Search packages:      
Sourcecode: scummvm version File versions  Download package

sfx_player.cpp

/* 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: https://svn.sourceforge.net/svnroot/scummvm/scummvm/tags/release-0-9-1/engines/cine/sfx_player.cpp $
 * $Id: sfx_player.cpp 21500 2006-03-29 15:59:37Z fingolfin $
 *
 */

#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

Generated by  Doxygen 1.6.0   Back to index