mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-08-09 02:07:04 +08:00
feat(audio): add per-channel volume control and config reload
This commit is contained in:
@@ -49,6 +49,7 @@ public:
|
||||
ClientWorld& client_world();
|
||||
ServerWorld& server_world();
|
||||
const Argument& argument() const;
|
||||
AudioEngine& audio();
|
||||
|
||||
private:
|
||||
Camera m_camera;
|
||||
|
||||
@@ -30,7 +30,10 @@ public:
|
||||
bool check = false);
|
||||
void update_listener(const glm::vec3& pos, const glm::vec3& forward,
|
||||
const glm::vec3& up);
|
||||
void update(float dt);
|
||||
void update();
|
||||
void reload_config();
|
||||
|
||||
float& bgm_target_volume();
|
||||
|
||||
private:
|
||||
using FadeMap = std::unordered_map<std::string, AudioFade>;
|
||||
@@ -42,5 +45,8 @@ private:
|
||||
FadeMap m_fade_map;
|
||||
SoundManager m_sounds;
|
||||
std::shared_ptr<SourcePool> m_pool;
|
||||
|
||||
float m_music_volume = 1.0f;
|
||||
float m_sfx_volume = 1.0f;
|
||||
};
|
||||
} // namespace Cubed
|
||||
@@ -12,7 +12,6 @@ private:
|
||||
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;
|
||||
};
|
||||
|
||||
@@ -9,7 +9,7 @@ enum class AudioState { INITIAL, PLAYING, PAUSED, STOPPED };
|
||||
|
||||
class AudioSource {
|
||||
public:
|
||||
AudioSource();
|
||||
AudioSource(float volume = 1.0f);
|
||||
~AudioSource();
|
||||
|
||||
void set_buffer_2d(const AudioBuffer& buffer);
|
||||
@@ -25,7 +25,9 @@ public:
|
||||
void pause();
|
||||
float duration() const;
|
||||
float current_time() const;
|
||||
float volume() const;
|
||||
float target_volume() const;
|
||||
float& target_volume();
|
||||
void set_target_volume(float volume);
|
||||
AudioState state() const;
|
||||
|
||||
void mark_in_use();
|
||||
@@ -34,7 +36,7 @@ public:
|
||||
|
||||
private:
|
||||
ALuint m_source = 0;
|
||||
float m_volume = 1.0f;
|
||||
float m_target_volume = 1.0f;
|
||||
float m_duration = 0.0f;
|
||||
bool m_using;
|
||||
};
|
||||
|
||||
@@ -20,6 +20,8 @@ class DevPanel {
|
||||
bool is_enable_aniso = false;
|
||||
bool is_support_aniso = true;
|
||||
bool is_reload = true;
|
||||
float volume_music = 1.0f;
|
||||
float volume_sfx = 1.0f;
|
||||
};
|
||||
struct PlayerProfile {
|
||||
int game_mode = 0;
|
||||
|
||||
@@ -361,7 +361,7 @@ void App::update() {
|
||||
}
|
||||
m_audio.update_listener(m_camera.get_camera_pos(),
|
||||
m_camera.get_camera_front(), glm::vec3(0, 1, 0));
|
||||
m_audio.update(dt);
|
||||
m_audio.update();
|
||||
m_renderer.update(dt);
|
||||
}
|
||||
|
||||
@@ -396,4 +396,5 @@ Window& App::window() { return m_window; }
|
||||
ClientWorld& App::client_world() { return m_client_world; }
|
||||
ServerWorld& App::server_world() { return m_server.server_world(); }
|
||||
const App::Argument& App::argument() const { return m_argument; }
|
||||
AudioEngine& App::audio() { return m_audio; }
|
||||
} // namespace Cubed
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "Cubed/audio/audio_engine.hpp"
|
||||
|
||||
#include "Cubed/config.hpp"
|
||||
#include "Cubed/tools/cubed_assert.hpp"
|
||||
#include "Cubed/tools/log.hpp"
|
||||
|
||||
@@ -33,8 +34,15 @@ void AudioEngine::init() {
|
||||
}
|
||||
alcMakeContextCurrent(context);
|
||||
|
||||
auto& config = Config::get();
|
||||
|
||||
m_music_volume = static_cast<float>(config.get<double>("volume.music"));
|
||||
m_sfx_volume = static_cast<float>(config.get<double>("volume.SFX"));
|
||||
|
||||
m_sounds.init();
|
||||
m_bgm = std::make_unique<AudioSource>();
|
||||
|
||||
m_bgm = std::make_unique<AudioSource>(m_music_volume);
|
||||
|
||||
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);
|
||||
@@ -66,6 +74,7 @@ void AudioEngine::play_3d(const std::string& sound, const glm::vec3& pos,
|
||||
return;
|
||||
}
|
||||
auto* source = m_pool->acquire();
|
||||
source->set_volume(m_sfx_volume);
|
||||
if (!source) {
|
||||
Logger::error("Source is Full");
|
||||
}
|
||||
@@ -91,11 +100,24 @@ void AudioEngine::update_listener(const glm::vec3& pos,
|
||||
|
||||
alListenerfv(AL_ORIENTATION, orientation);
|
||||
}
|
||||
void AudioEngine::update(float dt) {
|
||||
void AudioEngine::update() {
|
||||
|
||||
for (auto& [key, fade] : m_fade_map) {
|
||||
fade.update();
|
||||
}
|
||||
m_pool->update();
|
||||
}
|
||||
|
||||
void AudioEngine::reload_config() {
|
||||
auto& config = Config::get();
|
||||
|
||||
m_music_volume = static_cast<float>(config.get<double>("volume.music"));
|
||||
m_sfx_volume = static_cast<float>(config.get<double>("volume.SFX"));
|
||||
if (m_bgm) {
|
||||
m_bgm->set_target_volume(m_music_volume);
|
||||
}
|
||||
}
|
||||
|
||||
float& AudioEngine::bgm_target_volume() { return m_bgm->target_volume(); }
|
||||
|
||||
} // namespace Cubed
|
||||
@@ -10,8 +10,9 @@ AudioFade::AudioFade(AudioSource* source, float fade_in, float fade_out)
|
||||
m_active = false;
|
||||
return;
|
||||
}
|
||||
|
||||
m_start_gain = 0.0f;
|
||||
m_end_gain = m_source->volume();
|
||||
|
||||
m_source->set_volume(0.0f);
|
||||
}
|
||||
AudioFade::~AudioFade() {}
|
||||
@@ -27,13 +28,12 @@ void AudioFade::update() {
|
||||
// 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);
|
||||
float gain = std::lerp(m_start_gain, m_source->target_volume(), t);
|
||||
m_source->set_volume(gain);
|
||||
if (t >= 1.0f) {
|
||||
m_source->set_volume(m_end_gain);
|
||||
m_source->set_volume(m_source->target_volume());
|
||||
m_fade_in = false;
|
||||
m_start_gain = m_end_gain;
|
||||
m_end_gain = 0.0f;
|
||||
m_start_gain = m_source->target_volume();
|
||||
}
|
||||
} else {
|
||||
float start_time =
|
||||
@@ -50,11 +50,11 @@ void AudioFade::update() {
|
||||
// Smoothstep
|
||||
t = t * t * (3.0f - 2.0f * t);
|
||||
|
||||
float gain = std::lerp(m_start_gain, m_end_gain, t);
|
||||
float gain = std::lerp(m_start_gain, 0.0f, t);
|
||||
m_source->set_volume(gain);
|
||||
|
||||
if (t >= 1.0f) {
|
||||
m_source->set_volume(m_end_gain);
|
||||
m_source->set_volume(0.0f);
|
||||
m_active = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,10 @@
|
||||
#include <stdexcept>
|
||||
|
||||
namespace Cubed {
|
||||
AudioSource::AudioSource() { alGenSources(1, &m_source); }
|
||||
AudioSource::AudioSource(float volume) {
|
||||
alGenSources(1, &m_source);
|
||||
set_target_volume(volume);
|
||||
}
|
||||
AudioSource::~AudioSource() {
|
||||
if (m_source != 0) {
|
||||
stop();
|
||||
@@ -62,7 +65,6 @@ void AudioSource::set_loop(bool on) {
|
||||
|
||||
void AudioSource::set_volume(float volume) {
|
||||
volume = std::clamp(volume, 0.0f, 1.0f);
|
||||
m_volume = volume;
|
||||
alSourcef(m_source, AL_GAIN, volume);
|
||||
}
|
||||
|
||||
@@ -76,7 +78,6 @@ void AudioSource::play_2d(const AudioBuffer& buffer) {
|
||||
void AudioSource::play_3d(const AudioBuffer& buffer, const glm::vec3& pos) {
|
||||
set_buffer_3d(buffer, pos);
|
||||
play();
|
||||
check_al_error();
|
||||
}
|
||||
|
||||
void AudioSource::stop() { alSourceStop(m_source); }
|
||||
@@ -88,7 +89,14 @@ float AudioSource::current_time() const {
|
||||
alGetSourcef(m_source, AL_SEC_OFFSET, &sec);
|
||||
return static_cast<float>(sec);
|
||||
}
|
||||
float AudioSource::volume() const { return m_volume; }
|
||||
|
||||
float AudioSource::target_volume() const { return m_target_volume; }
|
||||
float& AudioSource::target_volume() { return m_target_volume; }
|
||||
|
||||
void AudioSource::set_target_volume(float volume) {
|
||||
m_target_volume = volume;
|
||||
set_volume(m_target_volume);
|
||||
}
|
||||
|
||||
AudioState AudioSource::state() const {
|
||||
ALint state;
|
||||
@@ -111,11 +119,33 @@ AudioState AudioSource::state() const {
|
||||
void AudioSource::mark_in_use() { m_using = true; }
|
||||
bool AudioSource::in_use() const { return m_using; }
|
||||
void AudioSource::reset() {
|
||||
alSourceStop(m_source);
|
||||
|
||||
alSourcei(m_source, AL_BUFFER, 0);
|
||||
|
||||
alSourcef(m_source, AL_GAIN, 1.0f);
|
||||
alSourcef(m_source, AL_PITCH, 1.0f);
|
||||
|
||||
alSource3f(m_source, AL_POSITION, 0.0f, 0.0f, 0.0f);
|
||||
alSource3f(m_source, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
|
||||
alSource3f(m_source, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
|
||||
|
||||
alSourcef(m_source, AL_REFERENCE_DISTANCE, 1.0f);
|
||||
alSourcef(m_source, AL_ROLLOFF_FACTOR, 1.0f);
|
||||
alSourcef(m_source, AL_MAX_DISTANCE, FLT_MAX);
|
||||
|
||||
alSourcef(m_source, AL_CONE_INNER_ANGLE, 360.0f);
|
||||
alSourcef(m_source, AL_CONE_OUTER_ANGLE, 360.0f);
|
||||
alSourcef(m_source, AL_CONE_OUTER_GAIN, 0.0f);
|
||||
|
||||
alSourcei(m_source, AL_LOOPING, AL_FALSE);
|
||||
|
||||
alSourcei(m_source, AL_SOURCE_RELATIVE, AL_FALSE);
|
||||
|
||||
alSourcef(m_source, AL_SEC_OFFSET, 0.0f);
|
||||
|
||||
m_duration = 0.0f;
|
||||
m_target_volume = 1.0f;
|
||||
m_using = false;
|
||||
}
|
||||
} // namespace Cubed
|
||||
@@ -44,6 +44,11 @@ void Config::create_config() {
|
||||
[texture]
|
||||
aniso = 1 # i is the minimun value, indicating off
|
||||
|
||||
[volume]
|
||||
music = 1.0
|
||||
SFX = 1.0
|
||||
|
||||
|
||||
)"sv;
|
||||
|
||||
try {
|
||||
|
||||
@@ -436,6 +436,17 @@ void DevPanel::show_settings_tab_item() {
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("Your need to click this button to apply config\n");
|
||||
}
|
||||
|
||||
if (ImGui::SliderFloat("Music", &m_config.volume_music, 0.0f, 1.0f)) {
|
||||
Config::get().set("volume.music",
|
||||
static_cast<double>(m_config.volume_music));
|
||||
m_app.audio().reload_config();
|
||||
}
|
||||
if (ImGui::SliderFloat("SFX", &m_config.volume_sfx, 0.0f, 1.0f)) {
|
||||
Config::get().set("volume.SFX",
|
||||
static_cast<double>(m_config.volume_sfx));
|
||||
m_app.audio().reload_config();
|
||||
}
|
||||
if (ImGui::Combo("Theme", &m_theme, THEMES, IM_ARRAYSIZE(THEMES))) {
|
||||
if (m_theme == 0) {
|
||||
ImGui::StyleColorsDark();
|
||||
@@ -752,6 +763,10 @@ void DevPanel::update_config_view() {
|
||||
} else {
|
||||
m_config.is_enable_aniso = true;
|
||||
}
|
||||
m_config.volume_music =
|
||||
static_cast<float>(config.val_view("volume.music").value_or(1.0));
|
||||
m_config.volume_sfx =
|
||||
static_cast<float>(config.val_view("volume.SFX").value_or(1.0));
|
||||
}
|
||||
void DevPanel::update_player_profile() {
|
||||
if (!m_player) {
|
||||
|
||||
Reference in New Issue
Block a user