/* 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 3 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, see . * */ #ifdef ENABLE_EOB #include "kyra/sound/sound_intern.h" #include "kyra/resource/resource.h" #include "kyra/sound/drivers/capcom98.h" #include "common/config-manager.h" namespace Kyra { SoundPC98_Darkmoon::SoundPC98_Darkmoon(KyraEngine_v1 *vm, MidiDriver::DeviceHandle dev, Audio::Mixer *mixer) : Sound(vm, mixer), _vm(vm), _driver(nullptr), _soundData(nullptr), _currentResourceSet(-1), _ready(false), _dev(dev), _drvType(kPC98), _lastTrack(-1) { memset(&_resInfo, 0, sizeof(_resInfo)); _soundData = new uint8[20600]; memset(_soundData, 0, 20600); _fileBuffer = new uint8[10500]; memset(_fileBuffer, 0, 10500); MusicType type = MidiDriver::getMusicType(dev); if (type == MT_MT32) _drvType = kMidiMT32; else if (type == MT_GM) _drvType = kMidiGM; } SoundPC98_Darkmoon::~SoundPC98_Darkmoon() { delete _driver; delete[] _soundData; delete[] _fileBuffer; for (int i = 0; i < 3; i++) initAudioResourceInfo(i, nullptr); } Sound::kType SoundPC98_Darkmoon::getMusicType() const { return _drvType; } Sound::kType SoundPC98_Darkmoon::getSfxType() const { return kPC98; } bool SoundPC98_Darkmoon::init() { _driver = new CapcomPC98AudioDriver(_mixer, _dev); _ready = (_soundData && _driver && _driver->isUsable()); return _ready; } void SoundPC98_Darkmoon::initAudioResourceInfo(int set, void *info) { if (set < kMusicIntro || set > kMusicFinale) return; delete _resInfo[set]; _resInfo[set] = info ? new SoundResourceInfo_PC(*(SoundResourceInfo_PC*)info) : nullptr; } void SoundPC98_Darkmoon::selectAudioResourceSet(int set) { if (set < kMusicIntro || set > kMusicFinale || set == _currentResourceSet || !_ready) return; if (_resInfo[set]) _currentResourceSet = set; } void SoundPC98_Darkmoon::loadSoundFile(uint file) { if (!_ready) return; if (file < res()->fileListSize) loadSoundFile(res()->fileList[file]); } void SoundPC98_Darkmoon::loadSoundFile(const Common::Path &name) { if (!_ready) return; haltTrack(); stopAllSoundEffects(); Common::Path path(name); path.appendInPlace(_drvType == kPC98 ? ".SDO" : ".SDM"); if (!_ready || _soundFileLoaded == path) return; Common::SeekableReadStream *in = _vm->resource()->createReadStream(path); if (!in) error("SoundPC98_Darkmoon::loadSoundFile(): Failed to load sound file '%s'", path.toString().c_str()); uint16 sz = in->readUint16LE(); uint8 cmp = in->readByte(); in->seek(1, SEEK_CUR); uint32 outSize = in->readUint32LE(); if ((cmp == 0 && outSize > 10500) || (cmp != 0 && outSize > 20600)) error("SoundPC98_Darkmoon::loadSoundFile(): Failed to load sound file '%s'", path.toString().c_str()); sz -= in->pos(); in->seek(2, SEEK_CUR); memset(_fileBuffer, 0, 10500); uint16 readSize = in->read(_fileBuffer, 10500); assert(sz == readSize); delete in; memset(_soundData, 0, 20600); if (cmp == 0) { memcpy(_soundData, _fileBuffer, outSize); } else if (cmp == 3) { Screen::decodeFrame3(_fileBuffer, _soundData, outSize, true); } else if (cmp == 4) { Screen::decodeFrame4(_fileBuffer, _soundData, outSize); } else { error("SoundPC98_Darkmoon::loadSoundFile(): Failed to load sound file '%s'", path.toString().c_str()); } uint16 instrOffs = READ_LE_UINT16(_soundData); if (instrOffs >= 20600) error("SoundPC98_Darkmoon::loadSoundFile(): Failed to load sound file '%s'", path.toString().c_str()); _driver->loadFMInstruments(_soundData + instrOffs); _driver->reset(); } void SoundPC98_Darkmoon::playTrack(uint8 track) { if (track == 0 || track == 2) _lastTrack = track; playSoundEffect(track, 127); } void SoundPC98_Darkmoon::haltTrack() { if (!_ready) return; _driver->stopSong(); _lastTrack = -1; } bool SoundPC98_Darkmoon::isPlaying() const { return _ready && _driver && _driver->songIsPlaying(); } void SoundPC98_Darkmoon::playSoundEffect(uint16 track, uint8 vol) { if (!_ready) return; if (track == 0 || track == 2) { restartBackgroundMusic(); return; } const uint8 *data = getData(track); if (!data) return; if (track < 52 || track > 67) { if (_sfxEnabled) _driver->startSoundEffect(data, vol); } else if (_musicEnabled) { _lastTrack = track; _driver->startSong(data, vol, false); } } void SoundPC98_Darkmoon::stopAllSoundEffects() { if (_ready) _driver->stopSoundEffect(); } void SoundPC98_Darkmoon::beginFadeOut() { _driver->fadeOut(); } void SoundPC98_Darkmoon::pause(bool paused) { if (_ready && paused) _driver->allNotesOff(); } int SoundPC98_Darkmoon::checkTrigger() { return _driver ? _driver->checkSoundMarker() : 99; } void SoundPC98_Darkmoon::restartBackgroundMusic() { if (_lastTrack == -1) { haltTrack(); stopAllSoundEffects(); } else { _lastTrack = -1; const uint8 *data = getData(0); if (!data) return; if (_musicEnabled) _driver->startSong(data, 127, true); } } const uint8 *SoundPC98_Darkmoon::getData(uint16 track) const { if (!_ready || track >= 120) return nullptr; uint16 offset = READ_LE_UINT16(&_soundData[(track + 1) << 1]); return (offset < 20600) ? &_soundData[offset] : nullptr; } void SoundPC98_Darkmoon::updateVolumeSettings() { if (!_driver || !_ready) return; bool mute = false; if (ConfMan.hasKey("mute")) mute = ConfMan.getBool("mute"); _driver->setMusicVolume((mute ? 0 : ConfMan.getInt("music_volume"))); _driver->setSoundEffectVolume((mute ? 0 : ConfMan.getInt("sfx_volume"))); } } // End of namespace Kyra #endif