KYRA: (EOB) - prepare for PC Speaker support

This commit does not include the actual driver. It only provides the necessary refactoring and resource handling.
This commit is contained in:
athrxx committed 2020-02-01 21:09:49 +01:00
1 parent ad046b1589
commit 46ef0109b5
17 files changed
+582 -459

No files matched your search

+1 -1
View File
@@ -45,7 +45,7 @@
enum {
kKyraDatVersion = 95
kKyraDatVersion = 96
};
const ExtractFilename extractFilenames[] = {
+9 -6
View File
@@ -1755,20 +1755,23 @@ static const EoBCharacter kEoB1NpcPresetsDOS[9] = {
static const EoBCharacterProvider kEoB1NpcPresetsDOSProvider = { ARRAYSIZE(kEoB1NpcPresetsDOS), kEoB1NpcPresetsDOS };
static const char *const kEoB1SoundFilesIntroDOS[1] = {
"SOUND"
static const char *const kEoB1SoundFilesIntroDOS[2] = {
"SOUND",
"PCSOUND"
};
static const StringListProvider kEoB1SoundFilesIntroDOSProvider = { ARRAYSIZE(kEoB1SoundFilesIntroDOS), kEoB1SoundFilesIntroDOS };
static const char *const kEoB1SoundFilesIngameDOS[1] = {
"ADLIB"
static const char *const kEoB1SoundFilesIngameDOS[2] = {
"ADLIB",
"PCGAMESN"
};
static const StringListProvider kEoB1SoundFilesIngameDOSProvider = { ARRAYSIZE(kEoB1SoundFilesIngameDOS), kEoB1SoundFilesIngameDOS };
static const char *const kEoB1SoundFilesFinaleDOS[1] = {
"ADLIB"
static const char *const kEoB1SoundFilesFinaleDOS[2] = {
"ADLIB",
"PCGAMESN"
};
static const StringListProvider kEoB1SoundFilesFinaleDOSProvider = { ARRAYSIZE(kEoB1SoundFilesFinaleDOS), kEoB1SoundFilesFinaleDOS };
Binary file not shown.
+3 -3
View File
@@ -1654,7 +1654,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::EN_ANY,
Common::kPlatformDOS,
ADGF_NO_FLAGS,
GUIO8(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIPCSPK, GUIO_RENDERVGA, GUIO_RENDEREGA, GUIO_RENDERCGA, GAMEOPTION_EOB_HPGRAPHS, GAMEOPTION_EOB_MOUSESWAP)
GUIO9(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIPCSPK, GUIO_MIDIPCJR, GUIO_RENDERVGA, GUIO_RENDEREGA, GUIO_RENDERCGA, GAMEOPTION_EOB_HPGRAPHS, GAMEOPTION_EOB_MOUSESWAP)
},
EOB_FLAGS
},
@@ -1670,7 +1670,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::DE_DEU,
Common::kPlatformDOS,
ADGF_NO_FLAGS,
GUIO8(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIPCSPK, GUIO_RENDERVGA, GUIO_RENDEREGA, GUIO_RENDERCGA, GAMEOPTION_EOB_HPGRAPHS, GAMEOPTION_EOB_MOUSESWAP)
GUIO9(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIPCSPK, GUIO_MIDIPCJR, GUIO_RENDERVGA, GUIO_RENDEREGA, GUIO_RENDERCGA, GAMEOPTION_EOB_HPGRAPHS, GAMEOPTION_EOB_MOUSESWAP)
},
EOB_FLAGS
},
@@ -1686,7 +1686,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::IT_ITA,
Common::kPlatformDOS,
ADGF_NO_FLAGS,
GUIO8(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIPCSPK, GUIO_RENDERVGA, GUIO_RENDEREGA, GUIO_RENDERCGA, GAMEOPTION_EOB_HPGRAPHS, GAMEOPTION_EOB_MOUSESWAP)
GUIO9(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIPCSPK, GUIO_MIDIPCJR, GUIO_RENDERVGA, GUIO_RENDEREGA, GUIO_RENDERCGA, GAMEOPTION_EOB_HPGRAPHS, GAMEOPTION_EOB_MOUSESWAP)
},
EOB_FLAGS
},
+7 -8
View File
@@ -25,7 +25,7 @@
#include "kyra/engine/kyra_rpg.h"
#include "kyra/resource/resource.h"
#include "kyra/sound/sound_intern.h"
#include "kyra/sound/sound_adlib.h"
#include "kyra/sound/sound_pc_v1.h"
#include "kyra/script/script_eob.h"
#include "kyra/engine/timer.h"
#include "kyra/gui/debugger.h"
@@ -411,11 +411,10 @@ Common::Error EoBCoreEngine::init() {
// don't really need one). We just disable the sound in the settings.
MidiDriver::DeviceHandle dev = 0;
if (_flags.platform == Common::kPlatformDOS) {
dev = MidiDriver::detectDevice(/*MDT_PCSPK | */MDT_ADLIB);
//if (MidiDriver::getMusicType(dev) == MT_ADLIB)
_sound = new SoundAdLibPC(this, _mixer);
//else
// _sound = new SoundPCS(this, _mixer);
int flags = MDT_ADLIB | MDT_PCSPK;
dev = MidiDriver::detectDevice(_flags.gameID == GI_EOB1 ? flags | MDT_PCJR : flags);
MusicType type = MidiDriver::getMusicType(dev);
_sound = new SoundPC_v1(this, _mixer, type == MT_ADLIB ? Sound::kAdLib : type == MT_PCSPK ? Sound::kPCSpkr : Sound::kPCjr);
} else if (_flags.platform == Common::kPlatformFMTowns) {
dev = MidiDriver::detectDevice(MDT_TOWNS);
// SoundTowns_Darkmoon requires initialized _staticres
@@ -435,8 +434,8 @@ Common::Error EoBCoreEngine::init() {
assert(_sound);
_sound->init();
// This if for EOB1 PC-98 only
_sound->loadSfxFile("EFECT.OBJ");
if (_flags.platform == Common::kPlatformPC98)
_sound->loadSfxFile("EFECT.OBJ");
// Setup volume settings (and read in all ConfigManager settings)
_configNullSound = (MidiDriver::getMusicType(dev) == MT_NULL);
+2 -2
View File
@@ -121,7 +121,7 @@ Common::Error KyraEngine_v1::init() {
// Kyra games.
MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_PCSPK | MDT_MIDI | MDT_ADLIB | ((_flags.gameID == GI_KYRA2 || _flags.gameID == GI_LOL) ? MDT_PREFER_GM : MDT_PREFER_MT32));
if (MidiDriver::getMusicType(dev) == MT_ADLIB) {
_sound = new SoundAdLibPC(this, _mixer);
_sound = new SoundPC_v1(this, _mixer, Sound::kAdLib);
} else {
Sound::kType type;
const MusicType midiType = MidiDriver::getMusicType(dev);
@@ -153,7 +153,7 @@ Common::Error KyraEngine_v1::init() {
// missing. It's just that at least at the time of writing they
// are decidedly inferior to the AdLib ones.
if (ConfMan.getBool("multi_midi")) {
SoundAdLibPC *adlib = new SoundAdLibPC(this, _mixer);
SoundPC_v1 *adlib = new SoundPC_v1(this, _mixer, Sound::kAdLib);
assert(adlib);
_sound = new MixedSoundDriver(this, _mixer, soundMidiPc, adlib);
+5 -4
View File
@@ -60,10 +60,10 @@ MODULE_OBJS := \
sequence/sequences_v2.o \
sequence/sequences_hof.o \
sequence/sequences_mr.o \
sound/sound_adlib.o \
sound/sound_amiga_lok.o \
sound/sound_digital_mr.o \
sound/sound_midi.o \
sound/sound_pc_midi.o \
sound/sound_pc_v1.o \
sound/sound_pc98_lok.o \
sound/sound_pc98_v2.o \
sound/sound_towns_lok.o \
@@ -72,7 +72,7 @@ MODULE_OBJS := \
sound/drivers/adlib.o \
sound/drivers/audstream.o \
sound/drivers/midi.o \
sound/drivers/pcspeaker.o \
sound/drivers/pcspeaker_v2.o \
text/text.o \
text/text_lok.o \
text/text_hof.o \
@@ -132,7 +132,8 @@ MODULE_OBJS += \
sound/sound_pc98_eob.o \
sound/sound_towns_darkmoon.o \
sound/drivers/audiomaster2.o \
sound/drivers/mlalf98.o
sound/drivers/mlalf98.o \
sound/drivers/pcspeaker_v1.o
endif
# This module can be built as a plugin
+1 -1
View File
@@ -39,7 +39,7 @@
namespace Kyra {
#define RESFILE_VERSION 95
#define RESFILE_VERSION 96
namespace {
bool checkKyraDat(Common::SeekableReadStream *file) {
+339 -3
View File
@@ -36,16 +36,348 @@
*
*/
// Basic AdLib Programming:
// https://web.archive.org/web/20050322080425/http://www.gamedev.net/reference/articles/article446.asp
#include "kyra/sound/drivers/adlib.h"
#include "kyra/sound/drivers/pc_base.h"
#include "audio/fmopl.h"
#include "common/mutex.h"
#define CALLBACKS_PER_SECOND 72
namespace Kyra {
AdLibDriver::AdLibDriver(Audio::Mixer *mixer, int version) {
class AdLibDriver : public PCSoundDriver {
public:
AdLibDriver(Audio::Mixer *mixer, int version);
virtual ~AdLibDriver();
virtual void initDriver() override;
virtual void setSoundData(uint8 *data, uint32 size) override;
virtual void queueTrack(int track, int volume) override;
virtual bool isChannelPlaying(int channel) const override;
virtual void stopAllChannels() override;
virtual int getSoundTrigger() const override { return _soundTrigger; }
virtual void resetSoundTrigger() override { _soundTrigger = 0; }
virtual void callback() override;
virtual void setSyncJumpMask(uint16 mask) override { _syncJumpMask = mask; }
virtual void setMusicVolume(uint8 volume) override;
virtual void setSfxVolume(uint8 volume) override;
private:
// These variables have not yet been named, but some of them are partly
// known nevertheless:
//
// pitchBend - Sound-related. Possibly some sort of pitch bend.
// unk18 - Sound-effect. Used for secondaryEffect1()
// unk19 - Sound-effect. Used for secondaryEffect1()
// unk20 - Sound-effect. Used for secondaryEffect1()
// unk21 - Sound-effect. Used for secondaryEffect1()
// unk22 - Sound-effect. Used for secondaryEffect1()
// unk29 - Sound-effect. Used for primaryEffect1()
// unk30 - Sound-effect. Used for primaryEffect1()
// unk31 - Sound-effect. Used for primaryEffect1()
// unk32 - Sound-effect. Used for primaryEffect2()
// unk33 - Sound-effect. Used for primaryEffect2()
// unk34 - Sound-effect. Used for primaryEffect2()
// unk35 - Sound-effect. Used for primaryEffect2()
// unk36 - Sound-effect. Used for primaryEffect2()
// unk37 - Sound-effect. Used for primaryEffect2()
// unk38 - Sound-effect. Used for primaryEffect2()
// unk39 - Currently unused, except for updateCallback56()
// unk40 - Currently unused, except for updateCallback56()
// unk41 - Sound-effect. Used for primaryEffect2()
struct Channel {
bool lock; // New to ScummVM
uint8 opExtraLevel2;
const uint8 *dataptr;
uint8 duration;
uint8 repeatCounter;
int8 baseOctave;
uint8 priority;
uint8 dataptrStackPos;
const uint8 *dataptrStack[4];
int8 baseNote;
uint8 unk29;
uint8 unk31;
uint16 unk30;
uint16 unk37;
uint8 unk33;
uint8 unk34;
uint8 unk35;
uint8 unk36;
uint8 unk32;
uint8 unk41;
uint8 unk38;
uint8 opExtraLevel1;
uint8 spacing2;
uint8 baseFreq;
uint8 tempo;
uint8 position;
uint8 regAx;
uint8 regBx;
typedef void (AdLibDriver::*Callback)(Channel&);
Callback primaryEffect;
Callback secondaryEffect;
uint8 fractionalSpacing;
uint8 opLevel1;
uint8 opLevel2;
uint8 opExtraLevel3;
uint8 twoChan;
uint8 unk39;
uint8 unk40;
uint8 spacing1;
uint8 durationRandomness;
uint8 unk19;
uint8 unk18;
int8 unk20;
int8 unk21;
uint8 unk22;
uint16 offset;
uint8 tempoReset;
uint8 rawNote;
int8 pitchBend;
uint8 volumeModifier;
};
void primaryEffect1(Channel &channel);
void primaryEffect2(Channel &channel);
void secondaryEffect1(Channel &channel);
void resetAdLibState();
void writeOPL(byte reg, byte val);
void initChannel(Channel &channel);
void noteOff(Channel &channel);
void unkOutput2(uint8 num);
uint16 getRandomNr();
void setupDuration(uint8 duration, Channel &channel);
void setupNote(uint8 rawNote, Channel &channel, bool flag = false);
void setupInstrument(uint8 regOffset, const uint8 *dataptr, Channel &channel);
void noteOn(Channel &channel);
void adjustVolume(Channel &channel);
uint8 calculateOpLevel1(Channel &channel);
uint8 calculateOpLevel2(Channel &channel);
uint16 checkValue(int16 val) {
if (val < 0)
val = 0;
else if (val > 0x3F)
val = 0x3F;
return val;
}
// The sound data has at least two lookup tables:
//
// * One for programs, starting at offset 0.
// * One for instruments, starting at offset 500.
uint8 *getProgram(int progId) {
const uint16 offset = READ_LE_UINT16(_soundData + 2 * progId);
// In case an invalid offset is specified we return nullptr to
// indicate an error. 0xFFFF seems to indicate "this is not a valid
// program/instrument". However, 0 is also invalid because it points
// inside the offset table itself. We also ignore any offsets outside
// of the actual data size.
// The original does not contain any safety checks and will simply
// read outside of the valid sound data in case an invalid offset is
// encountered.
if (offset == 0 || offset >= _soundDataSize) {
return nullptr;
} else {
return _soundData + offset;
}
}
const uint8 *getInstrument(int instrumentId) {
return getProgram(_numPrograms + instrumentId);
}
void setupPrograms();
void executePrograms();
struct ParserOpcode {
typedef int (AdLibDriver::*POpcode)(const uint8 *&dataptr, Channel &channel, uint8 value);
POpcode function;
const char *name;
};
void setupParserOpcodeTable();
const ParserOpcode *_parserOpcodeTable;
int _parserOpcodeTableSize;
int update_setRepeat(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_checkRepeat(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setupProgram(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setNoteSpacing(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_jump(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_jumpToSubroutine(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_returnFromSubroutine(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setBaseOctave(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_stopChannel(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_playRest(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_writeAdLib(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setupNoteAndDuration(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setBaseNote(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setupSecondaryEffect1(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_stopOtherChannel(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_waitForEndOfProgram(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setupInstrument(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setupPrimaryEffect1(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_removePrimaryEffect1(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setBaseFreq(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setupPrimaryEffect2(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setPriority(const uint8 *&dataptr, Channel &channel, uint8 value);
int updateCallback23(const uint8 *&dataptr, Channel &channel, uint8 value);
int updateCallback24(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setExtraLevel1(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setupDuration(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_playNote(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setFractionalNoteSpacing(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setTempo(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_removeSecondaryEffect1(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setChannelTempo(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setExtraLevel3(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setExtraLevel2(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_changeExtraLevel2(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setAMDepth(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setVibratoDepth(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_changeExtraLevel1(const uint8 *&dataptr, Channel &channel, uint8 value);
int updateCallback38(const uint8 *&dataptr, Channel &channel, uint8 value);
int updateCallback39(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_removePrimaryEffect2(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_pitchBend(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_resetToGlobalTempo(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_nop(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setDurationRandomness(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_changeChannelTempo(const uint8 *&dataptr, Channel &channel, uint8 value);
int updateCallback46(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setupRhythmSection(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_playRhythmSection(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_removeRhythmSection(const uint8 *&dataptr, Channel &channel, uint8 value);
int updateCallback51(const uint8 *&dataptr, Channel &channel, uint8 value);
int updateCallback52(const uint8 *&dataptr, Channel &channel, uint8 value);
int updateCallback53(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setSoundTrigger(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setTempoReset(const uint8 *&dataptr, Channel &channel, uint8 value);
int updateCallback56(const uint8 *&dataptr, Channel &channel, uint8 value);
private:
// These variables have not yet been named, but some of them are partly
// known nevertheless:
//
// _unkValue1 - Unknown. Used for updating _unkValue2
// _unkValue2 - Unknown. Used for updating _unkValue4
// _unkValue4 - Unknown. Used for updating _unkValue5
// _unkValue5 - Unknown. Used for controlling updateCallback24().
// _unkValue6 - Unknown. Rhythm section volume?
// _unkValue7 - Unknown. Rhythm section volume?
// _unkValue8 - Unknown. Rhythm section volume?
// _unkValue9 - Unknown. Rhythm section volume?
// _unkValue10 - Unknown. Rhythm section volume?
// _unkValue11 - Unknown. Rhythm section volume?
// _unkValue12 - Unknown. Rhythm section volume?
// _unkValue13 - Unknown. Rhythm section volume?
// _unkValue14 - Unknown. Rhythm section volume?
// _unkValue15 - Unknown. Rhythm section volume?
// _unkValue16 - Unknown. Rhythm section volume?
// _unkValue17 - Unknown. Rhythm section volume?
// _unkValue18 - Unknown. Rhythm section volume?
// _unkValue19 - Unknown. Rhythm section volume?
// _unkValue20 - Unknown. Rhythm section volume?
// _freqTable[] - Probably frequences for the 12-tone scale.
// _unkTable2[] - Unknown. Currently only used by updateCallback46()
// _unkTable2_1[] - One of the tables in _unkTable2[]
// _unkTable2_2[] - One of the tables in _unkTable2[]
// _unkTable2_3[] - One of the tables in _unkTable2[]
int _curChannel;
uint8 _soundTrigger;
uint16 _rnd;
uint8 _unkValue1;
uint8 _unkValue2;
uint8 _callbackTimer;
uint8 _unkValue4;
uint8 _unkValue5;
uint8 _unkValue6;
uint8 _unkValue7;
uint8 _unkValue8;
uint8 _unkValue9;
uint8 _unkValue10;
uint8 _unkValue11;
uint8 _unkValue12;
uint8 _unkValue13;
uint8 _unkValue14;
uint8 _unkValue15;
uint8 _unkValue16;
uint8 _unkValue17;
uint8 _unkValue18;
uint8 _unkValue19;
uint8 _unkValue20;
OPL::OPL *_adlib;
uint8 *_soundData;
uint32 _soundDataSize;
struct QueueEntry {
QueueEntry() : data(0), id(0), volume(0) {}
QueueEntry(uint8 *ptr, uint8 track, uint8 vol) : data(ptr), id(track), volume(vol) {}
uint8 *data;
uint8 id;
uint8 volume;
};
QueueEntry _programQueue[16];
int _programStartTimeout;
int _programQueueStart, _programQueueEnd;
bool _retrySounds;
void adjustSfxData(uint8 *data, int volume);
uint8 *_sfxPointer;
int _sfxPriority;
int _sfxVelocity;
Channel _channels[10];
uint8 _vibratoAndAMDepthBits;
uint8 _rhythmSectionBits;
uint8 _curRegOffset;
uint8 _tempo;
const uint8 *_tablePtr1;
const uint8 *_tablePtr2;
static const uint8 _regOffset[];
static const uint16 _freqTable[];
static const uint8 *const _unkTable2[];
static const uint8 _unkTable2_1[];
static const uint8 _unkTable2_2[];
static const uint8 _unkTable2_3[];
static const uint8 _pitchBendTables[][32];
uint16 _syncJumpMask;
Common::Mutex _mutex;
Audio::Mixer *_mixer;
uint8 _musicVolume, _sfxVolume;
int _numPrograms;
int _version;
};
AdLibDriver::AdLibDriver(Audio::Mixer *mixer, int version) : PCSoundDriver() {
setupParserOpcodeTable();
_version = version;
@@ -1961,6 +2293,10 @@ const uint8 AdLibDriver::_pitchBendTables[][32] = {
0x36, 0x37, 0x39, 0x3B, 0x3E, 0x41, 0x44, 0x47 }
};
PCSoundDriver *PCSoundDriver::createAdLib(Audio::Mixer *mixer, int version) {
return new AdLibDriver(mixer, version);
}
} // End of namespace Kyra
#undef CALLBACKS_PER_SECOND
-392
View File
@@ -1,392 +0,0 @@
/* 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.
*
* LGPL License
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef KYRA_SOUND_ADLIBDRIVER_H
#define KYRA_SOUND_ADLIBDRIVER_H
#include "kyra/resource/resource.h"
#include "common/mutex.h"
// Basic AdLib Programming:
// https://web.archive.org/web/20050322080425/http://www.gamedev.net/reference/articles/article446.asp
namespace Audio {
class Mixer;
}
namespace OPL {
class OPL;
}
namespace Kyra {
class AdLibDriver {
public:
AdLibDriver(Audio::Mixer *mixer, int version);
~AdLibDriver();
void initDriver();
void setSoundData(uint8 *data, uint32 size);
void queueTrack(int track, int volume);
bool isChannelPlaying(int channel) const;
void stopAllChannels();
int getSoundTrigger() const { return _soundTrigger; }
void resetSoundTrigger() { _soundTrigger = 0; }
void callback();
void setSyncJumpMask(uint16 mask) { _syncJumpMask = mask; }
void setMusicVolume(uint8 volume);
void setSfxVolume(uint8 volume);
private:
// These variables have not yet been named, but some of them are partly
// known nevertheless:
//
// pitchBend - Sound-related. Possibly some sort of pitch bend.
// unk18 - Sound-effect. Used for secondaryEffect1()
// unk19 - Sound-effect. Used for secondaryEffect1()
// unk20 - Sound-effect. Used for secondaryEffect1()
// unk21 - Sound-effect. Used for secondaryEffect1()
// unk22 - Sound-effect. Used for secondaryEffect1()
// unk29 - Sound-effect. Used for primaryEffect1()
// unk30 - Sound-effect. Used for primaryEffect1()
// unk31 - Sound-effect. Used for primaryEffect1()
// unk32 - Sound-effect. Used for primaryEffect2()
// unk33 - Sound-effect. Used for primaryEffect2()
// unk34 - Sound-effect. Used for primaryEffect2()
// unk35 - Sound-effect. Used for primaryEffect2()
// unk36 - Sound-effect. Used for primaryEffect2()
// unk37 - Sound-effect. Used for primaryEffect2()
// unk38 - Sound-effect. Used for primaryEffect2()
// unk39 - Currently unused, except for updateCallback56()
// unk40 - Currently unused, except for updateCallback56()
// unk41 - Sound-effect. Used for primaryEffect2()
struct Channel {
bool lock; // New to ScummVM
uint8 opExtraLevel2;
const uint8 *dataptr;
uint8 duration;
uint8 repeatCounter;
int8 baseOctave;
uint8 priority;
uint8 dataptrStackPos;
const uint8 *dataptrStack[4];
int8 baseNote;
uint8 unk29;
uint8 unk31;
uint16 unk30;
uint16 unk37;
uint8 unk33;
uint8 unk34;
uint8 unk35;
uint8 unk36;
uint8 unk32;
uint8 unk41;
uint8 unk38;
uint8 opExtraLevel1;
uint8 spacing2;
uint8 baseFreq;
uint8 tempo;
uint8 position;
uint8 regAx;
uint8 regBx;
typedef void (AdLibDriver::*Callback)(Channel&);
Callback primaryEffect;
Callback secondaryEffect;
uint8 fractionalSpacing;
uint8 opLevel1;
uint8 opLevel2;
uint8 opExtraLevel3;
uint8 twoChan;
uint8 unk39;
uint8 unk40;
uint8 spacing1;
uint8 durationRandomness;
uint8 unk19;
uint8 unk18;
int8 unk20;
int8 unk21;
uint8 unk22;
uint16 offset;
uint8 tempoReset;
uint8 rawNote;
int8 pitchBend;
uint8 volumeModifier;
};
void primaryEffect1(Channel &channel);
void primaryEffect2(Channel &channel);
void secondaryEffect1(Channel &channel);
void resetAdLibState();
void writeOPL(byte reg, byte val);
void initChannel(Channel &channel);
void noteOff(Channel &channel);
void unkOutput2(uint8 num);
uint16 getRandomNr();
void setupDuration(uint8 duration, Channel &channel);
void setupNote(uint8 rawNote, Channel &channel, bool flag = false);
void setupInstrument(uint8 regOffset, const uint8 *dataptr, Channel &channel);
void noteOn(Channel &channel);
void adjustVolume(Channel &channel);
uint8 calculateOpLevel1(Channel &channel);
uint8 calculateOpLevel2(Channel &channel);
uint16 checkValue(int16 val) {
if (val < 0)
val = 0;
else if (val > 0x3F)
val = 0x3F;
return val;
}
// The sound data has at least two lookup tables:
//
// * One for programs, starting at offset 0.
// * One for instruments, starting at offset 500.
uint8 *getProgram(int progId) {
const uint16 offset = READ_LE_UINT16(_soundData + 2 * progId);
// In case an invalid offset is specified we return nullptr to
// indicate an error. 0xFFFF seems to indicate "this is not a valid
// program/instrument". However, 0 is also invalid because it points
// inside the offset table itself. We also ignore any offsets outside
// of the actual data size.
// The original does not contain any safety checks and will simply
// read outside of the valid sound data in case an invalid offset is
// encountered.
if (offset == 0 || offset >= _soundDataSize) {
return nullptr;
} else {
return _soundData + offset;
}
}
const uint8 *getInstrument(int instrumentId) {
return getProgram(_numPrograms + instrumentId);
}
void setupPrograms();
void executePrograms();
struct ParserOpcode {
typedef int (AdLibDriver::*POpcode)(const uint8 *&dataptr, Channel &channel, uint8 value);
POpcode function;
const char *name;
};
void setupParserOpcodeTable();
const ParserOpcode *_parserOpcodeTable;
int _parserOpcodeTableSize;
int update_setRepeat(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_checkRepeat(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setupProgram(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setNoteSpacing(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_jump(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_jumpToSubroutine(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_returnFromSubroutine(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setBaseOctave(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_stopChannel(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_playRest(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_writeAdLib(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setupNoteAndDuration(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setBaseNote(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setupSecondaryEffect1(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_stopOtherChannel(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_waitForEndOfProgram(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setupInstrument(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setupPrimaryEffect1(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_removePrimaryEffect1(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setBaseFreq(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setupPrimaryEffect2(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setPriority(const uint8 *&dataptr, Channel &channel, uint8 value);
int updateCallback23(const uint8 *&dataptr, Channel &channel, uint8 value);
int updateCallback24(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setExtraLevel1(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setupDuration(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_playNote(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setFractionalNoteSpacing(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setTempo(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_removeSecondaryEffect1(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setChannelTempo(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setExtraLevel3(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setExtraLevel2(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_changeExtraLevel2(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setAMDepth(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setVibratoDepth(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_changeExtraLevel1(const uint8 *&dataptr, Channel &channel, uint8 value);
int updateCallback38(const uint8 *&dataptr, Channel &channel, uint8 value);
int updateCallback39(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_removePrimaryEffect2(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_pitchBend(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_resetToGlobalTempo(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_nop(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setDurationRandomness(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_changeChannelTempo(const uint8 *&dataptr, Channel &channel, uint8 value);
int updateCallback46(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setupRhythmSection(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_playRhythmSection(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_removeRhythmSection(const uint8 *&dataptr, Channel &channel, uint8 value);
int updateCallback51(const uint8 *&dataptr, Channel &channel, uint8 value);
int updateCallback52(const uint8 *&dataptr, Channel &channel, uint8 value);
int updateCallback53(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setSoundTrigger(const uint8 *&dataptr, Channel &channel, uint8 value);
int update_setTempoReset(const uint8 *&dataptr, Channel &channel, uint8 value);
int updateCallback56(const uint8 *&dataptr, Channel &channel, uint8 value);
private:
// These variables have not yet been named, but some of them are partly
// known nevertheless:
//
// _unkValue1 - Unknown. Used for updating _unkValue2
// _unkValue2 - Unknown. Used for updating _unkValue4
// _unkValue4 - Unknown. Used for updating _unkValue5
// _unkValue5 - Unknown. Used for controlling updateCallback24().
// _unkValue6 - Unknown. Rhythm section volume?
// _unkValue7 - Unknown. Rhythm section volume?
// _unkValue8 - Unknown. Rhythm section volume?
// _unkValue9 - Unknown. Rhythm section volume?
// _unkValue10 - Unknown. Rhythm section volume?
// _unkValue11 - Unknown. Rhythm section volume?
// _unkValue12 - Unknown. Rhythm section volume?
// _unkValue13 - Unknown. Rhythm section volume?
// _unkValue14 - Unknown. Rhythm section volume?
// _unkValue15 - Unknown. Rhythm section volume?
// _unkValue16 - Unknown. Rhythm section volume?
// _unkValue17 - Unknown. Rhythm section volume?
// _unkValue18 - Unknown. Rhythm section volume?
// _unkValue19 - Unknown. Rhythm section volume?
// _unkValue20 - Unknown. Rhythm section volume?
// _freqTable[] - Probably frequences for the 12-tone scale.
// _unkTable2[] - Unknown. Currently only used by updateCallback46()
// _unkTable2_1[] - One of the tables in _unkTable2[]
// _unkTable2_2[] - One of the tables in _unkTable2[]
// _unkTable2_3[] - One of the tables in _unkTable2[]
int _curChannel;
uint8 _soundTrigger;
uint16 _rnd;
uint8 _unkValue1;
uint8 _unkValue2;
uint8 _callbackTimer;
uint8 _unkValue4;
uint8 _unkValue5;
uint8 _unkValue6;
uint8 _unkValue7;
uint8 _unkValue8;
uint8 _unkValue9;
uint8 _unkValue10;
uint8 _unkValue11;
uint8 _unkValue12;
uint8 _unkValue13;
uint8 _unkValue14;
uint8 _unkValue15;
uint8 _unkValue16;
uint8 _unkValue17;
uint8 _unkValue18;
uint8 _unkValue19;
uint8 _unkValue20;
OPL::OPL *_adlib;
uint8 *_soundData;
uint32 _soundDataSize;
struct QueueEntry {
QueueEntry() : data(0), id(0), volume(0) {}
QueueEntry(uint8 *ptr, uint8 track, uint8 vol) : data(ptr), id(track), volume(vol) {}
uint8 *data;
uint8 id;
uint8 volume;
};
QueueEntry _programQueue[16];
int _programStartTimeout;
int _programQueueStart, _programQueueEnd;
bool _retrySounds;
void adjustSfxData(uint8 *data, int volume);
uint8 *_sfxPointer;
int _sfxPriority;
int _sfxVelocity;
Channel _channels[10];
uint8 _vibratoAndAMDepthBits;
uint8 _rhythmSectionBits;
uint8 _curRegOffset;
uint8 _tempo;
const uint8 *_tablePtr1;
const uint8 *_tablePtr2;
static const uint8 _regOffset[];
static const uint16 _freqTable[];
static const uint8 *const _unkTable2[];
static const uint8 _unkTable2_1[];
static const uint8 _unkTable2_2[];
static const uint8 _unkTable2_3[];
static const uint8 _pitchBendTables[][32];
uint16 _syncJumpMask;
Common::Mutex _mutex;
Audio::Mixer *_mixer;
uint8 _musicVolume, _sfxVolume;
int _numPrograms;
int _version;
};
} // End of namespace Kyra
#endif
+64
View File
@@ -0,0 +1,64 @@
/* 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.
*
*/
#ifndef KYRA_SOUND_PCDRIVER_H
#define KYRA_SOUND_PCDRIVER_H
#include "kyra/resource/resource.h"
namespace Audio {
class Mixer;
}
namespace Kyra {
class PCSoundDriver {
public:
PCSoundDriver() {}
virtual ~PCSoundDriver() {}
virtual void initDriver() = 0;
virtual void setSoundData(uint8 *data, uint32 size) = 0;
virtual void queueTrack(int track, int volume) = 0;
virtual bool isChannelPlaying(int channel) const = 0;
virtual void stopAllChannels() = 0;
virtual int getSoundTrigger() const = 0;
virtual void resetSoundTrigger() = 0;
virtual void callback() = 0;
// AdLiB specific
virtual void setSyncJumpMask(uint16) {}
virtual void setMusicVolume(uint8 volume) = 0;
virtual void setSfxVolume(uint8 volume) = 0;
static PCSoundDriver *createAdLib(Audio::Mixer *mixer, int version);
#ifdef ENABLE_EOB
static PCSoundDriver *createPCSpk(Audio::Mixer *mixer);
#endif
};
} // End of namespace Kyra
#endif
@@ -0,0 +1,99 @@
/* 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.
*
*/
#ifdef ENABLE_EOB
#include "kyra/sound/drivers/pc_base.h"
#include "audio/mixer.h"
#include "audio/softsynth/pcspk.h"
namespace Kyra {
class PCSpeakerDriver : public PCSoundDriver {
public:
PCSpeakerDriver(Audio::Mixer *mixer);
virtual ~PCSpeakerDriver();
virtual void initDriver() override;
virtual void setSoundData(uint8 *data, uint32 size) override;
virtual void queueTrack(int track, int volume) override;
virtual bool isChannelPlaying(int channel) const override;
virtual void stopAllChannels() override;
virtual int getSoundTrigger() const override { return _soundTrigger; }
virtual void resetSoundTrigger() override { _soundTrigger = 0; }
virtual void callback() override;
virtual void setMusicVolume(uint8 volume) override;
virtual void setSfxVolume(uint8 volume) override;
private:
int _soundTrigger;
};
PCSpeakerDriver::PCSpeakerDriver(Audio::Mixer *mixer) : PCSoundDriver() {
}
PCSpeakerDriver::~PCSpeakerDriver() {
}
void PCSpeakerDriver::initDriver() {
}
void PCSpeakerDriver::setSoundData(uint8 *data, uint32 size) {
}
void PCSpeakerDriver::queueTrack(int track, int volume) {
}
bool PCSpeakerDriver::isChannelPlaying(int channel) const {
return true;
}
void PCSpeakerDriver::stopAllChannels() {
}
void PCSpeakerDriver::callback() {
}
void PCSpeakerDriver::setMusicVolume(uint8 volume) {
}
void PCSpeakerDriver::setSfxVolume(uint8 volume) {
}
PCSoundDriver *PCSoundDriver::createPCSpk(Audio::Mixer *mixer) {
return new PCSpeakerDriver(mixer);
}
} // End of namespace Kyra
#endif
+1 -1
View File
@@ -25,7 +25,7 @@
#include "kyra/sound/sound.h"
#include "kyra/sound/sound_adlib.h"
#include "kyra/sound/sound_pc_v1.h"
#include "audio/midiparser.h"
#include "audio/softsynth/emumidi.h"
@@ -403,7 +403,7 @@ Common::String SoundMidiPC::getFileName(const Common::String &str) {
else if (_type == kMidiGM)
file += ".C55";
else if (_type == kPCSpkr)
file += ".PCS";
file += ".SND";//".PCS";
if (_vm->resource()->exists(file.c_str()))
return file;
@@ -21,7 +21,7 @@
*/
#include "kyra/sound/sound_intern.h"
#include "kyra/sound/drivers/adlib.h"
#include "kyra/sound/drivers/pc_base.h"
#include "common/system.h"
#include "common/config-manager.h"
@@ -34,14 +34,14 @@ namespace Kyra {
// used in other places throughout the game, but the player is less likely to
// spend enough time there to notice.
const int SoundAdLibPC::_kyra1SoundTriggers[] = {
const int SoundPC_v1::_kyra1SoundTriggers[] = {
0, 4, 5, 3
};
const int SoundAdLibPC::_kyra1NumSoundTriggers = ARRAYSIZE(SoundAdLibPC::_kyra1SoundTriggers);
const int SoundPC_v1::_kyra1NumSoundTriggers = ARRAYSIZE(SoundPC_v1::_kyra1SoundTriggers);
SoundAdLibPC::SoundAdLibPC(KyraEngine_v1 *vm, Audio::Mixer *mixer)
: Sound(vm, mixer), _driver(0), _trackEntries(), _soundDataPtr(0) {
SoundPC_v1::SoundPC_v1(KyraEngine_v1 *vm, Audio::Mixer *mixer, kType type)
: Sound(vm, mixer), _driver(0), _trackEntries(), _soundDataPtr(0), _type(type) {
memset(_trackEntries, 0, sizeof(_trackEntries));
_soundTriggers = 0;
@@ -73,23 +73,27 @@ SoundAdLibPC::SoundAdLibPC(KyraEngine_v1 *vm, Audio::Mixer *mixer)
break;
}
_driver = new AdLibDriver(mixer, _version);
// Correct the type to someting we support. NullSound is treated as a silent AdLib driver.
if (_type != kAdLib && _type != kPCSpkr)
_type = kAdLib;
_driver = (type == kAdLib) ? PCSoundDriver::createAdLib(mixer, _version) : PCSoundDriver::createPCSpk(mixer);
assert(_driver);
}
SoundAdLibPC::~SoundAdLibPC() {
SoundPC_v1::~SoundPC_v1() {
delete _driver;
delete[] _soundDataPtr;
for (int i = 0; i < 3; i++)
initAudioResourceInfo(i, 0);
}
bool SoundAdLibPC::init() {
bool SoundPC_v1::init() {
_driver->initDriver();
return true;
}
void SoundAdLibPC::process() {
void SoundPC_v1::process() {
int trigger = _driver->getSoundTrigger();
if (trigger < _numSoundTriggers) {
@@ -103,7 +107,7 @@ void SoundAdLibPC::process() {
}
}
void SoundAdLibPC::updateVolumeSettings() {
void SoundPC_v1::updateVolumeSettings() {
bool mute = false;
if (ConfMan.hasKey("mute"))
mute = ConfMan.getBool("mute");
@@ -120,7 +124,7 @@ void SoundAdLibPC::updateVolumeSettings() {
_driver->setSfxVolume(newSfxVolume);
}
void SoundAdLibPC::playTrack(uint8 track) {
void SoundPC_v1::playTrack(uint8 track) {
if (_musicEnabled) {
// WORKAROUND: There is a bug in the Kyra 1 "Pool of Sorrow"
// music which causes the channels to get progressively out of
@@ -135,22 +139,22 @@ void SoundAdLibPC::playTrack(uint8 track) {
}
}
void SoundAdLibPC::haltTrack() {
void SoundPC_v1::haltTrack() {
play(0, 0);
play(0, 0);
//_vm->_system->delayMillis(3 * 60);
}
bool SoundAdLibPC::isPlaying() const {
bool SoundPC_v1::isPlaying() const {
return _driver->isChannelPlaying(0);
}
void SoundAdLibPC::playSoundEffect(uint8 track, uint8 volume) {
void SoundPC_v1::playSoundEffect(uint8 track, uint8 volume) {
if (_sfxEnabled)
play(track, volume);
}
void SoundAdLibPC::play(uint8 track, uint8 volume) {
void SoundPC_v1::play(uint8 track, uint8 volume) {
uint16 soundId = 0;
if (_version == 4)
@@ -164,49 +168,51 @@ void SoundAdLibPC::play(uint8 track, uint8 volume) {
_driver->queueTrack(soundId, volume);
}
void SoundAdLibPC::beginFadeOut() {
void SoundPC_v1::beginFadeOut() {
play(_version > 2 ? 1 : 15, 0xFF);
}
int SoundAdLibPC::checkTrigger() {
int SoundPC_v1::checkTrigger() {
return _driver->getSoundTrigger();
}
void SoundAdLibPC::resetTrigger() {
void SoundPC_v1::resetTrigger() {
_driver->resetSoundTrigger();
}
void SoundAdLibPC::initAudioResourceInfo(int set, void *info) {
void SoundPC_v1::initAudioResourceInfo(int set, void *info) {
if (set >= kMusicIntro && set <= kMusicFinale) {
delete _resInfo[set];
_resInfo[set] = info ? new SoundResourceInfo_PC(*(SoundResourceInfo_PC*)info) : 0;
}
}
void SoundAdLibPC::selectAudioResourceSet(int set) {
void SoundPC_v1::selectAudioResourceSet(int set) {
if (set >= kMusicIntro && set <= kMusicFinale) {
if (_resInfo[set])
_currentResourceSet = set;
}
}
bool SoundAdLibPC::hasSoundFile(uint file) const {
bool SoundPC_v1::hasSoundFile(uint file) const {
if (file < res()->fileListSize)
return (res()->fileList[file] != 0);
return false;
}
void SoundAdLibPC::loadSoundFile(uint file) {
void SoundPC_v1::loadSoundFile(uint file) {
if (_version == 1 && _type == kPCSpkr)
file += 1;
if (file < res()->fileListSize)
internalLoadFile(res()->fileList[file]);
}
void SoundAdLibPC::loadSoundFile(Common::String file) {
void SoundPC_v1::loadSoundFile(Common::String file) {
internalLoadFile(file);
}
void SoundAdLibPC::internalLoadFile(Common::String file) {
file += ((_version == 1) ? ".DAT" : ".ADL");
void SoundPC_v1::internalLoadFile(Common::String file) {
file += ((_version == 1) ? ".DAT" : (_type == kPCSpkr ? ".SND" : ".ADL"));
if (_soundFileLoaded == file)
return;
@@ -28,25 +28,31 @@
#include "common/mutex.h"
namespace Kyra {
class AdLibDriver;
class PCSoundDriver;
/**
* AdLib implementation of the sound output device.
* AdLib/PC Speaker (early version) implementation of the
* sound output device.
*
* It uses a special sound file format special to
* Dune II, Kyrandia 1 and 2. While Dune II and
* Kyrandia 1 are using exact the same format, the
* one of Kyrandia 2 slightly differs.
* It uses a special sound file format special to EoB I, II,
* Dune II, Kyrandia 1 and 2 and LoL. EoB I has a slightly
* different (oldest) file format, EoB II, Dune II and
* Kyrandia 1 have the exact same format, Kyrandia 2 and
* LoL have a slightly different format.
*
* See AdLibDriver for more information.
* For PC Speaker this is a little different. Only the EoB
* games use the old driver with this data file format. The
* newer games use a MIDI-like driver (see pcspeaker_v2.cpp).
*
* See AdLibDriver / PCSpeakerDriver for more information.
* @see AdLibDriver
*/
class SoundAdLibPC : public Sound {
class SoundPC_v1 : public Sound {
public:
SoundAdLibPC(KyraEngine_v1 *vm, Audio::Mixer *mixer);
~SoundAdLibPC();
SoundPC_v1(KyraEngine_v1 *vm, Audio::Mixer *mixer, kType type);
~SoundPC_v1();
virtual kType getMusicType() const { return kAdLib; }
virtual kType getMusicType() const { return _type; }
virtual bool init();
virtual void process();
@@ -78,9 +84,10 @@ private:
SoundResourceInfo_PC *_resInfo[3];
int _currentResourceSet;
AdLibDriver *_driver;
PCSoundDriver *_driver;
int _version;
kType _type;
uint8 _trackEntries[500];
uint8 *_soundDataPtr;
int _sfxPlayingSound;