Files
projectm/tests/PCMTest.cpp
Kai Blaschke 0fe87a2c04 Moved Pcm class tests to the unit test project.
Added a helper function to reset autoleveler, made it public as might come in handy if there's a gap (pause/resume, new track etc.) in the audio data.
2022-04-14 15:59:06 +02:00

138 lines
3.4 KiB
C++

#include <gtest/gtest.h>
#include <PCM.hpp>
#include <cmath>
class PcmMock : public Pcm
{
public:
void CopyPcm(float* to, size_t channel, size_t count) const
{
Pcm::CopyPcm(to, channel, count);
}
void CopyPcm(double* to, size_t channel, size_t count) const
{
Pcm::CopyPcm(to, channel, count);
}
};
TEST(PCM, AddDataMonoFloat)
{
PcmMock pcm;
size_t constexpr samples = 301;
std::array<float, samples> data{};
for (size_t i = 0; i < samples; i++)
{
data[i] = ((float) i) / (samples - 1);
}
for (size_t i = 0; i < 10; i++)
{
pcm.AddMono(data.data(), samples);
}
std::array<float, samples> copy{};
pcm.ResetAutoLevel();
pcm.CopyPcm(copy.data(), 0, copy.size());
for (size_t i = 0; i < samples; i++)
{
EXPECT_FLOAT_EQ(copy[i], ((float) samples - 1 - i) / (samples - 1));
}
pcm.CopyPcm(copy.data(), 1, copy.size());
for (size_t i = 0; i < samples; i++)
{
EXPECT_FLOAT_EQ(copy[i], ((float) samples - 1 - i) / (samples - 1));
}
}
TEST(PCM, AddDataStereoFloat)
{
PcmMock pcm;
size_t constexpr samples = 301;
std::array<float, 2 * samples> data{};
for (size_t i = 0; i < samples; i++)
{
data[i * 2] = ((float) i) / (samples - 1);
data[i * 2 + 1] = 1.f - data[i * 2];
}
for (size_t i = 0; i < 10; i++)
{
pcm.AddStereo(data.data(), samples);
}
std::array<float, samples> copy0{};
std::array<float, samples> copy1{};
pcm.ResetAutoLevel();
pcm.CopyPcm(copy0.data(), 0, copy0.size());
pcm.CopyPcm(copy1.data(), 1, copy1.size());
for (size_t i = 0; i < samples; i++)
{
EXPECT_FLOAT_EQ(copy0[i] + copy1[i], 1.0);
}
}
TEST(PCM, FastFourierTransformLowFrequency)
{
PcmMock pcm;
size_t constexpr samples = 1024;
std::array<float, 2 * samples> data{};
for (size_t i = 0; i < samples; i++)
{
float const f = static_cast<float>(i) * 2 * 3.141592653589793f / (samples - 1);
data[i * 2] = std::sin(f);
data[i * 2 + 1] = std::sin(f + 1.f);// out of phase
}
pcm.AddStereo(data.data(), samples);
pcm.AddStereo(data.data(), samples);
std::array<float, fftLength> freq0{};
std::array<float, fftLength> freq1{};
pcm.ResetAutoLevel();
pcm.GetSpectrum(freq0.data(), CHANNEL_0, fftLength);
pcm.GetSpectrum(freq1.data(), CHANNEL_1, fftLength);
// freq0 and freq1 should be equal
for (size_t i = 0; i < fftLength; i++)
{
EXPECT_FLOAT_EQ(freq0[i], freq1[i]);
}
EXPECT_GT(freq0[0], 500);
for (size_t i = 1; i < fftLength; i++)
{
EXPECT_LT(freq0[i], 0.1);
}
}
TEST(PCM, FastFourierTransformHighFrequency)
{
PcmMock pcm;
size_t constexpr samples = 2;
std::array<float, 4> constexpr data{1.0, 0.0, 0.0, 1.0};
for (size_t i = 0; i < 1024; i++)
{
pcm.AddStereo(data.data(), samples);
}
std::array<float, fftLength> freq0{};
std::array<float, fftLength> freq1{};
pcm.ResetAutoLevel();
pcm.GetSpectrum(freq0.data(), CHANNEL_0, fftLength);
pcm.GetSpectrum(freq1.data(), CHANNEL_1, fftLength);
// freq0 and freq1 should be equal
for (size_t i = 0; i < fftLength; i++)
{
EXPECT_FLOAT_EQ(freq0[i], freq1[i]);
}
for (size_t i = 0; i < fftLength - 1; i++)
{
EXPECT_FLOAT_EQ(freq0[i], 0);
}
EXPECT_GT(freq0[fftLength - 1], 100000);
}