Commit 60656c71 authored by Philippe Normand's avatar Philippe Normand 🥑

audiornnoise: New element for audio denoising

The audiornnoise element can be used as playbin audio-filter for instance, to
suppress noise in the audio stream.

This plugin relies on the nnnoiseless crate which implements the noise removal
algorithm of the Xiph RNNoise library, in Rust. Some demos and documentation of
the RNNoise C library can be found on:

https://people.xiph.org/~jm/demo/rnnoise/

Fixes #114
parent b8f9e0ef
Pipeline #191927 passed with stages
in 20 minutes and 30 seconds
......@@ -31,7 +31,7 @@ You will find the following plugins in this repository:
* `audio`
- `audiofx`: Plugins to apply audio effects to a stream (such as adding
echo/reverb, or normalization).
echo/reverb, [removing noise](https://jmvalin.ca/demo/rnnoise/) or normalization).
- `claxon`: A FLAC decoder based on the
[Claxon](https://github.com/ruuda/claxon) library.
......
......@@ -16,6 +16,7 @@ byte-slice-cast = "0.3"
num-traits = "0.2"
lazy_static = "1.0"
ebur128 = "0.1"
nnnoiseless = "0.2"
[lib]
name = "gstrsaudiofx"
......
This diff is collapsed.
......@@ -20,9 +20,11 @@ extern crate lazy_static;
mod audioecho;
mod audioloudnorm;
mod audiornnoise;
fn plugin_init(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
audioecho::register(plugin)?;
audiornnoise::register(plugin)?;
audioloudnorm::register(plugin)
}
......
// Copyright (C) 2020 Philippe Normand <philn@igalia.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
extern crate gstreamer as gst;
extern crate gstreamer_app as gst_app;
extern crate gstreamer_audio as gst_audio;
extern crate gstreamer_check as gst_check;
use byte_slice_cast::*;
fn init() {
use std::sync::Once;
static INIT: Once = Once::new();
INIT.call_once(|| {
gst::init().unwrap();
gstrsaudiofx::plugin_register_static().expect("Failed to register rsaudiofx plugin");
});
}
#[test]
fn test_rnnoise_silence_big_buffers() {
init();
let audio_info = gst_audio::AudioInfo::builder(gst_audio::AUDIO_FORMAT_F32, 48000, 2)
.build()
.unwrap();
test_rnnoise(&audio_info, 4096);
}
#[test]
fn test_rnnoise_silence_small_buffers() {
init();
let audio_info = gst_audio::AudioInfo::builder(gst_audio::AUDIO_FORMAT_F32, 48000, 2)
.build()
.unwrap();
test_rnnoise(&audio_info, 1024);
}
fn test_rnnoise(audio_info: &gst_audio::AudioInfo, buffer_size: usize) {
let filter = gst::ElementFactory::make("audiornnoise", None).unwrap();
let mut h = gst_check::Harness::with_element(&filter, Some("sink"), Some("src"));
let sink_caps = audio_info.to_caps().unwrap();
let src_caps = sink_caps.clone();
h.set_caps(src_caps, sink_caps);
h.play();
let buffer = {
let mut buffer = gst::Buffer::with_size(buffer_size * audio_info.bpf() as usize).unwrap();
{
let format_info = audio_info.format_info();
let buffer_mut = buffer.get_mut().unwrap();
let mut omap = buffer_mut.map_writable().unwrap();
let odata = omap.as_mut_slice_of::<u8>().unwrap();
format_info.fill_silence(odata);
}
buffer
};
let num_buffers = 5;
let mut total_processed = 0;
for _ in 0..num_buffers {
let result = h.push_and_pull(buffer.clone()).unwrap();
let map = result.into_mapped_buffer_readable().unwrap();
let output = map.as_slice().as_slice_of::<f64>().unwrap();
// all samples in the output buffers must value 0
assert_eq!(output.iter().any(|sample| *sample as u16 != 0u16), false);
total_processed += output.len();
}
h.push_event(gst::event::Eos::new());
let last_buffer = h.pull().unwrap();
let map = last_buffer.into_mapped_buffer_readable().unwrap();
let output = map.as_slice().as_slice_of::<f64>().unwrap();
total_processed += output.len();
// The total amount of samples pushed into the element shall be equal to the
// total amount of samples pulled from it.
assert_eq!(total_processed, num_buffers * buffer_size);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment