Closed thewh1teagle closed 2 months ago
I'm also looking for it. it seems a little bit complex to me to understand what going on in the source code :-)
Not really a "simple" example, but maybe https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/blob/main/audio/audiofx/src/ebur128level/imp.rs helps.
Note that this crate only measures the loudness. Normalization has to be done separately based on the results.
@sdroege
Thanks.
Does the following looks correct? It works but maybe can be improved / has some mistakes.
/*
wget https://github.com/thewh1teagle/vibe/raw/main/samples/multi.wav
cargo run --example normalize_wav multi.wav multi.wav normalized.wav
*/
use ebur128::{EbuR128, Mode};
use hound::{WavReader, WavWriter, WavSpec, SampleFormat};
use std::env;
fn main() {
let input_path = env::args().nth(1).expect("Please specify input wav path");
let output_path = env::args().nth(2).expect("Please specify output wav path");
let mut reader = WavReader::open(&input_path).expect("Failed to open WAV file");
let spec = reader.spec();
let channels = spec.channels as usize;
let rate = spec.sample_rate as u32;
let mut ebur128 = EbuR128::new(channels as u32, rate, Mode::all()).expect("Failed to create ebur128");
let samples: Vec<f32> = reader
.samples::<f32>()
.map(|s| s.unwrap())
.collect();
let chunk_size = rate * 1; // 1s
// Analyze loudness
for chunk in samples.chunks(chunk_size as usize * channels) {
ebur128.add_frames_f32(chunk);
let loudness = ebur128
.loudness_global()
.expect("Failed to get global loudness");
println!("Loudness: {:?}", loudness);
}
// Get the global loudness and calculate the gain needed
let global_loudness = ebur128.loudness_global().expect("Failed to get global loudness");
let target_loudness = -23.0; // EBU R128 target loudness
let gain = 10f32.powf(((target_loudness - global_loudness) / 20.0) as f32);
// Apply gain and write to the output file
let mut writer = WavWriter::create(output_path, WavSpec {
channels: spec.channels,
sample_rate: spec.sample_rate,
bits_per_sample: 16,
sample_format: SampleFormat::Int,
}).expect("Failed to create WAV writer");
for sample in samples {
let normalized_sample = (sample * gain).clamp(-1.0, 1.0);
writer.write_sample((normalized_sample * i16::MAX as f32) as i16).expect("Failed to write sample");
}
}
Yes, something like that should work. Afterwards the global loudness should be about -23.
Do you want to put this into a PR and add it to the examples subdirectory here?
Hi there, Thanks for providing this crate!
I’m using cpal to record audio from the microphone in Rust, but the sound is coming through too quietly. I’m looking to normalize the audio, but I haven’t found a straightforward example in your repository. Could you clarify what the input and output should be for normalization? Specifically, should I use a sample array and sample rate?
It would be great if you could add a simple example with cpal or provide some guidance on how to achieve this.
Thank you!