scummvm/engines/gob/sound/sound.cpp
Sven Hesse fe44939eba GOB: Play the music on the title screen of Gob1 EGA
The EGA version of Gobliiins comes with an MDY track.
While the original doesn't play it, we thought it might
be a nice idea to play it nevertheless.
2012-06-11 06:20:34 +02:00

748 lines
16 KiB
C++

/* 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.
*
*/
#include "gob/gob.h"
#include "gob/sound/sound.h"
#include "gob/global.h"
#include "gob/util.h"
#include "gob/dataio.h"
#include "gob/game.h"
#include "gob/inter.h"
#include "gob/sound/pcspeaker.h"
#include "gob/sound/soundblaster.h"
#include "gob/sound/adlplayer.h"
#include "gob/sound/musplayer.h"
#include "gob/sound/infogrames.h"
#include "gob/sound/protracker.h"
#include "gob/sound/cdrom.h"
namespace Gob {
Sound::Sound(GobEngine *vm) : _vm(vm) {
_pcspeaker = new PCSpeaker(*_vm->_mixer);
_blaster = new SoundBlaster(*_vm->_mixer);
_adlPlayer = 0;
_mdyPlayer = 0;
_infogrames = 0;
_protracker = 0;
_cdrom = 0;
_bgatmos = 0;
_hasAdLib = (!_vm->_noMusic && _vm->hasAdLib());
_hasAdLibBg = _hasAdLib;
if (!_vm->_noMusic && (_vm->getPlatform() == Common::kPlatformAmiga)) {
_infogrames = new Infogrames(*_vm->_mixer);
_protracker = new Protracker(*_vm->_mixer);
}
if (_vm->isCD())
_cdrom = new CDROM;
if (_vm->getGameType() == kGameTypeWoodruff)
_bgatmos = new BackgroundAtmosphere(*_vm->_mixer);
if ((_vm->getGameType() == kGameTypeUrban) ||
(_vm->getGameType() == kGameTypeAdibou2)) {
_bgatmos = new BackgroundAtmosphere(*_vm->_mixer);
_bgatmos->setShadable(false);
}
}
Sound::~Sound() {
delete _pcspeaker;
delete _blaster;
delete _adlPlayer;
delete _mdyPlayer;
delete _infogrames;
delete _protracker;
delete _cdrom;
delete _bgatmos;
for (int i = 0; i < kSoundsCount; i++)
_sounds[i].free();
}
void Sound::convToSigned(byte *buffer, int length) {
while (length-- > 0)
*buffer++ ^= 0x80;
}
SoundDesc *Sound::sampleGetBySlot(int slot) {
if ((slot < 0) || (slot >= kSoundsCount))
return 0;
return &_sounds[slot];
}
const SoundDesc *Sound::sampleGetBySlot(int slot) const {
if ((slot < 0) || (slot >= kSoundsCount))
return 0;
return &_sounds[slot];
}
int Sound::sampleGetNextFreeSlot() const {
for (int i = 0; i < kSoundsCount; i++)
if (_sounds[i].empty())
return i;
return -1;
}
bool Sound::sampleLoad(SoundDesc *sndDesc, SoundType type, const char *fileName, bool tryExist) {
if (!sndDesc)
return false;
debugC(2, kDebugSound, "Loading sample \"%s\"", fileName);
int32 size;
byte *data = _vm->_dataIO->getFile(fileName, size);
if (!data) {
warning("Can't open sample file \"%s\"", fileName);
return false;
}
return sndDesc->load(type, data, size);
}
void Sound::sampleFree(SoundDesc *sndDesc, bool noteAdLib, int index) {
if (!sndDesc || sndDesc->empty())
return;
if (sndDesc->getType() == SOUND_ADL) {
if (noteAdLib) {
if (_adlPlayer)
if ((index == -1) || (_adlPlayer->getIndex() == index))
_adlPlayer->unload();
}
} else {
if (_blaster)
_blaster->stopSound(0, sndDesc);
}
sndDesc->free();
}
void Sound::speakerOn(int16 frequency, int32 length) {
if (!_pcspeaker)
return;
debugC(1, kDebugSound, "PCSpeaker: Playing tone (%d, %d)", frequency, length);
_pcspeaker->speakerOn(frequency, length);
}
void Sound::speakerOff() {
if (!_pcspeaker)
return;
debugC(1, kDebugSound, "PCSpeaker: Stopping tone");
_pcspeaker->speakerOff();
}
void Sound::speakerOnUpdate(uint32 millis) {
if (!_pcspeaker)
return;
_pcspeaker->onUpdate(millis);
}
bool Sound::infogramesLoadInstruments(const char *fileName) {
if (!_infogrames)
return false;
debugC(1, kDebugSound, "Infogrames: Loading instruments \"%s\"", fileName);
return _infogrames->loadInstruments(fileName);
}
bool Sound::infogramesLoadSong(const char *fileName) {
if (!_infogrames)
return false;
debugC(1, kDebugSound, "Infogrames: Loading song \"%s\"", fileName);
return _infogrames->loadSong(fileName);
}
bool Sound::protrackerPlay(const char *fileName) {
if (!_protracker)
return false;
debugC(1, kDebugSound, "Protracker: Playing song \"%s\"", fileName);
return _protracker->play(fileName);
}
void Sound::protrackerStop() {
if (!_protracker)
return;
debugC(1, kDebugSound, "Protracker: Stopping playback");
_protracker->stop();
}
void Sound::infogramesPlay() {
if (!_infogrames)
return;
debugC(1, kDebugSound, "Infogrames: Starting playback");
_infogrames->play();
}
void Sound::infogramesStop() {
if (!_infogrames)
return;
debugC(1, kDebugSound, "Infogrames: Stopping playback");
_infogrames->stop();
}
bool Sound::adlibLoadADL(const char *fileName) {
if (!_hasAdLib)
return false;
if (!_adlPlayer)
_adlPlayer = new ADLPlayer(*_vm->_mixer);
debugC(1, kDebugSound, "AdLib: Loading ADL data (\"%s\")", fileName);
Common::SeekableReadStream *stream = _vm->_dataIO->getFile(fileName);
if (!stream) {
warning("Can't open ADL file \"%s\"", fileName);
return false;
}
bool loaded = _adlPlayer->load(*stream);
delete stream;
return loaded;
}
bool Sound::adlibLoadADL(byte *data, uint32 size, int index) {
if (!_hasAdLib)
return false;
if (!_adlPlayer)
_adlPlayer = new ADLPlayer(*_vm->_mixer);
debugC(1, kDebugSound, "AdLib: Loading ADL data (%d)", index);
return _adlPlayer->load(data, size, index);
}
void Sound::adlibUnload() {
if (!_hasAdLib)
return;
debugC(1, kDebugSound, "AdLib: Unloading data");
if (_adlPlayer)
_adlPlayer->unload();
if (_mdyPlayer)
_mdyPlayer->unload();
}
bool Sound::adlibLoadMDY(const char *fileName) {
if (!_hasAdLib)
return false;
createMDYPlayer();
debugC(1, kDebugSound, "AdLib: Loading MDY data (\"%s\")", fileName);
Common::SeekableReadStream *stream = _vm->_dataIO->getFile(fileName);
if (!stream) {
warning("Can't open MDY file \"%s\"", fileName);
return false;
}
bool loaded = _mdyPlayer->loadMUS(*stream);
delete stream;
return loaded;
}
bool Sound::adlibLoadTBR(const char *fileName) {
if (!_hasAdLib)
return false;
createMDYPlayer();
Common::SeekableReadStream *stream = _vm->_dataIO->getFile(fileName);
if (!stream) {
warning("Can't open TBR file \"%s\"", fileName);
return false;
}
debugC(1, kDebugSound, "AdLib: Loading MDY instruments (\"%s\")", fileName);
bool loaded = _mdyPlayer->loadSND(*stream);
delete stream;
return loaded;
}
void Sound::adlibPlayTrack(const char *trackname) {
if (!_hasAdLib)
return;
createADLPlayer();
if (_adlPlayer->isPlaying())
return;
if (adlibLoadADL(trackname))
adlibPlay();
}
void Sound::adlibPlayBgMusic() {
if (!_hasAdLib || _hasAdLibBg)
return;
createADLPlayer();
static const char *const tracksMac[] = {
// "musmac1.adl", // This track seems to be missing instruments...
"musmac2.adl",
"musmac3.adl",
"musmac4.adl",
"musmac5.adl",
"musmac6.adl"
};
static const char *const tracksWin[] = {
"musmac1.mid",
"musmac2.mid",
"musmac3.mid",
"musmac4.mid",
"musmac5.mid"
};
const char *track = 0;
if (_vm->getPlatform() == Common::kPlatformWindows)
track = tracksWin[ARRAYSIZE(tracksWin)];
else
track = tracksMac[_vm->_util->getRandom(ARRAYSIZE(tracksMac))];
if (!track || !_vm->_dataIO->hasFile(track)) {
_hasAdLibBg = false;
return;
}
adlibPlayTrack(track);
}
void Sound::adlibPlay() {
if (!_hasAdLib)
return;
debugC(1, kDebugSound, "AdLib: Starting playback");
if (_adlPlayer)
_adlPlayer->startPlay();
if (_mdyPlayer)
_mdyPlayer->startPlay();
}
void Sound::adlibStop() {
if (!_hasAdLib)
return;
debugC(1, kDebugSound, "AdLib: Stopping playback");
if (_adlPlayer)
_adlPlayer->stopPlay();
if (_mdyPlayer)
_mdyPlayer->stopPlay();
}
bool Sound::adlibIsPlaying() const {
if (!_hasAdLib)
return false;
if (_adlPlayer && _adlPlayer->isPlaying())
return true;
if (_mdyPlayer && _mdyPlayer->isPlaying())
return true;
return false;
}
int Sound::adlibGetIndex() const {
if (!_hasAdLib)
return -1;
if (_adlPlayer)
return _adlPlayer->getIndex();
return -1;
}
int32 Sound::adlibGetRepeating() const {
if (!_hasAdLib)
return false;
if (_adlPlayer)
return _adlPlayer->getRepeating();
if (_mdyPlayer)
return _mdyPlayer->getRepeating();
return false;
}
void Sound::adlibSetRepeating(int32 repCount) {
if (!_hasAdLib)
return;
if (_adlPlayer)
_adlPlayer->setRepeating(repCount);
if (_mdyPlayer)
_mdyPlayer->setRepeating(repCount);
}
void Sound::blasterPlay(SoundDesc *sndDesc, int16 repCount,
int16 frequency, int16 fadeLength) {
if (!_blaster || !sndDesc)
return;
debugC(1, kDebugSound, "SoundBlaster: Playing sample (%d, %d, %d)",
repCount, frequency, fadeLength);
blasterStopComposition();
_blaster->playSample(*sndDesc, repCount, frequency, fadeLength);
}
void Sound::blasterStop(int16 fadeLength, SoundDesc *sndDesc) {
if (!_blaster)
return;
debugC(1, kDebugSound, "SoundBlaster: Stopping playback");
_blaster->stopSound(fadeLength, sndDesc);
}
void Sound::blasterPlayComposition(int16 *composition, int16 freqVal,
SoundDesc *sndDescs, int8 sndCount) {
if (!_blaster)
return;
debugC(1, kDebugSound, "SoundBlaster: Playing composition (%d, %d)",
freqVal, sndCount);
blasterWaitEndPlay();
_blaster->stopComposition();
if (!sndDescs)
sndDescs = _sounds;
_blaster->playComposition(composition, freqVal, sndDescs, sndCount);
}
void Sound::blasterStopComposition() {
if (!_blaster)
return;
debugC(1, kDebugSound, "SoundBlaster: Stopping composition");
_blaster->stopComposition();
}
char Sound::blasterPlayingSound() const {
if (!_blaster)
return 0;
return _blaster->getPlayingSound();
}
void Sound::blasterSetRepeating(int32 repCount) {
if (!_blaster)
return;
_blaster->setRepeating(repCount);
}
void Sound::blasterWaitEndPlay(bool interruptible, bool stopComp) {
if (!_blaster)
return;
debugC(1, kDebugSound, "SoundBlaster: Waiting for playback to end");
if (stopComp)
_blaster->endComposition();
while (_blaster->isPlaying() && !_vm->shouldQuit()) {
if (interruptible && (_vm->_util->checkKey() == kKeyEscape)) {
WRITE_VAR(57, (uint32) -1);
return;
}
_vm->_util->longDelay(200);
}
_blaster->stopSound(0);
}
void Sound::cdLoadLIC(const Common::String &fname) {
if (!_cdrom)
return;
debugC(1, kDebugSound, "CDROM: Loading LIC \"%s\"", fname.c_str());
Common::SeekableReadStream *stream = _vm->_dataIO->getFile(fname);
if (!stream)
return;
_cdrom->readLIC(*stream);
delete stream;
}
void Sound::cdUnloadLIC() {
if (!_cdrom)
return;
debugC(1, kDebugSound, "CDROM: Unloading LIC");
_cdrom->freeLICBuffer();
}
void Sound::cdPlayBgMusic() {
if (!_cdrom)
return;
static const char *const tracks[][2] = {
{"avt00.tot", "mine"},
{"avt001.tot", "nuit"},
{"avt002.tot", "campagne"},
{"avt003.tot", "extsor1"},
{"avt004.tot", "interieure"},
{"avt005.tot", "zombie"},
{"avt006.tot", "zombie"},
{"avt007.tot", "campagne"},
{"avt008.tot", "campagne"},
{"avt009.tot", "extsor1"},
{"avt010.tot", "extsor1"},
{"avt011.tot", "interieure"},
{"avt012.tot", "zombie"},
{"avt014.tot", "nuit"},
{"avt015.tot", "interieure"},
{"avt016.tot", "statue"},
{"avt017.tot", "zombie"},
{"avt018.tot", "statue"},
{"avt019.tot", "mine"},
{"avt020.tot", "statue"},
{"avt021.tot", "mine"},
{"avt022.tot", "zombie"}
};
for (int i = 0; i < ARRAYSIZE(tracks); i++)
if (_vm->isCurrentTot(tracks[i][0])) {
debugC(1, kDebugSound, "CDROM: Playing background music \"%s\" (\"%s\")", tracks[i][1], tracks[i][0]);
_cdrom->startTrack(tracks[i][1]);
break;
}
}
void Sound::cdPlayMultMusic() {
if (!_cdrom)
return;
static const char *const tracks[][6] = {
{"avt005.tot", "fra1", "all1", "ang1", "esp1", "ita1"},
{"avt006.tot", "fra2", "all2", "ang2", "esp2", "ita2"},
{"avt012.tot", "fra3", "all3", "ang3", "esp3", "ita3"},
{"avt016.tot", "fra4", "all4", "ang4", "esp4", "ita4"},
{"avt019.tot", "fra5", "all5", "ang5", "esp5", "ita5"},
{"avt022.tot", "fra6", "all6", "ang6", "esp6", "ita6"}
};
// Default to "ang?" for other languages (including EN_USA)
int language = _vm->_global->_language <= 4 ? _vm->_global->_language : 2;
for (int i = 0; i < ARRAYSIZE(tracks); i++)
if (_vm->isCurrentTot(tracks[i][0])) {
debugC(1, kDebugSound, "CDROM: Playing mult music \"%s\" (\"%s\")", tracks[i][language + 1], tracks[i][0]);
_cdrom->startTrack(tracks[i][language + 1]);
break;
}
}
void Sound::cdPlay(const Common::String &trackName) {
if (!_cdrom)
return;
debugC(1, kDebugSound, "CDROM: Playing track \"%s\"", trackName.c_str());
// WORKAROUND - In Fascination CD, in the storage room, a track has the wrong
// name in the scripts, and therefore doesn't play. This fixes the problem.
if ((_vm->getGameType() == kGameTypeFascination) && trackName.equalsIgnoreCase("boscle"))
_cdrom->startTrack("bosscle");
else
_cdrom->startTrack(trackName.c_str());
}
void Sound::cdStop() {
if (!_cdrom)
return;
debugC(1, kDebugSound, "CDROM: Stopping playback");
_cdrom->stopPlaying();
}
bool Sound::cdIsPlaying() const {
if (!_cdrom)
return false;
return _cdrom->isPlaying();
}
int32 Sound::cdGetTrackPos(const char *keyTrack) const {
if (!_cdrom)
return -1;
return _cdrom->getTrackPos(keyTrack);
}
const char *Sound::cdGetCurrentTrack() const {
if (!_cdrom)
return "";
return _cdrom->getCurTrack();
}
void Sound::cdTest(int trySubst, const char *label) {
if (!_cdrom)
return;
_cdrom->testCD(trySubst, label);
}
void Sound::bgPlay(const char *file, SoundType type) {
if (!_bgatmos)
return;
debugC(1, kDebugSound, "BackgroundAtmosphere: Playing \"%s\"", file);
_bgatmos->stopBA();
_bgatmos->queueClear();
SoundDesc *sndDesc = new SoundDesc;
if (!sampleLoad(sndDesc, type, file)) {
delete sndDesc;
return;
}
_bgatmos->queueSample(*sndDesc);
_bgatmos->playBA();
}
void Sound::bgPlay(const char *base, const char *ext, SoundType type, int count) {
if (!_bgatmos)
return;
debugC(1, kDebugSound, "BackgroundAtmosphere: Playing \"%s\" (%d)", base, count);
_bgatmos->stopBA();
_bgatmos->queueClear();
SoundDesc *sndDesc;
for (int i = 1; i <= count; i++) {
Common::String fileName = Common::String::format("%s%02d.%s", base, i, ext);
sndDesc = new SoundDesc;
if (sampleLoad(sndDesc, type, fileName.c_str()))
_bgatmos->queueSample(*sndDesc);
else
delete sndDesc;
}
_bgatmos->playBA();
}
void Sound::bgStop() {
if (!_bgatmos)
return;
debugC(1, kDebugSound, "BackgroundAtmosphere: Stopping playback");
_bgatmos->stopBA();
_bgatmos->queueClear();
}
void Sound::bgSetPlayMode(BackgroundAtmosphere::PlayMode mode) {
if (!_bgatmos)
return;
_bgatmos->setPlayMode(mode);
}
void Sound::bgShade() {
if (!_bgatmos)
return;
debugC(1, kDebugSound, "BackgroundAtmosphere: Shading playback");
_bgatmos->shade();
}
void Sound::bgUnshade() {
if (!_bgatmos)
return;
debugC(1, kDebugSound, "BackgroundAtmosphere: Unshading playback");
_bgatmos->unshade();
}
void Sound::createMDYPlayer() {
if (_mdyPlayer)
return;
delete _adlPlayer;
_adlPlayer = 0;
_mdyPlayer = new MUSPlayer(*_vm->_mixer);
}
void Sound::createADLPlayer() {
if (_adlPlayer)
return;
delete _mdyPlayer;
_mdyPlayer= 0;
_adlPlayer = new ADLPlayer(*_vm->_mixer);
}
} // End of namespace Gob