mirror of
https://github.com/scummvm/scummvm.git
synced 2026-06-20 05:45:29 +00:00
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:
1 parent
ad046b1589
commit
46ef0109b5
17 files changed
+582
-459
No files matched your search
@@ -45,7 +45,7 @@
|
||||
|
||||
|
||||
enum {
|
||||
kKyraDatVersion = 95
|
||||
kKyraDatVersion = 96
|
||||
};
|
||||
|
||||
const ExtractFilename extractFilenames[] = {
|
||||
|
||||
@@ -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.
@@ -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
|
||||
},
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
|
||||
namespace Kyra {
|
||||
|
||||
#define RESFILE_VERSION 95
|
||||
#define RESFILE_VERSION 96
|
||||
|
||||
namespace {
|
||||
bool checkKyraDat(Common::SeekableReadStream *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
|
||||
@@ -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
|
||||
@@ -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
|
||||
File renamed without changes.
@@ -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;
|
||||
Reference in new issue
Block a user