Files
scummvm-cursorfix/engines/scumm/he/sound_he.h
2026-02-02 04:50:13 +01:00

284 lines
8.8 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 SCUMM_HE_SOUND_HE_H
#define SCUMM_HE_SOUND_HE_H
#include "common/scummsys.h"
#include "common/mutex.h"
#include "scumm/sound.h"
#include "scumm/he/mixer_he.h"
#include "audio/audiostream.h"
namespace Scumm {
#define HSND_DYN_SOUND_CHAN -1
#define HSND_TALKIE_SLOT 1
#define HSND_SOUND_STOPPED 1
#define HSND_SOUND_ENDED 2
#define HSND_SOUND_TIMEOUT 3
#define HSND_TIMER_SLOT 4
#define HSND_MAX_CALLBACK_SCRIPTS 20
#define HSND_MAX_CHANNELS 8
#define HSND_CHANNEL_0 10000
#define HSND_CHANNEL_1 10001
#define HSND_CHANNEL_2 10002
#define HSND_CHANNEL_3 10003
#define HSND_CHANNEL_4 10004
#define HSND_CHANNEL_5 10005
#define HSND_CHANNEL_6 10006
#define HSND_CHANNEL_7 10007
#define HSND_MAX_SOUND_VARS 26
#define HSND_DEFAULT_FREQUENCY 11025
#define HSND_BASE_FREQ_FACTOR 1024
#define HSND_SOUND_FREQ_BASE 1024
#define HSND_MAX_VOLUME 255
#define HSND_SOUND_PAN_LEFT 0
#define HSND_SOUND_PAN_CENTER 64
#define HSND_SOUND_PAN_RIGHT 127
#define HSND_FIRST_SPOOLING_SOUND 4000
#define HSND_MAX_FREQ_RATIO 4
#define HSND_MAX_SPOOLING_CODE_SIZE 16384
#define HSND_SBNG_TYPE_ALL 0xF8
#define HSND_SBNG_DATA_ALL 0x07
#define HSND_SBNG_MAGIC_NUMBER 0x2000
#define HSND_SBNG_MAGIC_MASK 0xF000
#define HSND_SBNG_END 0x00
#define HSND_SBNG_FACE 0x10
#define HSND_SBNG_SET_SET 0x20
#define HSND_SBNG_SET_ADD 0x30
#define HSND_SBNG_SET_SUB 0x38
#define HSND_SBNG_SET_MUL 0x40
#define HSND_SBNG_SET_DIV 0x50
#define HSND_SBNG_SET_INC 0x60
#define HSND_SBNG_SET_DEC 0x68
#define HSND_SBNG_VARORVAL 0x03
#define HSND_SBNG_VARVAL 0x02
#define HSND_SNDVAR_TOKENS 26
#define XSH2_FLAG_HAS_PRIORITY 0x01
#define WAVE_FORMAT_PCM 1
#define WAVE_FORMAT_IMA_ADPCM 17
#define WAVE_RIFF_HEADER_LEN 44
#define HSND_RES_OFFSET_ID1 0 // uint32, DIGI or MIDI header
#define HSND_RES_OFFSET_LEN1 4 // uint32
#define HSND_RES_OFFSET_ID 8 // uint32, HSHD header
#define HSND_RES_OFFSET_LEN2 12 // uint32
#define HSND_RES_OFFSET_COMPRESSED 16 // uint8, header data
#define HSND_RES_OFFSET_FORMATTED 17 // uint8
#define HSND_RES_OFFSET_KILL_PRIO 18 // uint8
#define HSND_RES_OFFSET_DEAD_PRIO 19 // uint8
#define HSND_RES_OFFSET_LEFT_VOLUME 20 // uint8
#define HSND_RES_OFFSET_RIGHT_VOLUME 21 // uint8
#define HSND_RES_OFFSET_FREQUENCY 22 // uint16
#define HSND_RES_OFFSET_MONDO_OFFSET 24 // uint32
#define HSND_RES_OFFSET_BITS_PER_SAMPLE 28 // uint8
#define HSND_RES_OFFSET_SAMPLE_CHANNELS 29 // uint8
#define HSND_RES_OFFSET_UNUSED3 30 // uint8
#define HSND_RES_OFFSET_UNUSED4 31 // uint8
#define HSND_RES_OFFSET_ID3 32 // uint32, SDAT header
#define HSND_RES_OFFSET_LEN3 36 // uint32
#define HSND_RES_OFFSET_SOUND_DATA 40
// Used both in SoundHE and HEMixer
struct HESoundModifiers {
HESoundModifiers(int mFrequencyShift, int mPan, int mVolume) {
// Hey, turns out Moonbase Commander just LOVES sending out invalid modifiers :-)
/*
assert(mFrequencyShift >= HSND_SOUND_FREQ_BASE / HSND_MAX_FREQ_RATIO);
assert(mFrequencyShift <= HSND_SOUND_FREQ_BASE * HSND_MAX_FREQ_RATIO);
assert(mPan >= HSND_SOUND_PAN_LEFT && mPan <= HSND_SOUND_PAN_RIGHT);
assert(mVolume >= 0 && mVolume <= HSND_MAX_VOLUME);
*/
frequencyShift = mFrequencyShift;
pan = mPan;
volume = mVolume;
}
HESoundModifiers() {
frequencyShift = HSND_SOUND_FREQ_BASE;
pan = HSND_SOUND_PAN_CENTER;
volume = HSND_MAX_VOLUME;
}
int frequencyShift;
int pan;
int volume;
};
struct HESpoolingMusicItem {
int32 song;
int32 offset;
int32 size;
char filename[128];
};
class ScummEngine_v60he;
class HEMixer;
class SoundHE : public Sound {
friend class HEMixer;
protected:
ScummEngine_v60he *_vm;
int _overrideFreq;
Common::Mutex *_mutex;
HEMixer *_heMixer;
struct HESoundCallbackItem {
int32 sound;
int32 channel;
int32 whatFrame;
};
HESoundCallbackItem _soundCallbackScripts[HSND_MAX_CALLBACK_SCRIPTS];
HESpoolingMusicItem *_heSpoolingMusicTable;
struct PCMWaveFormat {
uint16 wFormatTag;
uint16 wChannels;
uint32 dwSamplesPerSec;
uint32 dwAvgBytesPerSec;
uint16 wBlockAlign;
uint16 wBitsPerSample;
};
int32 _heSpoolingMusicCount;
Common::File _heSpoolingMusicFile;
byte _heSpoolingCodeBuffer[HSND_MAX_SPOOLING_CODE_SIZE];
public: // Used by createSound()
struct {
int sound;
int codeOffset;
byte *codeBuffer;
int priority;
int frequency;
int timeout;
bool hasSoundTokens;
int soundVars[HSND_MAX_SOUND_VARS];
int age;
void clearChannel() {
sound = 0;
codeOffset = 0;
codeBuffer = nullptr;
priority = 0;
frequency = 0;
timeout = 0;
hasSoundTokens = false;
memset(soundVars, 0, sizeof(soundVars));
age = 0;
}
} _heChannel[HSND_MAX_CHANNELS];
// Used throughout script functions
int32 _createSndId;
int32 _createSndLastAppend;
int32 _createSndLastPos;
int32 _baseSndSize;
public:
SoundHE(ScummEngine *parent, Audio::Mixer *mixer, Common::Mutex *mutex);
~SoundHE() override;
void startSound(int sound, int heOffset = 0, int heChannel = 0, int heFlags = 0, int heFreq = 0, int hePan = 0, int heVol = 0) override;
void addSoundToQueue(int sound, int heOffset = 0, int heChannel = 0, int heFlags = 0, int heFreq = 0, int hePan = 0, int heVol = 0) override;
void modifySound(int sound, int offset, int frequencyShift, int pan, int volume, int flags) override;
int isSoundRunning(int sound) const override;
bool isSoundInUse(int sound) const override;
void stopSound(int sound) override;
void stopAllSounds() override;
int hsFindSoundChannel(int sound) const;
void setupSound() override;
void pauseSounds(bool pause) override;
bool getHEMusicDetails(int id, int &musicOffs, int &musicSize);
int getNextDynamicChannel();
bool isSoundCodeUsed(int sound);
int getSoundPosition(int sound);
int getSoundVar(int sound, int var);
void setSoundVar(int sound, int var, int val);
void setSoundVolume(int sound, int volume);
void triggerSound(int soundId, int heOffset, int heChannel, int heFlags, HESoundModifiers modifiers);
void triggerSpoolingSound(int soundId, int heOffset, int heChannel, int heFlags, HESoundModifiers modifiers);
void triggerDigitalSound(int soundId, int heOffset, int heChannel, int heFlags);
void triggerMidiSound(int soundId, int heOffset);
void triggerRIFFSound(int soundId, int heOffset, int heChannel, int heFlags, HESoundModifiers modifiers);
void triggerXSOUSound(int soundId, int heOffset, int heChannel, int heFlags);
void hsStartDigitalSound(int sound, int offset, byte *addr, int sound_data, int globType, int globNum,
int sampleCount, int frequency, int channel, int priority, int soundCode,
int flags, int bitsPerSample, int soundChannelCount, HESoundModifiers modifiers);
void hsStopDigitalSound(int sound);
void handleSoundFrame();
void feedMixer();
void unqueueSoundCallbackScripts();
void checkSoundTimeouts();
void digitalSoundCallback(int message, int channel, bool earlyCallback = false);
void queueSoundCallbackScript(int sound, int channel, int message);
void runSoundCode();
void processSoundOpcodes(int sound, byte *codePtr, int *soundVars);
void setOverrideFreq(int freq);
void setupHEMusicFile();
void playVoice(uint32 offset, uint32 length);
void playVoiceFile(char *filename);
void stopDigitalSound(int sound);
void createSound(int snd1id, int snd2id);
int getChannelPosition(int channel);
const byte *findWavBlock(uint32 tag, const byte *block);
int getCurrentSpeechOffset();
bool is3DOSound(int sound) const;
protected:
void processSoundQueues() override;
private:
int _heTalkOffset = 0;
bool _stopActorTalkingFlag = false;
bool _inSoundCallbackFlag = false;
int _soundCallbacksQueueSize = 0;
int _soundAlreadyInQueueCount = 0;
int _inUnqueueCallbackScripts = 0;
int _soundsDebugFrameCounter = 0;
int _dynamicSoundAgeCounter = 0;
};
} // End of namespace Scumm
#endif