rft 0.1.0

FFT handling library.
Documentation
/// Various average algorithms.
pub mod average;
pub use self::average::Average;
pub use self::average::compute as average;
pub use self::average::compute_in as average_in;

use {Precision, Complex};
use strided::{Strided, MutStrided};

/// Computes the spectrum of the given input and returns a vector with the
/// computed values.
#[inline(always)]
pub fn compute<C, I>(input: I) -> Vec<Precision>
	where C: Complex,
	      I: Strided<Elem=C>
{
	let mut output = vec![0.0; (input.as_stride().len() / 2) + 1];
	compute_in(input, &mut *output);

	output
}

/// Computes the spectrum of the given input into the given output.
pub fn compute_in<C, I, O>(input: I, mut output: O)
	where C: Complex,
	      I: Strided<Elem=C>,
	      O: MutStrided<Elem=Precision>
{
	let     input  = input.as_stride();
	let mut output = output.as_stride_mut();

	debug_assert_eq!(output.len(), input.len() / 2 + 1);

	for (input, output) in input.iter().zip(output.iter_mut()) {
		*output = (input.real() * input.real() + input.imag() * input.imag()).sqrt();
	}
}

/// Returns the value of the band in the given spectrum.
#[inline]
pub fn band<I>(input: I, mut band: usize) -> Precision
	where I: Strided<Elem=Precision>
{
	let input = input.as_stride();

	if band > input.len() - 1 {
		band = input.len() - 1;
	}

	input[band]
}

/// Returns the bandwidth for the given window size and sample rate.
#[inline(always)]
pub fn bandwidth(size: usize, rate: u32) -> Precision {
	(2.0 / size as Precision) * (rate as Precision / 2.0)
}

/// Gets the index for the given frequency in a window of the given size and
/// sample rate.
pub fn index_for(frequency: u32, size: usize, rate: u32) -> usize {
	let bandwidth = bandwidth(size, rate);

	if frequency < (bandwidth / 2.0) as u32 {
		return 0;
	}

	if frequency > ((rate as Precision / 2.0) - (bandwidth / 2.0)) as u32 {
		return size / 2;
	}

	(size as Precision * (frequency as Precision / rate as Precision)).round() as usize
}

/// Returns the frequency for the given index in a window of the given size and
/// sample rate.
pub fn frequency_for(index: usize, size: usize, rate: u32) -> u32 {
	let bandwidth = bandwidth(size, rate);

	if index == 0 {
		return (bandwidth * 0.25).round() as u32;
	}

	if index >= size / 2 {
		let last = (rate as Precision / 2.0) - (bandwidth / 2.0);
		let half = bandwidth * 0.25;

		return (last + half).round() as u32;
	}

	(index as Precision * bandwidth as Precision) as u32
}

#[cfg(test)]
mod tests {
	#[test]
	fn bandwidth() {
		assert_eq!(super::bandwidth(1024, 44100), 43.066406);
	}

	#[test]
	fn index_for() {
		assert_eq!(super::index_for(23, 1024, 44_100), 1);
		assert_eq!(super::index_for(40_000, 1024, 44_100), 512);
	}

	#[test]
	fn frequency() {
		assert_eq!(super::frequency_for(0,   1024, 44_100),    11);
		assert_eq!(super::frequency_for(256, 1024, 44_100), 11025);
		assert_eq!(super::frequency_for(512, 1024, 44_100), 22039);
	}
}