From 4e034a32d947e1ef5f357cc2477d6f1c3b8454a9 Mon Sep 17 00:00:00 2001 From: Kostya Shishkov Date: Wed, 19 Feb 2020 15:20:36 +0100 Subject: [PATCH] core/dsp: document module --- nihav-core/src/dsp/dct.rs | 7 +++++++ nihav-core/src/dsp/fft.rs | 25 +++++++++++++++++++++++++ nihav-core/src/dsp/mdct.rs | 5 +++++ nihav-core/src/dsp/mod.rs | 1 + nihav-core/src/dsp/window.rs | 8 ++++++++ 5 files changed, 46 insertions(+) diff --git a/nihav-core/src/dsp/dct.rs b/nihav-core/src/dsp/dct.rs index e58ccc7..2a74449 100644 --- a/nihav-core/src/dsp/dct.rs +++ b/nihav-core/src/dsp/dct.rs @@ -1,5 +1,7 @@ +//! Discrete 1-D cosine and sine transforms. use std::f32::consts; +/// A list of DCT and DST modes. #[allow(non_camel_case_types)] #[derive(Clone,Copy,Debug,PartialEq)] pub enum DCTMode { @@ -13,6 +15,7 @@ pub enum DCTMode { DST_IV, } +/// DCT/DST working context. #[allow(dead_code)] pub struct DCT { tmp: Vec, @@ -26,6 +29,7 @@ pub struct DCT { } impl DCT { + /// Constructs a new context for the selected DCT or DST operation. pub fn new(mode: DCTMode, size: usize) -> Self { let bits = 31 - (size as u32).leading_zeros(); let is_pow2 = (size & (size - 1)) == 0; @@ -111,6 +115,7 @@ impl DCT { _ => unreachable!(), }; } + /// Performs DCT/DST. pub fn do_dct(&mut self, src: &[f32], dst: &mut [f32]) { if self.can_do_fast() { for (i, ni) in self.perms.iter().enumerate() { dst[i] = src[*ni]; } @@ -119,6 +124,7 @@ impl DCT { do_ref_dct(self.mode, src, dst, self.size); } } + /// Performs inplace DCT/DST. pub fn do_dct_inplace(&mut self, buf: &mut [f32]) { if self.can_do_fast() { swap_buf(buf, &self.swaps); @@ -128,6 +134,7 @@ impl DCT { do_ref_dct(self.mode, &self.tmp, buf, self.size); } } + /// Returns the scale for output normalisation. pub fn get_scale(&self) -> f32 { let fsize = self.size as f32; match self.mode { diff --git a/nihav-core/src/dsp/fft.rs b/nihav-core/src/dsp/fft.rs index 936a8aa..4629f75 100644 --- a/nihav-core/src/dsp/fft.rs +++ b/nihav-core/src/dsp/fft.rs @@ -1,21 +1,28 @@ +//! FFT and RDFT implementation. use std::f32::{self, consts}; use std::ops::{Not, Neg, Add, AddAssign, Sub, SubAssign, Mul, MulAssign}; use std::fmt; +/// Complex number. #[repr(C)] #[derive(Debug,Clone,Copy,PartialEq)] pub struct FFTComplex { + /// Real part of the numner. pub re: f32, + /// Complex part of the number. pub im: f32, } impl FFTComplex { + /// Calculates `exp(i * val)`. pub fn exp(val: f32) -> Self { FFTComplex { re: val.cos(), im: val.sin() } } + /// Returns `-Im + i * Re`. pub fn rotate(self) -> Self { FFTComplex { re: -self.im, im: self.re } } + /// Multiplies complex number by scalar. pub fn scale(self, scale: f32) -> Self { FFTComplex { re: self.re * scale, im: self.im * scale } } @@ -86,8 +93,10 @@ impl fmt::Display for FFTComplex { } } +/// Complex number with zero value. pub const FFTC_ZERO: FFTComplex = FFTComplex { re: 0.0, im: 0.0 }; +/// Calculates forward or inverse FFT in the straightforward way. pub fn generic_fft(data: &mut [FFTComplex], forward: bool) { let mut tmp = Vec::with_capacity(data.len()); tmp.resize(data.len(), FFTC_ZERO); @@ -523,6 +532,7 @@ impl FFTMode { } } +/// FFT working context. pub struct FFT { perms: Vec, swaps: Vec, @@ -530,14 +540,17 @@ pub struct FFT { } impl FFT { + /// Calculates Fourier transform. pub fn do_fft(&mut self, src: &[FFTComplex], dst: &mut [FFTComplex]) { for k in 0..src.len() { dst[k] = src[self.perms[k]]; } self.do_fft_core(dst); } + /// Calculates inverse Fourier transform. pub fn do_ifft(&mut self, src: &[FFTComplex], dst: &mut [FFTComplex]) { for k in 0..src.len() { dst[k] = src[self.perms[k]]; } self.do_ifft_core(dst); } + /// Performs inplace FFT. pub fn do_fft_inplace(&mut self, data: &mut [FFTComplex]) { for idx in 0..self.swaps.len() { let nidx = self.swaps[idx]; @@ -547,6 +560,7 @@ impl FFT { } self.do_fft_core(data); } + /// Performs inplace inverse FFT. pub fn do_ifft_inplace(&mut self, data: &mut [FFTComplex]) { for idx in 0..self.swaps.len() { let nidx = self.swaps[idx]; @@ -606,6 +620,9 @@ impl FFT { } } +/// [`FFT`] context creator. +/// +/// [`FFT`]: ./struct.FFT.html pub struct FFTBuilder { } @@ -683,6 +700,7 @@ impl FFTBuilder { } } } + /// Constructs a new `FFT` context. pub fn new_fft(size: usize, forward: bool) -> FFT { let mut ffts: Vec<(FFTMode, FFTData)> = Vec::with_capacity(1); let mut perms: Vec = Vec::with_capacity(size); @@ -725,6 +743,7 @@ impl FFTBuilder { } } +/// RDFT working context. pub struct RDFT { table: Vec, fft: FFT, @@ -738,10 +757,12 @@ fn crossadd(a: FFTComplex, b: FFTComplex) -> FFTComplex { } impl RDFT { + /// Calculates RDFT. pub fn do_rdft(&mut self, src: &[FFTComplex], dst: &mut [FFTComplex]) { dst.copy_from_slice(src); self.do_rdft_inplace(dst); } + /// Calculates inplace RDFT. pub fn do_rdft_inplace(&mut self, buf: &mut [FFTComplex]) { if !self.fwd { for n in 0..self.size/2 { @@ -790,10 +811,14 @@ impl RDFT { } } +/// [`RDFT`] context creator. +/// +/// [`RDFT`]: ./struct.FFT.html pub struct RDFTBuilder { } impl RDFTBuilder { + /// Constructs a new `RDFT` context. pub fn new_rdft(size: usize, forward: bool, forward_fft: bool) -> RDFT { let mut table: Vec = Vec::with_capacity(size / 4); let (base, scale) = if forward { (consts::PI / (size as f32), 0.5) } else { (-consts::PI / (size as f32), 1.0) }; diff --git a/nihav-core/src/dsp/mdct.rs b/nihav-core/src/dsp/mdct.rs index f883c7f..e6ed3dc 100644 --- a/nihav-core/src/dsp/mdct.rs +++ b/nihav-core/src/dsp/mdct.rs @@ -1,6 +1,8 @@ +//! Modified Discrete Cosine transform functionality. use std::f32::consts; use super::fft::*; +/// IMDCT working context. pub struct IMDCT { twiddle: Vec, fft: FFT, @@ -19,6 +21,7 @@ fn imdct(src: &[f32], dst: &mut [f32], length: usize) { }*/ impl IMDCT { + /// Constructs a new instance of `IMDCT` context. pub fn new(size: usize, scaledown: bool) -> Self { let mut twiddle: Vec = Vec::with_capacity(size / 4); let factor = 2.0 * consts::PI / ((8 * size) as f32); @@ -31,6 +34,7 @@ impl IMDCT { z.resize(size / 2, FFTC_ZERO); IMDCT { twiddle, fft, size, z } } + /// Calculates IMDCT. pub fn imdct(&mut self, src: &[f32], dst: &mut [f32]) { let size2 = self.size / 2; let size4 = self.size / 4; @@ -54,6 +58,7 @@ impl IMDCT { dst[3 * size4 + 2 * n + 1] = -self.z[size4 - n - 1].re; } } + /// Calculates only non-mirrored part of IMDCT. pub fn imdct_half(&mut self, src: &[f32], dst: &mut [f32]) { let size2 = self.size / 2; let size4 = self.size / 4; diff --git a/nihav-core/src/dsp/mod.rs b/nihav-core/src/dsp/mod.rs index 8e8e6af..2ff322d 100644 --- a/nihav-core/src/dsp/mod.rs +++ b/nihav-core/src/dsp/mod.rs @@ -1,3 +1,4 @@ +//! DSP routines. #[cfg(feature="dct")] #[allow(clippy::erasing_op)] pub mod dct; diff --git a/nihav-core/src/dsp/window.rs b/nihav-core/src/dsp/window.rs index 92a2655..eb350e3 100644 --- a/nihav-core/src/dsp/window.rs +++ b/nihav-core/src/dsp/window.rs @@ -1,12 +1,20 @@ +//! Window generating functions. use std::f32::consts; +/// Known window types. #[derive(Debug,Clone,Copy,PartialEq)] pub enum WindowType { + /// Simple square window. Square, + /// Simple sine window. Sine, + /// Kaiser-Bessel derived window. KaiserBessel(f32), } +/// Calculates window coefficients for the requested window type and size. +/// +/// Set `half` flag to calculate only the first half of the window. pub fn generate_window(mode: WindowType, scale: f32, size: usize, half: bool, dst: &mut [f32]) { match mode { WindowType::Square => { -- 2.30.2