Rust音频响度分析库ebur128的使用,实现EBU R128标准的音频电平测量和响度归一化

Rust音频响度分析库ebur128的使用,实现EBU R128标准的音频电平测量和响度归一化

简介

ebur128是一个实现EBU R128响度标准的Rust库。欧洲广播联盟响度建议(EBU R128)为广播公司提供了分析和归一化音频的方法,使每段音频对人耳来说具有大致相同的音量。

该库提供API来分析音频并输出感知响度,结果可用于在播放期间归一化音量。

特性

  • 实现M、S和I模式
  • 实现响度范围测量
  • 真峰值扫描
  • 通过重新计算滤波器系数支持所有采样率

完整示例代码

以下是使用ebur128库进行音频响度分析和归一化的完整示例:

use ebur128::{EbuR128, Mode, Error};

fn main() -> Result<(), Error> {
    // 假设我们有一个44100Hz采样率、立体声的音频数据
    let sample_rate = 44100;
    let channels = 2;
    
    // 创建一个EBU R128分析器实例
    // 这里使用M模式(响度测量)和I模式(综合响度测量)
    let mut analyzer = EbuR128::new(
        sample_rate,
        channels,
        Mode::M | Mode::I
    )?;
    
    // 模拟音频数据 - 实际应用中应该从音频文件或流中读取
    // 这里生成1秒的静音音频(0.0值)
    let num_samples = sample_rate * channels as u32;
    let audio_data = vec![0.0f32; num_samples as usize];
    
    // 添加音频帧进行分析
    analyzer.add_frames_f32(&audio_data)?;
    
    // 获取瞬时响度(Loudness Momentary)
    let momentary_loudness = analyzer.loudness_momentary()?;
    println!("瞬时响度: {:.1} LUFS", momentary_loudness);
    
    // 获取短期响度(Loudness Short-term)
    let short_term_loudness = analyzer.loudness_short_term()?;
    println!("短期响度: {:.1} LUFS", short_term_loudness);
    
    // 获取综合响度(Loudness Integrated)
    let integrated_loudness = analyzer.loudness_integrated()?;
    println!("综合响度: {:.1} LUFS", integrated_loudness);
    
    // 获取响度范围(Loudness Range)
    let loudness_range = analyzer.loudness_range()?;
    println!("响度范围: {:.1} LU", loudness_range);
    
    // 获取真峰值(True Peak)
    let true_peak = analyzer.true_peak()?;
    println!("真峰值: {:.1} dBTP", true_peak);
    
    // 计算归一化增益
    // EBU R128标准目标响度为-23 LUFS
    let target_loudness = -23.0;
    let normalization_gain = target_loudness - integrated_loudness;
    println!("归一化增益: {:.1} dB", normalization_gain);
    
    Ok(())
}

扩展示例代码

以下是一个更完整的示例,演示如何从WAV文件读取音频并进行分析:

use ebur128::{EbuR128, Mode, Error};
use hound::{WavReader, SampleFormat};
use std::path::Path;

fn analyze_wav_file(path: &Path) -> Result<(), Error> {
    // 读取WAV文件
    let reader = WavReader::open(path)?;
    let spec = reader.spec();
    
    // 创建EBU R128分析器
    let mut analyzer = EbuR128::new(
        spec.sample_rate,
        spec.channels as usize,
        Mode::M | Mode::I | Mode::S | Mode::TRUE_PEAK
    )?;
    
    match spec.sample_format {
        SampleFormat::Int => {
            // 处理整数格式的音频数据
            let samples: Vec<i32> = reader.into_samples::<i32>().collect::<Result<_, _>>()?;
            let max_sample = 1 << (spec.bits_per_sample - 1);
            let float_samples: Vec<f32> = samples.iter()
                .map(|&s| s as f32 / max_sample as f32)
                .collect();
            analyzer.add_frames_f32(&float_samples)?;
        }
        SampleFormat::Float => {
            // 处理浮点格式的音频数据
            let samples: Vec<f32> = reader.into_samples::<f32>().collect::<Result<_, _>>()?;
            analyzer.add_frames_f32(&samples)?;
        }
    }
    
    // 打印分析结果
    println!("综合响度: {:.1} LUFS", analyzer.loudness_integrated()?);
    println!("瞬时响度: {:.1} LUFS", analyzer.loudness_momentary()?);
    println!("短期响度: {:.1} LUFS", analyzer.loudness_short_term()?);
    println!("响度范围: {:.1} LU", analyzer.loudness_range()?);
    println!("真峰值: {:.1} dBTP", analyzer.true_peak()?);
    
    Ok(())
}

fn main() -> Result<(), Error> {
    let path = Path::new("example.wav");
    analyze_wav_file(path)
}

安装

在您的项目中添加ebur128依赖:

[dependencies]
ebur128 = "0.1.10"
hound = "3.4.0"  # 用于WAV文件读取

或者运行以下命令:

cargo add ebur128 hound

许可证

ebur128采用MIT许可证授权。


1 回复

Rust音频响度分析库ebur128的使用指南

概述

ebur128是一个Rust实现的音频响度分析库,用于实现EBU R128标准的音频电平测量和响度归一化。该标准广泛应用于广播、流媒体和音频制作领域,用于确保不同音频内容之间的响度一致性。

主要功能

  • 计算瞬时响度、短期响度和综合响度
  • 支持多种音频格式和采样率
  • 实现响度归一化
  • 符合EBU R128和ITU-R BS.1770标准

使用方法

添加依赖

首先在Cargo.toml中添加依赖:

[dependencies]
ebur128 = "0.2"

基本使用示例

use ebur128::{EbuR128, Mode};

fn main() {
    // 创建分析器实例
    // 参数: 声道数, 采样率, 模式(这里使用所有模式)
    let mut analyzer = EbuR128::new(2, 44100, Mode::I | Mode::S | Mode::L).unwrap();
    
    // 假设我们有一些PCM音频数据(这里用静音数据示例)
    let samples = vec![0.0f32; 44100 * 2]; // 1秒立体声
    
    // 添加音频数据进行分析
    analyzer.add_frames_f32(&samples).unwrap();
    
    // 获取响度测量结果
    let momentary = analyzer.loudness_momentary().unwrap();
    let short_term = analyzer.loudness_short_term().unwrap();
    let integrated = analyzer.loudness_integrated().unwrap();
    
    println!("瞬时响度: {:.1} LUFS", momentary);
    println!("短期响度: {:.1} LUFS", short_term);
    println!("综合响度: {:.1} LUFS", integrated);
    
    // 获取真实峰值
    let true_peak = analyzer.true_peak().unwrap();
    println!("真实峰值: {:.1} dBTP", true_peak[0]); // 第一个声道
}

实际音频文件处理示例

以下是一个更完整的示例,展示如何处理实际音频文件:

use ebur128::{EbuR128, Mode};
use std::fs::File;
use std::io::BufReader;
use hound::{WavReader, SampleFormat};

fn analyze_wav_file(path: &str) -> Result<(), Box<dyn std::error::Error>> {
    // 打开WAV文件
    let reader = WavReader::open(path)?;
    let spec = reader.spec();
    
    // 创建响度分析器
    let mut analyzer = EbuR128::new(
        spec.channels as usize,
        spec.sample_rate,
        Mode::I | Mode::S | Mode::L
    )?;
    
    // 根据样本格式处理音频数据
    match spec.sample_format {
        SampleFormat::Float => {
            for sample in reader.into_samples::<f32>() {
                analyzer.add_frames_f32(&[sample?])?;
            }
        }
        SampleFormat::Int => {
            // 需要将整数样本转换为浮点数
            let max_val = (1 << (spec.bits_per_sample - 1)) as f32;
            for sample in reader.into_samples::<i32>() {
                let s = sample? as f32 / max_val;
                analyzer.add_frames_f32(&[s])?;
            }
        }
    }
    
    // 获取并打印结果
    println!("文件: {}", path);
    println!("综合响度: {:.1} LUFS", analyzer.loudness_integrated()?);
    println!("短期最大响度: {:.1} LUFS", analyzer.loudness_short_term()?);
    println!("真实峰值: {:.1} dBTP", analyzer.true_peak()?[0]);
    
    Ok(())
}

fn main() {
    if let Err(e) = analyze_wav_file("example.wav") {
        eprintln!("分析错误: {}", e);
    }
}

响度归一化示例

use ebur128::{EbuR128, Mode};

fn normalize_audio(samples: &mut [f32], target_lufs: f64) -> Result<(), Box<dyn std::error::Error>> {
    // 创建分析器
    let mut analyzer = EbuR128::new(2, 44100, Mode::I)?;
    
    // 分析原始响度
    analyzer.add_frames_f32(samples)?;
    let current_lufs = analyzer.loudness_integrated()?;
    
    // 计算增益调整值
    let gain = (target_lufs - current_lufs).exp2() as f32;
    
    // 应用增益
    for sample in samples.iter_mut() {
        *sample *= gain;
    }
    
    println!("已将音频从 {:.1} LUFS 归一化到 {:.1} LUFS", current_lufs, target_lufs);
    Ok(())
}

注意事项

  1. 采样率支持:库支持常见的音频采样率(44.1kHz, 48kHz等)
  2. 声道数:支持单声道、立体声和多声道音频
  3. 性能考虑:对于长音频文件,可能需要分块处理以避免内存问题
  4. 精度:EBU R128标准要求至少测量3秒音频才能获得有效结果

