#include // Other 1st party headers #include #include #include #include #include #include #include TEST_CASE("[Audio] sf::InputSoundFile") { SECTION("Type traits") { STATIC_CHECK(!std::is_default_constructible_v); STATIC_CHECK(!std::is_copy_constructible_v); STATIC_CHECK(!std::is_copy_assignable_v); STATIC_CHECK(std::is_nothrow_move_constructible_v); STATIC_CHECK(std::is_nothrow_move_assignable_v); } SECTION("openFromFile()") { SECTION("Invalid file") { CHECK(!sf::InputSoundFile::openFromFile("does/not/exist.wav")); } SECTION("Valid file") { SECTION("flac") { const auto inputSoundFile = sf::InputSoundFile::openFromFile("Audio/ding.flac").value(); CHECK(inputSoundFile.getSampleCount() == 87'798); CHECK(inputSoundFile.getChannelCount() == 1); CHECK(inputSoundFile.getSampleRate() == 44'100); CHECK(inputSoundFile.getDuration() == sf::microseconds(1'990'884)); CHECK(inputSoundFile.getTimeOffset() == sf::Time::Zero); CHECK(inputSoundFile.getSampleOffset() == 0); } SECTION("mp3") { const auto inputSoundFile = sf::InputSoundFile::openFromFile("Audio/ding.mp3").value(); CHECK(inputSoundFile.getSampleCount() == 87'798); CHECK(inputSoundFile.getChannelCount() == 1); CHECK(inputSoundFile.getSampleRate() == 44'100); CHECK(inputSoundFile.getDuration() == sf::microseconds(1'990'884)); CHECK(inputSoundFile.getTimeOffset() == sf::Time::Zero); CHECK(inputSoundFile.getSampleOffset() == 0); } SECTION("ogg") { const auto inputSoundFile = sf::InputSoundFile::openFromFile("Audio/doodle_pop.ogg").value(); CHECK(inputSoundFile.getSampleCount() == 2'116'992); CHECK(inputSoundFile.getChannelCount() == 2); CHECK(inputSoundFile.getSampleRate() == 44'100); CHECK(inputSoundFile.getDuration() == sf::microseconds(24'002'176)); CHECK(inputSoundFile.getTimeOffset() == sf::Time::Zero); CHECK(inputSoundFile.getSampleOffset() == 0); } SECTION("wav") { const auto inputSoundFile = sf::InputSoundFile::openFromFile("Audio/killdeer.wav").value(); CHECK(inputSoundFile.getSampleCount() == 112'941); CHECK(inputSoundFile.getChannelCount() == 1); CHECK(inputSoundFile.getSampleRate() == 22'050); CHECK(inputSoundFile.getDuration() == sf::microseconds(5'122'040)); CHECK(inputSoundFile.getTimeOffset() == sf::Time::Zero); CHECK(inputSoundFile.getSampleOffset() == 0); } } } SECTION("openFromMemory()") { const auto memory = loadIntoMemory("Audio/killdeer.wav"); const auto inputSoundFile = sf::InputSoundFile::openFromMemory(memory.data(), memory.size()).value(); CHECK(inputSoundFile.getSampleCount() == 112'941); CHECK(inputSoundFile.getChannelCount() == 1); CHECK(inputSoundFile.getSampleRate() == 22'050); CHECK(inputSoundFile.getDuration() == sf::microseconds(5'122'040)); CHECK(inputSoundFile.getTimeOffset() == sf::Time::Zero); CHECK(inputSoundFile.getSampleOffset() == 0); } SECTION("openFromStream()") { sf::FileInputStream stream; SECTION("Invalid stream") { CHECK(!sf::InputSoundFile::openFromStream(stream)); } SECTION("Valid stream") { SECTION("flac") { REQUIRE(stream.open("Audio/ding.flac")); const auto inputSoundFile = sf::InputSoundFile::openFromStream(stream).value(); CHECK(inputSoundFile.getSampleCount() == 87'798); CHECK(inputSoundFile.getChannelCount() == 1); CHECK(inputSoundFile.getSampleRate() == 44'100); CHECK(inputSoundFile.getDuration() == sf::microseconds(1'990'884)); CHECK(inputSoundFile.getTimeOffset() == sf::Time::Zero); CHECK(inputSoundFile.getSampleOffset() == 0); } SECTION("mp3") { REQUIRE(stream.open("Audio/ding.mp3")); const auto inputSoundFile = sf::InputSoundFile::openFromStream(stream).value(); CHECK(inputSoundFile.getSampleCount() == 87'798); CHECK(inputSoundFile.getChannelCount() == 1); CHECK(inputSoundFile.getSampleRate() == 44'100); CHECK(inputSoundFile.getDuration() == sf::microseconds(1'990'884)); CHECK(inputSoundFile.getTimeOffset() == sf::Time::Zero); CHECK(inputSoundFile.getSampleOffset() == 0); } SECTION("ogg") { REQUIRE(stream.open("Audio/doodle_pop.ogg")); const auto inputSoundFile = sf::InputSoundFile::openFromStream(stream).value(); CHECK(inputSoundFile.getSampleCount() == 2'116'992); CHECK(inputSoundFile.getChannelCount() == 2); CHECK(inputSoundFile.getSampleRate() == 44'100); CHECK(inputSoundFile.getDuration() == sf::microseconds(24'002'176)); CHECK(inputSoundFile.getTimeOffset() == sf::Time::Zero); CHECK(inputSoundFile.getSampleOffset() == 0); } SECTION("wav") { REQUIRE(stream.open("Audio/killdeer.wav")); const auto inputSoundFile = sf::InputSoundFile::openFromStream(stream).value(); CHECK(inputSoundFile.getSampleCount() == 112'941); CHECK(inputSoundFile.getChannelCount() == 1); CHECK(inputSoundFile.getSampleRate() == 22'050); CHECK(inputSoundFile.getDuration() == sf::microseconds(5'122'040)); CHECK(inputSoundFile.getTimeOffset() == sf::Time::Zero); CHECK(inputSoundFile.getSampleOffset() == 0); } } } SECTION("seek(std::uint64_t)") { SECTION("flac") { auto inputSoundFile = sf::InputSoundFile::openFromFile("Audio/ding.flac").value(); inputSoundFile.seek(1'000); CHECK(inputSoundFile.getTimeOffset() == sf::microseconds(22'675)); CHECK(inputSoundFile.getSampleOffset() == 1'000); } SECTION("mp3") { auto inputSoundFile = sf::InputSoundFile::openFromFile("Audio/ding.mp3").value(); inputSoundFile.seek(1'000); CHECK(inputSoundFile.getTimeOffset() == sf::microseconds(22'675)); CHECK(inputSoundFile.getSampleOffset() == 1'000); } SECTION("ogg") { auto inputSoundFile = sf::InputSoundFile::openFromFile("Audio/doodle_pop.ogg").value(); inputSoundFile.seek(1'000); CHECK(inputSoundFile.getTimeOffset() == sf::microseconds(11'337)); CHECK(inputSoundFile.getSampleOffset() == 1'000); } SECTION("wav") { auto inputSoundFile = sf::InputSoundFile::openFromFile("Audio/killdeer.wav").value(); inputSoundFile.seek(1'000); CHECK(inputSoundFile.getTimeOffset() == sf::microseconds(45'351)); CHECK(inputSoundFile.getSampleOffset() == 1'000); } } SECTION("seek(Time)") { auto inputSoundFile = sf::InputSoundFile::openFromFile("Audio/ding.flac").value(); inputSoundFile.seek(sf::milliseconds(100)); CHECK(inputSoundFile.getSampleCount() == 87'798); CHECK(inputSoundFile.getChannelCount() == 1); CHECK(inputSoundFile.getSampleRate() == 44'100); CHECK(inputSoundFile.getDuration() == sf::microseconds(1'990'884)); CHECK(inputSoundFile.getTimeOffset() == sf::milliseconds(100)); CHECK(inputSoundFile.getSampleOffset() == 4'410); } SECTION("read()") { auto inputSoundFile = sf::InputSoundFile::openFromFile("Audio/ding.flac").value(); SECTION("Null address") { CHECK(inputSoundFile.read(nullptr, 10) == 0); } std::array samples{}; SECTION("Zero count") { CHECK(inputSoundFile.read(samples.data(), 0) == 0); } SECTION("Successful read") { SECTION("flac") { inputSoundFile = sf::InputSoundFile::openFromFile("Audio/ding.flac").value(); CHECK(inputSoundFile.read(samples.data(), samples.size()) == 4); CHECK(samples == std::array{0, 1, -1, 4}); CHECK(inputSoundFile.read(samples.data(), samples.size()) == 4); CHECK(samples == std::array{1, 4, 9, 6}); } SECTION("mp3") { inputSoundFile = sf::InputSoundFile::openFromFile("Audio/ding.mp3").value(); CHECK(inputSoundFile.read(samples.data(), samples.size()) == 4); CHECK(samples == std::array{0, -2, 0, 2}); CHECK(inputSoundFile.read(samples.data(), samples.size()) == 4); CHECK(samples == std::array{1, 4, 6, 8}); } SECTION("ogg") { inputSoundFile = sf::InputSoundFile::openFromFile("Audio/doodle_pop.ogg").value(); CHECK(inputSoundFile.read(samples.data(), samples.size()) == 4); CHECK(samples == std::array{-827, -985, -1168, -1319}); CHECK(inputSoundFile.read(samples.data(), samples.size()) == 4); CHECK(samples == std::array{-1738, -1883, -2358, -2497}); } SECTION("wav") { // Cannot be tested since reading from a .wav file triggers UB } } } SECTION("close()") { auto inputSoundFile = sf::InputSoundFile::openFromFile("Audio/ding.flac").value(); inputSoundFile.close(); CHECK(inputSoundFile.getSampleCount() == 0); CHECK(inputSoundFile.getChannelCount() == 0); CHECK(inputSoundFile.getSampleRate() == 0); CHECK(inputSoundFile.getDuration() == sf::Time::Zero); CHECK(inputSoundFile.getTimeOffset() == sf::Time::Zero); CHECK(inputSoundFile.getSampleOffset() == 0); } }