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

player_v3a.cpp

/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001  Ludvig Strigeus
 * Copyright (C) 2001-2005 The ScummVM project
 *
 * 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.
 *
 * $Header: /cvsroot/scummvm/scummvm/scumm/player_v3a.cpp,v 1.25.2.1 2005/10/18 02:11:21 sev Exp $
 *
 */

#include "common/stdafx.h"
#include "base/engine.h"
#include "scumm/player_v3a.h"
#include "scumm/scumm.h"

namespace Scumm {

static const uint16 note_freqs[4][12] = {
      {0x06B0, 0x0650, 0x05F4, 0x05A0, 0x054C, 0x0500, 0x04B8, 0x0474, 0x0434, 0x03F8, 0x03C0, 0x0388},
      {0x0358, 0x0328, 0x02FA, 0x02D0, 0x02A6, 0x0280, 0x025C, 0x023A, 0x021A, 0x01FC, 0x01E0, 0x01C4},
      {0x01AC, 0x0194, 0x017D, 0x0168, 0x0153, 0x0140, 0x012E, 0x011D, 0x010D, 0x00FE, 0x00F0, 0x00E2},
      {0x00D6, 0x00CA, 0x00BE, 0x00B4, 0x00A9, 0x00A0, 0x0097, 0x008E, 0x0086, 0x007F, 0x00F0, 0x00E2}
};

Player_V3A::Player_V3A(ScummEngine *scumm) {
      int i;
      _vm = scumm;
      for (i = 0; i < V3A_MAXMUS; i++) {
            _mus[i].id = 0;
            _mus[i].dur = 0;
      }
      for (i = 0; i < V3A_MAXSFX; i++) {
            _sfx[i].id = 0;
            _sfx[i].dur = 0;
      }

      _curSong = 0;
      _songData = NULL;
      _songPtr = 0;
      _songDelay = 0;

      _music_timer = 0;

      _isinit = false;

      _mod = new Player_MOD(scumm);
      _mod->setUpdateProc(update_proc, this, 60);
}

Player_V3A::~Player_V3A() {
      int i;
      delete _mod;
      if (_isinit) {
            for (i = 0; _wavetable[i] != NULL; i++) {
                  for (int j = 0; j < 6; j++) {
                        free(_wavetable[i]->_idat[j]);
                        free(_wavetable[i]->_ldat[j]);
                  }
                  free(_wavetable[i]);
            }
            free(_wavetable);
      }
}

00077 void Player_V3A::setMusicVolume (int vol) {
      _mod->setMusicVolume(vol);
}

int Player_V3A::getMusChan (int id) const {
      int i;
      for (i = 0; i < V3A_MAXMUS; i++) {
            if (_mus[i].id == id)
                  break;
      }
      if (i == V3A_MAXMUS) {
            if (id == 0)
                  warning("player_v3a - out of music channels");
            return -1;
      }
      return i;
}
int Player_V3A::getSfxChan (int id) const {
      int i;
      for (i = 0; i < V3A_MAXSFX; i++) {
            if (_sfx[i].id == id)
                  break;
      }
      if (i == V3A_MAXSFX) {
            if (id == 0)
                  warning("player_v3a - out of sfx channels");
            return -1;
      }
      return i;
}

00108 void Player_V3A::stopAllSounds() {
      int i;
      for (i = 0; i < V3A_MAXMUS; i++) {
            if (_mus[i].id)
                  _mod->stopChannel(_mus[i].id);
            _mus[i].id = 0;
            _mus[i].dur = 0;
      }
      _curSong = 0;
      _songPtr = 0;
      _songDelay = 0;
      _songData = NULL;
      for (i = 0; i < V3A_MAXSFX; i++) {
            if (_sfx[i].id)
                  _mod->stopChannel(_sfx[i].id | 0x100);
            _sfx[i].id = 0;
            _sfx[i].dur = 0;
      }
}

00128 void Player_V3A::stopSound(int nr) {
      int i;
      if (nr == 0) {    // Amiga Loom does this near the end, when Chaos casts SILENCE on Hetchel
            stopAllSounds();
            return;
      }
      if (nr == _curSong) {
            for (i = 0; i < V3A_MAXMUS; i++) {
                  if (_mus[i].id)
                        _mod->stopChannel(_mus[i].id);
                  _mus[i].id = 0;
                  _mus[i].dur = 0;
            }
            _curSong = 0;
            _songPtr = 0;
            _songDelay = 0;
            _songData = NULL;
      } else {
            i = getSfxChan(nr);
            if (i != -1) {
                  _mod->stopChannel(nr | 0x100);
                  _sfx[i].id = 0;
                  _sfx[i].dur = 0;
            }
      }
}

00155 void Player_V3A::startSound(int nr) {
      assert(_vm);
      byte *data = _vm->getResourceAddress(rtSound, nr);
      assert(data);

      if ((_vm->_gameId != GID_INDY3) && (_vm->_gameId != GID_LOOM))
            error("player_v3a - unknown game!");

      if (!_isinit) {
            int i;
            unsigned char *ptr;
            int offset = 4;
            int numInstruments;

            if (_vm->_gameId == GID_INDY3) {
                  ptr = _vm->getResourceAddress(rtSound, 83);
                  numInstruments = 12;
            } else {
                  ptr = _vm->getResourceAddress(rtSound, 79);
                  numInstruments = 9;
            }
            assert(ptr);
            _wavetable = (instData **)malloc((numInstruments + 1) * sizeof(void *));
            for (i = 0; i < numInstruments; i++) {
                  _wavetable[i] = (instData *)malloc(sizeof(instData));
                  for (int j = 0; j < 6; j++) {
                        int off, len;
                        off = READ_BE_UINT16(ptr + offset + 0);
                        _wavetable[i]->_ilen[j] = len = READ_BE_UINT16(ptr + offset + 2);
                        if (len) {
                              _wavetable[i]->_idat[j] = (char *)malloc(len);
                              memcpy(_wavetable[i]->_idat[j],ptr + off,len);
                        } else      _wavetable[i]->_idat[j] = NULL;
                        off = READ_BE_UINT16(ptr + offset + 4);
                        _wavetable[i]->_llen[j] = len = READ_BE_UINT16(ptr + offset + 6);
                        if (len) {
                              _wavetable[i]->_ldat[j] = (char *)malloc(len);
                              memcpy(_wavetable[i]->_ldat[j],ptr + off,len);
                        } else      _wavetable[i]->_ldat[j] = NULL;
                        _wavetable[i]->_oct[j] = READ_BE_UINT16(ptr + offset + 8);
                        offset += 10;
                  }
                  if (_vm->_gameId == GID_INDY3) {
                        _wavetable[i]->_pitadjust = 0;
                        offset += 2;
                  } else {
                        _wavetable[i]->_pitadjust = READ_BE_UINT16(ptr + offset + 2);
                        offset += 4;
                  }
            }
            _wavetable[i] = NULL;
            _isinit = true;
      }

      if (getSoundStatus(nr))
            stopSound(nr);    // if a sound is playing, restart it

      if (data[26]) {
            if (_curSong)
                  stopSound(_curSong);
            _curSong = nr;
            _songData = data;
            _songPtr = 0x1C;
            _songDelay = 1;
            _music_timer = 0;
      } else {
            int size = READ_BE_UINT16(data + 12);
            int rate = 3579545 / READ_BE_UINT16(data + 20);
            char *sound = (char *)malloc(size);
            int vol = (data[24] << 1) | (data[24] >> 5);    // if I boost this to 0-255, it gets too loud and starts to clip
            memcpy(sound,data + READ_BE_UINT16(data + 8),size);
            int loopStart = 0, loopEnd = 0;
            bool looped = false;
            if ((READ_BE_UINT16(data + 16) || READ_BE_UINT16(data + 6))) {
                  loopStart = READ_BE_UINT16(data + 10) - READ_BE_UINT16(data + 8);
                  loopEnd = READ_BE_UINT16(data + 14);
                  looped = true;
            }
            int i = getSfxChan();
            if (i == -1)
            {
                  free(sound);
                  return;
            }
            _sfx[i].id = nr;
            _sfx[i].dur = looped ? -1 : (1 + 60 * size / rate);
            if ((_vm->_gameId == GID_INDY3) && (nr == 60))
                  _sfx[i].dur = 240;
            _mod->startChannel(nr | 0x100, sound, size, rate, vol, loopStart, loopEnd);
      }
}

void Player_V3A::update_proc(void *param) {
      ((Player_V3A *)param)->playMusic();
}

void Player_V3A::playMusic() {
      int i;
      for (i = 0; i < V3A_MAXMUS; i++) {
            if (_mus[i].id) {
                  _mus[i].dur--;
                  if (_mus[i].dur)
                        continue;
                  _mod->stopChannel(_mus[i].id);
                  _mus[i].id = 0;
            }
      }
      for (i = 0; i < V3A_MAXSFX; i++) {
            if (_sfx[i].id) {
                  _sfx[i].dur--;
                  if (_sfx[i].dur)
                        continue;
                  _mod->stopChannel(_sfx[i].id | 0x100);
                  _sfx[i].id = 0;
            }
      }

      _music_timer++;
      if (!_curSong)
            return;
      if (_songDelay && --_songDelay)
            return;
      if (_songPtr == 0) {
            // at the end of the song, and it wasn't looped - kill it
            _curSong = 0;
            return;
      }
      while (1) {
            int inst, pit, vol, dur, oct;
            inst = _songData[_songPtr++];
            if ((inst & 0xF0) != 0x80) {
                  // tune is at the end - figure out what's still playing
                  // and see how long we have to wait until we stop/restart
                  for (i = 0; i < V3A_MAXMUS; i++) {
                        if (_songDelay < _mus[i].dur)
                              _songDelay = _mus[i].dur;
                  }
                  if (inst == 0xFB) // it's a looped song, restart it afterwards
                        _songPtr = 0x1C;
                  else  _songPtr = 0;     // otherwise, terminate it
                  break;
            }
            inst &= 0xF;
            pit = _songData[_songPtr++];
            vol = _songData[_songPtr++] & 0x7F; // if I boost this to 0-255, it gets too loud and starts to clip
            dur = _songData[_songPtr++];
            if (pit == 0) {
                  _songDelay = dur;
                  break;
            }
            pit += _wavetable[inst]->_pitadjust;
            oct = (pit / 12) - 2;
            pit = pit % 12;
            if (oct < 0)
                  oct = 0;
            if (oct > 5)
                  oct = 5;
            int rate = 3579545 / note_freqs[_wavetable[inst]->_oct[oct]][pit];
            if (!_wavetable[inst]->_llen[oct])
                  dur = _wavetable[inst]->_ilen[oct] * 60 / rate;
            char *data = (char *)malloc(_wavetable[inst]->_ilen[oct] + _wavetable[inst]->_llen[oct]);
            if (_wavetable[inst]->_idat[oct])
                  memcpy(data, _wavetable[inst]->_idat[oct], _wavetable[inst]->_ilen[oct]);
            if (_wavetable[inst]->_ldat[oct])
                  memcpy(data + _wavetable[inst]->_ilen[oct], _wavetable[inst]->_ldat[oct], _wavetable[inst]->_llen[oct]);

            i = getMusChan();
            if (i == -1)
            {
                  free(data);
                  return;
            }
            _mus[i].id = i + 1;
            _mus[i].dur = dur + 1;
            _mod->startChannel(_mus[i].id, data, _wavetable[inst]->_ilen[oct] + _wavetable[inst]->_llen[oct], rate, vol,
                  _wavetable[inst]->_ilen[oct], _wavetable[inst]->_ilen[oct] + _wavetable[inst]->_llen[oct]);
      }
}

00334 int Player_V3A::getMusicTimer() const {
      return _music_timer / 30;
}

00338 int Player_V3A::getSoundStatus(int nr) const {
      if (nr == _curSong)
            return 1;
      if (getSfxChan(nr) != -1)
            return 1;
      return 0;
}

} // End of namespace Scumm

Generated by  Doxygen 1.6.0   Back to index