1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
#[cfg(feature = "simd")]
use std::simd::{f32x16, i16x16};
/// Convert an array of 16 bit mono audio samples to a vector of 32 bit floats.
///
/// This variant does not use SIMD instructions.
///
/// # Arguments
/// * `samples` - The array of 16 bit mono audio samples.
///
/// # Returns
/// A vector of 32 bit floats.
pub fn convert_integer_to_float_audio(samples: &[i16]) -> Vec<f32> {
let mut floats = Vec::with_capacity(samples.len());
for sample in samples {
floats.push(*sample as f32 / 32768.0);
}
floats
}
/// Convert an array of 16 bit mono audio samples to a vector of 32 bit floats.
///
/// This variant uses SIMD instructions, and as such is only available on
/// nightly Rust.
///
/// # Arguments
/// * `samples` - The array of 16 bit mono audio samples.
///
/// # Returns
/// A vector of 32 bit floats.
#[cfg(feature = "simd")]
pub fn convert_integer_to_float_audio_simd(samples: &[i16]) -> Vec<f32> {
let mut floats = Vec::with_capacity(samples.len());
let div_arr = f32x16::splat(32768.0);
let chunks = samples.chunks_exact(16);
let remainder = chunks.remainder();
for chunk in chunks {
let simd = i16x16::from_slice(chunk).cast::<f32>();
let simd = simd / div_arr;
floats.extend(&simd.to_array()[..]);
}
// Handle the remainder.
// do this normally because it's only a few samples and the overhead of
// converting to SIMD is not worth it.
for sample in remainder {
floats.push(*sample as f32 / 32768.0);
}
floats
}
/// Convert 32 bit floating point stereo PCM audio to 32 bit floating point mono PCM audio.
///
/// This variant does not use SIMD instructions.
///
/// # Arguments
/// * `samples` - The array of 32 bit floating point stereo PCM audio samples.
///
/// # Returns
/// A vector of 32 bit floating point mono PCM audio samples.
pub fn convert_stereo_to_mono_audio(samples: &[f32]) -> Result<Vec<f32>, &'static str> {
if samples.len() & 1 != 0 {
return Err("The stereo audio vector has an odd number of samples. \
This means a half-sample is missing somewhere");
}
Ok(samples
.chunks_exact(2)
.map(|x| (x[0] + x[1]) / 2.0)
.collect())
}
/// Convert 32 bit floating point stereo PCM audio to 32 bit floating point mono PCM audio.
///
/// This variant uses SIMD instructions, and as such is only available on
/// nightly Rust.
///
/// # Arguments
/// * `samples` - The array of 32 bit floating point stereo PCM audio samples.
///
/// # Returns
/// A vector of 32 bit floating point mono PCM audio samples.
#[cfg(feature = "simd")]
pub fn convert_stereo_to_mono_audio_simd(samples: &[f32]) -> Result<Vec<f32>, &'static str> {
let mut mono = Vec::with_capacity(samples.len() / 2);
let div_array = f32x16::splat(2.0);
let chunks = samples.chunks_exact(32);
let remainder = chunks.remainder();
for chunk in chunks {
let [c1, c2] = [0, 1].map(|offset| {
let mut arr = [0.0; 16];
std::iter::zip(&mut arr, chunk.iter().skip(offset).step_by(2).copied())
.for_each(|(a, c)| *a = c);
arr
});
let c1 = f32x16::from(c1);
let c2 = f32x16::from(c2);
let mono_simd = (c1 + c2) / div_array;
mono.extend(&mono_simd.to_array()[..]);
}
// Handle the remainder.
// do this normally because it's only a few samples and the overhead of
// converting to SIMD is not worth it.
mono.extend(convert_stereo_to_mono_audio(remainder)?);
Ok(mono)
}
#[cfg(feature = "simd")]
#[cfg(test)]
mod test {
use super::*;
#[test]
pub fn assert_stereo_to_mono_err() {
// fake some sample data
let samples = (0u16..1029).map(f32::from).collect::<Vec<f32>>();
let mono = convert_stereo_to_mono_audio(&samples);
assert!(mono.is_err());
}
}
#[cfg(feature = "simd")]
#[cfg(test)]
mod test_simd {
use super::*;
#[test]
pub fn assert_stereo_to_mono_simd() {
// fake some sample data
let samples = (0u16..1028).map(f32::from).collect::<Vec<f32>>();
let mono_simd = convert_stereo_to_mono_audio_simd(&samples);
let mono = convert_stereo_to_mono_audio(&samples);
assert_eq!(mono_simd, mono);
}
#[test]
pub fn assert_stereo_to_mono_simd_err() {
// fake some sample data
let samples = (0u16..1029).map(f32::from).collect::<Vec<f32>>();
let mono_simd = convert_stereo_to_mono_audio_simd(&samples);
let mono = convert_stereo_to_mono_audio(&samples);
assert_eq!(mono_simd, mono);
}
}