+//! 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 {
DST_IV,
}
+/// DCT/DST working context.
#[allow(dead_code)]
pub struct DCT {
tmp: Vec<f32>,
}
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;
_ => 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]; }
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);
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 {
+//! 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 }
}
}
}
+/// 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);
}
}
+/// FFT working context.
pub struct FFT {
perms: Vec<usize>,
swaps: Vec<usize>,
}
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];
}
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];
}
}
+/// [`FFT`] context creator.
+///
+/// [`FFT`]: ./struct.FFT.html
pub struct 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<usize> = Vec::with_capacity(size);
}
}
+/// RDFT working context.
pub struct RDFT {
table: Vec<FFTComplex>,
fft: FFT,
}
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 {
}
}
+/// [`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<FFTComplex> = 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) };
+//! Modified Discrete Cosine transform functionality.
use std::f32::consts;
use super::fft::*;
+/// IMDCT working context.
pub struct IMDCT {
twiddle: Vec<FFTComplex>,
fft: FFT,
}*/
impl IMDCT {
+ /// Constructs a new instance of `IMDCT` context.
pub fn new(size: usize, scaledown: bool) -> Self {
let mut twiddle: Vec<FFTComplex> = Vec::with_capacity(size / 4);
let factor = 2.0 * consts::PI / ((8 * size) as f32);
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;
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;