test(audio): implement automated 440 Hz audio loopback CI verification test
This commit is contained in:
parent
7f6828df0c
commit
c0d884bf94
1 changed files with 53 additions and 0 deletions
53
tests/ci_audio_loopback.rs
Normal file
53
tests/ci_audio_loopback.rs
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
use molotov_core::audio::pipewire::PipeWireStreamController;
|
||||
use molotov_core::audio::types::AAudioDirection;
|
||||
|
||||
#[test]
|
||||
fn test_440hz_loopback_frequency_and_amplitude() {
|
||||
let sample_rate = 48000;
|
||||
let freq = 440.0f32;
|
||||
let duration_samples = 48000 / 2; // 0.5s
|
||||
|
||||
let mut controller = PipeWireStreamController::new(AAudioDirection::Input, sample_rate, 1);
|
||||
controller.request_start().unwrap();
|
||||
|
||||
// Generate 440 Hz sine wave
|
||||
let mut generated = Vec::with_capacity(duration_samples);
|
||||
for i in 0..duration_samples {
|
||||
let t = i as f32 / sample_rate as f32;
|
||||
let sample = (2.0 * std::f32::consts::PI * freq * t).sin();
|
||||
generated.push(sample);
|
||||
}
|
||||
|
||||
controller.buffer.write(&generated);
|
||||
|
||||
let mut captured = vec![0.0f32; duration_samples];
|
||||
let read_count = controller.buffer.read(&mut captured);
|
||||
assert_eq!(read_count, duration_samples);
|
||||
|
||||
// Compute simple Discrete Fourier Transform (DFT) bin at 440 Hz
|
||||
let mut real = 0.0f32;
|
||||
let mut imag = 0.0f32;
|
||||
for (i, &sample) in captured.iter().enumerate() {
|
||||
let angle = 2.0 * std::f32::consts::PI * freq * (i as f32) / (sample_rate as f32);
|
||||
real += sample * angle.cos();
|
||||
imag -= sample * angle.sin();
|
||||
}
|
||||
let magnitude = (real * real + imag * imag).sqrt();
|
||||
|
||||
// Check adjacent bin at 460 Hz to ensure peak is at 440 Hz
|
||||
let mut off_real = 0.0f32;
|
||||
let mut off_imag = 0.0f32;
|
||||
let off_freq = 460.0f32;
|
||||
for (i, &sample) in captured.iter().enumerate() {
|
||||
let angle = 2.0 * std::f32::consts::PI * off_freq * (i as f32) / (sample_rate as f32);
|
||||
off_real += sample * angle.cos();
|
||||
off_imag -= sample * angle.sin();
|
||||
}
|
||||
let off_magnitude = (off_real * off_real + off_imag * off_imag).sqrt();
|
||||
|
||||
assert!(
|
||||
magnitude > off_magnitude * 10.0,
|
||||
"440 Hz peak must be dominant (>10x adjacent frequencies)"
|
||||
);
|
||||
}
|
||||
Reference in a new issue