diff --git a/assets/sound/block/dirt/walk.ogg b/assets/sound/block/dirt/walk.ogg new file mode 100644 index 0000000..a88f1d1 Binary files /dev/null and b/assets/sound/block/dirt/walk.ogg differ diff --git a/assets/sound/block/grass_block/walk.ogg b/assets/sound/block/grass_block/walk.ogg new file mode 100644 index 0000000..67cff62 Binary files /dev/null and b/assets/sound/block/grass_block/walk.ogg differ diff --git a/assets/sound/block/leaf/walk.ogg b/assets/sound/block/leaf/walk.ogg new file mode 100644 index 0000000..0f71d2b Binary files /dev/null and b/assets/sound/block/leaf/walk.ogg differ diff --git a/assets/sound/block/sand/place.wav b/assets/sound/block/sand/place.wav new file mode 100644 index 0000000..97f8433 Binary files /dev/null and b/assets/sound/block/sand/place.wav differ diff --git a/assets/sound/block/snowy_grass_block/walk.ogg b/assets/sound/block/snowy_grass_block/walk.ogg new file mode 100644 index 0000000..e1db3fa Binary files /dev/null and b/assets/sound/block/snowy_grass_block/walk.ogg differ diff --git a/assets/sound/block/stone/place.ogg b/assets/sound/block/stone/place.ogg new file mode 100644 index 0000000..ddf5ac6 Binary files /dev/null and b/assets/sound/block/stone/place.ogg differ diff --git a/assets/sound/block/stone/walk.ogg b/assets/sound/block/stone/walk.ogg new file mode 100644 index 0000000..44a3c7f Binary files /dev/null and b/assets/sound/block/stone/walk.ogg differ diff --git a/include/Cubed/audio/audio_engine.hpp b/include/Cubed/audio/audio_engine.hpp index f17fd9c..7a1abaa 100644 --- a/include/Cubed/audio/audio_engine.hpp +++ b/include/Cubed/audio/audio_engine.hpp @@ -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: diff --git a/include/Cubed/audio/audio_error.hpp b/include/Cubed/audio/audio_error.hpp new file mode 100644 index 0000000..5b8617d --- /dev/null +++ b/include/Cubed/audio/audio_error.hpp @@ -0,0 +1,15 @@ +#pragma once +#include "Cubed/tools/log.hpp" + +#include +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 diff --git a/include/Cubed/gameplay/client_player.hpp b/include/Cubed/gameplay/client_player.hpp index d03b991..39ef411 100644 --- a/include/Cubed/gameplay/client_player.hpp +++ b/include/Cubed/gameplay/client_player.hpp @@ -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 diff --git a/include/Cubed/gameplay/client_world.hpp b/include/Cubed/gameplay/client_world.hpp index 2ea9316..7ecb736 100644 --- a/include/Cubed/gameplay/client_world.hpp +++ b/include/Cubed/gameplay/client_world.hpp @@ -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 void register_timer(std::string_view id, TickType threshold, Fn&& f) { m_timers.emplace(std::piecewise_construct, diff --git a/src/app.cpp b/src/app.cpp index 1d7d611..f5b72a5 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -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); } diff --git a/src/audio/audio_buffer.cpp b/src/audio/audio_buffer.cpp index 269759d..8f26068 100644 --- a/src/audio/audio_buffer.cpp +++ b/src/audio/audio_buffer.cpp @@ -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(data.pcm.size() * sizeof(int16_t)), + static_cast(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(data.pcm.size()) / (data.channels * data.sample_rate); } diff --git a/src/audio/audio_engine.cpp b/src/audio/audio_engine.cpp index 79531fa..ff644f1 100644 --- a/src/audio/audio_engine.cpp +++ b/src/audio/audio_engine.cpp @@ -1,5 +1,6 @@ #include "Cubed/audio/audio_engine.hpp" +#include "Cubed/tools/cubed_assert.hpp" #include "Cubed/tools/log.hpp" #include @@ -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) { diff --git a/src/audio/audio_loader.cpp b/src/audio/audio_loader.cpp index 5eaa762..8ad8e6d 100644 --- a/src/audio/audio_loader.cpp +++ b/src/audio/audio_loader.cpp @@ -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 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; } diff --git a/src/audio/audio_source.cpp b/src/audio/audio_source.cpp index 5a0766a..063ec82 100644 --- a/src/audio/audio_source.cpp +++ b/src/audio/audio_source.cpp @@ -1,5 +1,6 @@ #include "Cubed/audio/audio_source.hpp" +#include "Cubed/audio/audio_error.hpp" #include "Cubed/tools/log.hpp" #include @@ -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); } diff --git a/src/audio/sound_manager.cpp b/src/audio/sound_manager.cpp index 29eaf51..c57fd16 100644 --- a/src/audio/sound_manager.cpp +++ b/src/audio/sound_manager.cpp @@ -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 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); } } diff --git a/src/gameplay/client_player.cpp b/src/gameplay/client_player.cpp index da46ecc..5731a8e 100644 --- a/src/gameplay/client_player.cpp +++ b/src/gameplay/client_player.cpp @@ -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; diff --git a/src/gameplay/client_world.cpp b/src/gameplay/client_world.cpp index ba487fe..852010a 100644 --- a/src/gameplay/client_world.cpp +++ b/src/gameplay/client_world.cpp @@ -607,6 +607,8 @@ AABB ClientWorld::get_block_aabb(const glm::ivec3& pos) { static_cast(z + 1)}}; } +AudioEngine& ClientWorld::get_audio() { return m_audio; } + void ClientWorld::request_exit() { if (m_receive_exit) { return;