use std::collections::HashMap;
use rand::Rng;
use fft_convolver::FFTConvolver;
use super::fft::SpectrumError;
use std::f64::consts::PI;
use crate::util;
pub fn partitioned_convolution(audio1: &mut Vec<f64>, audio2: &mut Vec<f64>, block_size: usize) -> Result<Vec<f64>, SpectrumError> {
let mut convolver = FFTConvolver::default();
let mut output: Vec<f64> = vec![0.0; audio1.len()];
match convolver.init(block_size, &audio2) {
Ok(()) => (),
Err(err) => {
return Err(SpectrumError{error_msg: err.to_string()});
}
}
match convolver.process(&audio1, &mut output) {
Ok(()) => (),
Err(err) => {
return Err(SpectrumError{error_msg: err.to_string()});
}
}
Ok(output)
}
pub fn stft_exchange_frames(magnitude_spectrogram: &mut [Vec<f64>], phase_spectrogram: &mut [Vec<f64>], hop: usize) {
let end_idx = magnitude_spectrogram.len() - magnitude_spectrogram.len() % (hop * 2);
let step = hop * 2;
for i in (0..end_idx).step_by(step) {
for j in i..i+hop {
for k in 0..magnitude_spectrogram[j].len() {
let temp_magnitude = magnitude_spectrogram[j][k];
let temp_phase = phase_spectrogram[j][k];
magnitude_spectrogram[j][k] = magnitude_spectrogram[j + hop][k];
magnitude_spectrogram[j + hop][k] = temp_magnitude;
phase_spectrogram[j][k] = phase_spectrogram[j + hop][k];
phase_spectrogram[j + hop][k] = temp_phase;
}
}
}
}
pub fn stft_exchange_frames_stochastic(magnitude_spectrogram: &mut [Vec<f64>], phase_spectrogram: &mut [Vec<f64>], max_hop: usize) {
let mut future_indices: HashMap<usize, bool> = HashMap::with_capacity(magnitude_spectrogram.len());
let mut idx = 0;
while idx < magnitude_spectrogram.len() {
if !future_indices.contains_key(&idx) {
let mut possible_indices: Vec<usize> = Vec::new();
for i in idx..usize::min(idx + max_hop, magnitude_spectrogram.len()) {
if !future_indices.contains_key(&i) {
possible_indices.push(i);
}
}
let swap_idx = rand::thread_rng().gen_range(0..possible_indices.len());
for i in 0..magnitude_spectrogram[idx].len() {
let temp_magnitude = magnitude_spectrogram[idx][i];
let temp_phase = phase_spectrogram[idx][i];
magnitude_spectrogram[idx][i] = magnitude_spectrogram[swap_idx][i];
magnitude_spectrogram[swap_idx][i] = temp_magnitude;
phase_spectrogram[idx][i] = phase_spectrogram[swap_idx][i];
phase_spectrogram[swap_idx][i] = temp_phase;
}
future_indices.insert(swap_idx, true);
}
idx += 1;
}
}
pub fn fft_exchange_bins(magnitude_spectrum: &mut [f64], phase_spectrum: &mut [f64], hop: usize) {
let end_idx = magnitude_spectrum.len() - magnitude_spectrum.len() % (hop * 2);
let step = hop * 2;
for i in (0..end_idx).step_by(step) {
for j in i..i+hop {
let temp_magnitude = magnitude_spectrum[j];
let temp_phase = phase_spectrum[j];
magnitude_spectrum[j] = magnitude_spectrum[j + hop];
magnitude_spectrum[j + hop] = temp_magnitude;
phase_spectrum[j] = phase_spectrum[j + hop];
phase_spectrum[j + hop] = temp_phase;
}
}
}
pub fn fft_exchange_bins_stochastic(magnitude_spectrum: &mut [f64], phase_spectrum: &mut [f64], max_hop: usize) {
let mut future_indices: HashMap<usize, bool> = HashMap::with_capacity(magnitude_spectrum.len());
let mut idx = 0;
while idx < magnitude_spectrum.len() {
if !future_indices.contains_key(&idx) {
let mut possible_indices: Vec<usize> = Vec::new();
for i in idx..usize::min(idx + max_hop, magnitude_spectrum.len()) {
if !future_indices.contains_key(&i) {
possible_indices.push(i);
}
}
let swap_idx = rand::thread_rng().gen_range(0..possible_indices.len());
let temp_magnitude = magnitude_spectrum[idx];
let temp_phase = phase_spectrum[idx];
magnitude_spectrum[idx] = magnitude_spectrum[swap_idx];
magnitude_spectrum[swap_idx] = temp_magnitude;
phase_spectrum[idx] = phase_spectrum[swap_idx];
phase_spectrum[swap_idx] = temp_phase;
future_indices.insert(swap_idx, true);
}
idx += 1;
}
}
pub fn fft_mag_gate(magnitude_spectrogram: &mut [Vec<f64>], gate_frac: f64, above: bool) {
for i in 0..magnitude_spectrogram.len() {
let maxval = match util::max(&magnitude_spectrogram[i]) {
Some(val) => val,
None => 0.0
};
let gateval = maxval * gate_frac;
if above {
for j in 0..magnitude_spectrogram[i].len() {
if magnitude_spectrogram[i][j] < gateval {
magnitude_spectrogram[i][j] = 0.0;
}
}
} else {
for j in 0..magnitude_spectrogram[i].len() {
if magnitude_spectrogram[i][j] > gateval {
magnitude_spectrogram[i][j] = 0.0;
}
}
}
}
}
pub fn fft_freeze(magnitude_spectrum: &Vec<f64>, phase_spectrum: &Vec<f64>, num_frames: usize, fft_size: usize, hop_size: usize) -> (Vec<Vec<f64>>, Vec<Vec<f64>>) {
let mut current_phases: Vec<f64> = vec![0.0; phase_spectrum.len()];
let mut phase_differences: Vec<f64> = vec![0.0; phase_spectrum.len()];
let mut stft_magnitudes: Vec<Vec<f64>> = Vec::with_capacity(num_frames);
let mut stft_phases: Vec<Vec<f64>> = Vec::with_capacity(num_frames);
let mut frame1_mag: Vec<f64> = vec![0.0; magnitude_spectrum.len()];
let mut frame1_phase: Vec<f64> = vec![0.0; magnitude_spectrum.len()];
for i in 0..magnitude_spectrum.len() {
frame1_mag[i] = magnitude_spectrum[i];
frame1_phase[i] = phase_spectrum[i];
current_phases[i] = phase_spectrum[i];
let period: usize = if i == 0 {0} else {fft_size / i};
let num_periods: f64 = hop_size as f64 / period as f64;
phase_differences[i] = if i == 0 {0.0} else {num_periods.fract() * 2.0 * PI};
}
stft_magnitudes.push(frame1_mag);
stft_phases.push(frame1_phase);
for _ in 1..num_frames {
let mut frame_mag: Vec<f64> = vec![0.0; magnitude_spectrum.len()];
let mut frame_phase: Vec<f64> = vec![0.0; magnitude_spectrum.len()];
for i in 0..magnitude_spectrum.len() {
frame_mag[i] = magnitude_spectrum[i];
let mut phase = current_phases[i] - phase_differences[i];
while phase > PI {
phase -= 2.0 * PI;
}
while phase < -PI {
phase += 2.0 * PI;
}
frame_phase[i] = phase;
current_phases[i] = phase;
}
stft_magnitudes.push(frame_mag);
stft_phases.push(frame_phase);
}
(stft_magnitudes, stft_phases)
}
pub fn fft_freeze2(magnitude_spectra: &[Vec<f64>], phase_spectra: &[Vec<f64>], index_to_freeze: usize, num_frames: usize) -> (Vec<Vec<f64>>, Vec<Vec<f64>>) {
let mut running_phase: Vec<f64> = vec![0.0; phase_spectra[0].len()];
let mut phase_differences: Vec<f64> = vec![0.0; phase_spectra[0].len()];
let mut stft_magnitudes: Vec<Vec<f64>> = Vec::with_capacity(num_frames);
let mut stft_phases: Vec<Vec<f64>> = Vec::with_capacity(num_frames);
let mut rng = rand::thread_rng();
let mut frame1_mag: Vec<f64> = vec![0.0; magnitude_spectra[index_to_freeze].len()];
let mut frame1_phase: Vec<f64> = vec![0.0; magnitude_spectra[index_to_freeze].len()];
for i in 0..magnitude_spectra[index_to_freeze].len() {
frame1_mag[i] = magnitude_spectra[index_to_freeze][i];
frame1_phase[i] = phase_spectra[index_to_freeze][i];
running_phase[i] = frame1_phase[i];
phase_differences[i] = phase_spectra[index_to_freeze + 1][i] - phase_spectra[index_to_freeze][i];
}
stft_magnitudes.push(frame1_mag);
stft_phases.push(frame1_phase);
for _ in 1..num_frames {
let mut frame_mag: Vec<f64> = vec![0.0; magnitude_spectra[index_to_freeze].len()];
let mut frame_phase: Vec<f64> = vec![0.0; phase_spectra[index_to_freeze].len()];
for i in 0..magnitude_spectra[index_to_freeze].len() {
frame_mag[i] = magnitude_spectra[index_to_freeze][i];
let mut phase = running_phase[i] + phase_differences[i];
frame_phase[i] = phase;
running_phase[i] = phase;
}
stft_magnitudes.push(frame_mag);
stft_phases.push(frame_phase);
}
(stft_magnitudes, stft_phases)
}
#[cfg(test)]
mod test {
use super::*;
use crate::{operations, spectrum};
use biquad::*;
#[test]
fn test_spectral_freeze() {
let fft_size: usize = 4096;
let hop_size: usize = fft_size / 2;
let window_type = crate::WindowType::Hamming;
let path = String::from("D:\\Recording\\Samples\\Iowa\\Cello.arco.mono.2444.1\\samples\\Cello.arco.ff.sulD.D3Db4.6.wav");
let mut audio = match crate::read(&path) {
Ok(x) => x,
Err(_) => panic!("could not read audio")
};
let filter_type = Type::HighPass;
let fs = Hertz::<f64>::from_hz(audio.sample_rate as f64).unwrap();
let cutoff = Hertz::<f64>::from_hz(40.0).unwrap();
let coefs = Coefficients::<f64>::from_params(filter_type, fs, cutoff, Q_BUTTERWORTH_F64).unwrap();
let mut filter = DirectForm2Transposed::<f64>::new(coefs);
let spectrogram = spectrum::rstft(&mut audio.samples[0], fft_size, hop_size, window_type);
let (mag, phase) = spectrum::complex_to_polar_rstft(&spectrogram);
let (mut freeze_mag, mut freeze_phase) = spectrum::fft_freeze2(&mag, &phase, 7, 200);
let mut freeze_spectrogram = spectrum::polar_to_complex_rstft(&freeze_mag, &freeze_phase).unwrap();
let mut output_audio = spectrum::irstft(&mut freeze_spectrogram, fft_size, fft_size / 2, crate::WindowType::Hamming).unwrap();
for i in 0..output_audio.len() {
output_audio[i] = filter.run(output_audio[i]);
}
operations::fade_in(&mut output_audio, crate::WindowType::Hanning, 10000);
operations::fade_out(&mut output_audio, crate::WindowType::Hanning, 10000);
let output_audiofile = crate::AudioFile::new_mono(crate::AudioFormat::S24, 44100, output_audio);
let path: String = String::from("D:\\Recording\\out7.wav");
match crate::write(&path, &output_audiofile) {
Ok(_) => (),
Err(_) => panic!("could not write audio")
}
}
#[test]
fn test_stochastic_exchange() {
let fft_size: usize = 4096;
let hop_size: usize = fft_size / 2;
let window_type = crate::WindowType::Hamming;
let path = String::from("D:\\Recording\\Samples\\freesound\\creative_commons_0\\wind_chimes\\eq\\217800__minian89__wind_chimes_eq.wav");
let mut audio = match crate::read(&path) {
Ok(x) => x,
Err(_) => panic!("could not read audio")
};
crate::mixdown(&mut audio);
let spectrogram: Vec<Vec<num::Complex<f64>>> = spectrum::rstft(&mut audio.samples[0], fft_size, hop_size, window_type);
let (mut magnitude_spectrogram, mut phase_spectrogram) = spectrum::complex_to_polar_rstft(&spectrogram);
spectrum::stft_exchange_frames_stochastic(&mut magnitude_spectrogram, &mut phase_spectrogram, 20);
let output_spectrogram = spectrum::polar_to_complex_rstft(&magnitude_spectrogram, &phase_spectrogram).unwrap();
let mut output_audio: Vec<f64> = spectrum::irstft(&output_spectrogram, fft_size, hop_size, window_type).unwrap();
operations::fade_in(&mut output_audio, crate::WindowType::Hanning, 1000);
operations::fade_out(&mut output_audio, crate::WindowType::Hanning, 1000);
let output_audiofile = crate::AudioFile::new_mono(crate::AudioFormat::S24, 44100, output_audio);
let path: String = String::from("D:\\Recording\\out5.wav");
match crate::write(&path, &output_audiofile) {
Ok(_) => (),
Err(_) => panic!("could not write audio")
}
}
}