632 lines
16 KiB
C++
632 lines
16 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#ifndef KYRA_SOUND_INTERN_H
|
|
#define KYRA_SOUND_INTERN_H
|
|
|
|
|
|
#include "kyra/sound/sound.h"
|
|
#include "kyra/sound/sound_pc_v1.h"
|
|
|
|
#include "audio/midiparser.h"
|
|
#include "audio/miles.h"
|
|
#include "audio/softsynth/emumidi.h"
|
|
#include "audio/softsynth/fmtowns_pc98/towns_audio.h"
|
|
|
|
#include "common/mutex.h"
|
|
|
|
class EuphonyPlayer;
|
|
class TownsPC98_AudioDriver;
|
|
|
|
namespace Audio {
|
|
class PCSpeakerStream;
|
|
class MaxTrax;
|
|
} // End of namespace Audio
|
|
|
|
namespace Common {
|
|
class MacResManager;
|
|
} // End of namespace Common
|
|
|
|
namespace Kyra {
|
|
|
|
class MidiOutput;
|
|
|
|
/**
|
|
* MIDI output device.
|
|
*
|
|
* This device supports both MT-32 MIDI, as used in
|
|
* Kyrandia 1 and 2, and GM MIDI, as used in Kyrandia 2.
|
|
*/
|
|
class SoundMidiPC : public Sound {
|
|
public:
|
|
SoundMidiPC(KyraEngine_v1 *vm, Audio::Mixer *mixer, MidiDriver *driver, kType type);
|
|
~SoundMidiPC() override;
|
|
|
|
kType getMusicType() const override { return _type; }
|
|
|
|
bool init() override;
|
|
|
|
void updateVolumeSettings() override;
|
|
|
|
void initAudioResourceInfo(int set, void *info) override;
|
|
void selectAudioResourceSet(int set) override;
|
|
bool hasSoundFile(uint file) const override;
|
|
void loadSoundFile(uint file) override;
|
|
void loadSoundFile(const Common::Path &file) override;
|
|
void loadSfxFile(const Common::Path &file) override;
|
|
|
|
void playTrack(uint8 track) override;
|
|
void haltTrack() override;
|
|
bool isPlaying() const override;
|
|
|
|
void playSoundEffect(uint16 track, uint8 volume = 0xFF) override;
|
|
void stopAllSoundEffects() override;
|
|
|
|
void beginFadeOut() override;
|
|
|
|
void pause(bool paused) override;
|
|
private:
|
|
static void onTimer(void *data);
|
|
|
|
// Our channel handling
|
|
int _musicVolume, _sfxVolume;
|
|
|
|
uint32 _fadeStartTime;
|
|
bool _fadeMusicOut;
|
|
|
|
// Midi file related
|
|
Common::Path _mFileName, _sFileName;
|
|
byte *_musicFile, *_sfxFile;
|
|
|
|
MidiParser *_music;
|
|
MidiParser *_sfx[3];
|
|
|
|
const SoundResourceInfo_PC *res() const {return _resInfo[_currentResourceSet]; }
|
|
SoundResourceInfo_PC *_resInfo[3];
|
|
int _currentResourceSet;
|
|
|
|
// misc
|
|
kType _type;
|
|
Common::Path getFileName(const Common::Path &str);
|
|
|
|
bool _nativeMT32;
|
|
MidiDriver *_driver;
|
|
Audio::MidiDriver_Miles_Midi *_output;
|
|
|
|
Common::Mutex _mutex;
|
|
};
|
|
|
|
class SoundTowns_LoK : public Sound {
|
|
public:
|
|
SoundTowns_LoK(KyraEngine_v1 *vm, Audio::Mixer *mixer);
|
|
~SoundTowns_LoK() override;
|
|
|
|
kType getMusicType() const override { return kTowns; }
|
|
|
|
bool init() override;
|
|
void process() override;
|
|
|
|
void initAudioResourceInfo(int set, void *info) override;
|
|
void selectAudioResourceSet(int set) override;
|
|
bool hasSoundFile(uint file) const override;
|
|
void loadSoundFile(uint file) override;
|
|
void loadSoundFile(const Common::Path &) override {}
|
|
|
|
void playTrack(uint8 track) override;
|
|
void haltTrack() override;
|
|
|
|
void playSoundEffect(uint16 track, uint8 volume = 0xFF) override;
|
|
void stopAllSoundEffects() override;
|
|
|
|
void beginFadeOut() override;
|
|
|
|
void updateVolumeSettings() override;
|
|
void enableMusic(int enable) override;
|
|
|
|
private:
|
|
bool loadInstruments();
|
|
void playEuphonyTrack(uint32 offset, int loop);
|
|
|
|
void fadeOutSoundEffects();
|
|
|
|
int _lastTrack;
|
|
Audio::SoundHandle _sfxHandle;
|
|
|
|
uint8 *_musicTrackData;
|
|
|
|
uint _sfxFileIndex;
|
|
uint8 *_sfxFileData;
|
|
uint8 _sfxChannel;
|
|
|
|
EuphonyPlayer *_player;
|
|
|
|
bool _cdaPlaying;
|
|
|
|
const SoundResourceInfo_Towns *res() const {return _resInfo[_currentResourceSet]; }
|
|
SoundResourceInfo_Towns *_resInfo[3];
|
|
int _currentResourceSet;
|
|
|
|
const uint8 *_musicFadeTable;
|
|
const uint8 *_sfxBTTable;
|
|
const uint8 *_sfxWDTable;
|
|
};
|
|
|
|
class SoundPC98_LoK : public Sound {
|
|
public:
|
|
SoundPC98_LoK(KyraEngine_v1 *vm, Audio::Mixer *mixer);
|
|
~SoundPC98_LoK() override;
|
|
|
|
kType getMusicType() const override { return kPC98; }
|
|
|
|
bool init() override;
|
|
|
|
void initAudioResourceInfo(int set, void *info) override;
|
|
void selectAudioResourceSet(int set) override;
|
|
bool hasSoundFile(uint file) const override;
|
|
void loadSoundFile(uint file) override;
|
|
void loadSoundFile(const Common::Path &file) override;
|
|
|
|
void playTrack(uint8 track) override;
|
|
void haltTrack() override;
|
|
void beginFadeOut() override;
|
|
|
|
int32 voicePlay(const char *file, Audio::SoundHandle *handle, uint8 volume, uint8 priority, bool isSfx) override { return -1; }
|
|
void playSoundEffect(uint16 track, uint8 volume = 0xFF) override;
|
|
|
|
void updateVolumeSettings() override;
|
|
|
|
private:
|
|
int _lastTrack;
|
|
uint8 *_musicTrackData;
|
|
uint8 *_sfxTrackData;
|
|
TownsPC98_AudioDriver *_driver;
|
|
|
|
const char *resPattern() {return _resInfo[_currentResourceSet]->c_str(); }
|
|
Common::String *_resInfo[3];
|
|
int _currentResourceSet;
|
|
};
|
|
|
|
class SoundTownsPC98_v2 : public Sound {
|
|
public:
|
|
SoundTownsPC98_v2(KyraEngine_v1 *vm, Audio::Mixer *mixer);
|
|
~SoundTownsPC98_v2() override;
|
|
|
|
kType getMusicType() const override { return _vm->gameFlags().platform == Common::kPlatformFMTowns ? kTowns : kPC98; }
|
|
|
|
bool init() override;
|
|
void process() override;
|
|
|
|
void initAudioResourceInfo(int set, void *info) override;
|
|
void selectAudioResourceSet(int set) override;
|
|
bool hasSoundFile(uint file) const override;
|
|
void loadSoundFile(uint file) override {}
|
|
void loadSoundFile(const Common::Path &file) override;
|
|
|
|
void playTrack(uint8 track) override;
|
|
void haltTrack() override;
|
|
void beginFadeOut() override;
|
|
|
|
int32 voicePlay(const char *file, Audio::SoundHandle *handle, uint8 volume = 255, uint8 priority = 255, bool isSfx = true) override;
|
|
void playSoundEffect(uint16 track, uint8 volume = 0xFF) override;
|
|
|
|
void updateVolumeSettings() override;
|
|
|
|
private:
|
|
Audio::AudioStream *_currentSFX;
|
|
int _lastTrack;
|
|
bool _useFmSfx;
|
|
|
|
uint8 *_musicTrackData;
|
|
uint8 *_sfxTrackData;
|
|
TownsPC98_AudioDriver *_driver;
|
|
|
|
const SoundResourceInfo_TownsPC98V2 *res() const { return _resInfo[_currentResourceSet]; }
|
|
SoundResourceInfo_TownsPC98V2 *_resInfo[3];
|
|
int _currentResourceSet;
|
|
};
|
|
|
|
// PC Speaker MIDI driver
|
|
class MidiDriver_PCSpeaker : public MidiDriver_Emulated {
|
|
public:
|
|
MidiDriver_PCSpeaker(Audio::Mixer *mixer);
|
|
~MidiDriver_PCSpeaker() override;
|
|
|
|
// MidiDriver interface
|
|
void close() override {}
|
|
|
|
void send(uint32 data) override;
|
|
|
|
MidiChannel *allocateChannel() override { return 0; }
|
|
MidiChannel *getPercussionChannel() override { return 0; }
|
|
|
|
// MidiDriver_Emulated interface
|
|
void generateSamples(int16 *buffer, int numSamples) override;
|
|
|
|
// AudioStream interface
|
|
bool isStereo() const override { return false; }
|
|
int getRate() const override { return _rate; }
|
|
private:
|
|
Common::Mutex _mutex;
|
|
Audio::PCSpeakerStream *_speaker;
|
|
int _rate;
|
|
|
|
struct Channel {
|
|
uint8 pitchBendLow, pitchBendHigh;
|
|
uint8 hold;
|
|
uint8 modulation;
|
|
uint8 voiceProtect;
|
|
uint8 noteCount;
|
|
} _channel[2];
|
|
|
|
void resetController(int channel);
|
|
|
|
struct Note {
|
|
bool enabled;
|
|
uint8 hardwareChannel;
|
|
uint8 midiChannel;
|
|
uint8 note;
|
|
bool processHold;
|
|
uint8 flags;
|
|
uint8 hardwareFlags;
|
|
uint16 priority;
|
|
int16 modulation;
|
|
uint16 precedence;
|
|
} _note[2];
|
|
|
|
void noteOn(int channel, int note);
|
|
void noteOff(int channel, int note);
|
|
|
|
void turnNoteOn(int note);
|
|
void overwriteNote(int note);
|
|
void turnNoteOff(int note);
|
|
|
|
void setupTone(int note);
|
|
|
|
uint16 _countdown;
|
|
uint8 _hardwareChannel[1];
|
|
bool _modulationFlag;
|
|
|
|
uint8 _timerValue;
|
|
void onTimer() override;
|
|
|
|
static const uint8 _noteTable1[];
|
|
static const uint8 _noteTable2[];
|
|
};
|
|
|
|
// for StaticResource (maybe we can find a nicer way to handle it)
|
|
struct AmigaSfxTable {
|
|
uint8 note;
|
|
uint8 patch;
|
|
uint16 duration;
|
|
uint8 volume;
|
|
uint8 pan;
|
|
};
|
|
|
|
class SoundAmiga_LoK : public Sound {
|
|
public:
|
|
SoundAmiga_LoK(KyraEngine_v1 *vm, Audio::Mixer *mixer);
|
|
~SoundAmiga_LoK() override;
|
|
|
|
kType getMusicType() const override { return kAmiga; } //FIXME
|
|
|
|
bool init() override;
|
|
|
|
void initAudioResourceInfo(int set, void *info) override;
|
|
void selectAudioResourceSet(int set) override;
|
|
bool hasSoundFile(uint file) const override;
|
|
void loadSoundFile(uint file) override;
|
|
void loadSoundFile(const Common::Path &) override {}
|
|
|
|
void playTrack(uint8 track) override;
|
|
void haltTrack() override;
|
|
void beginFadeOut() override;
|
|
|
|
int32 voicePlay(const char *file, Audio::SoundHandle *handle, uint8 volume, uint8 priority, bool isSfx) override { return -1; }
|
|
void playSoundEffect(uint16 track, uint8 volume = 0xFF) override;
|
|
|
|
protected:
|
|
Audio::MaxTrax *_driver;
|
|
Audio::SoundHandle _musicHandle;
|
|
enum FileType { kFileNone = -1, kFileIntro = 0, kFileGame = 1, kFileFinal = 2 } _fileLoaded;
|
|
|
|
const AmigaSfxTable *_tableSfxIntro;
|
|
int _tableSfxIntro_Size;
|
|
|
|
const AmigaSfxTable *_tableSfxGame;
|
|
int _tableSfxGame_Size;
|
|
};
|
|
|
|
class SoundMacRes;
|
|
class HalestormDriver;
|
|
class SoundMac : public Sound {
|
|
public:
|
|
SoundMac(KyraEngine_v1 *vm, Audio::Mixer *mixer);
|
|
~SoundMac() override;
|
|
|
|
kType getMusicType() const override;
|
|
|
|
bool init() override { return init(musicEnabled() == 1); }
|
|
bool init(bool hiQuality);
|
|
void initAudioResourceInfo(int, void*) override {}
|
|
void selectAudioResourceSet(int set) override;
|
|
bool hasSoundFile(uint) const override { return true; }
|
|
void loadSoundFile(uint) override {}
|
|
void loadSoundFile(const Common::Path &) override {}
|
|
void playTrack(uint8 track) override;
|
|
void haltTrack() override;
|
|
void playSoundEffect(uint16 track, uint8) override;
|
|
bool isPlaying() const override;
|
|
void beginFadeOut() override;
|
|
void updateVolumeSettings() override;
|
|
void enableMusic(int enable) override;
|
|
|
|
private:
|
|
void setQuality(bool hi);
|
|
|
|
SoundMacRes *_res;
|
|
HalestormDriver *_driver;
|
|
const int _talkieFlag;
|
|
bool _ready;
|
|
|
|
const uint16 *_resIDMusic;
|
|
int _currentResourceSet;
|
|
|
|
static const uint16 _resIDMusicIntro[4];
|
|
static const uint16 _resIDMusicIngame[35];
|
|
static const uint8 _musicLoopTable[35];
|
|
static const uint16 _resIDSfxIntro[2][39];
|
|
static const uint16 _resIDSfxIngame[2][39];
|
|
|
|
struct SoundEffectDef {
|
|
uint8 note;
|
|
uint8 number;
|
|
uint16 rate;
|
|
uint8 unk;
|
|
};
|
|
|
|
static const SoundEffectDef _soundEffectDefsIntro[16];
|
|
static const SoundEffectDef _soundEffectDefsIngame[120];
|
|
};
|
|
|
|
#ifdef ENABLE_EOB
|
|
|
|
class SoundTowns_Darkmoon : public Sound, public TownsAudioInterfacePluginDriver {
|
|
public:
|
|
SoundTowns_Darkmoon(KyraEngine_v1 *vm, Audio::Mixer *mixer);
|
|
~SoundTowns_Darkmoon() override;
|
|
|
|
kType getMusicType() const override { return kTowns; }
|
|
|
|
bool init() override;
|
|
|
|
void timerCallback(int timerId) override;
|
|
|
|
void initAudioResourceInfo(int set, void *info) override;
|
|
void selectAudioResourceSet(int set) override;
|
|
bool hasSoundFile(uint file) const override;
|
|
void loadSoundFile(uint file) override;
|
|
void loadSoundFile(const Common::Path &name) override;
|
|
|
|
void playTrack(uint8 track) override;
|
|
void haltTrack() override;
|
|
bool isPlaying() const override;
|
|
|
|
void playSoundEffect(uint16 track, uint8 volume = 0xFF) override;
|
|
void stopAllSoundEffects() override;
|
|
|
|
void beginFadeOut() override;
|
|
|
|
void updateVolumeSettings() override;
|
|
|
|
int checkTrigger() override;
|
|
|
|
void resetTrigger() override;
|
|
|
|
private:
|
|
struct SoundTableEntry {
|
|
int8 type;
|
|
int32 para1;
|
|
int16 para2;
|
|
} _soundTable[120];
|
|
|
|
const char *const *_fileList;
|
|
uint _fileListLen;
|
|
|
|
uint8 _lastSfxChan;
|
|
uint8 _lastEnvChan;
|
|
uint8 *_pcmData;
|
|
uint32 _pcmDataSize;
|
|
uint8 _pcmVol;
|
|
|
|
int _timer;
|
|
int _timerSwitch;
|
|
|
|
SoundResourceInfo_TownsEoB *_resource[3];
|
|
|
|
TownsAudioInterface *_intf;
|
|
};
|
|
|
|
class AudioMaster2;
|
|
class SoundAmiga_EoB: public Sound {
|
|
public:
|
|
SoundAmiga_EoB(KyraEngine_v1 *vm, Audio::Mixer *mixer);
|
|
~SoundAmiga_EoB() override;
|
|
|
|
kType getMusicType() const override;
|
|
|
|
bool init() override;
|
|
void initAudioResourceInfo(int set, void *info) override;
|
|
void selectAudioResourceSet(int set) override;
|
|
bool hasSoundFile(uint file) const override { return false; }
|
|
void loadSoundFile(uint) override {}
|
|
void loadSoundFile(const Common::Path &file) override;
|
|
void unloadSoundFile(const Common::String &file) override;
|
|
void playTrack(uint8 track) override;
|
|
void haltTrack() override;
|
|
void playSoundEffect(uint16 track, uint8 volume = 0xFF) override;
|
|
void beginFadeOut() override { beginFadeOut(160); }
|
|
void beginFadeOut(int delay) override;
|
|
void updateVolumeSettings() override;
|
|
int checkTrigger() override;
|
|
|
|
private:
|
|
uint8 *_fileBuffer;
|
|
|
|
KyraEngine_v1 *_vm;
|
|
AudioMaster2 *_driver;
|
|
SoundResourceInfo_AmigaEoB *_resInfo[3];
|
|
Common::String _lastSound;
|
|
|
|
int _currentResourceSet;
|
|
|
|
bool _ready;
|
|
};
|
|
|
|
class MLALF98;
|
|
class SoundPC98_EoB : public Sound {
|
|
public:
|
|
SoundPC98_EoB(KyraEngine_v1 *vm, Audio::Mixer *mixer);
|
|
~SoundPC98_EoB() override;
|
|
|
|
kType getMusicType() const override;
|
|
|
|
bool init() override;
|
|
void initAudioResourceInfo(int set, void *info) override;
|
|
void selectAudioResourceSet(int set) override;
|
|
bool hasSoundFile(uint file) const override { return false; }
|
|
void loadSoundFile(uint file) override;
|
|
void loadSoundFile(const Common::Path &file) override {}
|
|
void loadSfxFile(const Common::Path &file) override;
|
|
void playTrack(uint8 track) override;
|
|
void haltTrack() override;
|
|
void playSoundEffect(uint16 track, uint8) override;
|
|
void beginFadeOut() override {}
|
|
void updateVolumeSettings() override;
|
|
|
|
private:
|
|
KyraEngine_v1 *_vm;
|
|
MLALF98 *_driver;
|
|
|
|
SoundResourceInfo_PC *_resInfo[3];
|
|
int _currentResourceSet;
|
|
|
|
uint32 _sfxDelay;
|
|
|
|
bool _ready;
|
|
};
|
|
|
|
class CapcomPC98AudioDriver;
|
|
class SoundPC98_Darkmoon : public Sound {
|
|
public:
|
|
SoundPC98_Darkmoon(KyraEngine_v1 *vm, MidiDriver::DeviceHandle dev, Audio::Mixer *mixer);
|
|
~SoundPC98_Darkmoon() override;
|
|
|
|
kType getMusicType() const override;
|
|
kType getSfxType() const override;
|
|
|
|
bool init() override;
|
|
|
|
void initAudioResourceInfo(int set, void *info) override;
|
|
void selectAudioResourceSet(int set) override;
|
|
bool hasSoundFile(uint file) const override { return true; }
|
|
void loadSoundFile(uint file) override;
|
|
void loadSoundFile(const Common::Path &name) override;
|
|
|
|
void playTrack(uint8 track) override;
|
|
void haltTrack() override;
|
|
bool isPlaying() const override;
|
|
|
|
void playSoundEffect(uint16 track, uint8 volume = 0xFF) override;
|
|
void stopAllSoundEffects() override;
|
|
|
|
void beginFadeOut() override;
|
|
|
|
void pause(bool paused) override;
|
|
|
|
void updateVolumeSettings() override;
|
|
|
|
int checkTrigger() override;
|
|
void resetTrigger() override {} // This sound class is for EOB II only, this method is not needed there.
|
|
|
|
private:
|
|
void restartBackgroundMusic();
|
|
const uint8 *getData(uint16 track) const;
|
|
|
|
KyraEngine_v1 *_vm;
|
|
CapcomPC98AudioDriver *_driver;
|
|
uint8 *_soundData, *_fileBuffer;
|
|
|
|
int _lastTrack;
|
|
|
|
const SoundResourceInfo_PC *res() const {return _resInfo[_currentResourceSet]; }
|
|
SoundResourceInfo_PC *_resInfo[3];
|
|
int _currentResourceSet;
|
|
|
|
Common::Path _soundFileLoaded;
|
|
|
|
MidiDriver::DeviceHandle _dev;
|
|
kType _drvType;
|
|
bool _ready;
|
|
};
|
|
|
|
class SegaAudioDriver;
|
|
class SoundSegaCD_EoB : public Sound {
|
|
public:
|
|
SoundSegaCD_EoB(KyraEngine_v1 *vm, Audio::Mixer *mixer);
|
|
~SoundSegaCD_EoB() override;
|
|
|
|
kType getMusicType() const override;
|
|
|
|
bool init() override;
|
|
void initAudioResourceInfo(int, void*) override {}
|
|
void selectAudioResourceSet(int) override {}
|
|
bool hasSoundFile(uint file) const override { return false; }
|
|
void loadSoundFile(uint file) override {}
|
|
void loadSoundFile(const Common::Path &file) override {}
|
|
void playTrack(uint8 track) override;
|
|
void haltTrack() override;
|
|
void playSoundEffect(uint16 track, uint8 volume) override;
|
|
bool isPlaying() const override;
|
|
void beginFadeOut() override {}
|
|
void updateVolumeSettings() override;
|
|
|
|
private:
|
|
void loadPCMData();
|
|
void loadFMData();
|
|
|
|
KyraEngine_v1 *_vm;
|
|
SegaAudioDriver *_driver;
|
|
|
|
uint8 _pcmOffsets[8];
|
|
uint16 _fmOffsets[140];
|
|
const uint8 *_fmData;
|
|
int _lastSoundEffect;
|
|
bool _ready;
|
|
|
|
static const uint8 _fmTrackMap[140];
|
|
};
|
|
|
|
#endif
|
|
|
|
} // End of namespace Kyra
|
|
|
|
#endif
|