Files
2026-02-02 04:50:13 +01:00

224 lines
7.0 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/>.
*
* This file is dual-licensed.
* In addition to the GPLv3 license mentioned above, this code is also
* licensed under LGPL 2.1. See LICENSES/COPYING.LGPL file for the
* full text of the license.
*
*/
#ifndef SCUMM_HE_MIXER_HE_H
#define SCUMM_HE_MIXER_HE_H
#include "scumm/he/sound_he.h"
#include "scumm/he/intern_he.h"
#include "scumm/resource.h"
#include "common/util.h"
#include "common/file.h"
#include "common/debug.h"
#include "common/memstream.h"
#include "audio/decoders/adpcm.h"
#include "audio/audiostream.h"
#include "audio/decoders/raw.h"
#include "audio/decoders/wave.h"
#include "audio/decoders/mp3.h"
#include "audio/decoders/vorbis.h"
#include "audio/decoders/flac.h"
namespace Scumm {
#define CHANNEL_EMPTY_FLAGS (0 << 0)
#define CHANNEL_ACTIVE (1 << 0)
#define CHANNEL_FINISHED (1 << 1)
#define CHANNEL_LOOPING (1 << 2)
#define CHANNEL_LAST_CHUNK (1 << 3)
#define CHANNEL_SPOOLING (1 << 4)
#define CHANNEL_CALLBACK_EARLY (1 << 7)
#define CHANNEL_SOFT_REMIX (1 << 8)
#define MIXER_MAX_CHANNELS 8
#define MIXER_PCM_CHUNK_SIZE 4096
#define MIXER_MAX_QUEUED_STREAMS 8
#define MIXER_DEFAULT_SAMPLE_RATE 11025
#define MIXER_SPOOL_CHUNK_SIZE (8 * 1024)
#define MILES_MAX_CHANNELS 8
#define MILES_PCM_CHUNK_SIZE 4096u
#define MILES_IMA_ADPCM_PER_FRAME_CHUNKS_NUM 4u
#define MILES_MAX_QUEUED_STREAMS 16
struct HESoundModifiers;
struct HESpoolingMusicItem;
class ScummEngine_v60he;
struct MilesModifiers {
int frequencyShift;
int pan;
int volume;
};
class HEMilesChannel {
protected:
struct MilesStream {
Audio::QueuingAudioStream *streamObj = nullptr;
Audio::SoundHandle streamHandle;
bool loopFlag = false;
Common::File *fileHandle = nullptr;
uint32 dataLength = 0;
uint32 curDataPos = 0;
uint32 dataOffset = 0;
};
public:
MilesModifiers _modifiers;
MilesStream _stream;
int _baseFrequency;
Audio::SoundHandle _audioHandle;
bool _audioHandleActive = false;
uint32 _lastPlayPosition;
uint32 _playFlags;
int _dataOffset;
int _globType;
int _globNum;
uint16 _blockAlign = 0;
uint16 _numChannels = 1;
uint16 _bitsPerSample = 8;
uint16 _dataFormat = 1;
bool _isUsingStreamOverride = false;
HEMilesChannel() {
clearChannelData();
}
~HEMilesChannel() {
clearChannelData();
}
void startSpoolingChannel(const char *filename, long offset, int flags, HESoundModifiers modifiers, Audio::Mixer *mixer);
void clearChannelData();
void closeFileHandle();
void serviceStream();
byte getOutputFlags();
};
class HEMixer {
protected:
ScummEngine *_vm;
Audio::Mixer *_mixer;
bool _useMilesSoundSystem = false;
bool _mixerPaused = false;
int _pauseCount = 0;
Common::HashMap<int32, int32> _offsetsToSongId;
HEMilesChannel _milesChannels[MILES_MAX_CHANNELS];
struct HEMixerChannel {
Audio::SoundHandle handle;
Audio::QueuingAudioStream *stream = nullptr;
Common::File *fileHandle = nullptr;
int number = 0;
int volume = 0;
int frequency = 0;
int globType = 0;
int globNum = 0;
int callbackID = 0;
int endSampleAdjustment = 0;
uint32 lastReadPosition = 0;
uint32 initialSpoolingFileOffset = 0;
uint32 sampleLen = 0;
uint32 dataOffset = 0;
uint32 flags = 0;
bool callbackOnNextFrame = false;
bool isUsingStreamOverride = false;
byte *residualData = nullptr; // For early callbacks
};
HEMixerChannel _mixerChannels[MIXER_MAX_CHANNELS];
public:
HEMixer(Audio::Mixer *mixer, ScummEngine_v60he *vm, bool useMiles);
~HEMixer();
bool initSoftMixerSubSystem();
void deinitSoftMixerSubSystem();
bool stopChannel(int channel);
void stopAllChannels();
bool pauseMixerSubSystem(bool paused);
void feedMixer();
bool changeChannelVolume(int channel, int volume, bool soft);
bool startChannelNew(
int channel, int globType, int globNum, uint32 soundData, uint32 offset,
int sampleLen, int frequency, int bitsPerSample, int sampleChannels,
const HESoundModifiers &modifiers, int callbackId, int32 flags, ...);
bool startChannel(
int channel, int globType, int globNum, uint32 sampleDataOffset,
int sampleLen, int frequency, int volume, int callbackId, int32 flags, ...);
bool startSpoolingChannel(
int channel, int song, Common::File &spoolingFile, int sampleLen, int frequency,
int volume, int callbackID, int32 flags);
bool audioOverrideExists(int globNum, bool justGetInfo,
int *duration = nullptr, Audio::SeekableAudioStream **outStream = nullptr);
void setSpoolingSongsTable(HESpoolingMusicItem *heSpoolingMusicTable, int32 tableSize);
int32 matchOffsetToSongId(int32 offset);
/* --- MILES MIXER CODE --- */
bool isMilesActive();
void milesStartSpoolingChannel(int channel, const char *filename, long offset, int flags, HESoundModifiers modifiers);
bool milesStartChannel(
int channel, int globType, int globNum, uint32 sound_data, uint32 offset,
int sampleLen, int bitsPerSample, int sampleChannels,
int frequency, HESoundModifiers modifiers, int callbackID, uint32 flags, ...);
bool milesStopChannel(int channel);
void milesStopAllSounds();
void milesModifySound(int channel, int offset, HESoundModifiers modifiers, int flags);
void milesStopAndCallback(int channel, int messageId);
void milesFeedMixer();
void milesServiceAllStreams();
bool milesPauseMixerSubSystem(bool paused);
byte *milesGetAudioDataFromResource(int globType, int globNum, uint32 dataOffset, uint16 &compType, uint16 &blockAlign, uint32 &dataSize);
/* --- SOFTWARE MIXER CODE --- */
bool mixerInitMyMixerSubSystem();
void mixerFeedMixer();
bool mixerIsMixerDisabled();
bool mixerStopChannel(int channel);
bool mixerStopAllSounds();
bool mixerChangeChannelVolume(int channel, int volume, bool soft);
bool mixerPauseMixerSubSystem(bool paused);
bool mixerStartChannel(
int channel, int globType, int globNum, uint32 sampleDataOffset,
int sampleLen, int frequency, int volume, int callbackID, uint32 flags, ...);
bool mixerStartSpoolingChannel(
int channel, int song, Common::File &sampleFileIOHandle, int sampleLen, int frequency,
int volume, int callbackID, uint32 flags);
byte mixerGetOutputFlags(bool is3DOMusic = false);
};
} // End of namespace Scumm
#endif