1#![allow(unused_imports)]
7
8#[cfg(feature = "std")]
9use std::f32::consts::PI;
10
11#[cfg(not(feature = "std"))]
12use core::f32::consts::PI;
13
14use num_traits::{Float, FromPrimitive};
15
16pub struct Hadamard<T: Float> {
18 size: usize,
19 _marker: core::marker::PhantomData<T>,
20}
21
22impl<T: Float + FromPrimitive> Hadamard<T> {
23 pub fn new(size: usize) -> Self {
25 Self {
26 size,
27 _marker: core::marker::PhantomData,
28 }
29 }
30
31 pub fn in_place(&self, data: &mut [T]) {
33 self.unscaled_in_place(data);
34
35 let factor = self.scaling_factor();
36 for c in 0..self.size {
37 data[c] = data[c] * factor;
38 }
39 }
40
41 pub fn scaling_factor(&self) -> T {
43 if self.size == 0 {
44 T::one()
45 } else {
46 T::from_f32(1.0 / (self.size as f32).sqrt()).unwrap()
47 }
48 }
49
50 pub fn unscaled_in_place(&self, data: &mut [T]) {
51 if self.size <= 1 {
52 return;
53 }
54
55 let mut h_size = 1;
56 while h_size < self.size {
57 for start_index in (0..self.size).step_by(h_size * 2) {
58 for i in start_index..(start_index + h_size).min(self.size) {
59 if i + h_size < self.size {
60 let a = data[i];
61 let b = data[i + h_size];
62 data[i] = a + b;
63 data[i + h_size] = a - b;
64 }
65 }
66 }
67 h_size *= 2;
68 }
69 }
70}
71
72pub struct Householder<T: Float> {
74 size: usize,
75 _marker: core::marker::PhantomData<T>,
76}
77
78impl<T: Float + FromPrimitive> Householder<T> {
79 pub fn new(size: usize) -> Self {
81 Self {
82 size,
83 _marker: core::marker::PhantomData,
84 }
85 }
86
87 pub fn in_place(&self, data: &mut [T]) {
89 if self.size < 1 {
90 return;
91 }
92
93 let factor = T::from_f32(-2.0 / self.size as f32).unwrap();
94
95 let mut sum = data[0];
96 for i in 1..self.size {
97 sum = sum + data[i];
98 }
99 sum = sum * factor;
100
101 for i in 0..self.size {
102 data[i] = data[i] + sum;
103 }
104 }
105
106 pub fn scaling_factor(&self) -> T {
108 T::one()
109 }
110}
111
112pub struct StereoMultiMixer<T: Float> {
120 channels: usize,
121 coeffs: Vec<T>,
122}
123
124impl<T: Float + FromPrimitive> StereoMultiMixer<T> {
125 pub fn new(channels: usize) -> Self {
127 assert!(channels > 0, "StereoMultiMixer must have a positive number of channels");
128 assert_eq!(channels % 2, 0, "StereoMultiMixer must have an even number of channels");
129
130 let h_channels = channels / 2;
131 let mut coeffs = vec![T::zero(); channels];
132
133 coeffs[0] = T::one();
134 coeffs[1] = T::zero();
135
136 for i in 1..h_channels {
137 let phase = PI * i as f32 / channels as f32;
138 coeffs[2 * i] = T::from_f32(phase.cos()).unwrap();
139 coeffs[2 * i + 1] = T::from_f32(phase.sin()).unwrap();
140 }
141
142 Self { channels, coeffs }
143 }
144
145 pub fn stereo_to_multi(&self, input: &[T; 2], output: &mut [T]) {
147 let scale = T::from_f32((2.0 / self.channels as f32).sqrt()).unwrap();
148 output[0] = input[0] * scale;
149 output[1] = input[1] * scale;
150
151 for i in (2..self.channels).step_by(2) {
152 output[i] = (input[0] * self.coeffs[i] + input[1] * self.coeffs[i + 1]) * scale;
153 output[i + 1] = (input[1] * self.coeffs[i] - input[0] * self.coeffs[i + 1]) * scale;
154 }
155 }
156
157 pub fn multi_to_stereo(&self, input: &[T], output: &mut [T; 2]) {
159 output[0] = input[0];
160 output[1] = input[1];
161
162 for i in (2..self.channels).step_by(2) {
163 output[0] = output[0] + input[i] * self.coeffs[i] - input[i + 1] * self.coeffs[i + 1];
164 output[1] = output[1] + input[i + 1] * self.coeffs[i] + input[i] * self.coeffs[i + 1];
165 }
166 }
167
168 pub fn scaling_factor1(&self) -> T {
170 T::from_f32(2.0 / self.channels as f32).unwrap()
171 }
172
173 pub fn scaling_factor2(&self) -> T {
175 T::from_f32((2.0 / self.channels as f32).sqrt()).unwrap()
176 }
177}
178
179pub fn cheap_energy_crossfade<T: Float + FromPrimitive>(x: T, to_coeff: &mut T, from_coeff: &mut T) {
183 *to_coeff = x;
184 *from_coeff = T::one() - x;
185}
186
187#[cfg(test)]
188mod tests {
189 use super::*;
190
191 #[test]
192 fn test_householder() {
193 let householder = Householder::<f32>::new(4);
194 let mut data = vec![1.0, 2.0, 3.0, 4.0];
195
196 householder.in_place(&mut data);
197
198 let mean = (1.0 + 2.0 + 3.0 + 4.0) / 4.0;
200 let expected = vec![
201 1.0 - 2.0 * mean,
202 2.0 - 2.0 * mean,
203 3.0 - 2.0 * mean,
204 4.0 - 2.0 * mean,
205 ];
206
207 for i in 0..4 {
208 assert!((data[i] - expected[i]).abs() < 1e-10);
209 }
210 }
211
212 #[test]
213 fn test_hadamard() {
214 let hadamard = Hadamard::<f32>::new(4);
215 let mut data = vec![1.0, 2.0, 3.0, 4.0];
216
217 hadamard.in_place(&mut data);
218
219 let expected = vec![5.0, -1.0, -2.0, 0.0];
221 for i in 0..4 {
222 assert!((data[i] - expected[i]).abs() < 1e-6);
223 }
224 }
225
226 #[test]
227 fn test_stereo_multi_mixer() {
228 let mixer = StereoMultiMixer::<f32>::new(4);
229 let input = [1.0, 2.0];
230 let mut output = vec![0.0; 4];
231
232 mixer.stereo_to_multi(&input, &mut output);
233
234 let input_energy = input[0] * input[0] + input[1] * input[1];
236 let output_energy = output.iter().map(|&x| x * x).sum::<f32>();
237 assert!((input_energy - output_energy).abs() < 1e-6);
238
239 let mut round_trip = [0.0, 0.0];
241 mixer.multi_to_stereo(&output, &mut round_trip);
242
243 let scale = mixer.scaling_factor2();
245 assert!((round_trip[0] * scale - input[0]).abs() < 1e-6);
246 assert!((round_trip[1] * scale - input[1]).abs() < 1e-6);
247 }
248
249 #[test]
250 fn test_cheap_energy_crossfade() {
251 let mut to_coeff = 0.0;
252 let mut from_coeff = 0.0;
253
254 cheap_energy_crossfade(0.5, &mut to_coeff, &mut from_coeff);
255
256 assert!((to_coeff - from_coeff).abs() < 1e-6);
258
259 assert!((to_coeff + from_coeff - 1.0).abs() < 0.03);
261
262 cheap_energy_crossfade(0.0, &mut to_coeff, &mut from_coeff);
264 assert!(to_coeff < 0.01);
265 assert!((from_coeff - 1.0).abs() < 0.01);
266
267 cheap_energy_crossfade(1.0, &mut to_coeff, &mut from_coeff);
268 assert!((to_coeff - 1.0).abs() < 0.01);
269 assert!(from_coeff < 0.01);
270 }
271}