Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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