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

255 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/>.
*
*/
//=============================================================================
//
// ACSOUND - AGS sound system wrapper
//
//=============================================================================
#ifndef AGS_ENGINE_MEDIA_AUDIO_SOUNDCLIP_H
#define AGS_ENGINE_MEDIA_AUDIO_SOUNDCLIP_H
#include "audio/mixer.h"
#include "audio/audiostream.h"
#include "common/stream.h"
namespace AGS3 {
// SOUNDCLIP's state and parameter updates sync with the audio core in
// batches, only when the engine updates the game, never while the user script
// is being executed. The sync is performed by calling update().
// This is to ensure that the clip reference, state and properties don't change
// in the middle of the script's command sequence.
// TODO: one of the biggest problems with sound clips currently is that it
// provides several methods of applying volume, which may ignore or override
// each other, and does not shape a consistent interface.
// Improving this situation is only possible with massive refactory of
// sound clip use, taking backwards-compatible audio system in account.
enum SoundClipState {
SoundClipInitial, SoundClipPlaying, SoundClipPaused, SoundClipStopped
};
struct SOUNDCLIP {
SOUNDCLIP();
virtual ~SOUNDCLIP() {}
// TODO: move these to private
int _sourceClipID;
int _sourceClipType;
bool _repeat;
int _priority;
int _xSource, _ySource; // Used for positioning sounds in game rooms
int _maximumPossibleDistanceAway;
int _vol255;
int _vol100;
int _volModifier;
int _panning;
int _panningAsPercentage;
int _directionalVolModifier;
virtual int play() = 0;
virtual void pause() = 0;
virtual void resume() = 0;
/**
* Seeks to the position, where pos units depend on the audio type:
* - MIDI - the beat number
* - MOD / XM / S3M - the pattern number
* - WAV / VOC - the sample number
* - OGG / MP3 - milliseconds
*/
virtual void seek(int offset) = 0;
/**
* Seeks to the position in milliseconds
*/
virtual void seek_ms(int pos_ms) = 0;
virtual int play_from(int position) = 0;
virtual bool is_playing() = 0; // true if playing or paused. false if never played or stopped.
virtual bool is_paused() = 0; // true if paused
/**
* Get legacy sound format type
*/
virtual int get_sound_type() const = 0;
/**
* Return current position in frames
*/
virtual int get_pos() = 0;
/**
* Return the position in milliseconds
*/
virtual int get_pos_ms() = 0;
/**
* Return total track length in ms (or 0)
*/
virtual int get_length_ms() = 0;
virtual void set_panning(int newPanning) = 0;
virtual void set_speed(int new_speed) = 0;
virtual void poll() = 0;
/**
* Gets clip's volume property, as percentage (0 - 100);
* note this may not be the real volume of playback (which could e.g. be muted)
*/
inline int get_volume100() const { return _vol100; }
/**
* Gets clip's volume measured in 255 units
*/
inline int get_volume255() const { return _vol255; }
/**
* Gets clip's panning (-100 - +100)
*/
inline int get_panning() const { return _panning; }
/**
* Gets clip's playback speed in clip ms per real second
*/
inline int get_speed() const { return _speed; }
/**
* Gets if clip is muted (without changing the volume setting)
*/
inline bool is_muted() const { return _muted; }
/**
* Sets the current volume property, as percentage (0 - 100)
*/
void set_volume100(int volume);
/**
* Sets the current volume property, as a level (0 - 255)
*/
void set_volume255(int volume);
/**
* Explicitly defines both percentage and absolute volume value,
* without calculating it from given percentage.
* NOTE: this overrides the mute
*/
void set_volume_direct(int vol_percent, int vol_absolute);
/**
* Mutes sound clip, while preserving current volume property
* for the future reference; when unmuted, that property is
* used to restart previous volume.
*/
void set_mute(bool mute);
/**
* Apply arbitrary permanent volume modifier, in absolute units (0 - 255);
* this is distinct value that is used in conjunction with current volume
* (can be both positive and negative).
*/
void apply_volume_modifier(int mod);
/**
* Apply permanent directional volume modifier, in absolute units (0 - 255)
* this is distinct value that is used in conjunction with current volume
* (can be both positive and negative).
*/
void apply_directional_modifier(int mod);
inline bool is_ready() { return is_playing(); }
/**
* Returns if the clip is still playing, otherwise it's finished
*/
bool update();
protected:
virtual void adjust_volume() = 0;
// mute mode overrides the volume; if set, any volume assigned is stored
// in properties, but not applied to playback itself
bool _muted = false;
// speed of playback, in clip ms per real second
int _speed = 0;
bool _paramsChanged = false;
// helper function for calculating volume with applied modifiers
inline int get_final_volume() const {
int final_vol = _vol255 + _volModifier + _directionalVolModifier;
return final_vol >= 0 ? final_vol : 0;
}
};
struct SoundClipWaveBase : public SOUNDCLIP {
private:
Audio::Mixer::SoundType _soundType = Audio::Mixer::kPlainSoundType;
int pos_to_posms(int pos) const;
public:
Audio::Mixer *_mixer;
Audio::AudioStream *_stream;
Audio::SoundHandle _soundHandle;
SoundClipState _state;
bool _waitingToPlay = false;
SoundClipWaveBase(Audio::AudioStream *stream, bool repeat = false);
~SoundClipWaveBase() override;
void setType(Audio::Mixer::SoundType type);
void poll() override;
int play() override;
int play_from(int position) override;
void pause() override;
void resume() override;
bool is_playing() override;
bool is_paused() override;
void seek(int offset) override;
void seek_ms(int pos_ms) override;
int get_pos() override;
int get_pos_ms() override;
int get_length_ms() override;
void set_panning(int newPanning) override;
void set_speed(int new_speed) override;
void adjust_volume() override;
};
template<int SOUND_TYPE>
struct SoundClipWave : public SoundClipWaveBase {
SoundClipWave(Audio::AudioStream *stream, bool repeat = false) :
SoundClipWaveBase(stream, repeat) {}
int get_sound_type() const {
return SOUND_TYPE;
}
};
} // namespace AGS3
#endif