generated from CoolLibs/library-template
-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e0883d6
commit 9f6da51
Showing
1 changed file
with
6 additions
and
96 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,114 +1,24 @@ | ||
#include <exe_path/exe_path.h> | ||
#include <Audio/Audio.hpp> | ||
#include <algorithm> | ||
#include <complex> | ||
#include <iterator> | ||
#include <quick_imgui/quick_imgui.hpp> | ||
#include "imgui.h" | ||
|
||
#define DOCTEST_CONFIG_IMPLEMENT | ||
#include <doctest/doctest.h> | ||
|
||
// Learn how to use Dear ImGui: https://coollibs.github.io/contribute/Programming/dear-imgui | ||
|
||
static auto window(int64_t idx, int64_t size) -> float | ||
{ | ||
float const t = static_cast<float>(idx) / static_cast<float>(size - 1); | ||
return 1.f - std::abs(2.f * t - 1.f); // Triangular window | ||
} | ||
|
||
static auto get_device_name_impl(Audio::InputStream const& input_stream, Audio::UseDefaultDevice) -> std::string | ||
{ | ||
return "Use default device: " + input_stream.device_info(input_stream.default_device_id()).name; | ||
} | ||
static auto get_device_name_impl(Audio::InputStream const&, Audio::UseGivenDevice const& device) -> std::string | ||
{ | ||
return device.name; | ||
} | ||
|
||
static auto get_device_name(Audio::InputStream const& input_stream, Audio::SelectedDevice const& selected_device) -> std::string | ||
{ | ||
return std::visit([&](auto&& selected_device) { return get_device_name_impl(input_stream, selected_device); }, selected_device); | ||
} | ||
|
||
auto main() -> int | ||
{ | ||
// If we don't set a callback RtAudio sends to cerr by default, which causes doctest to consider that our tests failed. Since there is no audio device on GitHub Action runners these errors are expected and should not cause a test failure. | ||
Audio::set_error_callback([](RtAudioErrorType, std::string const& error) { | ||
std::cout << error << '\n'; | ||
}); | ||
// Audio::set_error_callback([](RtAudioErrorType, std::string const& error) { | ||
// std::cout << error << '\n'; | ||
// }); | ||
|
||
auto ctx = doctest::Context{}; | ||
const char* arg2v[3] = {"truc", "--success", "--reporters=console"}; | ||
ctx.applyCommandLine(3, arg2v); | ||
auto ctx = doctest::Context{}; | ||
// const char* arg2v[3] = {"truc", "--success", "--reporters=console"}; | ||
// ctx.applyCommandLine(3, arg2v); | ||
int const exit_code = ctx.run(); // Run all unit tests | ||
return exit_code; | ||
} | ||
|
||
TEST_CASE("At least one API has been compiled") | ||
{ | ||
Audio::Player player{}; // This will assert if no API is available, which is something we want to detect. | ||
} | ||
|
||
TEST_CASE("Loading a .wav file") | ||
{ | ||
Audio::load_audio_file(Audio::player(), exe_path::dir() / "../tests/res/10-1000-10000-20000.wav"); | ||
|
||
CHECK(Audio::player().audio_data().channels_count == 1); | ||
CHECK(Audio::player().audio_data().sample_rate == 41000); | ||
CHECK(Audio::player().audio_data().samples.size() == 164000); | ||
} | ||
|
||
TEST_CASE("Loading a .mp3 file") | ||
{ | ||
Audio::load_audio_file(Audio::player(), exe_path::dir() / "../tests/res/Monteverdi - L'Orfeo, Toccata.mp3"); | ||
|
||
CHECK(Audio::player().audio_data().channels_count == 2); | ||
CHECK(Audio::player().audio_data().sample_rate == 44100); | ||
CHECK(Audio::player().audio_data().samples.size() == 9819648); | ||
} | ||
|
||
static auto is_big(float x) -> bool | ||
{ | ||
return x > 5.f; | ||
} | ||
static auto is_small(float x) -> bool | ||
{ | ||
return x < 0.1f; | ||
} | ||
|
||
static constexpr float TAU = 6.2831853071f; | ||
|
||
TEST_CASE("Fourier transform") | ||
{ | ||
auto fft_input = std::vector<std::complex<float>>{}; | ||
|
||
static constexpr int64_t sample_rate = 44000; // Allows us to detect frequencies up to sample_rate / 2 = 22000Hz | ||
static constexpr int64_t fft_size = 8000; // Will give us a good enough resolution (fft_size / 2 = 4000 values, spread between 0Hz and 22000Hz) | ||
|
||
auto const spectrum = Audio::fourier_transform( | ||
fft_size, [&](std::function<void(float)> const& callback) { | ||
for (int64_t i = 0; i < fft_size; i++) | ||
{ | ||
float time = static_cast<float>(i) / static_cast<float>(sample_rate); | ||
callback( | ||
window(i, fft_size) | ||
* (std::sin(10.f * time * TAU) // 10Hz frequency | ||
+ std::sin(1000.f * time * TAU) // 1000Hz frequency | ||
+ std::sin(10000.f * time * TAU) // 10000Hz frequency | ||
+ std::sin(20000.f * time * TAU) // 20000Hz frequency | ||
) | ||
); | ||
} | ||
}, | ||
static_cast<float>(sample_rate) | ||
); | ||
|
||
CHECK(is_big(spectrum.at_frequency(10.f))); | ||
CHECK(is_big(spectrum.at_frequency(1000.f))); | ||
CHECK(is_big(spectrum.at_frequency(10000.f))); | ||
CHECK(is_big(spectrum.at_frequency(20000.f))); | ||
CHECK(is_small(spectrum.at_frequency(500.f))); | ||
CHECK(is_small(spectrum.at_frequency(5000.f))); | ||
CHECK(is_small(spectrum.at_frequency(15000.f))); | ||
} |