feat(audio): implement reverb effect and integrate into underwater system

This commit is contained in:
2026-07-08 11:36:13 +08:00
parent 44f83142ed
commit 9cd782122f
9 changed files with 115 additions and 1 deletions

View File

@@ -0,0 +1,19 @@
#pragma once
#include <AL/al.h>
namespace Cubed {
class AudioEffect {
public:
AudioEffect();
AudioEffect(const AudioEffect&) = delete;
AudioEffect(AudioEffect&&) = delete;
AudioEffect& operator=(const AudioEffect&) = default;
AudioEffect& operator=(AudioEffect&&) = delete;
~AudioEffect();
void set_reverb(float decay_time, float reverb_gain, float gain_hf,
float density = 1.0f, float diffusion = 1.0f);
ALuint effect() const;
private:
ALuint m_effect = 0;
};
} // namespace Cubed

View File

@@ -0,0 +1,18 @@
#pragma once
#include "Cubed/audio/audio_effect.hpp"
namespace Cubed {
class AudioEffectSlot {
public:
AudioEffectSlot();
AudioEffectSlot(const AudioEffectSlot&) = delete;
AudioEffectSlot(AudioEffectSlot&&) = delete;
AudioEffectSlot& operator=(const AudioEffectSlot&) = delete;
AudioEffectSlot& operator=(AudioEffectSlot&&) = delete;
~AudioEffectSlot();
void set_effect(const AudioEffect& effect);
ALuint slot() const;
private:
ALuint m_slot = 0;
};
} // namespace Cubed

View File

@@ -54,5 +54,7 @@ private:
float m_music_volume = 1.0f;
float m_sfx_volume = 1.0f;
std::unique_ptr<AudioFilter> m_low_pass_filter;
std::unique_ptr<AudioEffect> m_underwater_effect;
std::unique_ptr<AudioEffectSlot> m_underwater_slot;
};
} // namespace Cubed

View File

@@ -1,5 +1,6 @@
#pragma once
#include "Cubed/audio/audio_buffer.hpp"
#include "Cubed/audio/audio_effect_slot.hpp"
#include "Cubed/audio/audio_filter.hpp"
#include <AL/al.h>
@@ -37,6 +38,8 @@ public:
void set_filter(const AudioFilter& filter);
void clear_filter();
void set_effect_slot(const AudioEffectSlot& slot);
void clear_effect_slot();
private:
ALuint m_source = 0;

View File

@@ -52,4 +52,6 @@ target_sources(${PROJECT_NAME}
audio/source_pool.cpp
audio/audio_fade.cpp
audio/audio_filter.cpp
audio/audio_effect.cpp
audio/audio_effect_slot.cpp
)

View File

@@ -0,0 +1,26 @@
#include "Cubed/audio/audio_effect.hpp"
#ifndef AL_ALEXT_PROTOTYPES
#define AL_ALEXT_PROTOTYPES
#endif
#include <AL/efx.h>
namespace Cubed {
AudioEffect::AudioEffect() { alGenEffects(1, &m_effect); }
AudioEffect::~AudioEffect() {
if (m_effect) {
alDeleteEffects(1, &m_effect);
}
}
void AudioEffect::set_reverb(float decay_time, float reverb_gain, float gain_hf,
float density, float diffusion) {
alEffecti(m_effect, AL_EFFECT_TYPE, AL_EFFECT_REVERB);
alEffectf(m_effect, AL_REVERB_DECAY_TIME, decay_time);
alEffectf(m_effect, AL_REVERB_GAIN, reverb_gain);
alEffectf(m_effect, AL_REVERB_GAINHF, gain_hf);
alEffectf(m_effect, AL_REVERB_DENSITY, density);
alEffectf(m_effect, AL_REVERB_DIFFUSION, diffusion);
}
ALuint AudioEffect::effect() const { return m_effect; }
} // namespace Cubed

View File

