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();
|
ClientWorld& client_world();
|
||||||
ServerWorld& server_world();
|
ServerWorld& server_world();
|
||||||
const Argument& argument() const;
|
const Argument& argument() const;
|
||||||
|
AudioEngine& audio();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Camera m_camera;
|
Camera m_camera;
|
||||||
|
|||||||
@@ -30,7 +30,10 @@ public:
|
|||||||
bool check = false);
|
bool check = false);
|
||||||
void update_listener(const glm::vec3& pos, const glm::vec3& forward,
|
void update_listener(const glm::vec3& pos, const glm::vec3& forward,
|
||||||
const glm::vec3& up);
|
const glm::vec3& up);
|
||||||
void update(float dt);
|
void update();
|
||||||
|
void reload_config();
|
||||||
|
|
||||||
|
float& bgm_target_volume();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using FadeMap = std::unordered_map<std::string, AudioFade>;
|
using FadeMap = std::unordered_map<std::string, AudioFade>;
|
||||||
@@ -42,5 +45,8 @@ private:
|
|||||||
FadeMap m_fade_map;
|
FadeMap m_fade_map;
|
||||||
SoundManager m_sounds;
|
SoundManager m_sounds;
|
||||||
std::shared_ptr<SourcePool> m_pool;
|
std::shared_ptr<SourcePool> m_pool;
|
||||||
|
|
||||||
|
float m_music_volume = 1.0f;
|
||||||
|
float m_sfx_volume = 1.0f;
|
||||||
};
|
};
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
@@ -12,7 +12,6 @@ private:
|
|||||||
float m_in_duration = 0.0f;
|
float m_in_duration = 0.0f;
|
||||||
float m_out_duration = 0.0f;
|
float m_out_duration = 0.0f;
|
||||||
float m_start_gain = 0.0f;
|
float m_start_gain = 0.0f;
|
||||||
float m_end_gain = 0.0f;
|
|
||||||
bool m_fade_in = true;
|
bool m_fade_in = true;
|
||||||
bool m_active = true;
|
bool m_active = true;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ enum class AudioState { INITIAL, PLAYING, PAUSED, STOPPED };
|
|||||||
|
|
||||||
class AudioSource {
|
class AudioSource {
|
||||||
public:
|
public:
|
||||||
AudioSource();
|
AudioSource(float volume = 1.0f);
|
||||||
~AudioSource();
|
~AudioSource();
|
||||||
|
|
||||||
void set_buffer_2d(const AudioBuffer& buffer);
|
void set_buffer_2d(const AudioBuffer& buffer);
|
||||||
@@ -25,7 +25,9 @@ public:
|
|||||||
void pause();
|
void pause();
|
||||||
float duration() const;
|
float duration() const;
|
||||||
float current_time() const;
|
float current_time() const;
|
||||||
float volume() const;
|
float target_volume() const;
|
||||||
|
float& target_volume();
|
||||||
|
void set_target_volume(float volume);
|
||||||
AudioState state() const;
|
AudioState state() const;
|
||||||
|
|
||||||
void mark_in_use();
|
void mark_in_use();
|
||||||
@@ -34,7 +36,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
ALuint m_source = 0;
|
ALuint m_source = 0;
|
||||||
float m_volume = 1.0f;
|
float m_target_volume = 1.0f;
|
||||||
float m_duration = 0.0f;
|
float m_duration = 0.0f;
|
||||||
bool m_using;
|
bool m_using;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ class DevPanel {
|
|||||||
bool is_enable_aniso = false;
|
bool is_enable_aniso = false;
|
||||||
bool is_support_aniso = true;
|
bool is_support_aniso = true;
|
||||||
bool is_reload = true;
|
bool is_reload = true;
|
||||||
|
float volume_music = 1.0f;
|
||||||
|
float volume_sfx = 1.0f;
|
||||||
};
|
};
|
||||||
struct PlayerProfile {
|
struct PlayerProfile {
|
||||||
int game_mode = 0;
|
int game_mode = 0;
|
||||||
|
|||||||
@@ -361,7 +361,7 @@ void App::update() {
|
|||||||
}
|
}
|
||||||
m_audio.update_listener(m_camera.get_camera_pos(),
|
m_audio.update_listener(m_camera.get_camera_pos(),
|
||||||
m_camera.get_camera_front(), glm::vec3(0, 1, 0));
|
m_camera.get_camera_front(), glm::vec3(0, 1, 0));
|
||||||
m_audio.update(dt);
|
m_audio.update();
|
||||||
m_renderer.update(dt);
|
m_renderer.update(dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -396,4 +396,5 @@ Window& App::window() { return m_window; }
|
|||||||
ClientWorld& App::client_world() { return m_client_world; }
|
ClientWorld& App::client_world() { return m_client_world; }
|
||||||
ServerWorld& App::server_world() { return m_server.server_world(); }
|
ServerWorld& App::server_world() { return m_server.server_world(); }
|
||||||
const App::Argument& App::argument() const { return m_argument; }
|
const App::Argument& App::argument() const { return m_argument; }
|
||||||
|
AudioEngine& App::audio() { return m_audio; }
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "Cubed/audio/audio_engine.hpp"
|
#include "Cubed/audio/audio_engine.hpp"
|
||||||
|
|
||||||
|
#include "Cubed/config.hpp"
|
||||||
#include "Cubed/tools/cubed_assert.hpp"
|
#include "Cubed/tools/cubed_assert.hpp"
|
||||||
#include "Cubed/tools/log.hpp"
|
#include "Cubed/tools/log.hpp"
|
||||||
|
|
||||||
@@ -33,8 +34,15 @@ void AudioEngine::init() {
|
|||||||
}
|
}
|
||||||
alcMakeContextCurrent(context);
|
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_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_bgm->set_buffer_2d(m_sounds.get_buffer("bgm/bgm001.mp3"));
|
||||||
|
|
||||||
m_fade_map.try_emplace("bgm", m_bgm.get(), 5.0f, 2.0f);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
auto* source = m_pool->acquire();
|
auto* source = m_pool->acquire();
|
||||||
|
source->set_volume(m_sfx_volume);
|
||||||
if (!source) {
|
if (!source) {
|
||||||
Logger::error("Source is Full");
|
Logger::error("Source is Full");
|
||||||
}
|
}
|
||||||
@@ -91,11 +100,24 @@ void AudioEngine::update_listener(const glm::vec3& pos,
|
|||||||
|
|
||||||
alListenerfv(AL_ORIENTATION, orientation);
|
alListenerfv(AL_ORIENTATION, orientation);
|
||||||
}
|
}
|
||||||
void AudioEngine::update(float dt) {
|
void AudioEngine::update() {
|
||||||
|
|
||||||
for (auto& [key, fade] : m_fade_map) {
|
for (auto& [key, fade] : m_fade_map) {
|
||||||
fade.update();
|
fade.update();
|
||||||
}
|
}
|
||||||
m_pool->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
|
} // namespace Cubed
|
||||||
@@ -10,8 +10,9 @@ AudioFade::AudioFade(AudioSource* source, float fade_in, float fade_out)
|
|||||||
m_active = false;
|
m_active = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_start_gain = 0.0f;
|
m_start_gain = 0.0f;
|
||||||
m_end_gain = m_source->volume();
|
|
||||||
m_source->set_volume(0.0f);
|
m_source->set_volume(0.0f);
|
||||||
}
|
}
|
||||||
AudioFade::~AudioFade() {}
|
AudioFade::~AudioFade() {}
|
||||||
@@ -27,13 +28,12 @@ void AudioFade::update() {
|
|||||||
// Ease Out Sine
|
// Ease Out Sine
|
||||||
t = std::sin(t * std::numbers::pi_v<float> * 0.5f);
|
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);
|
m_source->set_volume(gain);
|
||||||
if (t >= 1.0f) {
|
if (t >= 1.0f) {
|
||||||
m_source->set_volume(m_end_gain);
|
m_source->set_volume(m_source->target_volume());
|
||||||
m_fade_in = false;
|
m_fade_in = false;
|
||||||
m_start_gain = m_end_gain;
|
m_start_gain = m_source->target_volume();
|
||||||
m_end_gain = 0.0f;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
float start_time =
|
float start_time =
|
||||||
@@ -50,11 +50,11 @@ void AudioFade::update() {
|
|||||||
// Smoothstep
|
// Smoothstep
|
||||||
t = t * t * (3.0f - 2.0f * t);
|
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);
|
m_source->set_volume(gain);
|
||||||
|
|
||||||
if (t >= 1.0f) {
|
if (t >= 1.0f) {
|
||||||
m_source->set_volume(m_end_gain);
|
m_source->set_volume(0.0f);
|
||||||
m_active = false;
|
m_active = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,10 @@
|
|||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
AudioSource::AudioSource() { alGenSources(1, &m_source); }
|
AudioSource::AudioSource(float volume) {
|
||||||
|
alGenSources(1, &m_source);
|
||||||
|
set_target_volume(volume);
|
||||||
|
}
|
||||||
AudioSource::~AudioSource() {
|
AudioSource::~AudioSource() {
|
||||||
if (m_source != 0) {
|
if (m_source != 0) {
|
||||||
stop();
|
stop();
|
||||||
@@ -62,7 +65,6 @@ void AudioSource::set_loop(bool on) {
|
|||||||
|
|
||||||
void AudioSource::set_volume(float volume) {
|
void AudioSource::set_volume(float volume) {
|
||||||
volume = std::clamp(volume, 0.0f, 1.0f);
|
volume = std::clamp(volume, 0.0f, 1.0f);
|
||||||
m_volume = volume;
|
|
||||||
alSourcef(m_source, AL_GAIN, 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) {
|
void AudioSource::play_3d(const AudioBuffer& buffer, const glm::vec3& pos) {
|
||||||
set_buffer_3d(buffer, pos);
|
set_buffer_3d(buffer, pos);
|
||||||
play();
|
play();
|
||||||
check_al_error();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioSource::stop() { alSourceStop(m_source); }
|
void AudioSource::stop() { alSourceStop(m_source); }
|
||||||
@@ -88,7 +89,14 @@ float AudioSource::current_time() const {
|
|||||||
alGetSourcef(m_source, AL_SEC_OFFSET, &sec);
|
alGetSourcef(m_source, AL_SEC_OFFSET, &sec);
|
||||||
return static_cast<float>(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 {
|
AudioState AudioSource::state() const {
|
||||||
ALint state;
|
ALint state;
|
||||||
@@ -111,11 +119,33 @@ AudioState AudioSource::state() const {
|
|||||||
void AudioSource::mark_in_use() { m_using = true; }
|
void AudioSource::mark_in_use() { m_using = true; }
|
||||||
bool AudioSource::in_use() const { return m_using; }
|
bool AudioSource::in_use() const { return m_using; }
|
||||||
void AudioSource::reset() {
|
void AudioSource::reset() {
|
||||||
|
alSourceStop(m_source);
|
||||||
|
|
||||||
alSourcei(m_source, AL_BUFFER, 0);
|
alSourcei(m_source, AL_BUFFER, 0);
|
||||||
|
|
||||||
alSourcef(m_source, AL_GAIN, 1.0f);
|
alSourcef(m_source, AL_GAIN, 1.0f);
|
||||||
alSourcef(m_source, AL_PITCH, 1.0f);
|
alSourcef(m_source, AL_PITCH, 1.0f);
|
||||||
|
|
||||||
alSource3f(m_source, AL_POSITION, 0.0f, 0.0f, 0.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_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;
|
m_using = false;
|
||||||
}
|
}
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
@@ -44,6 +44,11 @@ void Config::create_config() {
|
|||||||
[texture]
|
[texture]
|
||||||
aniso = 1 # i is the minimun value, indicating off
|
aniso = 1 # i is the minimun value, indicating off
|
||||||
|
|
||||||
|
[volume]
|
||||||
|
music = 1.0
|
||||||
|
SFX = 1.0
|
||||||
|
|
||||||
|
|
||||||
)"sv;
|
)"sv;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -436,6 +436,17 @@ void DevPanel::show_settings_tab_item() {
|
|||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::Text("Your need to click this button to apply config\n");
|
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 (ImGui::Combo("Theme", &m_theme, THEMES, IM_ARRAYSIZE(THEMES))) {
|
||||||
if (m_theme == 0) {
|
if (m_theme == 0) {
|
||||||
ImGui::StyleColorsDark();
|
ImGui::StyleColorsDark();
|
||||||
@@ -752,6 +763,10 @@ void DevPanel::update_config_view() {
|
|||||||
} else {
|
} else {
|
||||||
m_config.is_enable_aniso = true;
|
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() {
|
void DevPanel::update_player_profile() {
|
||||||
if (!m_player) {
|
if (!m_player) {
|
||||||
|
|||||||
Reference in New Issue
Block a user