`AudioLevelMeter` measured one number for everything. It now also keeps smoothed per-channel levels with the same attack/decay, plus `ImbalanceDb`. Mono samples report both sides equal (a mono source is centred), so the two never disagree about whether audio exists. The dock shows ONE ladder per source — two ladders per bay was visual noise for a rare failure — but this creator is profoundly deaf on the right, so the one case that matters is "the sound is panned away from me". That is now measurable and will drive a flag, not a second ladder. Semantics that mattered: a silent side is compared at the −60 dBFS floor, so a fully one-sided signal reads ≈54 dB rather than "nothing to compare". My first version returned 0 for exactly the case the feature exists for; the test caught it. Guard: StereoMeterTests — hard left, hard right (the inaudible case), balanced stereo, mono centred, and silence-is-not-an-imbalance. 31 audio tests green.
57 lines
2.4 KiB
C#
57 lines
2.4 KiB
C#
using Xunit;
|
|
using ytLive.Services.Audio;
|
|
|
|
namespace ytLive.Tests;
|
|
|
|
/// <summary>The dock shows ONE ladder per source, but the creator is profoundly deaf on the right,
|
|
/// so the meter has to know which side a signal is on: hard-panned content is inaudible, not merely
|
|
/// quieter. These levels drive the imbalance flag, and they must be measured — never decorative.
|
|
/// </summary>
|
|
public class StereoMeterTests
|
|
{
|
|
private const int Rate = 48000;
|
|
|
|
private static AudioLevelMeter Pushed(int channels, float left, float right, int frames = 64, int pushes = 12)
|
|
{
|
|
var meter = new AudioLevelMeter();
|
|
var buffer = new float[frames * channels];
|
|
for (var f = 0; f < frames; f++)
|
|
{
|
|
buffer[f * channels] = left;
|
|
if (channels > 1) buffer[f * channels + 1] = right;
|
|
}
|
|
for (var i = 0; i < pushes; i++) meter.Push(new AudioSample(buffer, Rate, channels));
|
|
return meter;
|
|
}
|
|
|
|
[Fact]
|
|
public void The_meter_knows_which_side_the_signal_is_on()
|
|
{
|
|
// Hard left: the left side carries it, the right is silent, and the gap is reported.
|
|
var hardLeft = Pushed(channels: 2, left: 0.5f, right: 0f);
|
|
Assert.True(hardLeft.Left > 0.1f, $"left should carry the tone, got {hardLeft.Left}");
|
|
Assert.True(hardLeft.Right < 0.01f, $"right should be silent, got {hardLeft.Right}");
|
|
Assert.True(hardLeft.ImbalanceDb > 20f, "a one-sided signal must report a large imbalance");
|
|
|
|
// Hard right is the mirror case — the one this creator cannot hear.
|
|
var hardRight = Pushed(channels: 2, left: 0f, right: 0.5f);
|
|
Assert.True(hardRight.Right > 0.1f);
|
|
Assert.True(hardRight.Left < 0.01f);
|
|
|
|
// Balanced stereo reports no imbalance.
|
|
var centred = Pushed(channels: 2, left: 0.5f, right: 0.5f);
|
|
Assert.True(centred.Left > 0.1f && centred.Right > 0.1f);
|
|
Assert.True(centred.ImbalanceDb < 1f, $"balanced audio must not flag, got {centred.ImbalanceDb}");
|
|
|
|
// Mono is centred by definition: both sides equal, no flag — never "one-sided".
|
|
var mono = Pushed(channels: 1, left: 0.5f, right: 0f);
|
|
Assert.True(mono.Left > 0.1f);
|
|
Assert.Equal(mono.Left, mono.Right, 5);
|
|
Assert.Equal(0f, mono.ImbalanceDb);
|
|
|
|
// Silence on both sides is not an imbalance (nothing to compare).
|
|
var silent = Pushed(channels: 2, left: 0f, right: 0f);
|
|
Assert.Equal(0f, silent.ImbalanceDb);
|
|
}
|
|
}
|