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

res_snd.cpp

/* 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.
 *
 * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/tags/release-1-2-0/engines/agos/res_snd.cpp $
 * $Id: res_snd.cpp 48645 2010-04-12 21:21:06Z salty-horse $
 *
 */

#include "common/config-manager.h"
#include "common/file.h"

#include "agos/intern.h"
#include "agos/agos.h"
#include "agos/vga.h"

#include "sound/audiocd.h"
#include "sound/audiostream.h"
#include "sound/mididrv.h"
#include "sound/mods/protracker.h"

using Common::File;

namespace AGOS {

void AGOSEngine_Simon1::playSpeech(uint16 speech_id, uint16 vgaSpriteId) {
      if (speech_id == 9999) {
            if (_subtitles)
                  return;
            if (!getBitFlag(14) && !getBitFlag(28)) {
                  setBitFlag(14, true);
                  _variableArray[100] = 15;
                  animate(4, 1, 130, 0, 0, 0);
                  waitForSync(130);
            }
            _skipVgaWait = true;
      } else {
            if (_subtitles && _scriptVar2) {
                  animate(4, 2, 204, 0, 0, 0);
                  waitForSync(204);
                  stopAnimate(204);
            }
            if (vgaSpriteId < 100)
                  stopAnimate(201 + vgaSpriteId);

            loadVoice(speech_id);

            if (vgaSpriteId < 100)
                  animate(4, 2, 201 + vgaSpriteId, 0, 0, 0);
      }
}

void AGOSEngine_Simon2::playSpeech(uint16 speech_id, uint16 vgaSpriteId) {
      if (speech_id == 0xFFFF) {
            if (_subtitles)
                  return;
            if (!getBitFlag(14) && !getBitFlag(28)) {
                  setBitFlag(14, true);
                  _variableArray[100] = 5;
                  animate(4, 1, 30, 0, 0, 0);
                  waitForSync(130);
            }
            _skipVgaWait = true;
      } else {
            if (getGameType() == GType_SIMON2 && _subtitles && _language != Common::HE_ISR) {
                  loadVoice(speech_id);
                  return;
            }

            if (_subtitles && _scriptVar2) {
                  animate(4, 2, 5, 0, 0, 0);
                  waitForSync(205);
                  stopAnimateSimon2(2,5);
            }

            stopAnimateSimon2(2, vgaSpriteId + 2);
            loadVoice(speech_id);
            animate(4, 2, vgaSpriteId + 2, 0, 0, 0);
      }
}

void AGOSEngine::skipSpeech() {
      _sound->stopVoice();
      if (!getBitFlag(28)) {
            setBitFlag(14, true);
            if (getGameType() == GType_FF) {
                  _variableArray[103] = 5;
                  animate(4, 2, 13, 0, 0, 0);
                  waitForSync(213);
                  stopAnimateSimon2(2, 1);
            } else if (getGameType() == GType_SIMON2) {
                  _variableArray[100] = 5;
                  animate(4, 1, 30, 0, 0, 0);
                  waitForSync(130);
                  stopAnimateSimon2(2, 1);
            } else {
                  _variableArray[100] = 15;
                  animate(4, 1, 130, 0, 0, 0);
                  waitForSync(130);
                  stopAnimate(1);
            }
      }
}

void AGOSEngine::loadMusic(uint16 music) {
      char buf[4];

      stopMusic();

      _gameFile->seek(_gameOffsetsPtr[_musicIndexBase + music - 1], SEEK_SET);
      _gameFile->read(buf, 4);
      if (!memcmp(buf, "FORM", 4)) {
            _gameFile->seek(_gameOffsetsPtr[_musicIndexBase + music - 1], SEEK_SET);
            _midi.loadXMIDI(_gameFile);
      } else {
            _gameFile->seek(_gameOffsetsPtr[_musicIndexBase + music - 1], SEEK_SET);
            _midi.loadMultipleSMF(_gameFile);
      }

      _lastMusicPlayed = music;
      _nextMusicToPlay = -1;
}

struct ModuleOffs {
      uint8 tune;
      uint8 fileNum;
      uint32 offs;
};

static const ModuleOffs amigaWaxworksOffs[20] = {
      // Pyramid
      {2,   2, 0,   },
      {3,   2, 50980},
      {4,   2, 56160},
      {5,   2, 62364},
      {6,   2, 73688},

      // Zombie
      {8,   8, 0},
      {11,  8, 51156},
      {12,  8, 56336},
      {13,  8, 65612},
      {14,  8, 68744},

      // Mine
      {9,   9, 0},
      {15,  9, 47244},
      {16,  9, 52424},
      {17,  9, 59652},
      {18,  9, 62784},

      // Jack
      {10, 10, 0},
      {19, 10, 42054},
      {20, 10, 47234},
      {21, 10, 49342},
      {22, 10, 51450},
};

void AGOSEngine::playModule(uint16 music) {
      char filename[15];
      File f;
      uint32 offs = 0;

      if (getPlatform() == Common::kPlatformAmiga && getGameType() == GType_WW) {
            // Multiple tunes are stored in music files for main locations
            for (uint i = 0; i < 20; i++) {
                  if (amigaWaxworksOffs[i].tune == music) {
                        music = amigaWaxworksOffs[i].fileNum;
                        offs = amigaWaxworksOffs[i].offs;
                  }
            }
      }

      if (getGameType() == GType_ELVIRA1 && getFeatures() & GF_DEMO)
            sprintf(filename, "elvira2");
      else if (getPlatform() == Common::kPlatformAcorn)
            sprintf(filename, "%dtune.DAT", music);
      else
            sprintf(filename, "%dtune", music);

      f.open(filename);
      if (f.isOpen() == false) {
            error("playModule: Can't load module from '%s'", filename);
      }

      Audio::AudioStream *audioStream;
      if (!(getGameType() == GType_ELVIRA1 && getFeatures() & GF_DEMO) &&
            getFeatures() & GF_CRUNCHED) {

            uint32 srcSize = f.size();
            byte *srcBuf = (byte *)malloc(srcSize);
            if (f.read(srcBuf, srcSize) != srcSize)
                  error("playModule: Read failed");

            uint32 dstSize = READ_BE_UINT32(srcBuf + srcSize - 4);
            byte *dstBuf = (byte *)malloc(dstSize);
            decrunchFile(srcBuf, dstBuf, srcSize);
            free(srcBuf);

            Common::MemoryReadStream stream(dstBuf, dstSize);
            audioStream = Audio::makeProtrackerStream(&stream, offs);
            free(dstBuf);
      } else {
            audioStream = Audio::makeProtrackerStream(&f);
      }

      _mixer->playStream(Audio::Mixer::kMusicSoundType, &_modHandle, audioStream);
}

void AGOSEngine_Simon1::playMusic(uint16 music, uint16 track) {
      stopMusic();

      // Support for compressed music from the ScummVM Music Enhancement Project
      AudioCD.stop();
      AudioCD.play(music + 1, -1, 0, 0);
      if (AudioCD.isPlaying())
            return;

      if (getPlatform() == Common::kPlatformAmiga) {
            playModule(music);
      } else if (getFeatures() & GF_TALKIE) {
            char buf[4];

            // WORKAROUND: For a script bug in the CD versions
            // We skip this music resource, as it was replaced by
            // a sound effect, and the script was never updated.
            if (music == 35)
                  return;

            _midi.setLoop(true); // Must do this BEFORE loading music. (GMF may have its own override.)

            _gameFile->seek(_gameOffsetsPtr[_musicIndexBase + music], SEEK_SET);
            _gameFile->read(buf, 4);
            if (!memcmp(buf, "GMF\x1", 4)) {
                  _gameFile->seek(_gameOffsetsPtr[_musicIndexBase + music], SEEK_SET);
                  _midi.loadSMF(_gameFile, music);
            } else {
                  _gameFile->seek(_gameOffsetsPtr[_musicIndexBase + music], SEEK_SET);
                  _midi.loadMultipleSMF(_gameFile);
            }

            _midi.startTrack(0);
            _midi.startTrack(track);
      } else if (getPlatform() == Common::kPlatformAcorn) {
            // TODO: Add support for Desktop Tracker format in Acorn disk version
      } else {
            char filename[15];
            File f;
            sprintf(filename, "MOD%d.MUS", music);
            f.open(filename);
            if (f.isOpen() == false)
                  error("playMusic: Can't load music from '%s'", filename);

            _midi.setLoop(true); // Must do this BEFORE loading music. (GMF may have its own override.)

            if (getFeatures() & GF_DEMO)
                  _midi.loadS1D(&f);
            else
                  _midi.loadSMF(&f, music);

            _midi.startTrack(0);
            _midi.startTrack(track);
      }
}

void AGOSEngine::playMusic(uint16 music, uint16 track) {
      stopMusic();

      if (getPlatform() == Common::kPlatformAmiga) {
            playModule(music);
      } else if (getPlatform() == Common::kPlatformAtariST) {
            // TODO: Add support for music formats used
      } else {
            _midi.setLoop(true); // Must do this BEFORE loading music.

            char filename[15];
            File f;
            sprintf(filename, "MOD%d.MUS", music);
            f.open(filename);
            if (f.isOpen() == false)
                  error("playMusic: Can't load music from '%s'", filename);

            _midi.loadS1D(&f);
            _midi.startTrack(0);
            _midi.startTrack(track);
      }
}

void AGOSEngine::stopMusic() {
      if (_midiEnabled) {
            _midi.stop();
      }
      _mixer->stopHandle(_modHandle);
}

void AGOSEngine::playSting(uint16 soundId) {
      if (!_midi._enable_sfx)
            return;

      char filename[15];

      File mus_file;
      uint16 mus_offset;

      sprintf(filename, "STINGS%i.MUS", _soundFileId);
      mus_file.open(filename);
      if (!mus_file.isOpen())
            error("playSting: Can't load sound effect from '%s'", filename);

      mus_file.seek(soundId * 2, SEEK_SET);
      mus_offset = mus_file.readUint16LE();
      if (mus_file.err())
            error("playSting: Can't read sting %d offset", soundId);

      mus_file.seek(mus_offset, SEEK_SET);
      _midi.loadSMF(&mus_file, soundId, true);
      _midi.startTrack(0);
}

static const byte elvira1_soundTable[100] = {
      0, 2, 0, 1, 0, 0, 0, 0, 0, 3,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 6, 4, 0, 0, 9, 0,
      0, 2, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 8, 0, 0, 0, 0, 0, 0, 0, 0,
      1, 1, 0, 0, 5, 0, 6, 6, 0, 0,
      0, 5, 0, 0, 6, 0, 0, 0, 0, 8,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};

bool AGOSEngine::loadVGASoundFile(uint16 id, uint8 type) {
      File in;
      char filename[15];
      byte *dst;
      uint32 srcSize, dstSize;

      if (getPlatform() == Common::kPlatformAmiga || getPlatform() == Common::kPlatformAtariST) {
            if (getGameType() == GType_ELVIRA1 && (getFeatures() & GF_DEMO) &&
                  getPlatform() == Common::kPlatformAmiga) {
                  sprintf(filename, "%c%d.out", 48 + id, type);
            } else if (getGameType() == GType_ELVIRA1 || getGameType() == GType_ELVIRA2) {
                  sprintf(filename, "%.2d%d.out", id, type);
            } else if (getGameType() == GType_PN) {
                  sprintf(filename, "%c%d.in", id + 48, type);
            } else {
                  sprintf(filename, "%.3d%d.out", id, type);
            }
      } else {
            if (getGameType() == GType_ELVIRA1) {
                  if (elvira1_soundTable[id] == 0)
                        return false;

                  sprintf(filename, "%.2d.SND", elvira1_soundTable[id]);
            } else if (getGameType() == GType_ELVIRA2 || getGameType() == GType_WW) {
                  sprintf(filename, "%.2d%d.VGA", id, type);
            } else if (getGameType() == GType_PN) {
                  sprintf(filename, "%c%d.out", id + 48, type);
            } else {
                  sprintf(filename, "%.3d%d.VGA", id, type);
            }
      }

      in.open(filename);
      if (in.isOpen() == false || in.size() == 0) {
            return false;
      }

      dstSize = srcSize = in.size();
      if (getGameType() == GType_PN && (getFeatures() & GF_CRUNCHED)) {
            Common::Stack<uint32> data;
            byte *dataOut = 0;
            int dataOutSize = 0;

            for (uint i = 0; i < srcSize / 4; ++i)
                  data.push(in.readUint32BE());

            decompressPN(data, dataOut, dataOutSize);
            dst = allocBlock (dataOutSize);
            memcpy(dst, dataOut, dataOutSize);
            delete[] dataOut;
      } else if (getGameType() == GType_ELVIRA1 && getFeatures() & GF_DEMO) {
            byte *srcBuffer = (byte *)malloc(srcSize);
            if (in.read(srcBuffer, srcSize) != srcSize)
                  error("loadVGASoundFile: Read failed");

            dstSize = READ_BE_UINT32(srcBuffer + srcSize - 4);
            dst = allocBlock (dstSize);
            decrunchFile(srcBuffer, dst, srcSize);
            free(srcBuffer);
      } else {
            dst = allocBlock(dstSize);
            if (in.read(dst, dstSize) != dstSize)
                  error("loadVGASoundFile: Read failed");
      }
      in.close();

      return true;
}

static const char *dimpSoundList[32] = {
      "Beep",
      "Birth",
      "Boiling",
      "Burp",
      "Cough",
      "Die1",
      "Die2",
      "Fart",
      "Inject",
      "Killchik",
      "Puke",
      "Lights",
      "Shock",
      "Snore",
      "Snotty",
      "Whip",
      "Whistle",
      "Work1",
      "Work2",
      "Yawn",
      "And0w",
      "And0x",
      "And0y",
      "And0z",
      "And10",
      "And11",
      "And12",
      "And13",
      "And14",
      "And15",
      "And16",
      "And17",
};


void AGOSEngine::loadSoundFile(const char* filename) {
      File in;

      in.open(filename);
      if (in.isOpen() == false)
            error("loadSound: Can't load %s", filename);

      uint32 dstSize = in.size();
      byte *dst = (byte *)malloc(dstSize);
      if (in.read(dst, dstSize) != dstSize)
            error("loadSound: Read failed");
      in.close();

      _sound->playSfxData(dst, 0, 0, 0);
}

void AGOSEngine::loadSound(uint16 sound, int16 pan, int16 vol, uint16 type) {
      byte *dst;

      if (getGameId() == GID_DIMP) {
            File in;
            char filename[15];

            assert(sound >= 1 && sound <= 32);
            sprintf(filename, "%s.wav", dimpSoundList[sound - 1]);

            in.open(filename);
            if (in.isOpen() == false)
                  error("loadSound: Can't load %s", filename);

            uint32 dstSize = in.size();
            dst = (byte *)malloc(dstSize);
            if (in.read(dst, dstSize) != dstSize)
                  error("loadSound: Read failed");
            in.close();
      } else if (getFeatures() & GF_ZLIBCOMP) {
            char filename[15];

            uint32 file, offset, srcSize, dstSize;
            if (getPlatform() == Common::kPlatformAmiga) {
                  loadOffsets((const char*)"sfxindex.dat", _zoneNumber * 22 + sound, file, offset, srcSize, dstSize);
            } else {
                  loadOffsets((const char*)"effects.wav", _zoneNumber * 22 + sound, file, offset, srcSize, dstSize);
            }

            if (getPlatform() == Common::kPlatformAmiga)
                  sprintf(filename, "sfx%d.wav", file);
            else
                  sprintf(filename, "effects.wav");

            dst = (byte *)malloc(dstSize);
            decompressData(filename, dst, offset, srcSize, dstSize);
      } else {
            if (_curSfxFile == NULL)
                  return;

            dst = _curSfxFile + READ_LE_UINT32(_curSfxFile + sound * 4);
      }

      if (type == Sound::TYPE_AMBIENT)
            _sound->playAmbientData(dst, sound, pan, vol);
      else if (type == Sound::TYPE_SFX)
            _sound->playSfxData(dst, sound, pan, vol);
      else if (type == Sound::TYPE_SFX5)
            _sound->playSfx5Data(dst, sound, pan, vol);
}

void AGOSEngine::loadSound(uint16 sound, uint16 freq, uint16 flags) {
      byte *dst;
      uint32 offs, size = 0;
      uint32 rate = 8000;

      if (_curSfxFile == NULL)
            return;

      dst = _curSfxFile;
      if (getGameType() == GType_WW) {
            uint16 tmp = sound;

            while (tmp--) {
                  size += READ_LE_UINT16(dst) + 4;
                  dst += READ_LE_UINT16(dst) + 4;

                  if (size > _curSfxFileSize)
                        error("loadSound: Reading beyond EOF (%d, %d)", size, _curSfxFileSize);
            }

            size = READ_LE_UINT16(dst);
            offs = 4;
      } else if (getGameType() == GType_ELVIRA2) {
            while (READ_BE_UINT32(dst + 4) != sound) {
                  size += 12;
                  dst += 12;

                  if (size > _curSfxFileSize)
                        error("loadSound: Reading beyond EOF (%d, %d)", size, _curSfxFileSize);
            }

            size = READ_BE_UINT32(dst);
            offs = READ_BE_UINT32(dst + 8);
      } else {
            while (READ_BE_UINT16(dst + 6) != sound) {
                  size += 12;
                  dst += 12;

                  if (size > _curSfxFileSize)
                        error("loadSound: Reading beyond EOF (%d, %d)", size, _curSfxFileSize);

            }

            size = READ_BE_UINT16(dst + 2);
            offs = READ_BE_UINT32(dst + 8);
      }

      if (getGameType() == GType_PN) {
            if (freq == 0) {
                  rate = 4600;
            } else if (freq == 1) {
                  rate = 7400;
            } else {
                  rate = 9400;
            }
      }

      // TODO: Handle other sound flags in Amiga/AtariST versions
      if (flags == 2 && _sound->isSfxActive()) {
            _sound->queueSound(dst + offs, sound, size, rate);
      } else {
            if (flags == 0)
                  _sound->stopSfx();
            _sound->playRawData(dst + offs, sound, size, rate);
      }
}

void AGOSEngine::loadVoice(uint speechId) {
      if (getGameType() == GType_PP && speechId == 99) {
            _sound->stopVoice();
            return;
      }

      if (getFeatures() & GF_ZLIBCOMP) {
            char filename[15];

            uint32 file, offset, srcSize, dstSize;
            if (getPlatform() == Common::kPlatformAmiga) {
                  loadOffsets((const char*)"spindex.dat", speechId, file, offset, srcSize, dstSize);
            } else {
                  loadOffsets((const char*)"speech.wav", speechId, file, offset, srcSize, dstSize);
            }

            // Voice segment doesn't exist
            if (offset == 0xFFFFFFFF && srcSize == 0xFFFFFFFF && dstSize == 0xFFFFFFFF) {
                  debug(0, "loadVoice: speechId %d removed", speechId);
                  return;
            }

            if (getPlatform() == Common::kPlatformAmiga)
                  sprintf(filename, "sp%d.wav", file);
            else
                  sprintf(filename, "speech.wav");

            byte *dst = (byte *)malloc(dstSize);
            decompressData(filename, dst, offset, srcSize, dstSize);
            _sound->playVoiceData(dst, speechId);
      } else {
            _sound->playVoice(speechId);
      }
}

} // End of namespace AGOS

Generated by  Doxygen 1.6.0   Back to index