@@ -0,0 +1,19 @@
#include "Cubed/audio/audio_effect_slot.hpp"
#ifndef AL_ALEXT_PROTOTYPES
#define AL_ALEXT_PROTOTYPES
#endif
#include <AL/efx.h>
namespace Cubed {
AudioEffectSlot::AudioEffectSlot() { alGenAuxiliaryEffectSlots(1, &m_slot); }
AudioEffectSlot::~AudioEffectSlot() {
if (m_slot) {
alDeleteAuxiliaryEffectSlots(1, &m_slot);
}
}
void AudioEffectSlot::set_effect(const AudioEffect& effect) {
alAuxiliaryEffectSloti(m_slot, AL_EFFECTSLOT_EFFECT, effect.effect());
}
ALuint AudioEffectSlot::slot() const { return m_slot; }
} // namespace Cubed

View File

@@ -19,6 +19,10 @@ AudioEngine::~AudioEngine() {
m_pool.reset();
m_sounds.clear();
m_low_pass_filter.reset();
m_underwater_effect.reset();
m_underwater_slot.reset();
alcMakeContextCurrent(nullptr);
alcDestroyContext(context);
alcCloseDevice(device);
@@ -49,6 +53,12 @@ void AudioEngine::init() {
m_low_pass_filter = std::make_unique<AudioFilter>();
m_low_pass_filter->set_lowpass(1.0f, 0.15f);
m_underwater_effect = std::make_unique<AudioEffect>();
m_underwater_effect->set_reverb(0.8f, 0.3162f, 0.01f);
// m_underwater_effect->set_reverb(20.0f, 1.0f, 1.0f);
m_underwater_slot = std::make_unique<AudioEffectSlot>();
m_underwater_slot->set_effect(*m_underwater_effect);
}
alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);
@@ -120,6 +130,7 @@ void AudioEngine::play_3d(const std::string& sound, const glm::vec3& pos,
auto& buffer = m_sounds.get_buffer(sound);
if (m_efx_supported && m_underwater) {
source->set_filter(*m_low_pass_filter);
source->set_effect_slot(*m_underwater_slot);
}
source->play_3d(buffer, pos);
} catch (const std::exception& e) {
@@ -145,6 +156,7 @@ void AudioEngine::play_2d(const std::string& sound, bool check) {
auto& buffer = m_sounds.get_buffer(sound);
if (m_efx_supported && m_underwater) {
source->set_filter(*m_low_pass_filter);
source->set_effect_slot(*m_underwater_slot);
}
source->play_2d(buffer);
} catch (const std::exception& e) {
@@ -195,9 +207,10 @@ void AudioEngine::underwater_change(bool underwater) {
for (auto& source : m_pool->sources()) {
if (m_underwater) {
source.set_filter(*m_low_pass_filter);
source.set_effect_slot(*m_underwater_slot);
} else {
source.clear_filter();
source.clear_effect_slot();
}
}
if (underwater) {

View File

@@ -156,6 +156,7 @@ void AudioSource::reset() {
alSourcef(m_source, AL_SEC_OFFSET, 0.0f);
clear_filter();
clear_effect_slot();
m_duration = 0.0f;
m_target_volume = 1.0f;
@@ -168,4 +169,15 @@ void AudioSource::set_filter(const AudioFilter& filter) {
void AudioSource::clear_filter() {
alSourcei(m_source, AL_DIRECT_FILTER, AL_FILTER_NULL);
}
void AudioSource::set_effect_slot(const AudioEffectSlot& slot) {
alSource3i(m_source, AL_AUXILIARY_SEND_FILTER, slot.slot(), 0,
AL_FILTER_NULL);
}
void AudioSource::clear_effect_slot() {
alSource3i(m_source, AL_AUXILIARY_SEND_FILTER, AL_EFFECTSLOT_NULL, 0,
AL_FILTER_NULL);
}
} // namespace Cubed