255 lines
7.0 KiB
C++
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
|