feat(audio): add audio fade in/out and fix delta time naming

This commit is contained in:
2026-07-06 17:25:18 +08:00
parent 747b152fdf
commit 960df4a459
14 changed files with 144 additions and 15 deletions

View File

@@ -38,7 +38,7 @@ public:
static int start_cubed_application(int argc, char** argv);
static unsigned int seed();
static float delte_time();
static float delta_time();
static float get_fps();
Camera& camera();
@@ -67,7 +67,7 @@ private:
inline static double last_time = glfwGetTime();
inline static double current_time = glfwGetTime();
inline static double delta_time = 0.0f;
inline static double dt = 0.0f;
inline static double fps_time_count = 0.0f;
inline static int frame_count = 0;
inline static int fps = 0;

View File

@@ -12,9 +12,11 @@ public:
AudioBuffer& operator=(AudioBuffer&&) = delete;
~AudioBuffer();
ALuint buffer() const;
float duration() const;
private:
ALuint m_buffer = 0;
float m_duration = 0.0f;
void set_data(const AudioData& data);
};
} // namespace Cubed

View File

@@ -1,5 +1,6 @@
#pragma once
#include "Cubed/audio/audio_fade.hpp"
#include "Cubed/audio/audio_source.hpp"
#include "Cubed/audio/sound_manager.hpp"
@@ -24,15 +25,18 @@ public:
void init();
void play_bgm();
void update(glm::vec3 listener_pos);
void update_listener(glm::vec3 listener_pos);
void update(float dt);
private:
using SourcePool = std::unordered_map<std::string, ALuint>;
using FadeMap = std::unordered_map<std::string, AudioFade>;
bool m_init{false};
ALCdevice* device{nullptr};
ALCcontext* context{nullptr};
glm::vec3 listener_pos;
std::unique_ptr<AudioSource> m_bgm;
FadeMap m_fade_map;
SoundManager m_sounds;
};
} // namespace Cubed

View File

@@ -0,0 +1,19 @@
#pragma once
#include "Cubed/audio/audio_source.hpp"
namespace Cubed {
class AudioFade {
public:
AudioFade(AudioSource* source, float fade_in = 0.0f, float fade_out = 0.0f);
~AudioFade();
void update();
private:
AudioSource* m_source = nullptr;
float m_in_duration = 0.0f;
float m_out_duration = 0.0f;
float m_start_gain = 0.0f;
float m_end_gain = 0.0f;
bool m_fade_in = true;
bool m_active = true;
};
} // namespace Cubed

View File

@@ -11,16 +11,20 @@ public:
AudioSource();
~AudioSource();
void set_buffer(const AudioBuffer& buffer);
void set_buffer_2d(const AudioBuffer& buffer);
void set_loop(bool on = true);
void set_volume(float volume);
void play();
void stop();
void pause();
float duration() const;
float current_time() const;
float volume() const;
AudioState state();
private:
ALuint m_source = 0;
float m_volume = 1.0f;
float m_duration = 0.0f;
};
} // namespace Cubed

View File

View File

@@ -104,6 +104,8 @@ inline float distance2(const glm::vec3& a, const glm::vec3& b) {
return glm::dot(diff, diff);
}
inline float lerp(float a, float b, float t) { return a + t * (b - a); }
} // namespace Math
} // namespace Cubed

View File

@@ -50,4 +50,5 @@ target_sources(${PROJECT_NAME}
audio/audio_buffer.cpp
audio/sound_manager.cpp
audio/source_pool.cpp
audio/audio_fade.cpp
)

View File

