@@ -7,6 +7,7 @@ add_executable(sonus_test
|
||||
test.cpp
|
||||
render_snapshot.cpp
|
||||
control.cpp
|
||||
transport.cpp
|
||||
sequence.cpp
|
||||
)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <sonus.hpp>
|
||||
#include <array>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
struct recordings {
|
||||
std::filesystem::path root;
|
||||
recordings() {
|
||||
auto path = (std::filesystem::temp_directory_path() / "sonus-recordings-XXXXXX").string();
|
||||
BOOST_REQUIRE(::mkdtemp(path.data()));
|
||||
root = path;
|
||||
write("backing.wav", 16, 1024, -1024);
|
||||
write("beat1.wav", 2, 8192, -8192);
|
||||
write("beat2.wav", 2, 4096, -4096);
|
||||
}
|
||||
~recordings() {
|
||||
std::error_code error;
|
||||
std::filesystem::remove_all(root, error);
|
||||
}
|
||||
auto write(char const *name, unsigned frames, int left, int right) -> void {
|
||||
auto output = std::ofstream{root / name, std::ios::binary};
|
||||
auto word = [&](unsigned value, unsigned bytes) { for (unsigned i = 0; i < bytes; ++i){ output.put(static_cast<char>(value >> (8 * i)));
|
||||
} };
|
||||
output.write("RIFF", 4);
|
||||
word(36 + frames * 4, 4);
|
||||
output.write("WAVEfmt ", 8);
|
||||
word(16, 4);
|
||||
word(1, 2);
|
||||
word(2, 2);
|
||||
word(48000, 4);
|
||||
word(192000, 4);
|
||||
word(4, 2);
|
||||
word(16, 2);
|
||||
output.write("data", 4);
|
||||
word(frames * 4, 4);
|
||||
for (unsigned i = 0; i < frames; ++i) {
|
||||
word(static_cast<unsigned>(left), 2);
|
||||
word(static_cast<unsigned>(right), 2);
|
||||
}
|
||||
}
|
||||
auto config() const -> sonus::transport_config {
|
||||
return {.backing = root / "backing.wav", .beat1 = root / "beat1.wav", .beat2 = root / "beat2.wav", .clicks = {{4, true}, {8, false}}, .duration_frames = 10, .click_volume = 1.F};
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(recording_transport_preserves_stereo_and_has_one_sample_clock) {
|
||||
auto files = recordings{};
|
||||
auto prepared = sonus::prepared_transport::create(files.config(), 48000, 2);
|
||||
BOOST_REQUIRE(prepared);
|
||||
auto engine = sonus::engine::create({.sample_rate = 48000, .channels = 2, .master_volume = 1.F, .no_device = true});
|
||||
BOOST_REQUIRE(engine);
|
||||
auto session = engine->play_transport(std::move(*prepared));
|
||||
BOOST_REQUIRE(session);
|
||||
std::array<float, 40> output{};
|
||||
BOOST_REQUIRE(engine->render(output.data(), 20));
|
||||
BOOST_TEST(session->frames() == 16U);
|
||||
BOOST_CHECK(session->status() == sonus::playback_status::COMPLETED);
|
||||
for (unsigned frame = 0; frame < 20; ++frame) {
|
||||
auto value = frame < 16 ? .03125F : 0.F;
|
||||
if (frame == 4 || frame == 5) {
|
||||
value += .25F;
|
||||
}
|
||||
if (frame == 8 || frame == 9) {
|
||||
value += .125F;
|
||||
}
|
||||
BOOST_TEST(output[frame * 2] == value);
|
||||
BOOST_TEST(output[frame * 2 + 1] == -value);
|
||||
}
|
||||
engine->collect_finished();
|
||||
BOOST_CHECK(session->status() == sonus::playback_status::COMPLETED);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(recording_transport_replacement_cancels_old_session_and_validates_inputs) {
|
||||
auto files = recordings{};
|
||||
auto engine = sonus::engine::create({.sample_rate = 48000, .channels = 2, .no_device = true});
|
||||
BOOST_REQUIRE(engine);
|
||||
auto config = files.config();
|
||||
auto first = sonus::prepared_transport::create(config, 48000, 2);
|
||||
BOOST_REQUIRE(first);
|
||||
auto session = engine->play_transport(std::move(*first));
|
||||
BOOST_REQUIRE(session);
|
||||
auto second = sonus::prepared_transport::create(config, 48000, 2);
|
||||
BOOST_REQUIRE(second);
|
||||
auto replacement = engine->play_transport(std::move(*second));
|
||||
BOOST_REQUIRE(replacement);
|
||||
BOOST_CHECK(session->status() == sonus::playback_status::STOPPED);
|
||||
replacement->stop();
|
||||
std::array<float, 16> output{};
|
||||
BOOST_REQUIRE(engine->render(output.data(), 8));
|
||||
BOOST_TEST(replacement->frames() == 0U);
|
||||
BOOST_TEST(output.front() == 0.F);
|
||||
config.duration_frames = 17;
|
||||
BOOST_CHECK(!sonus::prepared_transport::create(config, 48000, 2));
|
||||
config = files.config();
|
||||
config.beat1 = files.root / "missing.wav";
|
||||
BOOST_CHECK(!sonus::prepared_transport::create(config, 48000, 2));
|
||||
config = files.config();
|
||||
config.clicks = {{9, true}, {4, false}};
|
||||
BOOST_CHECK(!sonus::prepared_transport::create(config, 48000, 2));
|
||||
config = files.config();
|
||||
config.backing.clear();
|
||||
config.clicks.push_back({10, true});
|
||||
BOOST_CHECK(!sonus::prepared_transport::create(config, 48000, 2));
|
||||
}
|
||||
Reference in New Issue
Block a user