From 59b96ddf95f50f91bf0dd82d9acb8a7ea6637352 Mon Sep 17 00:00:00 2001 From: khodowany Date: Mon, 14 Sep 2026 23:56:16 -0500 Subject: [PATCH] Formatting --- .gitea/workflows/ci.yml | 4 + README.md | 2 + conanfile.py | 8 -- include/sonus/config.hpp | 3 +- include/sonus/detail/errors.hpp | 7 +- include/sonus/engine.hpp | 30 ++---- modulus.py | 8 +- src/detail/errors.cpp | 3 +- src/detail/playback_devices.hpp | 1 + src/detail/render_snapshot.hpp | 37 ++++--- src/engine.cpp | 182 +++++++++++--------------------- test_package/conanfile.py | 5 - test_package/main.cpp | 1 + tests/control.cpp | 1 + tests/render_snapshot.cpp | 12 ++- tests/test.cpp | 55 ++-------- 16 files changed, 127 insertions(+), 232 deletions(-) diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 680d21b..b1116d1 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -48,6 +48,10 @@ jobs: restore-keys: conan-${{ runner.os }}- - name: Configure native release run: python3 modulus.py configure --target x86_64_gcc12_release + - name: Check code style + run: | + python3 -m pip install --no-cache-dir -r build/build_tools/docker/format-requirements.txt + python3 modulus.py format --check - name: Build native release run: python3 modulus.py build --target x86_64_gcc12_release - name: Test native release diff --git a/README.md b/README.md index 9d9131a..7216372 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,8 @@ Call `collect_finished()` periodically to release sounds that reach EOF without ## Build +Code style is managed by Modulus: run `./modulus.py format` or `./modulus.py format --check`. The generated Neovim integration uses the same pinned container formatter for C++ and Python, including existing format-on-save toggles. Configure first to prepare tooling; customize `tooling.editor.clang_format` and `tooling.format.exclude` in `modulus.json`, not generated editor files. See the shared Modulus README for the compact layout and no-alias policy. + Configure, build, and test the default target: ```sh diff --git a/conanfile.py b/conanfile.py index f1b1268..00f89ae 100644 --- a/conanfile.py +++ b/conanfile.py @@ -42,15 +42,12 @@ class sonus_conan(conan.ConanFile): "tests/*.cpp", "tests/*.hpp", ) - def config_options(self): if self.settings.os == "Windows": del self.options.fPIC - def configure(self): if self.options.shared: del self.options.fPIC - def requirements(self): self.requires( "modulus/latest", @@ -63,7 +60,6 @@ class sonus_conan(conan.ConanFile): transitive_headers=False, transitive_libs=False, ) - def generate(self): dependencies = conan.tools.cmake.CMakeDeps(self) dependencies.generate() @@ -73,14 +69,12 @@ class sonus_conan(conan.ConanFile): toolchain.variables["BUILD_SHARED_LIBS"] = bool(self.options.shared) toolchain.variables["BUILD_TESTING"] = bool(self.options.with_tests) toolchain.generate() - def build(self): cmake = conan.tools.cmake.CMake(self) cmake.configure() cmake.build() if self.options.with_tests and conan.tools.build.can_run(self): cmake.test(target="check") - def package_id(self): self.info.options.rm_safe("with_tests") for requirement in ( @@ -90,11 +84,9 @@ class sonus_conan(conan.ConanFile): ): if requirement in self.info.requires.pkg_names: self.info.requires.remove(requirement) - def package(self): cmake = conan.tools.cmake.CMake(self) cmake.install() - def package_info(self): self.cpp_info.set_property( "cmake_file_name", diff --git a/include/sonus/config.hpp b/include/sonus/config.hpp index 5f1a6b8..d54898b 100644 --- a/include/sonus/config.hpp +++ b/include/sonus/config.hpp @@ -6,6 +6,7 @@ #include + namespace sonus { enum class performance_profile : std::uint8_t { @@ -47,6 +48,4 @@ struct playback_options { std::bool_t stream{true}; }; -using sound_handle = std::uint64_t; - } diff --git a/include/sonus/detail/errors.hpp b/include/sonus/detail/errors.hpp index 8081665..89b2293 100644 --- a/include/sonus/detail/errors.hpp +++ b/include/sonus/detail/errors.hpp @@ -8,6 +8,7 @@ #include + namespace sonus::detail { constexpr std::int32_t error_invalid_argument{1}; @@ -18,13 +19,13 @@ constexpr std::int32_t error_internal{4}; auto make_error(std::int32_t code, std::string message, modulus::source_location location = modulus::source_location(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION())) -> modulus::error; auto fail_void(modulus::error error) -> std::expected; auto fail_void(std::int32_t code, std::string message, modulus::source_location location = modulus::source_location(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION())) -> std::expected; -auto fail_void(std::expected const& result) -> std::expected; +auto fail_void(std::expected const &result) -> std::expected; template auto fail(modulus::error error) -> std::expected; template -auto fail(std::expected const& result) -> std::expected; +auto fail(std::expected const &result) -> std::expected; template auto fail(std::int32_t code, std::string message, modulus::source_location location = modulus::source_location(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION())) -> std::expected; @@ -37,7 +38,7 @@ auto sonus::detail::fail(modulus::error error) -> std::expected -auto sonus::detail::fail(std::expected const& result) -> std::expected { +auto sonus::detail::fail(std::expected const &result) -> std::expected { assert(!result); return modulus::fail(result.error()); } diff --git a/include/sonus/engine.hpp b/include/sonus/engine.hpp index e3497a8..0bd4b46 100644 --- a/include/sonus/engine.hpp +++ b/include/sonus/engine.hpp @@ -11,47 +11,39 @@ namespace sonus { -auto validate(sonus::audio_config const& config) -> std::expected; -auto validate(sonus::metronome_config const& config) -> std::expected; -auto validate(sonus::playback_options const& options) -> std::expected; +auto validate(sonus::audio_config const &config) -> std::expected; +auto validate(sonus::metronome_config const &config) -> std::expected; +auto validate(sonus::playback_options const &options) -> std::expected; auto enumerate_playback_devices() -> std::expected, modulus::error>; class engine { public: static auto create(sonus::audio_config config = {}) -> std::expected; - - engine(sonus::engine const&) = delete; - auto operator=(sonus::engine const&) -> sonus::engine& = delete; - engine(sonus::engine&& other) noexcept; - auto operator=(sonus::engine&& other) noexcept -> sonus::engine&; + engine(sonus::engine const &) = delete; + auto operator=(sonus::engine const &) -> sonus::engine & = delete; + engine(sonus::engine &&other) noexcept; + auto operator=(sonus::engine &&other) noexcept -> sonus::engine &; ~engine(); - auto start() -> std::expected; auto stop() -> void; auto started() const -> std::bool_t; auto sample_rate() const -> std::uint32_t; auto channels() const -> std::uint32_t; auto set_master_volume(std::float32_t volume) -> std::expected; - - auto play_file(std::filesystem::path const& path, sonus::playback_options options = {}) -> std::expected; - auto stop(sonus::sound_handle handle) -> std::expected; + auto play_file(std::filesystem::path const &path, sonus::playback_options options = {}) -> std::expected; + auto stop(std::uint64_t handle) -> std::expected; auto stop_all() -> void; - auto is_playing(sonus::sound_handle handle) -> std::expected; + auto is_playing(std::uint64_t handle) -> std::expected; auto collect_finished() -> std::uint64_t; auto active_sound_count() -> std::uint64_t; - auto start_metronome(sonus::metronome_config config = {}) -> std::expected; auto update_metronome(sonus::metronome_config config) -> std::expected; auto stop_metronome() -> void; auto metronome_active() const -> std::bool_t; - - auto render(std::float32_t* output, std::uint64_t frame_count) -> std::expected; - + auto render(std::float32_t *output, std::uint64_t frame_count) -> std::expected; private: struct impl; - explicit engine(std::unique_ptr implementation) noexcept; - std::unique_ptr implementation_; }; diff --git a/modulus.py b/modulus.py index b27d44c..1b69392 100755 --- a/modulus.py +++ b/modulus.py @@ -16,6 +16,7 @@ COMMANDS = ( "package", "lsp", "clangd", + "format", ) COMMON_DIR = pathlib.Path("build") / "build_common" TOOLS_DIR = pathlib.Path("build") / "build_tools" @@ -60,6 +61,9 @@ def runtime_ready(root): and (root / TOOLS_DIR / "clangd.py").is_file() and (root / RUNTIME_DIR / "modulus" / "cli.py").is_file() and (root / RUNTIME_DIR / "modulus" / "export.py").is_file() + and (root / TOOLS_DIR / "format.py").is_file() + and (root / RUNTIME_DIR / "modulus" / "formatting.py").is_file() + and (root / RUNTIME_DIR / "modulus" / "format_layout.py").is_file() ) def optional_credentials(): @@ -340,9 +344,9 @@ def ensure_runtime(root): def delegate(command, argv): root = repo_root() - if command == "clangd": + if command in {"clangd", "format"}: if not runtime_ready(root): - print("Modulus clangd tooling is missing; run ./modulus.py configure first", file=sys.stderr) + print(f"Modulus {command} tooling is missing; run ./modulus.py configure first", file=sys.stderr) return 1 else: ensure_runtime(root) diff --git a/src/detail/errors.cpp b/src/detail/errors.cpp index f5df249..1bf6f35 100644 --- a/src/detail/errors.cpp +++ b/src/detail/errors.cpp @@ -8,6 +8,7 @@ #include + auto sonus::detail::make_error(std::int32_t code, std::string message, modulus::source_location location) -> modulus::error { return modulus::make_error("sonus", code, std::move(message), location); } @@ -20,7 +21,7 @@ auto sonus::detail::fail_void(std::int32_t code, std::string message, modulus::s return sonus::detail::fail_void(sonus::detail::make_error(code, std::move(message), location)); } -auto sonus::detail::fail_void(std::expected const& result) -> std::expected { +auto sonus::detail::fail_void(std::expected const &result) -> std::expected { assert(!result); return sonus::detail::fail_void(result.error()); } diff --git a/src/detail/playback_devices.hpp b/src/detail/playback_devices.hpp index b6bf639..fe52d95 100644 --- a/src/detail/playback_devices.hpp +++ b/src/detail/playback_devices.hpp @@ -7,6 +7,7 @@ #include + namespace sonus::detail { inline auto find_playback_device(std::span devices, std::string_view id, std::string_view name) -> std::optional { diff --git a/src/detail/render_snapshot.hpp b/src/detail/render_snapshot.hpp index d3141c1..b6ad9fd 100644 --- a/src/detail/render_snapshot.hpp +++ b/src/detail/render_snapshot.hpp @@ -6,36 +6,41 @@ #include #include + namespace sonus::detail { // Publishers/collectors must be serialized; readers never lock or destroy snapshots. -template + +template class render_snapshot { static_assert(std::atomic::is_always_lock_free); - static_assert(std::atomic::is_always_lock_free); - + static_assert(std::atomic::is_always_lock_free); public: class read_guard { public: - explicit read_guard(render_snapshot& owner) : owner_(owner) { + explicit read_guard(render_snapshot &owner) + : owner_(owner) { owner_.active_render_count_.fetch_add(1, std::memory_order_seq_cst); value_ = owner_.active_.load(std::memory_order_seq_cst); } - read_guard(read_guard const&) = delete; - auto operator=(read_guard const&) -> read_guard& = delete; + read_guard(read_guard const &) = delete; + auto operator=(read_guard const &) -> read_guard & = delete; ~read_guard() { owner_.active_render_count_.fetch_sub(1, std::memory_order_seq_cst); } - auto get() const -> T const* { return value_; } - + auto get() const -> T const * { + return value_; + } private: - render_snapshot& owner_; - T const* value_{}; + render_snapshot &owner_; + T const *value_{}; }; - - auto read() -> read_guard { return read_guard{*this}; } - auto current() const -> T const* { return current_.get(); } - + auto read() -> read_guard { + return read_guard{*this}; + } + auto current() const -> T const * { + return current_.get(); + } auto publish(std::unique_ptr next) -> void { if (current_) { retired_.push_back(std::move(current_)); @@ -44,7 +49,6 @@ public: active_.store(current_.get(), std::memory_order_seq_cst); collect(); } - auto collect() -> void { // SC orders publication/count observation against reader entry/pointer load: // a reader either contributes to the count or sees the new snapshot. @@ -52,11 +56,10 @@ public: retired_.clear(); } } - private: std::unique_ptr current_{}; std::vector> retired_{}; - std::atomic active_{nullptr}; + std::atomic active_{nullptr}; std::atomic active_render_count_{0}; }; diff --git a/src/engine.cpp b/src/engine.cpp index 0f99e79..2b91d7e 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -26,6 +26,7 @@ #include "detail/render_snapshot.hpp" #include "detail/playback_devices.hpp" + namespace { constexpr auto pi = 3.141592653589793238462643383279502884; @@ -39,7 +40,7 @@ auto unavailable(std::string message) -> modulus::error { } auto miniaudio_error(ma_result result, std::string action) -> modulus::error { - auto const* description = ma_result_description(result); + auto const *description = ma_result_description(result); auto message = std::move(action); if (description != nullptr && std::string_view{description} != "No error") { message += ": "; @@ -60,7 +61,7 @@ auto contains_null(std::string_view value) -> std::bool_t { return value.find('\0') != std::string_view::npos; } -auto make_playback_device_id(ma_uint32 index, ma_device_info const& info) -> std::string { +auto make_playback_device_id(ma_uint32 index, ma_device_info const &info) -> std::string { auto result = std::to_string(index); result += ':'; result += (info.isDefault == MA_TRUE ? '1' : '0'); @@ -69,7 +70,7 @@ auto make_playback_device_id(ma_uint32 index, ma_device_info const& info) -> std return result; } -auto describe_playback_devices(ma_device_info const* devices, ma_uint32 count) -> std::vector { +auto describe_playback_devices(ma_device_info const *devices, ma_uint32 count) -> std::vector { auto result = std::vector{}; result.reserve(count); for (auto index = ma_uint32{}; index < count; ++index) { @@ -84,10 +85,10 @@ auto describe_playback_devices(ma_device_info const* devices, ma_uint32 count) - auto to_miniaudio_profile(sonus::performance_profile profile) -> ma_performance_profile { switch (profile) { - case sonus::performance_profile::LOW_LATENCY: - return ma_performance_profile_low_latency; - case sonus::performance_profile::CONSERVATIVE: - return ma_performance_profile_conservative; + case sonus::performance_profile::LOW_LATENCY: + return ma_performance_profile_low_latency; + case sonus::performance_profile::CONSERVATIVE: + return ma_performance_profile_conservative; } return ma_performance_profile_low_latency; } @@ -110,21 +111,18 @@ struct active_sound { std::bool_t initialized{false}; std::bool_t loop{false}; std::atomic_bool finished{false}; - active_sound() = default; - active_sound(active_sound const&) = delete; - auto operator=(active_sound const&) -> active_sound& = delete; - active_sound(active_sound&&) = delete; - auto operator=(active_sound&&) -> active_sound& = delete; - + active_sound(active_sound const &) = delete; + auto operator=(active_sound const &) -> active_sound & = delete; + active_sound(active_sound &&) = delete; + auto operator=(active_sound &&) -> active_sound & = delete; ~active_sound() { if (initialized) { ma_sound_uninit(&sound); } } - - static auto end_callback(void* user_data, ma_sound*) -> void { - auto* self = static_cast(user_data); + static auto end_callback(void *user_data, ma_sound *) -> void { + auto *self = static_cast(user_data); if (self != nullptr) { self->finished.store(true, std::memory_order_release); } @@ -134,11 +132,9 @@ struct active_sound { struct temporary_context { ma_context context{}; std::bool_t initialized{false}; - temporary_context() = default; - temporary_context(temporary_context const&) = delete; - auto operator=(temporary_context const&) -> temporary_context& = delete; - + temporary_context(temporary_context const &) = delete; + auto operator=(temporary_context const &) -> temporary_context & = delete; ~temporary_context() { if (initialized) { ma_context_uninit(&context); @@ -169,32 +165,26 @@ struct sonus::engine::impl { std::bool_t started{false}; mutable std::mutex mutex{}; mutable std::mutex render_mutex{}; - std::unordered_map> sounds{}; - sonus::sound_handle next_sound_handle{1}; - + std::unordered_map> sounds{}; + std::uint64_t next_sound_handle{1}; sonus::detail::render_snapshot metronome_configs{}; std::atomic_bool metronome_enabled{false}; std::uint32_t next_metronome_generation{1}; - std::uint32_t observed_metronome_generation{0}; std::uint32_t beat_index{0}; std::uint64_t frames_until_next_beat{0}; std::size_t click_frame_index{0}; std::size_t click_frames_remaining{0}; std::bool_t click_is_downbeat{false}; - impl() = default; - impl(impl const&) = delete; - auto operator=(impl const&) -> impl& = delete; - + impl(impl const &) = delete; + auto operator=(impl const &) -> impl & = delete; ~impl() { shutdown(); } - auto initialize(sonus::audio_config value) -> std::expected { config = std::move(value); publish_metronome_locked(make_disabled_metronome_config_locked()); - auto engine_config = ma_engine_config_init(); engine_config.noDevice = MA_TRUE; engine_config.channels = config.channels; @@ -202,19 +192,16 @@ struct sonus::engine::impl { engine_config.periodSizeInFrames = config.period_size_frames; engine_config.periodSizeInMilliseconds = config.period_size_milliseconds; engine_config.noAutoStart = MA_TRUE; - auto result = ma_engine_init(&engine_config, &mixer); if (result != MA_SUCCESS) { return sonus::detail::fail_void(miniaudio_error(result, "failed to initialize miniaudio engine")); } mixer_initialized = true; - result = ma_engine_set_volume(&mixer, config.master_volume); if (result != MA_SUCCESS) { shutdown(); return sonus::detail::fail_void(miniaudio_error(result, "failed to set engine volume")); } - if (!config.no_device) { auto device_config = ma_device_config_init(ma_device_type_playback); device_config.playback.format = ma_format_f32; @@ -226,13 +213,11 @@ struct sonus::engine::impl { device_config.performanceProfile = to_miniaudio_profile(config.performance); device_config.dataCallback = sonus::engine::impl::device_callback; device_config.pUserData = this; - auto selected = configure_playback_device(device_config); if (!selected) { shutdown(); return selected; } - result = ma_device_init(context_initialized ? &context : nullptr, &device_config, &device); if (result != MA_SUCCESS) { shutdown(); @@ -240,10 +225,8 @@ struct sonus::engine::impl { } device_initialized = true; } - return {}; } - auto start() -> std::expected { auto lock = std::scoped_lock{mutex}; if (started) { @@ -263,7 +246,6 @@ struct sonus::engine::impl { started = true; return {}; } - auto stop_device() -> void { auto lock = std::scoped_lock{mutex}; if (!started) { @@ -275,7 +257,6 @@ struct sonus::engine::impl { started = false; collect_retired_metronome_configs_locked(); } - auto shutdown() -> void { auto lock = std::scoped_lock{mutex}; if (device_initialized) { @@ -298,26 +279,22 @@ struct sonus::engine::impl { metronome_enabled.store(false, std::memory_order_release); reset_metronome_render_state(); } - - auto configure_playback_device(ma_device_config& device_config) -> std::expected { + auto configure_playback_device(ma_device_config &device_config) -> std::expected { if (config.playback_device_id.empty() && config.playback_device_name.empty()) { return {}; } - auto context_config = ma_context_config_init(); auto result = ma_context_init(nullptr, 0, &context_config, &context); if (result != MA_SUCCESS) { return sonus::detail::fail_void(miniaudio_error(result, "failed to initialize miniaudio context")); } context_initialized = true; - - ma_device_info* playback_devices = nullptr; + ma_device_info *playback_devices = nullptr; auto playback_device_count = ma_uint32{}; result = ma_context_get_devices(&context, &playback_devices, &playback_device_count, nullptr, nullptr); if (result != MA_SUCCESS) { return sonus::detail::fail_void(miniaudio_error(result, "failed to enumerate playback devices")); } - auto devices = describe_playback_devices(playback_devices, playback_device_count); auto selected = sonus::detail::find_playback_device(devices, config.playback_device_id, config.playback_device_name); if (selected) { @@ -325,16 +302,13 @@ struct sonus::engine::impl { device_config.playback.pDeviceID = &playback_device_id; return {}; } - auto selector = config.playback_device_id.empty() ? config.playback_device_name : config.playback_device_id; return sonus::detail::fail_void(sonus::detail::error_not_found, "playback device not found: " + selector); } - auto set_master_volume(std::float32_t volume) -> std::expected { if (!valid_unit_interval(volume)) { return sonus::detail::fail_void(invalid("audio master_volume must be between 0 and 1")); } - auto lock = std::scoped_lock{mutex}; auto result = ma_engine_set_volume(&mixer, volume); if (result != MA_SUCCESS) { @@ -343,55 +317,49 @@ struct sonus::engine::impl { config.master_volume = volume; return {}; } - - auto play_file(std::filesystem::path const& path, sonus::playback_options options) -> std::expected { + auto play_file(std::filesystem::path const &path, sonus::playback_options options) -> std::expected { if (path.empty()) { - return sonus::detail::fail(sonus::detail::error_invalid_argument, "sound path must not be empty"); + return sonus::detail::fail(sonus::detail::error_invalid_argument, "sound path must not be empty"); } auto valid_options = sonus::validate(options); if (!valid_options) { - return sonus::detail::fail(valid_options.error()); + return sonus::detail::fail(valid_options.error()); } auto file_error = std::error_code{}; if (!std::filesystem::is_regular_file(path, file_error)) { - return sonus::detail::fail(sonus::detail::make_error(sonus::detail::error_not_found, "sound file not found: " + path.string())); + return sonus::detail::fail(sonus::detail::make_error(sonus::detail::error_not_found, "sound file not found: " + path.string())); } - auto sound = std::make_unique(); sound->loop = options.loop; auto const path_text = path.string(); auto flags = static_cast(MA_SOUND_FLAG_NO_SPATIALIZATION); flags |= options.stream ? MA_SOUND_FLAG_STREAM : MA_SOUND_FLAG_DECODE; - auto lock = std::scoped_lock{mutex}; static_cast(collect_finished_locked()); collect_retired_metronome_configs_locked(); - auto result = ma_sound_init_from_file(&mixer, path_text.c_str(), flags, nullptr, nullptr, &sound->sound); if (result != MA_SUCCESS) { - return sonus::detail::fail(miniaudio_error(result, "failed to load sound file")); + return sonus::detail::fail(miniaudio_error(result, "failed to load sound file")); } sound->initialized = true; result = ma_sound_set_end_callback(&sound->sound, active_sound::end_callback, sound.get()); if (result != MA_SUCCESS) { - return sonus::detail::fail(miniaudio_error(result, "failed to set sound end callback")); + return sonus::detail::fail(miniaudio_error(result, "failed to set sound end callback")); } ma_sound_set_volume(&sound->sound, options.volume); ma_sound_set_looping(&sound->sound, options.loop ? MA_TRUE : MA_FALSE); result = ma_sound_start(&sound->sound); if (result != MA_SUCCESS) { - return sonus::detail::fail(miniaudio_error(result, "failed to start sound file")); + return sonus::detail::fail(miniaudio_error(result, "failed to start sound file")); } - auto handle = allocate_sound_handle_locked(); if (!handle) { - return sonus::detail::fail(handle.error()); + return sonus::detail::fail(handle.error()); } sounds.emplace(*handle, std::move(sound)); return *handle; } - - auto stop_sound(sonus::sound_handle handle) -> std::expected { + auto stop_sound(std::uint64_t handle) -> std::expected { if (handle == 0) { return sonus::detail::fail_void(sonus::detail::error_invalid_argument, "sound handle must not be zero"); } @@ -404,16 +372,14 @@ struct sonus::engine::impl { sounds.erase(found); return {}; } - auto stop_all_sounds() -> void { auto lock = std::scoped_lock{mutex}; - for (auto& entry : sounds) { + for (auto &entry : sounds) { static_cast(ma_sound_stop(&entry.second->sound)); } sounds.clear(); } - - auto is_sound_playing(sonus::sound_handle handle) -> std::expected { + auto is_sound_playing(std::uint64_t handle) -> std::expected { if (handle == 0) { return sonus::detail::fail(sonus::detail::error_invalid_argument, "sound handle must not be zero"); } @@ -428,65 +394,54 @@ struct sonus::engine::impl { } return ma_sound_is_playing(&found->second->sound) == MA_TRUE; } - auto collect_finished_sounds() -> std::uint64_t { auto lock = std::scoped_lock{mutex}; auto const collected = collect_finished_locked(); collect_retired_metronome_configs_locked(); return collected; } - auto active_sound_count() -> std::uint64_t { auto lock = std::scoped_lock{mutex}; static_cast(collect_finished_locked()); collect_retired_metronome_configs_locked(); return sounds.size(); } - auto store_metronome(sonus::metronome_config value, std::bool_t enable) -> std::expected { auto valid = sonus::validate(value); if (!valid) { return valid; } - auto lock = std::scoped_lock{mutex}; return publish_metronome_config_locked(value, enable); } - auto update_metronome(sonus::metronome_config value) -> std::expected { auto valid = sonus::validate(value); if (!valid) { return valid; } - auto lock = std::scoped_lock{mutex}; - auto const* current = metronome_configs.current(); + auto const *current = metronome_configs.current(); auto const enable = current != nullptr && current->enabled; return publish_metronome_config_locked(value, enable); } - auto stop_metronome() -> void { auto lock = std::scoped_lock{mutex}; publish_metronome_locked(make_disabled_metronome_config_locked()); collect_retired_metronome_configs_locked(); } - auto publish_metronome_config_locked(sonus::metronome_config value, std::bool_t enable) -> std::expected { auto next = make_metronome_config(value, enable); if (!next) { return sonus::detail::fail_void(next.error()); } - publish_metronome_locked(std::move(*next)); collect_retired_metronome_configs_locked(); return {}; } - auto make_metronome_config(sonus::metronome_config value, std::bool_t enable) -> std::expected, modulus::error> { auto click_frames = static_cast(config.sample_rate) * static_cast(value.click_duration.count()) / 1000U; click_frames = std::clamp(click_frames, 1U, std::numeric_limits::max()); auto frames_per_beat = std::max(1U, static_cast(std::llround((static_cast(config.sample_rate) * 60.0) / static_cast(value.bpm)))); - auto result = std::make_unique(); result->enabled = enable; result->beats_per_bar = value.beats_per_bar; @@ -497,33 +452,27 @@ struct sonus::engine::impl { } return std::move(result); } - auto make_disabled_metronome_config_locked() -> std::unique_ptr { auto result = std::make_unique(); result->enabled = false; return result; } - auto publish_metronome_locked(std::unique_ptr next) -> void { next->generation = next_metronome_generation++; if (next_metronome_generation == 0U) { next_metronome_generation = 1U; } - auto const enabled = next->enabled; metronome_configs.publish(std::move(next)); metronome_enabled.store(enabled, std::memory_order_release); } - auto collect_retired_metronome_configs_locked() -> void { metronome_configs.collect(); } - - auto allocate_sound_handle_locked() -> std::expected { - if (sounds.size() >= static_cast(std::numeric_limits::max() - 1U)) { - return sonus::detail::fail(sonus::detail::error_internal, "sound handle space exhausted"); + auto allocate_sound_handle_locked() -> std::expected { + if (sounds.size() >= static_cast(std::numeric_limits::max() - 1U)) { + return sonus::detail::fail(sonus::detail::error_internal, "sound handle space exhausted"); } - auto attempts = std::size_t{}; auto const max_attempts = sounds.size() + 1U; while (attempts < max_attempts) { @@ -536,14 +485,11 @@ struct sonus::engine::impl { } ++attempts; } - - return sonus::detail::fail(sonus::detail::error_internal, "failed to allocate sound handle"); + return sonus::detail::fail(sonus::detail::error_internal, "failed to allocate sound handle"); } - - static auto sound_finished(active_sound const& sound) -> std::bool_t { + static auto sound_finished(active_sound const &sound) -> std::bool_t { return !sound.loop && (sound.finished.load(std::memory_order_acquire) || ma_sound_at_end(&sound.sound) == MA_TRUE); } - auto collect_finished_locked() -> std::uint64_t { auto collected = std::uint64_t{}; auto current = sounds.begin(); @@ -557,14 +503,11 @@ struct sonus::engine::impl { } return collected; } - - auto render_to(std::float32_t* output, std::uint64_t frame_count) -> ma_result { + auto render_to(std::float32_t *output, std::uint64_t frame_count) -> ma_result { if (output == nullptr || frame_count == 0U) { return MA_SUCCESS; } - auto guard = metronome_configs.read(); - auto const sample_count = frame_count * config.channels; std::fill(output, output + sample_count, 0.0F); auto result = ma_engine_read_pcm_frames(&mixer, output, frame_count, nullptr); @@ -575,8 +518,7 @@ struct sonus::engine::impl { mix_metronome(output, frame_count, guard.get()); return MA_SUCCESS; } - - auto mix_metronome(std::float32_t* output, std::uint64_t frame_count, metronome_render_config const* metro) -> void { + auto mix_metronome(std::float32_t *output, std::uint64_t frame_count, metronome_render_config const *metro) -> void { if (metro == nullptr || !metro->enabled) { if (metro != nullptr) { observed_metronome_generation = metro->generation; @@ -588,7 +530,6 @@ struct sonus::engine::impl { observed_metronome_generation = metro->generation; reset_metronome_render_state(); } - for (auto frame = std::uint64_t{}; frame < frame_count; ++frame) { if (frames_until_next_beat == 0U) { auto const downbeat = beat_index == 0U; @@ -598,10 +539,9 @@ struct sonus::engine::impl { beat_index = (beat_index + 1U) % std::max(1U, metro->beats_per_bar); frames_until_next_beat = metro->frames_per_beat; } - auto sample = 0.0F; if (click_frames_remaining > 0U) { - auto const& click = click_is_downbeat ? metro->downbeat_click : metro->beat_click; + auto const &click = click_is_downbeat ? metro->downbeat_click : metro->beat_click; if (click_frame_index < click.size()) { sample = click[click_frame_index]; ++click_frame_index; @@ -610,9 +550,8 @@ struct sonus::engine::impl { click_frames_remaining = 0; } } - if (sample != 0.0F) { - auto* frame_out = output + frame * config.channels; + auto *frame_out = output + frame * config.channels; for (auto channel = std::uint32_t{}; channel < config.channels; ++channel) { auto const mixed = static_cast(frame_out[channel] + sample); frame_out[channel] = std::clamp(mixed, static_cast(-1.0F), static_cast(1.0F)); @@ -621,7 +560,6 @@ struct sonus::engine::impl { --frames_until_next_beat; } } - auto reset_metronome_render_state() -> void { beat_index = 0; frames_until_next_beat = 0; @@ -629,13 +567,12 @@ struct sonus::engine::impl { click_frames_remaining = 0; click_is_downbeat = false; } - - static auto device_callback(ma_device* device, void* output, void const*, ma_uint32 frame_count) -> void { - auto* self = static_cast(device == nullptr ? nullptr : device->pUserData); + static auto device_callback(ma_device *device, void *output, void const *, ma_uint32 frame_count) -> void { + auto *self = static_cast(device == nullptr ? nullptr : device->pUserData); if (self == nullptr || output == nullptr) { return; } - auto result = self->render_to(static_cast(output), frame_count); + auto result = self->render_to(static_cast(output), frame_count); if (result != MA_SUCCESS) { auto const sample_count = static_cast(frame_count) * self->config.channels; std::memset(output, 0, static_cast(sample_count * sizeof(std::float32_t))); @@ -643,7 +580,7 @@ struct sonus::engine::impl { } }; -auto sonus::validate(sonus::audio_config const& config) -> std::expected { +auto sonus::validate(sonus::audio_config const &config) -> std::expected { if (config.sample_rate < 8000U || config.sample_rate > 384000U) { return sonus::detail::fail_void(invalid("audio sample_rate must be between 8000 and 384000")); } @@ -685,18 +622,16 @@ auto sonus::enumerate_playback_devices() -> std::expected>(miniaudio_error(result, "failed to initialize miniaudio context")); } context.initialized = true; - - ma_device_info* playback_devices = nullptr; + ma_device_info *playback_devices = nullptr; auto playback_device_count = ma_uint32{}; result = ma_context_get_devices(&context.context, &playback_devices, &playback_device_count, nullptr, nullptr); if (result != MA_SUCCESS) { return sonus::detail::fail>(miniaudio_error(result, "failed to enumerate playback devices")); } - return describe_playback_devices(playback_devices, playback_device_count); } -auto sonus::validate(sonus::metronome_config const& config) -> std::expected { +auto sonus::validate(sonus::metronome_config const &config) -> std::expected { if (config.bpm == 0U || config.bpm > 400U) { return sonus::detail::fail_void(invalid("metronome bpm must be between 1 and 400")); } @@ -715,7 +650,7 @@ auto sonus::validate(sonus::metronome_config const& config) -> std::expected std::expected { +auto sonus::validate(sonus::playback_options const &options) -> std::expected { if (!valid_unit_interval(options.volume)) { return sonus::detail::fail_void(invalid("playback volume must be between 0 and 1")); } @@ -735,11 +670,12 @@ auto sonus::engine::create(sonus::audio_config config) -> std::expected implementation) noexcept : implementation_{std::move(implementation)} {} +sonus::engine::engine(std::unique_ptr implementation) noexcept + : implementation_{std::move(implementation)} {} -sonus::engine::engine(sonus::engine&& other) noexcept = default; +sonus::engine::engine(sonus::engine &&other) noexcept = default; -auto sonus::engine::operator=(sonus::engine&& other) noexcept -> sonus::engine& = default; +auto sonus::engine::operator=(sonus::engine &&other) noexcept -> sonus::engine & = default; sonus::engine::~engine() = default; @@ -779,14 +715,14 @@ auto sonus::engine::set_master_volume(std::float32_t volume) -> std::expectedset_master_volume(volume); } -auto sonus::engine::play_file(std::filesystem::path const& path, sonus::playback_options options) -> std::expected { +auto sonus::engine::play_file(std::filesystem::path const &path, sonus::playback_options options) -> std::expected { if (!implementation_) { - return sonus::detail::fail(sonus::detail::error_invalid_argument, "audio engine is empty"); + return sonus::detail::fail(sonus::detail::error_invalid_argument, "audio engine is empty"); } return implementation_->play_file(path, options); } -auto sonus::engine::stop(sonus::sound_handle handle) -> std::expected { +auto sonus::engine::stop(std::uint64_t handle) -> std::expected { if (!implementation_) { return sonus::detail::fail_void(sonus::detail::error_invalid_argument, "audio engine is empty"); } @@ -799,7 +735,7 @@ auto sonus::engine::stop_all() -> void { } } -auto sonus::engine::is_playing(sonus::sound_handle handle) -> std::expected { +auto sonus::engine::is_playing(std::uint64_t handle) -> std::expected { if (!implementation_) { return sonus::detail::fail(sonus::detail::error_invalid_argument, "audio engine is empty"); } @@ -838,7 +774,7 @@ auto sonus::engine::metronome_active() const -> std::bool_t { return implementation_ && implementation_->metronome_enabled.load(std::memory_order_acquire); } -auto sonus::engine::render(std::float32_t* output, std::uint64_t frame_count) -> std::expected { +auto sonus::engine::render(std::float32_t *output, std::uint64_t frame_count) -> std::expected { if (!implementation_) { return sonus::detail::fail_void(sonus::detail::error_invalid_argument, "audio engine is empty"); } diff --git a/test_package/conanfile.py b/test_package/conanfile.py index 348f184..da9d9c3 100644 --- a/test_package/conanfile.py +++ b/test_package/conanfile.py @@ -4,23 +4,18 @@ import conan import conan.tools.build import conan.tools.cmake - class sonus_test_package(conan.ConanFile): settings = "os", "arch", "compiler", "build_type" generators = "CMakeDeps", "CMakeToolchain" test_type = "explicit" - def requirements(self): self.requires(self.tested_reference_str) - def layout(self): conan.tools.cmake.cmake_layout(self) - def build(self): cmake = conan.tools.cmake.CMake(self) cmake.configure() cmake.build() - def test(self): if conan.tools.build.can_run(self): self.run(os.path.join(self.cpp.build.bindirs[0], "sonus-consumer"), env="conanrun") diff --git a/test_package/main.cpp b/test_package/main.cpp index d6f39fa..0a1e13f 100644 --- a/test_package/main.cpp +++ b/test_package/main.cpp @@ -3,6 +3,7 @@ #include #include + auto main() -> int { auto config = sonus::audio_config{}; config.no_device = true; diff --git a/tests/control.cpp b/tests/control.cpp index 9c98a2f..7d83dc4 100644 --- a/tests/control.cpp +++ b/tests/control.cpp @@ -8,6 +8,7 @@ #include #include "detail/playback_devices.hpp" + BOOST_AUTO_TEST_CASE(sonus_updates_cannot_undo_concurrent_start_or_stop) { auto config = sonus::audio_config{}; config.no_device = true; diff --git a/tests/render_snapshot.cpp b/tests/render_snapshot.cpp index c83ceff..cca21c0 100644 --- a/tests/render_snapshot.cpp +++ b/tests/render_snapshot.cpp @@ -8,16 +8,20 @@ #include "detail/render_snapshot.hpp" + namespace { struct snapshot { - std::atomic& live; + std::atomic &live; std::array samples{}; - explicit snapshot(std::atomic& count, int value = 0) : live(count) { + explicit snapshot(std::atomic &count, int value = 0) + : live(count) { ++live; samples.fill(value); } - ~snapshot() { --live; } + ~snapshot() { + --live; + } }; } @@ -66,7 +70,7 @@ BOOST_AUTO_TEST_CASE(sonus_snapshot_publication_overlaps_readers) { start.arrive_and_wait(); for (auto index = 0; index < 20000; ++index) { auto guard = state.read(); - auto const* value = guard.get(); + auto const *value = guard.get(); for (auto sample : value->samples) { if (sample != value->samples.front()) { failed.store(true); diff --git a/tests/test.cpp b/tests/test.cpp index 1097db9..501389d 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -15,6 +15,7 @@ #include + namespace { constexpr auto pi = 3.141592653589793238462643383279502884; @@ -29,7 +30,7 @@ auto test_file(std::string_view name) -> std::filesystem::path { return std::filesystem::temp_directory_path() / name; } -auto peak(std::vector const& samples, std::size_t begin_frame, std::size_t frame_count, std::size_t channels) -> std::float32_t { +auto peak(std::vector const &samples, std::size_t begin_frame, std::size_t frame_count, std::size_t channels) -> std::float32_t { auto result = std::float32_t{}; auto const begin = begin_frame * channels; auto const end = std::min(samples.size(), begin + frame_count * channels); @@ -39,11 +40,11 @@ auto peak(std::vector const& samples, std::size_t begin_frame, s return result; } -auto write_bytes(std::ofstream& output, std::string_view value) -> void { +auto write_bytes(std::ofstream &output, std::string_view value) -> void { output.write(value.data(), static_cast(value.size())); } -auto write_u16_le(std::ofstream& output, std::uint16_t value) -> void { +auto write_u16_le(std::ofstream &output, std::uint16_t value) -> void { auto bytes = std::array{ static_cast(value & 0xFFU), static_cast((value >> 8U) & 0xFFU), @@ -51,7 +52,7 @@ auto write_u16_le(std::ofstream& output, std::uint16_t value) -> void { output.write(bytes.data(), static_cast(bytes.size())); } -auto write_u32_le(std::ofstream& output, std::uint32_t value) -> void { +auto write_u32_le(std::ofstream &output, std::uint32_t value) -> void { auto bytes = std::array{ static_cast(value & 0xFFU), static_cast((value >> 8U) & 0xFFU), @@ -61,16 +62,14 @@ auto write_u32_le(std::ofstream& output, std::uint32_t value) -> void { output.write(bytes.data(), static_cast(bytes.size())); } -auto write_test_wav(std::filesystem::path const& path, std::uint32_t sample_rate, std::uint16_t channels, std::uint32_t frame_count, double frequency_hz) -> void { +auto write_test_wav(std::filesystem::path const &path, std::uint32_t sample_rate, std::uint16_t channels, std::uint32_t frame_count, double frequency_hz) -> void { auto output = std::ofstream{path, std::ios::binary | std::ios::trunc}; BOOST_REQUIRE(output.good()); - auto const bits_per_sample = std::uint16_t{16}; auto const bytes_per_sample = bits_per_sample / 8U; auto const block_align = static_cast(channels * bytes_per_sample); auto const byte_rate = sample_rate * block_align; auto const data_size = frame_count * block_align; - write_bytes(output, "RIFF"); write_u32_le(output, 36U + data_size); write_bytes(output, "WAVE"); @@ -84,7 +83,6 @@ auto write_test_wav(std::filesystem::path const& path, std::uint32_t sample_rate write_u16_le(output, bits_per_sample); write_bytes(output, "data"); write_u32_le(output, data_size); - for (auto frame = std::uint32_t{}; frame < frame_count; ++frame) { auto const t = static_cast(frame) / static_cast(sample_rate); auto const sample = static_cast(std::sin(2.0 * pi * frequency_hz * t) * 12000.0); @@ -92,7 +90,6 @@ auto write_test_wav(std::filesystem::path const& path, std::uint32_t sample_rate write_u16_le(output, static_cast(sample)); } } - BOOST_REQUIRE(output.good()); } @@ -101,7 +98,6 @@ auto write_test_wav(std::filesystem::path const& path, std::uint32_t sample_rate BOOST_AUTO_TEST_CASE(sonus_validates_configs) { auto audio = sonus::audio_config{}; BOOST_TEST(static_cast(sonus::validate(audio))); - audio.sample_rate = 0; BOOST_TEST(!sonus::validate(audio)); audio = {}; @@ -136,7 +132,6 @@ BOOST_AUTO_TEST_CASE(sonus_validates_configs) { audio = {}; audio.playback_device_name.assign("a\0b", 3); BOOST_TEST(!sonus::validate(audio)); - auto metronome = sonus::metronome_config{}; BOOST_TEST(static_cast(sonus::validate(metronome))); metronome.bpm = 0; @@ -155,13 +150,11 @@ BOOST_AUTO_TEST_CASE(sonus_playback_devices_can_be_enumerated) { BOOST_TEST(!enumerated.error().message().empty()); return; } - - for (auto const& device : *enumerated) { + for (auto const &device : *enumerated) { BOOST_TEST(!device.id.empty()); BOOST_TEST(device.id.find('\0') == std::string::npos); BOOST_TEST(device.name.find('\0') == std::string::npos); } - if (!enumerated->empty()) { auto config = sonus::audio_config{}; config.playback_device_id = enumerated->front().id; @@ -172,11 +165,9 @@ BOOST_AUTO_TEST_CASE(sonus_playback_devices_can_be_enumerated) { BOOST_AUTO_TEST_CASE(sonus_no_device_engine_renders_silence_when_idle) { auto created = sonus::engine::create(no_device_config()); BOOST_REQUIRE(created); - auto samples = std::vector(2048U * created->channels(), 1.0F); auto rendered = created->render(samples.data(), 2048U); BOOST_REQUIRE(rendered); - BOOST_TEST(std::all_of(samples.begin(), samples.end(), [](auto sample) { return sample == 0.0F; })); @@ -185,7 +176,6 @@ BOOST_AUTO_TEST_CASE(sonus_no_device_engine_renders_silence_when_idle) { BOOST_AUTO_TEST_CASE(sonus_master_volume_can_be_changed_concurrently) { auto created = sonus::engine::create(no_device_config()); BOOST_REQUIRE(created); - auto failed = std::atomic_bool{false}; auto volume_worker = [&created, &failed](std::uint32_t offset) { for (auto index = std::uint32_t{}; index < 250U; ++index) { @@ -203,14 +193,12 @@ BOOST_AUTO_TEST_CASE(sonus_master_volume_can_be_changed_concurrently) { } } }; - auto first = std::thread{volume_worker, 0U}; auto second = std::thread{volume_worker, 37U}; auto renderer = std::thread{render_worker}; first.join(); second.join(); renderer.join(); - BOOST_TEST(!failed.load(std::memory_order_acquire)); BOOST_TEST(!created->set_master_volume(-0.01F)); BOOST_TEST(!created->set_master_volume(1.01F)); @@ -222,21 +210,17 @@ BOOST_AUTO_TEST_CASE(sonus_metronome_renders_accented_clicks) { config.channels = 2; auto created = sonus::engine::create(config); BOOST_REQUIRE(created); - auto metro = sonus::metronome_config{}; metro.bpm = 120; metro.beats_per_bar = 4; metro.volume = 0.70F; metro.click_duration = std::chrono::milliseconds{25}; BOOST_REQUIRE(created->start_metronome(metro)); - auto samples = std::vector(config.sample_rate * config.channels); BOOST_REQUIRE(created->render(samples.data(), config.sample_rate)); - auto downbeat_peak = peak(samples, 0, 2400, config.channels); auto beat_peak = peak(samples, config.sample_rate / 2, 2400, config.channels); auto between_peak = peak(samples, config.sample_rate / 4, 2400, config.channels); - BOOST_TEST(downbeat_peak > 0.2F); BOOST_TEST(beat_peak > 0.1F); BOOST_TEST(downbeat_peak > beat_peak * 1.2F); @@ -246,12 +230,10 @@ BOOST_AUTO_TEST_CASE(sonus_metronome_renders_accented_clicks) { BOOST_AUTO_TEST_CASE(sonus_metronome_update_keeps_inactive_metronome_stopped) { auto created = sonus::engine::create(no_device_config()); BOOST_REQUIRE(created); - auto metro = sonus::metronome_config{}; metro.bpm = 140; BOOST_REQUIRE(created->update_metronome(metro)); BOOST_TEST(!created->metronome_active()); - BOOST_REQUIRE(created->start_metronome(metro)); BOOST_TEST(created->metronome_active()); metro.bpm = 180; @@ -265,7 +247,6 @@ BOOST_AUTO_TEST_CASE(sonus_stopped_metronome_updates_stay_silent_and_restart) { config.channels = 2; auto created = sonus::engine::create(config); BOOST_REQUIRE(created); - for (auto index = std::uint32_t{}; index < 500U; ++index) { auto metro = sonus::metronome_config{}; metro.bpm = 60U + (index % 180U); @@ -274,13 +255,11 @@ BOOST_AUTO_TEST_CASE(sonus_stopped_metronome_updates_stay_silent_and_restart) { BOOST_REQUIRE(created->update_metronome(metro)); BOOST_TEST(!created->metronome_active()); } - auto samples = std::vector(4096U * config.channels, 1.0F); BOOST_REQUIRE(created->render(samples.data(), 4096U)); BOOST_TEST(std::all_of(samples.begin(), samples.end(), [](auto sample) { return sample == 0.0F; })); - auto metro = sonus::metronome_config{}; metro.bpm = 120; BOOST_REQUIRE(created->start_metronome(metro)); @@ -292,7 +271,6 @@ BOOST_AUTO_TEST_CASE(sonus_stopped_metronome_updates_stay_silent_and_restart) { BOOST_AUTO_TEST_CASE(sonus_metronome_can_be_updated_concurrently) { auto created = sonus::engine::create(no_device_config()); BOOST_REQUIRE(created); - auto worker = [&created](std::uint32_t offset) { for (auto index = std::uint32_t{}; index < 100U; ++index) { auto metro = sonus::metronome_config{}; @@ -304,14 +282,12 @@ BOOST_AUTO_TEST_CASE(sonus_metronome_can_be_updated_concurrently) { } } }; - auto first = std::thread{worker, 0U}; auto second = std::thread{worker, 11U}; auto third = std::thread{worker, 23U}; first.join(); second.join(); third.join(); - auto samples = std::vector(4096U * created->channels()); BOOST_TEST(static_cast(created->render(samples.data(), 4096U))); } @@ -319,7 +295,6 @@ BOOST_AUTO_TEST_CASE(sonus_metronome_can_be_updated_concurrently) { BOOST_AUTO_TEST_CASE(sonus_file_playback_reports_missing_files) { auto created = sonus::engine::create(no_device_config()); BOOST_REQUIRE(created); - auto missing = std::filesystem::path{"/tmp/sonus-missing-file.wav"}; auto played = created->play_file(missing); BOOST_TEST(!played); @@ -331,18 +306,14 @@ BOOST_AUTO_TEST_CASE(sonus_file_playback_renders_audio) { config.channels = 2; auto created = sonus::engine::create(config); BOOST_REQUIRE(created); - auto path = test_file("sonus-tone-long.wav"); write_test_wav(path, config.sample_rate, 1, config.sample_rate, 440.0); - auto played = created->play_file(path); BOOST_REQUIRE(played); BOOST_TEST(created->active_sound_count() == 1U); - auto samples = std::vector(4096U * config.channels); BOOST_REQUIRE(created->render(samples.data(), 4096U)); BOOST_TEST(peak(samples, 0, 4096U, config.channels) > 0.05F); - auto playing = created->is_playing(*played); BOOST_REQUIRE(playing); BOOST_TEST(*playing); @@ -354,16 +325,12 @@ BOOST_AUTO_TEST_CASE(sonus_finished_file_playback_can_be_collected) { config.channels = 2; auto created = sonus::engine::create(config); BOOST_REQUIRE(created); - auto path = test_file("sonus-tone-short.wav"); write_test_wav(path, config.sample_rate, 1, 256U, 880.0); - auto played = created->play_file(path); BOOST_REQUIRE(played); - auto samples = std::vector(2048U * config.channels); BOOST_REQUIRE(created->render(samples.data(), 2048U)); - auto playing = created->is_playing(*played); BOOST_REQUIRE(playing); BOOST_TEST(!*playing); @@ -376,10 +343,8 @@ BOOST_AUTO_TEST_CASE(sonus_repeated_short_sounds_are_retired) { config.channels = 2; auto created = sonus::engine::create(config); BOOST_REQUIRE(created); - auto path = test_file("sonus-tone-repeated.wav"); write_test_wav(path, config.sample_rate, 1, 64U, 660.0); - auto samples = std::vector(512U * config.channels); auto collected = std::uint64_t{}; for (auto index = 0; index < 20; ++index) { @@ -388,7 +353,6 @@ BOOST_AUTO_TEST_CASE(sonus_repeated_short_sounds_are_retired) { BOOST_REQUIRE(created->render(samples.data(), 512U)); collected += created->collect_finished(); } - BOOST_TEST(collected == 20U); BOOST_TEST(created->active_sound_count() == 0U); } @@ -399,10 +363,8 @@ BOOST_AUTO_TEST_CASE(sonus_no_device_render_serializes_with_control_paths) { config.channels = 2; auto created = sonus::engine::create(config); BOOST_REQUIRE(created); - auto path = test_file("sonus-tone-concurrent.wav"); write_test_wav(path, config.sample_rate, 1, 512U, 330.0); - auto render_worker = [&created, channels = config.channels] { auto samples = std::vector(512U * channels); for (auto index = 0; index < 150; ++index) { @@ -420,7 +382,6 @@ BOOST_AUTO_TEST_CASE(sonus_no_device_render_serializes_with_control_paths) { } else { static_cast(created->start_metronome(metro)); } - auto played = created->play_file(path); if (played && index % 3 == 0) { static_cast(created->stop(*played)); @@ -428,12 +389,10 @@ BOOST_AUTO_TEST_CASE(sonus_no_device_render_serializes_with_control_paths) { static_cast(created->collect_finished()); } }; - auto renderer = std::thread{render_worker}; auto controller = std::thread{control_worker}; renderer.join(); controller.join(); - created->stop_all(); created->stop_metronome(); BOOST_TEST(created->active_sound_count() == 0U);