diff --git a/libs/audio/CMakeLists.txt b/libs/audio/CMakeLists.txt index 77dca757..d9d09945 100644 --- a/libs/audio/CMakeLists.txt +++ b/libs/audio/CMakeLists.txt @@ -5,4 +5,4 @@ file(GLOB_RECURSE PSEMEK_AUDIO_SOURCES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "s psemek_add_library(psemek-audio ${PSEMEK_AUDIO_HEADERS} ${PSEMEK_AUDIO_SOURCES}) target_include_directories(psemek-audio PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include") -target_link_libraries(psemek-audio PUBLIC psemek-sdl2 psemek-util psemek-log SDL2_mixer) +target_link_libraries(psemek-audio PUBLIC psemek-sdl2 psemek-geom psemek-util psemek-log SDL2_mixer) diff --git a/libs/audio/include/psemek/audio/3d.hpp b/libs/audio/include/psemek/audio/3d.hpp new file mode 100644 index 00000000..cf789d79 --- /dev/null +++ b/libs/audio/include/psemek/audio/3d.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include +#include + +#include +#include +#include + +namespace psemek::audio +{ + + struct listener_3d_mono + { + void set_position(geom::point const & position); + + virtual std::shared_ptr make_effect(geom::point const & position, float distance_factor); + + private: + geom::point position_; + std::mutex position_mutex_; + }; + +} diff --git a/libs/audio/source/3d.cpp b/libs/audio/source/3d.cpp new file mode 100644 index 00000000..35f40462 --- /dev/null +++ b/libs/audio/source/3d.cpp @@ -0,0 +1,68 @@ +#include +#include + +#include +#include + +namespace psemek::audio +{ + + namespace + { + + struct mono_impl + : effect + { + mono_impl(geom::point const & source_position, geom::point & target_position, std::mutex & target_position_mutex, float distance_factor) + : source_position_(source_position) + , target_position_(target_position) + , cached_target_position_(target_position) + , target_position_mutex_(target_position_mutex) + , distance_factor_(distance_factor) + {} + + std::string_view name() const override + { + return "mono_3d"; + } + + void init(int, int) override + { } + + void operator()(sample * data, std::size_t count) override + { + { + std::unique_lock lock{target_position_mutex_, std::try_to_lock}; + if (lock.owns_lock()) + cached_target_position_ = target_position_; + } + + float distance = geom::distance(cached_target_position_, source_position_) / distance_factor_; + float factor = std::min(1.f, 1.f / (1.f + distance * distance)); + + for (std::size_t i = 0; i < count; ++i) + data[i] = pack(unpack(data[i]) * factor); + } + + private: + geom::point source_position_; + geom::point & target_position_; + geom::point cached_target_position_; + std::mutex & target_position_mutex_; + float distance_factor_; + }; + + } + + void listener_3d_mono::set_position(geom::point const & position) + { + std::lock_guard lock{position_mutex_}; + position_ = position; + } + + std::shared_ptr listener_3d_mono::make_effect(const geom::point &position, float distance_factor) + { + return std::make_shared(position, position_, position_mutex_, distance_factor); + } + +}