@@ -329,9 +329,9 @@ static Gait player_gait = Gait::WALK;
void App::update() {
glfwPollEvents();
current_time = glfwGetTime();
delta_time = current_time - last_time;
dt = current_time - last_time;
last_time = current_time;
fps_time_count += delta_time;
fps_time_count += dt;
frame_count++;
if (fps_time_count >= 1.0f) {
fps = static_cast<int>(frame_count / fps_time_count);
@@ -346,7 +346,7 @@ void App::update() {
std::format("RSS: {}mb", Tools::get_current_rss() / (1024 * 1024)));
}
m_texture_manager.update();
m_client_world.update(delta_time);
m_client_world.update(dt);
m_camera.update_move_camera();
const auto& player = m_client_world.get_player();
if (player_gait != player.get_gait()) {
@@ -359,8 +359,9 @@ void App::update() {
m_renderer.update_fov(fov + 5.0f);
}
}
m_audio.update(m_camera.get_camera_pos());
m_renderer.update(delta_time);
m_audio.update_listener(m_camera.get_camera_pos());
m_audio.update(dt);
m_renderer.update(dt);
}
int App::start_cubed_application(int argc, char** argv) {
@@ -382,7 +383,7 @@ int App::start_cubed_application(int argc, char** argv) {
return 1;
}
float App::delte_time() { return delta_time; }
float App::delta_time() { return dt; }
float App::get_fps() { return fps; }

View File

@@ -8,6 +8,8 @@ AudioBuffer::AudioBuffer(const AudioData& data) {
AudioBuffer::~AudioBuffer() { alDeleteBuffers(1, &m_buffer); }
ALuint AudioBuffer::buffer() const { return m_buffer; }
float AudioBuffer::duration() const { return m_duration; }
void AudioBuffer::set_data(const AudioData& data) {
ALenum format;
if (data.channels == 1) {
@@ -17,6 +19,8 @@ void AudioBuffer::set_data(const AudioData& data) {
}
alBufferData(m_buffer, format, data.pcm.data(), data.pcm.size(),
data.sample_rate);
m_duration = static_cast<float>(data.pcm.size()) /
(data.channels * data.sample_rate);
}
} // namespace Cubed

View File

@@ -33,7 +33,10 @@ void AudioEngine::init() {
m_sounds.init();
m_bgm = std::make_unique<AudioSource>();
m_bgm->set_buffer(m_sounds.get_buffer("bgm/bgm001.mp3"));
m_bgm->set_buffer_2d(m_sounds.get_buffer("bgm/bgm001.mp3"));
m_fade_map.try_emplace("bgm", m_bgm.get(), 5.0f, 2.0f);
Logger::info("Audio Engine Init Success");
m_init = true;
@@ -41,6 +44,11 @@ void AudioEngine::init() {
void AudioEngine::play_bgm() { m_bgm->play(); }
void AudioEngine::update(glm::vec3 listener_pos) {}
void AudioEngine::update_listener(glm::vec3 listener_pos) {}
void AudioEngine::update(float dt) {
for (auto& [key, fade] : m_fade_map) {
fade.update();
}
}
} // namespace Cubed

62
src/audio/audio_fade.cpp Normal file
View File

@@ -0,0 +1,62 @@
#include "Cubed/audio/audio_fade.hpp"
#include <algorithm>
#include <cmath>
namespace Cubed {
AudioFade::AudioFade(AudioSource* source, float fade_in, float fade_out)
: m_source(source), m_in_duration(fade_in), m_out_duration(fade_out) {
if (!m_source) {
m_active = false;
return;
}
m_start_gain = 0.0f;
m_end_gain = m_source->volume();
m_source->set_volume(0.0f);
}
AudioFade::~AudioFade() {}
void AudioFade::update() {
if (!m_active || !m_source) {
return;
}
if (m_fade_in) {
float t =
std::clamp(m_source->current_time() / m_in_duration, 0.0f, 1.0f);
// Ease Out Sine
t = std::sin(t * std::numbers::pi_v<float> * 0.5f);
float gain = std::lerp(m_start_gain, m_end_gain, t);
m_source->set_volume(gain);
if (t >= 1.0f) {
m_source->set_volume(m_end_gain);
m_fade_in = false;
m_start_gain = m_end_gain;
m_end_gain = 0.0f;
}
} else {
float start_time =
std::max(0.0f, m_source->duration() - m_out_duration);
if (m_source->current_time() < start_time) {
return;
}
float elapsed = m_source->current_time() - start_time;
float t = std::clamp(elapsed / m_out_duration, 0.0f, 1.0f);
// Smoothstep
t = t * t * (3.0f - 2.0f * t);
float gain = std::lerp(m_start_gain, m_end_gain, t);
m_source->set_volume(gain);
if (t >= 1.0f) {
m_source->set_volume(m_end_gain);
m_active = false;
}
}
}
} // namespace Cubed

View File

@@ -1,5 +1,7 @@
#include "Cubed/audio/audio_source.hpp"
#include "Cubed/tools/log.hpp"
#include <stdexcept>
namespace Cubed {
@@ -11,11 +13,14 @@ AudioSource::~AudioSource() {
}
}
void AudioSource::set_buffer(const AudioBuffer& buffer) {
void AudioSource::set_buffer_2d(const AudioBuffer& buffer) {
if (state() == AudioState::PLAYING) {
stop();
}
m_duration = buffer.duration();
alSourcei(m_source, AL_BUFFER, buffer.buffer());
alSourcei(m_source, AL_SOURCE_RELATIVE, AL_TRUE);
alSource3f(m_source, AL_POSITION, 0, 0, 0);
}
void AudioSource::set_loop(bool on) {
@@ -26,11 +31,28 @@ void AudioSource::set_loop(bool on) {
}
}
void AudioSource::set_volume(float volume) {
if (volume > 1.0f) {
Logger::error("Volume {} is too large", volume);
return;
}
m_volume = volume;
alSourcef(m_source, AL_GAIN, volume);
}
void AudioSource::play() { alSourcePlay(m_source); }
void AudioSource::stop() { alSourceStop(m_source); }
void AudioSource::pause() { alSourcePause(m_source); }
float AudioSource::duration() const { return m_duration; }
float AudioSource::current_time() const {
ALfloat sec = 0.0f;
alGetSourcef(m_source, AL_SEC_OFFSET, &sec);
return static_cast<float>(sec);
}
float AudioSource::volume() const { return m_volume; }
AudioState AudioSource::state() {
ALint state;
alGetSourcei(m_source, AL_SOURCE_STATE, &state);

View File