Initial commit
This commit is contained in:
55
engines/ags/engine/media/audio/ambient_sound.cpp
Normal file
55
engines/ags/engine/media/audio/ambient_sound.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ags/engine/media/audio/ambient_sound.h"
|
||||
#include "ags/engine/media/audio/audio.h"
|
||||
#include "ags/engine/media/audio/sound_clip.h"
|
||||
#include "ags/shared/util/stream.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
using AGS::Shared::Stream;
|
||||
|
||||
bool AmbientSound::IsPlaying() {
|
||||
if (channel <= 0)
|
||||
return false;
|
||||
return AudioChans::ChannelIsPlaying(channel);
|
||||
}
|
||||
|
||||
void AmbientSound::ReadFromFile(Stream *in) {
|
||||
channel = in->ReadInt32();
|
||||
x = in->ReadInt32();
|
||||
y = in->ReadInt32();
|
||||
vol = in->ReadInt32();
|
||||
num = in->ReadInt32();
|
||||
maxdist = in->ReadInt32();
|
||||
}
|
||||
|
||||
void AmbientSound::WriteToFile(Stream *out) {
|
||||
out->WriteInt32(channel);
|
||||
out->WriteInt32(x);
|
||||
out->WriteInt32(y);
|
||||
out->WriteInt32(vol);
|
||||
out->WriteInt32(num);
|
||||
out->WriteInt32(maxdist);
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
53
engines/ags/engine/media/audio/ambient_sound.h
Normal file
53
engines/ags/engine/media/audio/ambient_sound.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/* 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 AGS_ENGINE_MEDIA_AUDIO_AMBIENTSOUND_H
|
||||
#define AGS_ENGINE_MEDIA_AUDIO_AMBIENTSOUND_H
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
// Forward declaration
|
||||
namespace AGS {
|
||||
namespace Shared {
|
||||
class Stream;
|
||||
} // namespace Shared
|
||||
} // namespace AGS
|
||||
|
||||
using namespace AGS; // FIXME later
|
||||
|
||||
#define AMBIENCE_FULL_DIST 25
|
||||
|
||||
struct AmbientSound {
|
||||
int channel; // channel number, 1 upwards
|
||||
int x, y;
|
||||
int vol;
|
||||
int num; // sound number, eg. 3 = sound3.wav
|
||||
int maxdist;
|
||||
|
||||
bool IsPlaying();
|
||||
|
||||
void ReadFromFile(Shared::Stream *in);
|
||||
void WriteToFile(Shared::Stream *out);
|
||||
};
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
1061
engines/ags/engine/media/audio/audio.cpp
Normal file
1061
engines/ags/engine/media/audio/audio.cpp
Normal file
File diff suppressed because it is too large
Load Diff
125
engines/ags/engine/media/audio/audio.h
Normal file
125
engines/ags/engine/media/audio/audio.h
Normal file
@@ -0,0 +1,125 @@
|
||||
/* 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 AGS_ENGINE_MEDIA_AUDIO_AUDIO_H
|
||||
#define AGS_ENGINE_MEDIA_AUDIO_AUDIO_H
|
||||
|
||||
#include "common/std/array.h"
|
||||
#include "ags/engine/media/audio/audio_defines.h"
|
||||
#include "ags/shared/ac/dynobj/script_audio_clip.h"
|
||||
#include "ags/engine/ac/dynobj/script_audio_channel.h"
|
||||
#include "ags/engine/media/audio/ambient_sound.h"
|
||||
#include "ags/engine/ac/timer.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
struct SOUNDCLIP;
|
||||
|
||||
class AudioChans {
|
||||
public:
|
||||
// Gets a clip from the channel
|
||||
static SOUNDCLIP *GetChannel(int index);
|
||||
// Gets a clip from the channel but only if it's in playback state
|
||||
static SOUNDCLIP *GetChannelIfPlaying(int index);
|
||||
// Assign new clip to the channel
|
||||
static SOUNDCLIP *SetChannel(int index, SOUNDCLIP *clip);
|
||||
// Move clip from one channel to another, clearing the first channel
|
||||
static SOUNDCLIP *MoveChannel(int to, int from);
|
||||
|
||||
// Tells if channel has got a clip; does not care about its state
|
||||
static inline bool ChannelHasClip(int index) {
|
||||
return GetChannel(index) != nullptr;
|
||||
}
|
||||
// Tells if channel has got a clip and clip is in playback state
|
||||
static inline bool ChannelIsPlaying(int index) {
|
||||
return GetChannelIfPlaying(index) != nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
AudioChans() = delete;
|
||||
~AudioChans() = delete;
|
||||
};
|
||||
|
||||
void calculate_reserved_channel_count();
|
||||
void update_clip_default_volume(ScriptAudioClip *audioClip);
|
||||
void start_fading_in_new_track_if_applicable(int fadeInChannel, ScriptAudioClip *newSound);
|
||||
void stop_or_fade_out_channel(int fadeOutChannel, int fadeInChannel = -1, ScriptAudioClip *newSound = nullptr);
|
||||
SOUNDCLIP *load_sound_clip(ScriptAudioClip *audioClip, bool repeat);
|
||||
ScriptAudioChannel *play_audio_clip_on_channel(int channel, ScriptAudioClip *clip, int priority, int repeat, int fromOffset, SOUNDCLIP *cachedClip = nullptr);
|
||||
void remove_clips_of_type_from_queue(int audioType);
|
||||
void update_queued_clips_volume(int audioType, int new_vol);
|
||||
// Checks if speech voice-over is currently playing, and reapply volume drop to all other active clips
|
||||
void update_volume_drop_if_voiceover();
|
||||
ScriptAudioChannel *play_audio_clip(ScriptAudioClip *clip, int priority, int repeat, int fromOffset, bool queueIfNoChannel);
|
||||
ScriptAudioChannel *play_audio_clip_by_index(int audioClipIndex);
|
||||
void stop_and_destroy_channel_ex(int chid, bool resetLegacyMusicSettings);
|
||||
void stop_and_destroy_channel(int chid);
|
||||
// Exports missing AudioChannel objects to script (for importing older saves)
|
||||
void export_missing_audiochans();
|
||||
|
||||
// ***** BACKWARDS COMPATIBILITY WITH OLD AUDIO SYSTEM ***** //
|
||||
int get_old_style_number_for_sound(int sound_number);
|
||||
SOUNDCLIP *load_sound_clip_from_old_style_number(bool isMusic, int indexNumber, bool repeat);
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int get_volume_adjusted_for_distance(int volume, int sndX, int sndY, int sndMaxDist);
|
||||
void update_directional_sound_vol();
|
||||
void update_ambient_sound_vol();
|
||||
// Tells if the audio type is allowed to play with regards to current sound config
|
||||
bool is_audiotype_allowed_to_play(AudioFileType type);
|
||||
// Loads sound data referenced by audio clip item, and starts playback;
|
||||
// returns NULL on failure
|
||||
SOUNDCLIP *load_sound_and_play(ScriptAudioClip *aclip, bool repeat);
|
||||
void stop_all_sound_and_music();
|
||||
void shutdown_sound();
|
||||
int play_sound(int val1);
|
||||
|
||||
//=============================================================================
|
||||
|
||||
void clear_music_cache();
|
||||
void play_next_queued();
|
||||
int calculate_max_volume();
|
||||
// add/remove the volume drop to the audio channels while speech is playing
|
||||
void apply_volume_drop_modifier(bool applyModifier);
|
||||
// syncs logical audio channels with the audio backend state
|
||||
void sync_audio_playback();
|
||||
// Update the music, and advance the crossfade on a step
|
||||
// (this should only be called once per game loop);
|
||||
void update_audio_system_on_game_loop();
|
||||
void stopmusic();
|
||||
void update_music_volume();
|
||||
void post_new_music_check();
|
||||
// Sets up the crossfading for playing the new music track,
|
||||
// and returns the channel number to use; the channel is guaranteed to be free
|
||||
int prepare_for_new_music();
|
||||
// Gets audio clip from legacy music number, which also may contain queue flag
|
||||
ScriptAudioClip *get_audio_clip_for_music(int mnum);
|
||||
SOUNDCLIP *load_music_from_disk(int mnum, bool doRepeat);
|
||||
void newmusic(int mnum);
|
||||
|
||||
extern void cancel_scheduled_music_update();
|
||||
extern void schedule_music_update_at(AGS_Clock::time_point);
|
||||
extern void postpone_scheduled_music_update_by(std::chrono::milliseconds);
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
51
engines/ags/engine/media/audio/audio_defines.h
Normal file
51
engines/ags/engine/media/audio/audio_defines.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/* 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 AGS_ENGINE_MEDIA_AUDIO_AUDIODEFINES_H
|
||||
#define AGS_ENGINE_MEDIA_AUDIO_AUDIODEFINES_H
|
||||
|
||||
#define MUS_MIDI 1
|
||||
#define MUS_MP3 2
|
||||
#define MUS_WAVE 3
|
||||
#define MUS_MOD 4
|
||||
#define MUS_OGG 5
|
||||
|
||||
// Max channels that are distributed among game's audio types
|
||||
#define MAX_GAME_CHANNELS 16
|
||||
#define MAX_SOUND_CHANNELS 8
|
||||
#define SPECIAL_CROSSFADE_CHANNEL (MAX_GAME_CHANNELS)
|
||||
// Total number of channels: game chans + utility chans
|
||||
#define TOTAL_AUDIO_CHANNELS (MAX_GAME_CHANNELS + 1)
|
||||
// Number of game channels reserved for speech voice-over
|
||||
#define NUM_SPEECH_CHANS 1
|
||||
// Legacy channel numbers
|
||||
#define MAX_GAME_CHANNELS_v320 8
|
||||
#define TOTAL_AUDIO_CHANNELS_v320 (MAX_GAME_CHANNELS_v320 + 1)
|
||||
|
||||
#define SCHAN_SPEECH 0
|
||||
#define SCHAN_AMBIENT 1
|
||||
#define SCHAN_MUSIC 2
|
||||
#define SCHAN_NORMAL 3
|
||||
#define AUDIOTYPE_LEGACY_AMBIENT_SOUND 1
|
||||
#define AUDIOTYPE_LEGACY_MUSIC 2
|
||||
#define AUDIOTYPE_LEGACY_SOUND 3
|
||||
|
||||
#endif
|
||||
35
engines/ags/engine/media/audio/audio_system.h
Normal file
35
engines/ags/engine/media/audio/audio_system.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/* 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 AGS_ENGINE_MEDIA_AUDIO_AUDIO_SYSTEM_H
|
||||
#define AGS_ENGINE_MEDIA_AUDIO_AUDIO_SYSTEM_H
|
||||
|
||||
#include "ags/engine/media/audio/audio_defines.h"
|
||||
#include "ags/engine/media/audio/ambient_sound.h"
|
||||
|
||||
#include "ags/engine/media/audio/audio.h"
|
||||
|
||||
#include "ags/engine/media/audio/sound_clip.h"
|
||||
#include "ags/engine/media/audio/sound.h"
|
||||
|
||||
#include "ags/engine/media/audio/queued_audio_item.h"
|
||||
|
||||
#endif
|
||||
124
engines/ags/engine/media/audio/clip_my_midi.cpp
Normal file
124
engines/ags/engine/media/audio/clip_my_midi.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ags/shared/util/wgt2_allg.h"
|
||||
#include "ags/engine/media/audio/clip_my_midi.h"
|
||||
#include "ags/ags.h"
|
||||
#include "ags/music.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
MYMIDI::MYMIDI(Common::SeekableReadStream *data, bool repeat) :
|
||||
_state(SoundClipInitial), _data(data), lengthInSeconds(0) {
|
||||
_mixer = ::AGS::g_vm->_mixer;
|
||||
_repeat = repeat;
|
||||
}
|
||||
|
||||
MYMIDI::~MYMIDI() {
|
||||
::AGS::g_music->stop();
|
||||
delete _data;
|
||||
_data = nullptr;
|
||||
}
|
||||
|
||||
void MYMIDI::poll() {
|
||||
bool playing = is_playing();
|
||||
if (playing)
|
||||
_state = SoundClipPlaying;
|
||||
else if (_state == SoundClipPlaying)
|
||||
_state = SoundClipStopped;
|
||||
}
|
||||
|
||||
void MYMIDI::seek(int pos) {
|
||||
// pos is the beat number
|
||||
warning("TODO: MYMIDI::seek");
|
||||
}
|
||||
|
||||
void MYMIDI::seek_ms(int pos_ms) {
|
||||
warning("TODO: MYMIDI::seek_ms");
|
||||
}
|
||||
|
||||
int MYMIDI::get_pos() {
|
||||
// We don't know ms with midi
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MYMIDI::get_pos_ms() {
|
||||
// We don't know ms with midi
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MYMIDI::get_length_ms() {
|
||||
warning("TODO: MYMIDI::get_length_ms");
|
||||
return lengthInSeconds * 1000;
|
||||
}
|
||||
|
||||
void MYMIDI::pause() {
|
||||
::AGS::g_music->pause();
|
||||
_state = SoundClipPaused;
|
||||
}
|
||||
|
||||
void MYMIDI::resume() {
|
||||
if (_state != SoundClipPaused)
|
||||
return;
|
||||
|
||||
::AGS::g_music->resume();
|
||||
_state = SoundClipPlaying;
|
||||
}
|
||||
|
||||
int MYMIDI::play() {
|
||||
::AGS::g_music->playMusic(_data, _repeat);
|
||||
_state = SoundClipPlaying;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int MYMIDI::play_from(int position) {
|
||||
// TODO: Implement playing from arbitrary positions
|
||||
if (position == 0) {
|
||||
play();
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool MYMIDI::is_playing() {
|
||||
return ::AGS::g_music->isPlaying();
|
||||
}
|
||||
|
||||
bool MYMIDI::is_paused() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void MYMIDI::set_panning(int newPanning) {
|
||||
// No implementation for MIDI
|
||||
}
|
||||
|
||||
void MYMIDI::set_speed(int new_speed) {
|
||||
if (new_speed != 1000) // default
|
||||
warning("TODO: MYMIDI::set_speed=%d", new_speed);
|
||||
_speed = new_speed;
|
||||
}
|
||||
|
||||
void MYMIDI::adjust_volume() {
|
||||
_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, _vol255);
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
70
engines/ags/engine/media/audio/clip_my_midi.h
Normal file
70
engines/ags/engine/media/audio/clip_my_midi.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/* 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 AGS_ENGINE_MEDIA_AUDIO_CLIP_MYMIDI_H
|
||||
#define AGS_ENGINE_MEDIA_AUDIO_CLIP_MYMIDI_H
|
||||
|
||||
#include "ags/engine/media/audio/sound_clip.h"
|
||||
#include "ags/engine/media/audio/audio_defines.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
// MIDI
|
||||
struct MYMIDI : public SOUNDCLIP {
|
||||
Audio::Mixer *_mixer;
|
||||
Common::SeekableReadStream *_data;
|
||||
int lengthInSeconds;
|
||||
SoundClipState _state;
|
||||
|
||||
MYMIDI(Common::SeekableReadStream *data, bool repeat);
|
||||
~MYMIDI() override;
|
||||
|
||||
void poll() override;
|
||||
|
||||
void seek(int pos) override;
|
||||
void seek_ms(int pos_ms) override;
|
||||
|
||||
int get_pos() override;
|
||||
|
||||
int get_pos_ms() override;
|
||||
|
||||
int get_length_ms() override;
|
||||
|
||||
void pause() override;
|
||||
|
||||
void resume() override;
|
||||
|
||||
int get_sound_type() const override {
|
||||
return MUS_MIDI;
|
||||
}
|
||||
|
||||
int play() override;
|
||||
int play_from(int position) override;
|
||||
bool is_playing() override;
|
||||
bool is_paused() override;
|
||||
void set_panning(int newPanning) override;
|
||||
void set_speed(int new_speed) override;
|
||||
void adjust_volume() override;
|
||||
};
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
52
engines/ags/engine/media/audio/queued_audio_item.cpp
Normal file
52
engines/ags/engine/media/audio/queued_audio_item.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ags/engine/media/audio/queued_audio_item.h"
|
||||
#include "ags/shared/ac/common_defines.h"
|
||||
#include "ags/shared/util/stream.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
using AGS::Shared::Stream;
|
||||
|
||||
void QueuedAudioItem::ReadFromSavegame_v321(Stream *in) {
|
||||
audioClipIndex = in->ReadInt16();
|
||||
priority = in->ReadInt16();
|
||||
repeat = in->ReadBool();
|
||||
in->Seek(3); // alignment padding to int32
|
||||
in->ReadInt32(); // cachedClip 32-bit ptr (legacy format)
|
||||
}
|
||||
|
||||
void QueuedAudioItem::ReadFromSavegame(Stream *in) {
|
||||
audioClipIndex = in->ReadInt16();
|
||||
priority = in->ReadInt16();
|
||||
repeat = in->ReadBool();
|
||||
in->ReadInt32(); // reserved
|
||||
}
|
||||
|
||||
void QueuedAudioItem::WriteToSavegame(Stream *out) const {
|
||||
out->WriteInt16(audioClipIndex);
|
||||
out->WriteInt16(priority);
|
||||
out->WriteBool(repeat);
|
||||
out->WriteInt32(0); // reserved
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
50
engines/ags/engine/media/audio/queued_audio_item.h
Normal file
50
engines/ags/engine/media/audio/queued_audio_item.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/* 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 AGS_ENGINE_MEDIA_AUDIO_QUEUEDAUDIOITEM_H
|
||||
#define AGS_ENGINE_MEDIA_AUDIO_QUEUEDAUDIOITEM_H
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
struct SOUNDCLIP;
|
||||
|
||||
namespace AGS {
|
||||
namespace Shared {
|
||||
class Stream;
|
||||
} // namespace Shared
|
||||
} // namespace AGS
|
||||
|
||||
using namespace AGS; // FIXME later
|
||||
|
||||
struct QueuedAudioItem {
|
||||
short audioClipIndex = 0;
|
||||
short priority = 0;
|
||||
bool repeat = false;
|
||||
SOUNDCLIP *cachedClip = nullptr;
|
||||
|
||||
void ReadFromSavegame_v321(Shared::Stream *in);
|
||||
void ReadFromSavegame(Shared::Stream *in);
|
||||
void WriteToSavegame(Shared::Stream *out) const;
|
||||
};
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
138
engines/ags/engine/media/audio/sound.cpp
Normal file
138
engines/ags/engine/media/audio/sound.cpp
Normal file
@@ -0,0 +1,138 @@
|
||||
/* 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
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "ags/engine/media/audio/audio_defines.h"
|
||||
#include "ags/engine/media/audio/sound.h"
|
||||
#include "ags/engine/media/audio/sound_clip.h"
|
||||
#include "ags/engine/media/audio/clip_my_midi.h"
|
||||
#include "ags/shared/core/asset_manager.h"
|
||||
#include "audio/mods/universaltracker.h"
|
||||
#include "audio/mods/mod_xm_s3m.h"
|
||||
#include "audio/mods/protracker.h"
|
||||
#include "audio/decoders/mp3.h"
|
||||
#include "audio/decoders/vorbis.h"
|
||||
#include "audio/decoders/wave.h"
|
||||
#include "ags/globals.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
SOUNDCLIP *my_load_wave(const AssetPath &asset_name, bool loop) {
|
||||
Common::SeekableReadStream *data = _GP(AssetMgr)->OpenAssetStream(asset_name.Name, asset_name.Filter);
|
||||
if (data) {
|
||||
Audio::AudioStream *audioStream = Audio::makeWAVStream(data, DisposeAfterUse::YES);
|
||||
return new SoundClipWave<MUS_WAVE>(audioStream, loop);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
SOUNDCLIP *my_load_static_mp3(const AssetPath &asset_name, bool loop) {
|
||||
#ifdef USE_MAD
|
||||
Common::SeekableReadStream *data = _GP(AssetMgr)->OpenAssetStream(asset_name.Name, asset_name.Filter);
|
||||
if (data) {
|
||||
Audio::AudioStream *audioStream = Audio::makeMP3Stream(data, DisposeAfterUse::YES);
|
||||
return new SoundClipWave<MUS_MP3>(audioStream, loop);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
SOUNDCLIP *my_load_mp3(const AssetPath &asset_name, bool loop) {
|
||||
return my_load_static_mp3(asset_name, loop);
|
||||
}
|
||||
|
||||
SOUNDCLIP *my_load_static_ogg(const AssetPath &asset_name, bool loop) {
|
||||
#ifdef USE_VORBIS
|
||||
Common::SeekableReadStream *data = _GP(AssetMgr)->OpenAssetStream(asset_name.Name, asset_name.Filter);
|
||||
if (data) {
|
||||
Audio::AudioStream *audioStream = Audio::makeVorbisStream(data, DisposeAfterUse::YES);
|
||||
return new SoundClipWave<MUS_OGG>(audioStream, loop);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
SOUNDCLIP *my_load_ogg(const AssetPath &asset_name, bool loop) {
|
||||
return my_load_static_ogg(asset_name, loop);
|
||||
}
|
||||
|
||||
SOUNDCLIP *my_load_midi(const AssetPath &asset_name, bool loop) {
|
||||
Common::SeekableReadStream *data = _GP(AssetMgr)->OpenAssetStream(asset_name.Name, asset_name.Filter);
|
||||
if (data) {
|
||||
return new MYMIDI(data, loop);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
SOUNDCLIP *my_load_mod(const AssetPath &asset_name, bool loop) {
|
||||
Common::SeekableReadStream *data = _GP(AssetMgr)->OpenAssetStream(asset_name.Name, asset_name.Filter);
|
||||
if (data) {
|
||||
// determine the file extension
|
||||
size_t lastDot = asset_name.Name.FindCharReverse('.');
|
||||
if (lastDot == AGS::Shared::String::NoIndex || lastDot == asset_name.Name.GetLength() - 1) {
|
||||
delete data;
|
||||
return nullptr;
|
||||
}
|
||||
// get the first char of the extension
|
||||
char charAfterDot = toupper(asset_name.Name[lastDot + 1]);
|
||||
|
||||
// use the appropriate loader
|
||||
Audio::AudioStream *audioStream = nullptr;
|
||||
if (charAfterDot == 'I') {
|
||||
// Impulse Tracker
|
||||
audioStream = Audio::makeUniversalTrackerStream(data, DisposeAfterUse::YES);
|
||||
if (!audioStream) {
|
||||
audioStream = Audio::makeSilentAudioStream(22050, true);
|
||||
delete data;
|
||||
}
|
||||
|
||||
} else if (charAfterDot == 'X') {
|
||||
audioStream = Audio::makeModXmS3mStream(data, DisposeAfterUse::YES);
|
||||
} else if (charAfterDot == 'S') {
|
||||
audioStream = Audio::makeModXmS3mStream(data, DisposeAfterUse::YES);
|
||||
} else if (charAfterDot == 'M') {
|
||||
audioStream = Audio::makeModXmS3mStream(data, DisposeAfterUse::YES);
|
||||
} else {
|
||||
warning("MOD file format not recognized");
|
||||
delete data;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return new SoundClipWave<MUS_MOD>(audioStream, loop);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
46
engines/ags/engine/media/audio/sound.h
Normal file
46
engines/ags/engine/media/audio/sound.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// SOUNDCLIP factory methods.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef AGS_ENGINE_MEDIA_AUDIO_SOUND_H
|
||||
#define AGS_ENGINE_MEDIA_AUDIO_SOUND_H
|
||||
|
||||
#include "ags/engine/ac/asset_helper.h"
|
||||
#include "ags/engine/media/audio/sound_clip.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
SOUNDCLIP *my_load_wave(const AssetPath &asset_name, bool loop);
|
||||
SOUNDCLIP *my_load_mp3(const AssetPath &asset_name, bool loop);
|
||||
SOUNDCLIP *my_load_static_mp3(const AssetPath &asset_name, bool loop);
|
||||
SOUNDCLIP *my_load_static_ogg(const AssetPath &asset_name, bool loop);
|
||||
SOUNDCLIP *my_load_ogg(const AssetPath &asset_name, bool doLoop);
|
||||
SOUNDCLIP *my_load_midi(const AssetPath &asset_name, bool loop);
|
||||
SOUNDCLIP *my_load_mod(const AssetPath &asset_name, bool loop);
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
280
engines/ags/engine/media/audio/sound_clip.cpp
Normal file
280
engines/ags/engine/media/audio/sound_clip.cpp
Normal file
@@ -0,0 +1,280 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ags/engine/media/audio/sound_clip.h"
|
||||
#include "ags/engine/media/audio/audio_defines.h"
|
||||
#include "ags/ags.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
SOUNDCLIP::SOUNDCLIP() : _panning(12. / 8), _panningAsPercentage(0),
|
||||
_sourceClipID(-1), _sourceClipType(0), _speed(1000), _priority(50),
|
||||
_xSource(-1), _ySource(-1), _maximumPossibleDistanceAway(0), _muted(false),
|
||||
_vol100(0), _vol255(0), _volModifier(0), _repeat(false), _directionalVolModifier(0) {
|
||||
}
|
||||
|
||||
void SOUNDCLIP::set_volume100(int volume) {
|
||||
_vol100 = volume;
|
||||
_vol255 = (volume * 255) / 100;
|
||||
adjust_volume();
|
||||
}
|
||||
|
||||
// Sets the current volume property in units of 255
|
||||
void SOUNDCLIP::set_volume255(int volume) {
|
||||
_vol255 = volume;
|
||||
_vol100 = (_vol255 * 100) / 255;
|
||||
adjust_volume();
|
||||
}
|
||||
|
||||
void SOUNDCLIP::set_volume_direct(int vol_percent, int vol_absolute) {
|
||||
_vol255 = vol_absolute;
|
||||
_vol100 = vol_percent;
|
||||
adjust_volume();
|
||||
}
|
||||
|
||||
void SOUNDCLIP::set_mute(bool mute) {
|
||||
_muted = mute;
|
||||
adjust_volume();
|
||||
}
|
||||
|
||||
void SOUNDCLIP::apply_volume_modifier(int mod) {
|
||||
_volModifier = mod;
|
||||
adjust_volume();
|
||||
}
|
||||
|
||||
void SOUNDCLIP::apply_directional_modifier(int mod) {
|
||||
_directionalVolModifier = mod;
|
||||
adjust_volume();
|
||||
}
|
||||
|
||||
bool SOUNDCLIP::update() {
|
||||
if (!is_ready())
|
||||
return false;
|
||||
|
||||
if (_paramsChanged) {
|
||||
auto vol_f = static_cast<float>(get_final_volume()) / 255.0f;
|
||||
if (vol_f < 0.0f) {
|
||||
vol_f = 0.0f;
|
||||
}
|
||||
if (vol_f > 1.0f) {
|
||||
vol_f = 1.0f;
|
||||
}
|
||||
|
||||
auto speed_f = static_cast<float>(_speed) / 1000.0f;
|
||||
if (speed_f <= 0.0) {
|
||||
speed_f = 1.0f;
|
||||
}
|
||||
|
||||
// Sets the pan position, ranging from -100 (left) to +100 (right)
|
||||
auto panning_f = (static_cast<float>(_panning) / 100.0f);
|
||||
if (panning_f < -1.0f) {
|
||||
panning_f = -1.0f;
|
||||
}
|
||||
if (panning_f > 1.0f) {
|
||||
panning_f = 1.0f;
|
||||
}
|
||||
|
||||
//audio_core_slot_configure(slot_, vol_f, speed_f, panning_f);
|
||||
_paramsChanged = false;
|
||||
}
|
||||
/*
|
||||
float pos_f, posms_f;
|
||||
PlaybackState core_state = audio_core_slot_get_play_state(slot_, pos_f, posms_f);
|
||||
pos = static_cast<int>(pos_f);
|
||||
posMs = static_cast<int>(posms_f);
|
||||
if (state == core_state || core_state == PlayStateError || core_state == PlayStateFinished) {
|
||||
state = core_state;
|
||||
return is_ready();
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
case PlaybackState::PlayStatePlaying:
|
||||
state = audio_core_slot_play(slot_);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
*/
|
||||
return is_ready();
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
|
||||
SoundClipWaveBase::SoundClipWaveBase(Audio::AudioStream *stream, bool repeat) :
|
||||
SOUNDCLIP(), _state(SoundClipInitial), _stream(stream) {
|
||||
_mixer = ::AGS::g_vm->_mixer;
|
||||
_repeat = repeat;
|
||||
_vol255 = 255;
|
||||
|
||||
if (repeat) {
|
||||
Audio::RewindableAudioStream *str = dynamic_cast<Audio::RewindableAudioStream *>(stream);
|
||||
if (str)
|
||||
_stream = new Audio::LoopingAudioStream(str, 0);
|
||||
}
|
||||
}
|
||||
|
||||
SoundClipWaveBase::~SoundClipWaveBase() {
|
||||
_mixer->stopHandle(_soundHandle);
|
||||
delete _stream;
|
||||
_stream = nullptr;
|
||||
}
|
||||
|
||||
void SoundClipWaveBase::poll() {
|
||||
bool playing = is_playing();
|
||||
if (playing)
|
||||
_state = SoundClipPlaying;
|
||||
else if (_state == SoundClipPlaying)
|
||||
_state = SoundClipStopped;
|
||||
}
|
||||
|
||||
int SoundClipWaveBase::play() {
|
||||
if (_soundType != Audio::Mixer::kPlainSoundType) {
|
||||
if (!_stream) {
|
||||
warning("Sound stream is null");
|
||||
return 0;
|
||||
}
|
||||
if (_stream->getRate() < 262144) // maximum accepted value in audio/rate.cpp
|
||||
_mixer->playStream(_soundType, &_soundHandle, _stream,
|
||||
-1, _vol255, 0, DisposeAfterUse::NO);
|
||||
else
|
||||
warning("Invalid sound clip sample rate: %d! Skipping", _stream->getRate());
|
||||
} else {
|
||||
_waitingToPlay = true;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void SoundClipWaveBase::setType(Audio::Mixer::SoundType type) {
|
||||
assert(type != Audio::Mixer::kPlainSoundType);
|
||||
_soundType = type;
|
||||
|
||||
if (_waitingToPlay) {
|
||||
_waitingToPlay = false;
|
||||
|
||||
play();
|
||||
}
|
||||
}
|
||||
|
||||
int SoundClipWaveBase::play_from(int position) {
|
||||
if (position != 0)
|
||||
seek(position);
|
||||
|
||||
play();
|
||||
return 1;
|
||||
}
|
||||
|
||||
void SoundClipWaveBase::pause() {
|
||||
_mixer->pauseHandle(_soundHandle, false);
|
||||
_state = SoundClipPaused;
|
||||
}
|
||||
|
||||
void SoundClipWaveBase::resume() {
|
||||
_mixer->pauseHandle(_soundHandle, false);
|
||||
_state = SoundClipPlaying;
|
||||
poll();
|
||||
}
|
||||
|
||||
bool SoundClipWaveBase::is_playing() {
|
||||
return _mixer->isSoundHandleActive(_soundHandle) || is_paused();
|
||||
}
|
||||
|
||||
bool SoundClipWaveBase::is_paused() {
|
||||
return _state == SoundClipPaused;
|
||||
}
|
||||
|
||||
int SoundClipWaveBase::pos_to_posms(int pos) const {
|
||||
// The pos meaning depends on the sound type:
|
||||
// - WAV / VOC - the sample number
|
||||
// - OGG / MP3 - milliseconds
|
||||
// - MOD - the pattern number
|
||||
switch (get_sound_type()) {
|
||||
case MUS_WAVE: // Pos is in samples
|
||||
if (!_stream)
|
||||
return 0;
|
||||
return static_cast<int>((static_cast<int64_t>(pos) * 1000) / _stream->getRate());
|
||||
case MUS_MOD: /* TODO: reimplement */
|
||||
// better say that it does not work than return wrong value
|
||||
return 0;
|
||||
default:
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
|
||||
void SoundClipWaveBase::seek(int pos) {
|
||||
seek_ms(pos_to_posms(pos));
|
||||
}
|
||||
|
||||
void SoundClipWaveBase::seek_ms(int pos_ms) {
|
||||
Audio::SeekableAudioStream *stream =
|
||||
dynamic_cast<Audio::SeekableAudioStream *>(_stream);
|
||||
|
||||
if (stream) {
|
||||
stream->seek(Audio::Timestamp(pos_ms));
|
||||
} else {
|
||||
warning("Audio stream did not support seeking");
|
||||
}
|
||||
}
|
||||
|
||||
int SoundClipWaveBase::get_pos() {
|
||||
return _mixer->getSoundElapsedTime(_soundHandle);
|
||||
}
|
||||
|
||||
int SoundClipWaveBase::get_pos_ms() {
|
||||
return _mixer->getSoundElapsedTime(_soundHandle);
|
||||
}
|
||||
|
||||
int SoundClipWaveBase::get_length_ms() {
|
||||
Audio::SeekableAudioStream *stream =
|
||||
dynamic_cast<Audio::SeekableAudioStream *>(_stream);
|
||||
|
||||
if (stream) {
|
||||
return stream->getLength().msecs();
|
||||
} else {
|
||||
warning("Unable to determine audio stream length");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void SoundClipWaveBase::set_panning(int newPanning) {
|
||||
_mixer->setChannelBalance(_soundHandle, newPanning);
|
||||
}
|
||||
|
||||
void SoundClipWaveBase::set_speed(int new_speed) {
|
||||
_speed = new_speed;
|
||||
|
||||
if (!_stream) {
|
||||
warning("set_speed: sound stream is null");
|
||||
return;
|
||||
}
|
||||
|
||||
// get initial channel rate
|
||||
const uint32_t rate = _stream->getRate();
|
||||
|
||||
// default speed = 1000, calculate new sample rate proportionally
|
||||
_mixer->setChannelRate(_soundHandle, rate * new_speed / 1000);
|
||||
}
|
||||
|
||||
void SoundClipWaveBase::adjust_volume() {
|
||||
_mixer->setChannelVolume(_soundHandle, get_final_volume());
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
254
engines/ags/engine/media/audio/sound_clip.h
Normal file
254
engines/ags/engine/media/audio/sound_clip.h
Normal file
@@ -0,0 +1,254 @@
|
||||
/* 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
|
||||
Reference in New Issue
Block a user