use crate::sample::{cast, Sample};
use alloc::vec::Vec;
use num_complex::Complex;
pub fn magnitude_into<T: Sample>(spectrum: &[Complex<T>], out: &mut [T]) {
assert_eq!(spectrum.len(), out.len(), "magnitude_into length mismatch");
for (dst, z) in out.iter_mut().zip(spectrum) {
*dst = z.norm();
}
}
#[must_use]
pub fn magnitude<T: Sample>(spectrum: &[Complex<T>]) -> Vec<T> {
spectrum.iter().map(|z| z.norm()).collect()
}
pub fn power_into<T: Sample>(spectrum: &[Complex<T>], out: &mut [T]) {
assert_eq!(spectrum.len(), out.len(), "power_into length mismatch");
for (dst, z) in out.iter_mut().zip(spectrum) {
*dst = z.norm_sqr();
}
}
#[must_use]
pub fn power<T: Sample>(spectrum: &[Complex<T>]) -> Vec<T> {
spectrum.iter().map(|z| z.norm_sqr()).collect()
}
pub fn phase_into<T: Sample>(spectrum: &[Complex<T>], out: &mut [T]) {
assert_eq!(spectrum.len(), out.len(), "phase_into length mismatch");
for (dst, z) in out.iter_mut().zip(spectrum) {
*dst = z.arg();
}
}
#[must_use]
pub fn phase<T: Sample>(spectrum: &[Complex<T>]) -> Vec<T> {
spectrum.iter().map(|z| z.arg()).collect()
}
fn amin<T: Sample>() -> T {
cast(1e-10)
}
pub fn amplitude_to_db<T: Sample>(amplitudes: &mut [T], reference: T, top_db: Option<T>) {
let amin = amin::<T>();
let twenty = cast::<T>(20.0);
let log_ref = reference.abs().max(amin).log10();
convert_to_db(amplitudes, twenty, log_ref, amin, top_db);
}
pub fn power_to_db<T: Sample>(powers: &mut [T], reference: T, top_db: Option<T>) {
let amin = amin::<T>();
let ten = cast::<T>(10.0);
let log_ref = reference.abs().max(amin).log10();
convert_to_db(powers, ten, log_ref, amin, top_db);
}
fn convert_to_db<T: Sample>(values: &mut [T], factor: T, log_ref: T, amin: T, top_db: Option<T>) {
let mut max_db = T::neg_infinity();
for v in values.iter_mut() {
let db = factor * (v.max(amin).log10() - log_ref);
*v = db;
if db > max_db {
max_db = db;
}
}
if let Some(top) = top_db {
let floor = max_db - top.abs();
for v in values.iter_mut() {
if *v < floor {
*v = floor;
}
}
}
}