Skip to content

Commit

Permalink
Refactor AmbientSound
Browse files Browse the repository at this point in the history
  • Loading branch information
mrkubax10 committed Dec 1, 2023
1 parent ea58eb2 commit 4d17844
Show file tree
Hide file tree
Showing 9 changed files with 100 additions and 414 deletions.
3 changes: 2 additions & 1 deletion src/audio/dummy_sound_source.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ class DummySoundSource final : public SoundSource
is_playing = true;
}

virtual void stop() override
virtual void stop(bool unload_buffer = true) override
{
(void) unload_buffer;
is_playing = false;
}

Expand Down
5 changes: 3 additions & 2 deletions src/audio/openal_sound_source.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,16 @@ OpenALSoundSource::~OpenALSoundSource()
}

void
OpenALSoundSource::stop()
OpenALSoundSource::stop(bool unload_buffer)
{
#ifdef WIN32
// See commit 417a8e7a8c599bfc2dceaec7b6f64ac865318ef1
alSourceRewindv(1, &m_source); // Stops the source
#else
alSourceStop(m_source);
#endif
alSourcei(m_source, AL_BUFFER, AL_NONE);
if (unload_buffer)
alSourcei(m_source, AL_BUFFER, AL_NONE);
try
{
SoundManager::check_al_error("Problem stopping audio source: ");
Expand Down
2 changes: 1 addition & 1 deletion src/audio/openal_sound_source.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class OpenALSoundSource : public SoundSource
~OpenALSoundSource() override;

virtual void play() override;
virtual void stop() override;
virtual void stop(bool unload_buffer = true) override;
virtual bool playing() const override;

virtual void set_looping(bool looping) override;
Expand Down
2 changes: 1 addition & 1 deletion src/audio/sound_source.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class SoundSource
virtual ~SoundSource() {}

virtual void play() = 0;
virtual void stop() = 0;
virtual void stop(bool unload_buffer = true) = 0;
virtual bool playing() const = 0;

virtual void set_looping(bool looping) = 0;
Expand Down
280 changes: 75 additions & 205 deletions src/object/ambient_sound.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// SuperTux
// Copyright (C) 2006 Matthias Braun <matze@braunis.de>
// 2023 mrkubax10 <mrkubax10@onet.pl>
//
// 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
Expand All @@ -21,253 +22,122 @@
#include "audio/sound_manager.hpp"
#include "audio/sound_source.hpp"
#include "editor/editor.hpp"
#include "object/camera.hpp"
#include "supertux/sector.hpp"
#include "util/reader_mapping.hpp"
#include "video/drawing_context.hpp"

AmbientSound::AmbientSound(const ReaderMapping& mapping) :
MovingObject(mapping),
GameObject(mapping),
ExposedObject<AmbientSound, scripting::AmbientSound>(this),
sample(),
sound_source(),
latency(),
distance_factor(),
distance_bias(),
silence_distance(),
maximumvolume(),
targetvolume(),
currentvolume(0)
m_sample(),
m_sound_source(),
m_volume(),
m_play_interval(),
m_delay(0.0f),
m_playing(false),
m_scheduled_for_removal(false)
{
m_col.m_group = COLGROUP_DISABLED;
mapping.get("sample", m_sample, "");
mapping.get("volume", m_volume, 1.0f);
mapping.get("play-interval", m_play_interval, 0.0f);

float w, h;
mapping.get("x", m_col.m_bbox.get_left(), 0.0f);
mapping.get("y", m_col.m_bbox.get_top(), 0.0f);
mapping.get("width" , w, 32.0f);
mapping.get("height", h, 32.0f);
m_col.m_bbox.set_size(w, h);

mapping.get("distance_factor",distance_factor, 0.0f);
mapping.get("distance_bias" ,distance_bias , 0.0f);
mapping.get("sample" ,sample , "");
mapping.get("volume" ,maximumvolume , 1.0f);

// Square all distances (saves us a sqrt later).

if (!Editor::is_active()) {
distance_bias*=distance_bias;
distance_factor*=distance_factor;
}

// Set default silence_distance.

if (distance_factor == 0)
silence_distance = std::numeric_limits<float>::max();
else
silence_distance = 1/distance_factor;

mapping.get("silence_distance",silence_distance);

if (!Editor::is_active()) {
sound_source.reset(); // Resetting the sound source to stop playing at the beginning.
SoundManager::current()->preload(sample);
}
latency=0;
prepare_sound_source();
}

AmbientSound::AmbientSound(const Vector& pos, float factor, float bias, float vol, const std::string& file) :
AmbientSound::AmbientSound(float vol, float play_interval, const std::string& file) :
ExposedObject<AmbientSound, scripting::AmbientSound>(this),
sample(file),
sound_source(),
latency(0),
distance_factor(factor * factor),
distance_bias(bias * bias),
silence_distance(),
maximumvolume(vol),
targetvolume(),
currentvolume()
m_sample(file),
m_sound_source(),
m_volume(vol),
m_play_interval(play_interval),
m_delay(0.0f),
m_playing(false),
m_scheduled_for_removal(false)
{
m_col.m_group = COLGROUP_DISABLED;

m_col.m_bbox.set_pos(pos);
m_col.m_bbox.set_size(32, 32);

// Set default silence_distance.

if (distance_factor == 0)
silence_distance = std::numeric_limits<float>::max();
else
silence_distance = 1/distance_factor;

if (!Editor::is_active()) {
sound_source.reset(); // Resetting the sound source to stop playing at the beginning.
SoundManager::current()->preload(sample);
}
prepare_sound_source();
}

AmbientSound::~AmbientSound()
{
stop_playing();
}

ObjectSettings
AmbientSound::get_settings()
{
ObjectSettings result = MovingObject::get_settings();

result.add_sound(_("Sound"), &sample, "sample");
result.add_float(_("Distance factor"), &distance_factor, "distance_factor");
result.add_float(_("Distance bias"), &distance_bias, "distance_bias");
result.add_float(_("Volume"), &maximumvolume, "volume");

result.reorder({"sample", "distance_factor", "distance_bias", "volume", "region", "name", "x", "y", "width", "height"});

return result;
}

void
AmbientSound::after_editor_set()
{
}

void
AmbientSound::stop_playing()
{
sound_source.reset();
stop_looping_sounds();
}

void
AmbientSound::start_playing()
AmbientSound::update(float dt_sec)
{
if (Editor::is_active()) return;

try {
sound_source = SoundManager::current()->create_sound_source(sample);
if (!sound_source)
throw std::runtime_error("file not found");

sound_source->set_gain(0);
sound_source->set_looping(true);
sound_source->set_position(m_col.m_bbox.get_middle());
currentvolume=targetvolume=1e-20f;
sound_source->play();
} catch(std::exception& e) {
log_warning << "Couldn't play '" << sample << "': " << e.what() << "" << std::endl;
sound_source.reset();
if (m_scheduled_for_removal)
{
remove_me();
return;
}
}

void
AmbientSound::update(float dt_sec)
{
if (latency-- <= 0) {
float px,py;
float rx,ry;

// Get the central position of the camera.
px=Sector::get().get_camera().get_center().x;
py=Sector::get().get_camera().get_center().y;

// Determine the nearest point within the area bounds.
rx=px<m_col.m_bbox.get_left()?m_col.m_bbox.get_left():
(px<m_col.m_bbox.get_right()?px:m_col.m_bbox.get_right());
ry=py<m_col.m_bbox.get_top()?m_col.m_bbox.get_top():
(py<m_col.m_bbox.get_bottom()?py:m_col.m_bbox.get_bottom());

// Calculate the square of the distance.
float sqrdistance=(px-rx)*(px-rx)+(py-ry)*(py-ry);
sqrdistance-=distance_bias;

// Inside the bias: full volume (distance 0).
if (sqrdistance<0)
sqrdistance=0;

// Calculate target volume - will never become 0.
targetvolume=1/(1+sqrdistance*distance_factor);
float rise=targetvolume/currentvolume;

// Determine the rise/fall half-life.
currentvolume *= powf(rise, dt_sec * 10.0f);
currentvolume += 1e-6f; // volume is at least 1e-6 (0 would never rise)

if (sound_source != nullptr) {

// Set the volume.
sound_source->set_gain(currentvolume*maximumvolume);

if (sqrdistance>=silence_distance && currentvolume < 1e-3f)
stop_playing();
latency=0;
} else {
if (sqrdistance<silence_distance) {
start_playing();
latency=0;
}
else // Set a reasonable latency.
latency = static_cast<int>(0.001f / distance_factor);
//(int)(10*((sqrdistance-silence_distance)/silence_distance));
if (!m_sound_source->playing())
{
if (m_playing && m_delay>=m_play_interval)
{
m_sound_source->play();
m_delay = 0.0f;
}
m_delay+=dt_sec;
}

// Heuristically measured "good" maximum latency.

// if (latency > 0.001 / distance_factor)
// latency =
}

#ifndef SCRIPTING_API
void
AmbientSound::set_pos(const Vector& pos)
{
MovingObject::set_pos(pos);
}
#endif

void
AmbientSound::set_pos(float x, float y)
ObjectSettings
AmbientSound::get_settings()
{
m_col.m_bbox.set_pos(Vector(x, y));
}
ObjectSettings result = GameObject::get_settings();

float
AmbientSound::get_pos_x() const
{
return m_col.m_bbox.get_left();
}
result.add_sound(_("Sound"), &m_sample, "sample");
result.add_float(_("Volume"), &m_volume, "volume");
result.add_float(_("Play interval"), &m_play_interval, "play-interval");

float
AmbientSound::get_pos_y() const
{
return m_col.m_bbox.get_top();
}
result.reorder({"sample", "volume", "play-interval", "name"});

HitResponse
AmbientSound::collision(GameObject& other, const CollisionHit& hit_)
{
return ABORT_MOVE;
return result;
}

void
AmbientSound::draw(DrawingContext& context)
AmbientSound::stop_looping_sounds()
{
if (Editor::is_active()) {
context.color().draw_filled_rect(m_col.m_bbox, Color(0.0f, 0.0f, 1.0f, 0.6f),
0.0f, LAYER_OBJECTS);
if (m_sound_source)
{
m_sound_source->stop(false);
m_playing = false;
}
}

void
AmbientSound::stop_looping_sounds()
AmbientSound::play_looping_sounds()
{
stop_playing();
if (!Editor::is_active() && m_sound_source)
{
m_playing = true;
m_delay = 0.0f;
}
}

void
AmbientSound::play_looping_sounds()
AmbientSound::prepare_sound_source()
{
start_playing();
try
{
m_sound_source = SoundManager::current()->create_sound_source(m_sample);
if (!m_sound_source)
throw std::runtime_error("file not found");
m_sound_source->set_gain(m_volume);
m_sound_source->set_relative(true);

if (!Editor::is_active())
{
m_playing = true;
m_delay = 0.0f;
m_sound_source->play();
}
}
catch(const std::exception& e)
{
log_warning << "Couldn't play '" << m_sample << "': " << e.what() << "" << std::endl;
m_sound_source.reset();
m_scheduled_for_removal = true;
}
}

/* EOF */
Loading

0 comments on commit 4d17844

Please sign in to comment.