Files
video-shader-toys/tests/AudioSupportTests.cpp
2026-05-04 14:32:29 +10:00

116 lines
3.6 KiB
C++

#include "AudioSupport.h"
#include <algorithm>
#include <cmath>
#include <cstdint>
#include <iostream>
#include <vector>
namespace
{
int gFailures = 0;
void Expect(bool condition, const char* message)
{
if (condition)
return;
std::cerr << "FAIL: " << message << "\n";
++gFailures;
}
int32_t ToSample(float value)
{
const double clamped = std::max(-1.0, std::min(1.0, static_cast<double>(value)));
return static_cast<int32_t>(clamped * 2147483647.0);
}
void TestFrameSampleCounts()
{
Expect(AudioSamplesForVideoFrame(0, 1, 50) == 960, "50 fps first frame has 960 audio samples");
Expect(AudioSamplesForVideoFrame(0, 1, 60) == 800, "60 fps first frame has 800 audio samples");
uint64_t total = 0;
for (uint64_t frame = 0; frame < 600; ++frame)
total += AudioSamplesForVideoFrame(frame, 1001, 60000);
Expect(total == AudioSampleTimeForVideoFrame(600, 1001, 60000), "59.94 fps sample counts do not drift");
}
void TestDelayBuffer()
{
AudioDelayBuffer buffer;
buffer.Reset(4);
std::vector<int32_t> input = {
11, 12,
21, 22,
31, 32,
41, 42
};
buffer.PushInterleaved(input.data(), 4);
bool underrun = false;
AudioFrameBlock first = buffer.Pop(4, underrun);
Expect(!underrun, "delay-buffer initial silence does not underrun");
Expect(first.frameCount() == 4, "delay-buffer returns requested frame count");
Expect(first.interleavedSamples[0] == 0 && first.interleavedSamples[7] == 0, "delay-buffer emits initial silence");
AudioFrameBlock second = buffer.Pop(4, underrun);
Expect(!underrun, "delay-buffer emits delayed input without underrun");
Expect(second.interleavedSamples == input, "delay-buffer preserves delayed interleaved samples");
AudioFrameBlock third = buffer.Pop(2, underrun);
Expect(underrun, "delay-buffer reports underrun");
Expect(third.interleavedSamples[0] == 0 && third.interleavedSamples[3] == 0, "delay-buffer underrun fills silence");
}
void TestAnalyzerSilence()
{
AudioAnalyzer analyzer;
AudioFrameBlock block;
block.interleavedSamples.resize(512 * kAudioChannelCount, 0);
AudioAnalysisSnapshot analysis = analyzer.Analyze(block);
Expect(analysis.rms[0] == 0.0f && analysis.rms[1] == 0.0f, "silence rms is zero");
Expect(analysis.peak[0] == 0.0f && analysis.peak[1] == 0.0f, "silence peak is zero");
Expect(analysis.bands[0] == 0.0f && analysis.bands[3] == 0.0f, "silence bands are zero");
}
void TestAnalyzerSineAndStereo()
{
AudioAnalyzer analyzer;
AudioFrameBlock block;
block.interleavedSamples.resize(1024 * kAudioChannelCount, 0);
for (std::size_t frame = 0; frame < 1024; ++frame)
{
const float phase = static_cast<float>(frame) * 2.0f * 3.14159265f * 300.0f / static_cast<float>(kAudioSampleRate);
block.interleavedSamples[frame * 2] = ToSample(std::sin(phase) * 0.8f);
block.interleavedSamples[frame * 2 + 1] = ToSample(0.25f);
}
AudioAnalysisSnapshot analysis = analyzer.Analyze(block);
Expect(analysis.peak[0] > 0.75f && analysis.peak[0] <= 0.81f, "left sine peak is detected");
Expect(analysis.rms[0] > 0.45f && analysis.rms[0] < 0.65f, "left sine rms is detected");
Expect(analysis.peak[1] > 0.24f && analysis.peak[1] < 0.26f, "right constant peak remains independent");
Expect(analysis.rms[1] > 0.24f && analysis.rms[1] < 0.26f, "right constant rms remains independent");
Expect(analysis.bands[1] >= analysis.bands[0], "300 Hz sine activates lower-mid band");
}
}
int main()
{
TestFrameSampleCounts();
TestDelayBuffer();
TestAnalyzerSilence();
TestAnalyzerSineAndStereo();
if (gFailures != 0)
{
std::cerr << gFailures << " AudioSupport test failure(s).\n";
return 1;
}
std::cout << "AudioSupport tests passed.\n";
return 0;
}