Skip to content
Permalink
a72f2aed6b
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
683 lines (602 sloc) 17 KB
// Tests can be downloaded from https://tech.ebu.ch/publications/ebu_loudness_test_set
// and should be put into tests/reference_files
//
// Expected results are in
// - https://tech.ebu.ch/docs/tech/tech3341.pdf
// - https://tech.ebu.ch/docs/tech/tech3342.pdf
macro_rules! read_samples {
($reader:expr, 16) => {
$reader
.into_samples::<i16>()
.map(|s| s.expect("Failed to read samples from reference file"))
.collect::<Vec<_>>()
};
($reader:expr, 24) => {
$reader
.into_samples::<i32>()
.map(|s| s.expect("Failed to read samples from reference file") << 8)
.collect::<Vec<_>>()
};
}
macro_rules! prepare_file {
($file_name:expr, $rate:expr, $bpp:tt, $mode:expr, $channel_map:expr) => {{
let input_path = {
let mut r = std::path::PathBuf::new();
r.push(env!("CARGO_MANIFEST_DIR"));
r.push("tests");
r.push("reference_files");
r.push($file_name);
r
};
if !input_path.exists() {
panic!("Reference file {} not found", input_path.display());
}
let mut e = ebur128::EbuR128::new($channel_map.len() as u32, $rate, $mode)
.expect("Can't create EbuR128 instance");
e.set_channel_map(&$channel_map).unwrap();
let reader = hound::WavReader::open(&input_path).expect("Failed to read reference file");
let samples = read_samples!(reader, $bpp);
(e, samples)
}};
}
macro_rules! add_samples {
($e:expr, $samples:expr, 16) => {
$e.add_frames_i16(&*$samples).expect("Failed to analyze samples");
};
($e:expr, $samples:expr, 24) => {
$e.add_frames_i32(&*$samples).expect("Failed to analyze samples");
};
}
macro_rules! test_global_loudness(
($file_name:expr, $rate:expr, $bpp:tt, $channel_map:expr, $expected_loudness:expr) => {
{
let (mut e, samples) = prepare_file!($file_name, $rate, $bpp, ebur128::Mode::I, $channel_map);
add_samples!(e, samples, $bpp);
float_eq::assert_float_eq!(e.loudness_global().expect("Failed to get global loudness"), $expected_loudness, abs <= 0.1);
}
{
let (mut e, samples) = prepare_file!($file_name, $rate, $bpp, ebur128::Mode::I | ebur128::Mode::HISTOGRAM, $channel_map);
add_samples!(e, samples, $bpp);
float_eq::assert_float_eq!(e.loudness_global().expect("Failed to get global loudness"), $expected_loudness, abs <= 0.1);
}
};
);
macro_rules! test_true_peak(
($file_name:expr, $rate:expr, $bpp:tt, $channel_map:expr, $expected_true_peak:expr) => {
let (mut e, samples) = prepare_file!($file_name, $rate, $bpp, ebur128::Mode::TRUE_PEAK, $channel_map);
add_samples!(e, samples, $bpp);
let mut max_true_peak = f64::MIN;
for peak in (0..$channel_map.len())
.map(|c| e.true_peak(c as u32).expect("Failed to get true peak")) {
if peak > max_true_peak {
max_true_peak = peak;
}
}
let max_true_peak = 20.0 * f64::log10(max_true_peak);
assert!(
max_true_peak <= $expected_true_peak + 0.2 && max_true_peak >= $expected_true_peak - 0.4,
"{} != {}",
max_true_peak,
$expected_true_peak,
);
};
);
macro_rules! test_loudness_range(
($file_name:expr, $rate:expr, $bpp:tt, $channel_map:expr, $expected_loudness_range:expr) => {
{
let (mut e, samples) = prepare_file!($file_name, $rate, $bpp, ebur128::Mode::LRA, $channel_map);
add_samples!(e, samples, $bpp);
let loudness_range = e.loudness_range().expect("Failed to get loudness range");
float_eq::assert_float_eq!(loudness_range, $expected_loudness_range, abs <= 1.0, "queue mode");
}
{
let (mut e, samples) = prepare_file!($file_name, $rate, $bpp, ebur128::Mode::LRA | ebur128::Mode::HISTOGRAM, $channel_map);
add_samples!(e, samples, $bpp);
let loudness_range = e.loudness_range().expect("Failed to get loudness range in histogram mode");
float_eq::assert_float_eq!(loudness_range, $expected_loudness_range, abs <= 1.0, "histogram mode");
}
};
);
#[test]
fn seq_3341_1() {
{
test_global_loudness!(
"seq-3341-1-16bit.wav",
48_000,
16,
[ebur128::Channel::Left, ebur128::Channel::Right],
-23.0
);
}
{
let (mut e, samples) = prepare_file!(
"seq-3341-1-16bit.wav",
48_000,
16,
ebur128::Mode::S,
[ebur128::Channel::Left, ebur128::Channel::Right]
);
// 100ms chunks / 10Hz
for (i, chunk) in samples.chunks(2 * 48_000 / 10).enumerate() {
e.add_frames_i16(chunk).expect("Failed to analyze samples");
// Constant after 3s
if i >= 29 {
float_eq::assert_float_eq!(
e.loudness_shortterm()
.expect("Failed to get shortterm loudness"),
-23.0,
abs <= 0.1
);
}
}
}
{
let (mut e, samples) = prepare_file!(
"seq-3341-1-16bit.wav",
48_000,
16,
ebur128::Mode::M,
[ebur128::Channel::Left, ebur128::Channel::Right]
);
// 100ms chunks / 10Hz
for (i, chunk) in samples.chunks(2 * 48_000 / 10).enumerate() {
e.add_frames_i16(chunk).expect("Failed to analyze samples");
// Constant after 1s
if i >= 10 {
float_eq::assert_float_eq!(
e.loudness_momentary()
.expect("Failed to get momentary loudness"),
-23.0,
abs <= 0.1
);
}
}
}
}
#[test]
fn seq_3341_2() {
test_global_loudness!(
"seq-3341-2-16bit.wav",
48_000,
16,
[ebur128::Channel::Left, ebur128::Channel::Right],
-33.0
);
{
let (mut e, samples) = prepare_file!(
"seq-3341-2-16bit.wav",
48_000,
16,
ebur128::Mode::S,
[ebur128::Channel::Left, ebur128::Channel::Right]
);
// 100ms chunks / 10Hz
for (i, chunk) in samples.chunks(2 * 48_000 / 10).enumerate() {
e.add_frames_i16(chunk).expect("Failed to analyze samples");
// Constant after 3s
if i >= 29 {
float_eq::assert_float_eq!(
e.loudness_shortterm()
.expect("Failed to get shortterm loudness"),
-33.0,
abs <= 0.1
);
}
}
}
{
let (mut e, samples) = prepare_file!(
"seq-3341-2-16bit.wav",
48_000,
16,
ebur128::Mode::M,
[ebur128::Channel::Left, ebur128::Channel::Right]
);
// 100ms chunks / 10Hz
for (i, chunk) in samples.chunks(2 * 48_000 / 10).enumerate() {
e.add_frames_i16(chunk).expect("Failed to analyze samples");
// Constant after 1s
if i >= 10 {
float_eq::assert_float_eq!(
e.loudness_momentary()
.expect("Failed to get momentary loudness"),
-33.0,
abs <= 0.1
);
}
}
}
}
#[test]
fn seq_3341_3() {
test_global_loudness!(
"seq-3341-3-16bit-v02.wav",
48_000,
16,
[ebur128::Channel::Left, ebur128::Channel::Right],
-23.0
);
}
#[test]
fn seq_3341_4() {
test_global_loudness!(
"seq-3341-4-16bit-v02.wav",
48_000,
16,
[ebur128::Channel::Left, ebur128::Channel::Right],
-23.0
);
}
#[test]
fn seq_3341_5() {
test_global_loudness!(
"seq-3341-5-16bit-v02.wav",
48_000,
16,
[ebur128::Channel::Left, ebur128::Channel::Right],
-23.0
);
}
#[test]
fn seq_3341_6() {
test_global_loudness!(
"seq-3341-6-5channels-16bit.wav",
48_000,
16,
[
ebur128::Channel::Left,
ebur128::Channel::Right,
ebur128::Channel::Center,
ebur128::Channel::LeftSurround,
ebur128::Channel::RightSurround
],
-23.0
);
}
#[test]
fn seq_3341_6_1() {
test_global_loudness!(
"seq-3341-6-6channels-WAVEEX-16bit.wav",
48_000,
16,
[
ebur128::Channel::Left,
ebur128::Channel::Right,
ebur128::Channel::Center,
ebur128::Channel::Unused,
ebur128::Channel::LeftSurround,
ebur128::Channel::RightSurround
],
-23.0
);
}
#[test]
fn seq_3341_7() {
test_global_loudness!(
"seq-3341-7_seq-3342-5-24bit.wav",
48_000,
24,
[ebur128::Channel::Left, ebur128::Channel::Right],
-23.0
);
}
#[test]
fn seq_3341_8() {
test_global_loudness!(
"seq-3341-2011-8_seq-3342-6-24bit-v02.wav",
48_000,
24,
[ebur128::Channel::Left, ebur128::Channel::Right],
-23.0
);
}
#[test]
fn seq_3341_9() {
let (mut e, samples) = prepare_file!(
"seq-3341-9-24bit.wav",
48_000,
24,
ebur128::Mode::S,
[ebur128::Channel::Left, ebur128::Channel::Right]
);
// 100ms chunks / 10Hz
for (i, chunk) in samples.chunks(2 * 48_000 / 10).enumerate() {
e.add_frames_i32(chunk).expect("Failed to analyze samples");
// Constant after 3s
if i >= 29 {
float_eq::assert_float_eq!(
e.loudness_shortterm()
.expect("Failed to get shortterm loudness"),
-23.0,
abs <= 0.1
);
}
}
}
#[test]
fn seq_3341_10() {
for i in 1..=20 {
let (mut e, samples) = prepare_file!(
format!("seq-3341-10-{}-24bit.wav", i),
48_000,
24,
ebur128::Mode::S,
[ebur128::Channel::Left, ebur128::Channel::Right]
);
// 100ms chunks / 10Hz
let mut max_loudness = f64::MIN;
for chunk in samples.chunks(2 * 48_000 / 10) {
e.add_frames_i32(chunk).expect("Failed to analyze samples");
let loudness = e
.loudness_shortterm()
.expect("Failed to get shortterm loudness");
if loudness > max_loudness {
max_loudness = loudness;
}
}
float_eq::assert_float_eq!(max_loudness, -23.0, abs <= 0.1, "file {}", i);
}
}
#[test]
fn seq_3341_11() {
let (mut e, samples) = prepare_file!(
"seq-3341-11-24bit.wav",
48_000,
24,
ebur128::Mode::S,
[ebur128::Channel::Left, ebur128::Channel::Right]
);
// 100ms chunks / 10Hz
let mut max_loudness = f64::MIN;
for (i, chunk) in samples.chunks(2 * 48_000 / 10).enumerate() {
e.add_frames_i32(chunk).expect("Failed to analyze samples");
let loudness = e
.loudness_shortterm()
.expect("Failed to get shortterm loudness");
if loudness > max_loudness {
max_loudness = loudness;
}
if (i + 1) % 60 == 0 {
let expected = -38.0 + ((i + 1) / 60 - 1) as f64;
float_eq::assert_float_eq!(
max_loudness,
expected,
abs <= 0.1,
"chunk {}",
(i + 1) / 60 - 1
);
}
}
}
#[test]
fn seq_3341_12() {
let (mut e, samples) = prepare_file!(
"seq-3341-12-24bit.wav",
48_000,
24,
ebur128::Mode::M,
[ebur128::Channel::Left, ebur128::Channel::Right]
);
// 100ms chunks / 10Hz
for (i, chunk) in samples.chunks(2 * 48_000 / 10).enumerate() {
e.add_frames_i32(chunk).expect("Failed to analyze samples");
// Constant after 1s
if i >= 10 {
float_eq::assert_float_eq!(
e.loudness_momentary()
.expect("Failed to get momentary loudness"),
-23.0,
abs <= 0.1
);
}
}
}
#[test]
fn seq_3341_13() {
for i in 1..=20 {
let (mut e, samples) = prepare_file!(
format!(
"seq-3341-13-{}-24bit.wav{}",
i,
if i > 2 { ".wav" } else { "" }
),
48_000,
24,
ebur128::Mode::M,
[ebur128::Channel::Left, ebur128::Channel::Right]
);
// 10ms chunks / 100Hz
let mut max_loudness = f64::MIN;
for chunk in samples.chunks(2 * 48_000 / 100) {
e.add_frames_i32(chunk).expect("Failed to analyze samples");
let loudness = e
.loudness_momentary()
.expect("Failed to get momentary loudness");
if loudness > max_loudness {
max_loudness = loudness;
}
}
float_eq::assert_float_eq!(max_loudness, -23.0, abs <= 0.1, "file {}", i);
}
}
#[test]
fn seq_3341_14() {
let (mut e, samples) = prepare_file!(
"seq-3341-14-24bit.wav.wav",
48_000,
24,
ebur128::Mode::M,
[ebur128::Channel::Left, ebur128::Channel::Right]
);
// 10ms chunks / 100Hz
let mut max_loudness = f64::MIN;
for (i, chunk) in samples.chunks(2 * 48_000 / 100).enumerate() {
e.add_frames_i32(chunk).expect("Failed to analyze samples");
let loudness = e
.loudness_momentary()
.expect("Failed to get momentary loudness");
if loudness > max_loudness {
max_loudness = loudness;
}
if (i + 1) % 80 == 0 {
let expected = -38.0 + ((i + 1) / 80 - 1) as f64;
float_eq::assert_float_eq!(
max_loudness,
expected,
abs <= 0.1,
"chunk {}",
(i + 1) / 80 - 1
);
}
}
}
#[test]
fn seq_3341_15() {
test_true_peak!(
"seq-3341-15-24bit.wav.wav",
48_000,
24,
[ebur128::Channel::Left, ebur128::Channel::Right],
-6.0
);
}
#[test]
fn seq_3341_16() {
test_true_peak!(
"seq-3341-16-24bit.wav.wav",
48_000,
24,
[ebur128::Channel::Left, ebur128::Channel::Right],
-6.0
);
}
#[test]
fn seq_3341_17() {
test_true_peak!(
"seq-3341-17-24bit.wav.wav",
48_000,
24,
[ebur128::Channel::Left, ebur128::Channel::Right],
-6.0
);
}
#[test]
fn seq_3341_18() {
test_true_peak!(
"seq-3341-18-24bit.wav.wav",
48_000,
24,
[ebur128::Channel::Left, ebur128::Channel::Right],
-6.0
);
}
#[test]
fn seq_3341_19() {
test_true_peak!(
"seq-3341-19-24bit.wav.wav",
48_000,
24,
[ebur128::Channel::Left, ebur128::Channel::Right],
3.0
);
}
#[test]
fn seq_3341_20() {
test_true_peak!(
"seq-3341-20-24bit.wav.wav",
48_000,
24,
[ebur128::Channel::Left, ebur128::Channel::Right],
0.0
);
}
#[test]
fn seq_3341_21() {
test_true_peak!(
"seq-3341-21-24bit.wav.wav",
48_000,
24,
[ebur128::Channel::Left, ebur128::Channel::Right],
0.0
);
}
#[test]
fn seq_3341_22() {
test_true_peak!(
"seq-3341-22-24bit.wav.wav",
48_000,
24,
[ebur128::Channel::Left, ebur128::Channel::Right],
0.0
);
}
#[test]
fn seq_3341_23() {
test_true_peak!(
"seq-3341-23-24bit.wav.wav",
48_000,
24,
[ebur128::Channel::Left, ebur128::Channel::Right],
0.0
);
}
#[test]
fn seq_3342_1() {
test_loudness_range!(
"seq-3342-1-16bit.wav",
48_000,
16,
[ebur128::Channel::Left, ebur128::Channel::Right],
10.0
);
}
#[test]
fn seq_3342_2() {
test_loudness_range!(
"seq-3342-2-16bit.wav",
48_000,
16,
[ebur128::Channel::Left, ebur128::Channel::Right],
5.0
);
}
#[test]
fn seq_3342_3() {
test_loudness_range!(
"seq-3342-3-16bit.wav",
48_000,
16,
[ebur128::Channel::Left, ebur128::Channel::Right],
20.0
);
}
#[test]
fn seq_3342_4() {
test_loudness_range!(
"seq-3342-4-16bit.wav",
48_000,
16,
[ebur128::Channel::Left, ebur128::Channel::Right],
15.0
);
}
#[test]
fn seq_3342_5() {
test_loudness_range!(
"seq-3341-7_seq-3342-5-24bit.wav",
48_000,
24,
[ebur128::Channel::Left, ebur128::Channel::Right],
5.0
);
}
#[test]
fn seq_3342_6() {
test_loudness_range!(
"seq-3341-2011-8_seq-3342-6-24bit-v02.wav",
48_000,
24,
[ebur128::Channel::Left, ebur128::Channel::Right],
15.0
);
}