mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-08-09 02:07:04 +08:00
feat(audio): add footstep sounds and fix audio listener orientation
This commit is contained in:
BIN
assets/sound/block/dirt/walk.ogg
Normal file
BIN
assets/sound/block/dirt/walk.ogg
Normal file
Binary file not shown.
BIN
assets/sound/block/grass_block/walk.ogg
Normal file
BIN
assets/sound/block/grass_block/walk.ogg
Normal file
Binary file not shown.
BIN
assets/sound/block/leaf/walk.ogg
Normal file
BIN
assets/sound/block/leaf/walk.ogg
Normal file
Binary file not shown.
BIN
assets/sound/block/sand/place.wav
Normal file
BIN
assets/sound/block/sand/place.wav
Normal file
Binary file not shown.
BIN
assets/sound/block/snowy_grass_block/walk.ogg
Normal file
BIN
assets/sound/block/snowy_grass_block/walk.ogg
Normal file
Binary file not shown.
BIN
assets/sound/block/stone/place.ogg
Normal file
BIN
assets/sound/block/stone/place.ogg
Normal file
Binary file not shown.
BIN
assets/sound/block/stone/walk.ogg
Normal file
BIN
assets/sound/block/stone/walk.ogg
Normal file
Binary file not shown.
@@ -26,8 +26,10 @@ public:
|
||||
|
||||
void init();
|
||||
void play_bgm();
|
||||
void play_3d(const std::string& sound, const glm::vec3& pos);
|
||||
void update_listener(glm::vec3 listener_pos);
|
||||
void play_3d(const std::string& sound, const glm::vec3& pos,
|
||||
bool check = false);
|
||||
void update_listener(const glm::vec3& pos, const glm::vec3& forward,
|
||||
const glm::vec3& up);
|
||||
void update(float dt);
|
||||
|
||||
private:
|
||||
|
||||
15
include/Cubed/audio/audio_error.hpp
Normal file
15
include/Cubed/audio/audio_error.hpp
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
#include "Cubed/tools/log.hpp"
|
||||
|
||||
#include <AL/al.h>
|
||||
namespace Cubed {
|
||||
inline void check_al_error(
|
||||
std::source_location loaction = std::source_location::current()) {
|
||||
ALenum error = alGetError();
|
||||
if (error != AL_NO_ERROR) {
|
||||
Logger::error("File {} Line {} Function {} OpenAL Error {} ",
|
||||
loaction.file_name(), loaction.line(),
|
||||
loaction.function_name(), alGetString(error));
|
||||
}
|
||||
}
|
||||
} // namespace Cubed
|
||||
@@ -123,6 +123,8 @@ private:
|
||||
float m_angle{0.0f};
|
||||
float m_walk_time{0.0f};
|
||||
|
||||
float m_footstep_timer = 0.0f;
|
||||
|
||||
mutable std::shared_mutex m_player_pos_mutex;
|
||||
mutable std::shared_mutex m_chunk_pos_mutex;
|
||||
ChunkPosSet m_player_chunk_pos_set;
|
||||
@@ -134,6 +136,7 @@ private:
|
||||
void update_y_move(glm::vec3& player_pos);
|
||||
void update_z_move(glm::vec3& player_pos);
|
||||
void update_player_chunk();
|
||||
void play_walk_sound(float dt);
|
||||
Gait compute_gait() const;
|
||||
};
|
||||
} // namespace Cubed
|
||||
|
||||
@@ -90,7 +90,7 @@ public:
|
||||
bool is_receive_exit();
|
||||
int chunk_size() const;
|
||||
static AABB get_block_aabb(const glm::ivec3& pos);
|
||||
|
||||
AudioEngine& get_audio();
|
||||
template <typename Fn>
|
||||
void register_timer(std::string_view id, TickType threshold, Fn&& f) {
|
||||
m_timers.emplace(std::piecewise_construct,
|
||||
|
||||
@@ -359,7 +359,8 @@ void App::update() {
|
||||
m_renderer.update_fov(fov + 5.0f);
|
||||
}
|
||||
}
|
||||
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_audio.update(dt);
|
||||
m_renderer.update(dt);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "Cubed/audio/audio_buffer.hpp"
|
||||
|
||||
#include "Cubed/audio/audio_error.hpp"
|
||||
namespace Cubed {
|
||||
AudioBuffer::AudioBuffer(const AudioData& data) {
|
||||
alGenBuffers(1, &m_buffer);
|
||||
@@ -12,6 +13,9 @@ float AudioBuffer::duration() const { return m_duration; }
|
||||
uint32_t AudioBuffer::channels() const { return m_channels; }
|
||||
|
||||
void AudioBuffer::set_data(const AudioData& data) {
|
||||
Logger::info("buffer={} valid={}", m_buffer, (int)alIsBuffer(m_buffer));
|
||||
|
||||
Logger::info("buffer={} isBuffer={}", m_buffer, (int)alIsBuffer(m_buffer));
|
||||
ALenum format;
|
||||
if (data.channels == 1) {
|
||||
format = AL_FORMAT_MONO16;
|
||||
@@ -19,8 +23,19 @@ void AudioBuffer::set_data(const AudioData& data) {
|
||||
format = AL_FORMAT_STEREO16;
|
||||
}
|
||||
m_channels = data.channels;
|
||||
alBufferData(m_buffer, format, data.pcm.data(), data.pcm.size(),
|
||||
data.sample_rate);
|
||||
|
||||
Logger::info("channels={} rate={} samples={} bytes={} format={}",
|
||||
data.channels, data.sample_rate, data.pcm.size(),
|
||||
data.pcm.size() * sizeof(int16_t), format);
|
||||
alBufferData(m_buffer, format, data.pcm.data(),
|
||||
static_cast<ALsizei>(data.pcm.size() * sizeof(int16_t)),
|
||||
static_cast<ALsizei>(data.sample_rate));
|
||||
check_al_error();
|
||||
ALint size = 0;
|
||||
alGetBufferi(m_buffer, AL_SIZE, &size);
|
||||
check_al_error();
|
||||
|
||||
Logger::info("buffer size={}", size);
|
||||
m_duration = static_cast<float>(data.pcm.size()) /
|
||||
(data.channels * data.sample_rate);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "Cubed/audio/audio_engine.hpp"
|
||||
|
||||
#include "Cubed/tools/cubed_assert.hpp"
|
||||
#include "Cubed/tools/log.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
@@ -58,7 +59,8 @@ void AudioEngine::init() {
|
||||
|
||||
void AudioEngine::play_bgm() { m_bgm->play(); }
|
||||
|
||||
void AudioEngine::play_3d(const std::string& sound, const glm::vec3& pos) {
|
||||
void AudioEngine::play_3d(const std::string& sound, const glm::vec3& pos,
|
||||
bool check) {
|
||||
if (!m_pool) {
|
||||
Logger::error("Source Pool is nullptr");
|
||||
return;
|
||||
@@ -67,11 +69,28 @@ void AudioEngine::play_3d(const std::string& sound, const glm::vec3& pos) {
|
||||
if (!source) {
|
||||
Logger::error("Source is Full");
|
||||
}
|
||||
auto& buffer = m_sounds.get_buffer(sound);
|
||||
source->play_3d(buffer, pos);
|
||||
|
||||
try {
|
||||
auto& buffer = m_sounds.get_buffer(sound);
|
||||
source->play_3d(buffer, pos);
|
||||
} catch (const std::exception& e) {
|
||||
if (check) {
|
||||
ASSERT_MSG(false, e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioEngine::update_listener(glm::vec3 listener_pos) {}
|
||||
void AudioEngine::update_listener(const glm::vec3& pos,
|
||||
const glm::vec3& forward,
|
||||
const glm::vec3& up) {
|
||||
alListener3f(AL_POSITION, pos.x, pos.y, pos.z);
|
||||
|
||||
float orientation[] = {forward.x, forward.y, forward.z,
|
||||
|
||||
up.x, up.y, up.z};
|
||||
|
||||
alListenerfv(AL_ORIENTATION, orientation);
|
||||
}
|
||||
void AudioEngine::update(float dt) {
|
||||
|
||||
for (auto& [key, fade] : m_fade_map) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "Cubed/audio/audio_loader.hpp"
|
||||
|
||||
#include "Cubed/tools/cubed_assert.hpp"
|
||||
#include "Cubed/tools/log.hpp"
|
||||
|
||||
#define STB_VORBIS_IMPLEMENTATION
|
||||
#include "stb/stb_vorbis.h"
|
||||
@@ -14,7 +14,7 @@ namespace Cubed {
|
||||
AudioData AudioLoader::load(const std::filesystem::path& path) {
|
||||
if (!fs::is_regular_file(path)) {
|
||||
std::string err = std::format("Path {} is not a file", path.string());
|
||||
ASSERT_MSG(false, err);
|
||||
|
||||
throw std::runtime_error(err);
|
||||
}
|
||||
auto ext = path.extension().string();
|
||||
@@ -46,6 +46,8 @@ AudioData AudioLoader::load_wav(const std::filesystem::path& path) {
|
||||
drwav_read_pcm_frames_s16(&wav, wav.totalPCMFrameCount, data.pcm.data());
|
||||
|
||||
drwav_uninit(&wav);
|
||||
Logger::info("{} channels={} rate={} samples={}", path.filename().string(),
|
||||
data.channels, data.sample_rate, data.pcm.size());
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -68,7 +70,8 @@ AudioData AudioLoader::load_mp3(const std::filesystem::path& path) {
|
||||
data.pcm.assign(pcm, pcm + frame_count * config.channels);
|
||||
|
||||
drmp3_free(pcm, nullptr);
|
||||
|
||||
Logger::info("{} channels={} rate={} samples={}", path.filename().string(),
|
||||
data.channels, data.sample_rate, data.pcm.size());
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -90,7 +93,8 @@ AudioData AudioLoader::load_flac(const std::filesystem::path& path) {
|
||||
data.pcm.assign(pcm, pcm + frame_count * channels);
|
||||
|
||||
drflac_free(pcm, nullptr);
|
||||
|
||||
Logger::info("{} channels={} rate={} samples={}", path.filename().string(),
|
||||
data.channels, data.sample_rate, data.pcm.size());
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -117,7 +121,7 @@ AudioData AudioLoader::load_ogg(const std::filesystem::path& path) {
|
||||
std::vector<int16_t> pcm(total_frames * channels);
|
||||
|
||||
int frames_read = stb_vorbis_get_samples_short_interleaved(
|
||||
vorbis, channels, pcm.data(), total_frames);
|
||||
vorbis, channels, pcm.data(), pcm.size());
|
||||
|
||||
if (frames_read < total_frames) {
|
||||
pcm.resize(frames_read * channels);
|
||||
@@ -129,6 +133,10 @@ AudioData AudioLoader::load_ogg(const std::filesystem::path& path) {
|
||||
data.channels = channels;
|
||||
data.sample_rate = sample_rate;
|
||||
data.pcm = std::move(pcm);
|
||||
|
||||
Logger::info("{} channels={} rate={} samples={}", path.filename().string(),
|
||||
data.channels, data.sample_rate, data.pcm.size());
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "Cubed/audio/audio_source.hpp"
|
||||
|
||||
#include "Cubed/audio/audio_error.hpp"
|
||||
#include "Cubed/tools/log.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
@@ -35,9 +36,20 @@ void AudioSource::set_buffer_3d(const AudioBuffer& buffer,
|
||||
stop();
|
||||
}
|
||||
m_duration = buffer.duration();
|
||||
|
||||
Logger::info("buffer={}", buffer.buffer());
|
||||
Logger::info("source={} isSource={}", m_source, alIsSource(m_source));
|
||||
Logger::info("buffer={} isBuffer={}", buffer.buffer(),
|
||||
alIsBuffer(buffer.buffer()));
|
||||
alSourcei(m_source, AL_BUFFER, buffer.buffer());
|
||||
check_al_error();
|
||||
alSource3f(m_source, AL_POSITION, pos.x, pos.y, pos.z);
|
||||
check_al_error();
|
||||
|
||||
alSourcef(m_source, AL_REFERENCE_DISTANCE, 4.0f);
|
||||
|
||||
alSourcef(m_source, AL_ROLLOFF_FACTOR, 1.0f);
|
||||
|
||||
alSourcef(m_source, AL_MAX_DISTANCE, 100.0f);
|
||||
}
|
||||
|
||||
void AudioSource::set_loop(bool on) {
|
||||
@@ -64,6 +76,7 @@ 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); }
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "Cubed/audio/sound_manager.hpp"
|
||||
|
||||
#include "Cubed/audio/audio_loader.hpp"
|
||||
#include "Cubed/tools/cubed_assert.hpp"
|
||||
#include "Cubed/tools/log.hpp"
|
||||
|
||||
#include <filesystem>
|
||||
namespace fs = std::filesystem;
|
||||
@@ -38,7 +38,7 @@ const AudioBuffer& SoundManager::get_buffer(const std::string& name) {
|
||||
return load(name);
|
||||
} catch (const std::exception& e) {
|
||||
std::string err = std::format("Can't Find Buffer {}", name);
|
||||
ASSERT_MSG(false, err);
|
||||
|
||||
throw std::runtime_error(err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "Cubed/gameplay/client_player.hpp"
|
||||
|
||||
#include "Cubed/audio/audio_engine.hpp"
|
||||
#include "Cubed/config.hpp"
|
||||
#include "Cubed/debug_collector.hpp"
|
||||
#include "Cubed/gameplay/client_world.hpp"
|
||||
|
||||
namespace Cubed {
|
||||
ClientPlayer::ClientPlayer(ClientWorld& world) : m_world(world) {}
|
||||
ClientPlayer::~ClientPlayer() {}
|
||||
@@ -144,42 +144,35 @@ void ClientPlayer::update_player_move_state(int key, int action) {
|
||||
case GLFW_KEY_W:
|
||||
if (action == GLFW_PRESS) {
|
||||
m_move_state.forward = true;
|
||||
m_moving = true;
|
||||
}
|
||||
if (action == GLFW_RELEASE) {
|
||||
m_move_state.forward = false;
|
||||
m_moving = false;
|
||||
|
||||
m_sprinting = false;
|
||||
}
|
||||
break;
|
||||
case GLFW_KEY_S:
|
||||
if (action == GLFW_PRESS) {
|
||||
m_move_state.back = true;
|
||||
m_moving = true;
|
||||
}
|
||||
if (action == GLFW_RELEASE) {
|
||||
m_move_state.back = false;
|
||||
m_moving = false;
|
||||
}
|
||||
break;
|
||||
case GLFW_KEY_A:
|
||||
if (action == GLFW_PRESS) {
|
||||
m_move_state.left = true;
|
||||
m_moving = true;
|
||||
}
|
||||
if (action == GLFW_RELEASE) {
|
||||
m_move_state.left = false;
|
||||
m_moving = false;
|
||||
}
|
||||
break;
|
||||
case GLFW_KEY_D:
|
||||
if (action == GLFW_PRESS) {
|
||||
m_move_state.right = true;
|
||||
m_moving = true;
|
||||
}
|
||||
if (action == GLFW_RELEASE) {
|
||||
m_move_state.right = false;
|
||||
m_moving = false;
|
||||
}
|
||||
break;
|
||||
case GLFW_KEY_SPACE:
|
||||
@@ -223,6 +216,8 @@ void ClientPlayer::update_player_move_state(int key, int action) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
m_moving = m_move_state.forward || m_move_state.back || m_move_state.left ||
|
||||
m_move_state.right;
|
||||
}
|
||||
|
||||
void ClientPlayer::update_front_vec(float offset_x, float offset_y) {
|
||||
@@ -391,6 +386,7 @@ void ClientPlayer::update_move(float delta_time) {
|
||||
m_player_pos = player_pos;
|
||||
}
|
||||
update_player_chunk();
|
||||
play_walk_sound(delta_time);
|
||||
}
|
||||
|
||||
void ClientPlayer::update_x_move(glm::vec3& player_pos) {
|
||||
@@ -503,6 +499,42 @@ void ClientPlayer::update_player_chunk() {
|
||||
}
|
||||
}
|
||||
|
||||
void ClientPlayer::play_walk_sound(float dt) {
|
||||
if (!m_moving || is_fly) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_footstep_timer += dt;
|
||||
if (m_sprinting) {
|
||||
const float WALK_INTERVAL = 0.3f;
|
||||
|
||||
if (m_footstep_timer < WALK_INTERVAL) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
const float WALK_INTERVAL = 0.45f;
|
||||
|
||||
if (m_footstep_timer < WALK_INTERVAL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_footstep_timer = 0.0f;
|
||||
|
||||
glm::ivec3 block = glm::floor(m_player_pos);
|
||||
block.y -= 1;
|
||||
BlockType id = m_world.get_block_tpye(block);
|
||||
Logger::info("player Block {} Walk Sound", id);
|
||||
if (id == 0) {
|
||||
return;
|
||||
}
|
||||
std::string name = BlockManager::name_form_id(id);
|
||||
std::string sound = "block/" + name + "/walk.ogg";
|
||||
auto& audio = m_world.get_audio();
|
||||
audio.play_3d(sound, m_player_pos);
|
||||
Logger::info("Player block {} walk sound", name);
|
||||
}
|
||||
|
||||
Gait ClientPlayer::compute_gait() const {
|
||||
if (m_xz_speed < 0.01f)
|
||||
return Gait::STOP;
|
||||
|
||||
@@ -607,6 +607,8 @@ AABB ClientWorld::get_block_aabb(const glm::ivec3& pos) {
|
||||
static_cast<float>(z + 1)}};
|
||||
}
|
||||
|
||||
AudioEngine& ClientWorld::get_audio() { return m_audio; }
|
||||
|
||||
void ClientWorld::request_exit() {
|
||||
if (m_receive_exit) {
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user