高级功能

自定义测量间隔

use ebur128::{EbuR128, Mode};

fn custom_interval_analysis() {
    let mut analyzer = EbuR128::new(2, 44100, Mode::I).unwrap();
    
    // 自定义测量间隔(默认为100ms)
    analyzer.set_max_window(500); // 设置为500ms
    
    // ...处理音频数据...
}

多线程处理

对于大型音频文件,可以考虑分块并行处理:

use ebur128::{EbuR128, Mode};
use rayon::prelude::*;

fn parallel_analysis(samples: &[f32], chunk_size: usize) -> f64 {
    let mut analyzer = EbuR128::new(2, 44100, Mode::I).unwrap();
    
    samples
        .par_chunks(chunk_size)
        .for_each(|chunk| {
            analyzer.add_frames_f32(chunk).unwrap();
        });
    
    analyzer.loudness_integrated().unwrap()
}

完整示例代码

以下是一个完整的音频处理示例,结合了文件读取、响度分析和归一化功能:

use ebur128::{EbuR128, Mode};
use hound::{WavReader, SampleFormat};
use std::path::Path;

// 音频处理结构体
struct AudioProcessor {
    analyzer: EbuR128,
    sample_rate: u32,
    channels: usize,
}

impl AudioProcessor {
    // 创建新的音频处理器
    fn new(channels: usize, sample_rate: u32) -> Result<Self, Box<dyn std::error::Error>> {
        Ok(Self {
            analyzer: EbuR128::new(channels, sample_rate, Mode::all())?,
            sample_rate,
            channels,
        })
    }

    // 分析WAV文件
    fn analyze_wav(&mut self, path: &Path) -> Result<(), Box<dyn std::error::Error>> {
        let reader = WavReader::open(path)?;
        let spec = reader.spec();

        // 检查音频参数是否匹配
        if spec.channels as usize != self.channels || spec.sample_rate != self.sample_rate {
            return Err("音频参数不匹配".into());
        }

        match spec.sample_format {
            SampleFormat::Float => {
                for sample in reader.into_samples::<f32>() {
                    self.analyzer.add_frames_f32(&[sample?])?;
                }
            }
            SampleFormat::Int => {
                let max_val = (1 << (spec.bits_per_sample - 1)) as f32;
                for sample in reader.into_samples::<i32>() {
                    let s = sample? as f32 / max_val;
                    self.analyzer.add_frames_f32(&[s])?;
                }
            }
        }

        Ok(())
    }

    // 获取分析结果
    fn get_results(&self) -> Result<(f64, f64, f64, Vec<f64>), Box<dyn std::error::Error>> {
        Ok((
            self.analyzer.loudness_momentary()?,
            self.analyzer.loudness_short_term()?,
            self.analyzer.loudness_integrated()?,
            self.analyzer.true_peak()?,
        ))
    }

    // 归一化音频数据
    fn normalize_audio(samples: &mut [f32], target_lufs: f64) -> Result<f32, Box<dyn std::error::Error>> {
        let mut analyzer = EbuR128::new(2, 44100, Mode::I)?;
        analyzer.add_frames_f32(samples)?;
        let current_lufs = analyzer.loudness_integrated()?;
        let gain = (target_lufs - current_lufs).exp2() as f32;
        
        for sample in samples.iter_mut() {
            *sample *= gain;
        }
        
        Ok(gain)
    }
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 初始化音频处理器 (立体声,44.1kHz)
    let mut processor = AudioProcessor::new(2, 44100)?;

    // 分析音频文件
    let audio_path = Path::new("audio.wav");
    processor.analyze_wav(audio_path)?;

    // 获取并打印结果
    let (momentary, short_term, integrated, true_peak) = processor.get_results()?;
    println!("音频分析结果:");
    println!("瞬时响度: {:.1} LUFS", momentary);
    println!("短期响度: {:.1} LUFS", short_term);
    println!("综合响度: {:.1} LUFS", integrated);
    println!("真实峰值: {:.1} dBTP", true_peak[0]);

    // 示例:归一化音频数据
    let target_lufs = -23.0; // EBU R128推荐值
    let mut samples = vec![0.5f32; 44100 * 2]; // 示例音频数据
    let gain = AudioProcessor::normalize_audio(&mut samples, target_lufs)?;
    println!("应用增益: {:.2}x 将音频归一化到 {:.1} LUFS", gain, target_lufs);

    Ok(())
}

总结

ebur128库为Rust开发者提供了完整的EBU R128标准实现,可以方便地集成到音频处理工具链中。通过上述示例,您可以快速开始进行音频响度分析和归一化处理。

回到顶部