112 lines
4.0 KiB
C++
112 lines
4.0 KiB
C++
#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));
|
|
}
|