rill_core/math/
functions.rs1use super::num::Transcendental;
4use super::vector::scalar::ScalarVector4;
5use super::vector::traits::Vector as VecTrait;
6
7#[inline(always)]
9pub fn lerp<T: Transcendental>(a: T, b: T, t: T) -> T {
10 a + (b - a) * t
11}
12
13#[inline(always)]
15pub fn db_to_linear<T: Transcendental>(db: T) -> T {
16 T::from_f32(10.0_f32.powf(db.to_f32() / 20.0))
17}
18
19#[inline(always)]
21pub fn linear_to_db<T: Transcendental>(linear: T) -> T {
22 T::from_f32(20.0 * linear.to_f32().log10())
23}
24#[inline(always)]
26pub fn seconds_to_samples(seconds: f32, sample_rate: f32) -> usize {
27 (seconds * sample_rate) as usize
28}
29
30#[inline(always)]
32pub fn samples_to_seconds(samples: usize, sample_rate: f32) -> f32 {
33 samples as f32 / sample_rate
34}
35
36#[inline(always)]
38pub fn fast_tanh<T: Transcendental>(x: T) -> T {
39 let xf = x.to_f32();
40 T::from_f32(xf / (1.0 + xf.abs()))
41}
42
43#[inline(always)]
45pub fn soft_clip<T: Transcendental>(x: T, threshold: T) -> T {
46 let xf = x.to_f32();
47 let t = threshold.to_f32();
48
49 if xf > t {
50 T::from_f32(t + (xf - t) / (1.0 + ((xf - t) / (1.0 - t)).powi(2)))
51 } else if xf < -t {
52 T::from_f32(-t - (-xf - t) / (1.0 + ((-xf - t) / (1.0 - t)).powi(2)))
53 } else {
54 x
55 }
56}
57
58#[inline(always)]
60pub fn hann_window<T: Transcendental>(x: T) -> T {
61 let cos_term = (x * T::from_f32(2.0) * T::PI).cos();
62 T::from_f32(0.5) * (T::ONE - cos_term)
63}
64
65pub fn f32_to_i16_chunk(src: &[f32], dst: &mut [i16]) {
73 let len = src.len().min(dst.len());
74 let chunks = len / 4;
75
76 for chunk in 0..chunks {
77 let o = chunk * 4;
78 let v = ScalarVector4::load(&src[o..o + 4]);
79 let lo = ScalarVector4::splat(-1.0f32);
80 let hi = ScalarVector4::splat(1.0f32);
81 let scale = ScalarVector4::splat(32767.0f32);
82 let clamped = v.clamp(&lo, &hi);
83 let scaled = clamped.mul(&scale);
84 dst[o] = scaled.extract(0) as i16;
85 dst[o + 1] = scaled.extract(1) as i16;
86 dst[o + 2] = scaled.extract(2) as i16;
87 dst[o + 3] = scaled.extract(3) as i16;
88 }
89
90 for i in chunks * 4..len {
91 dst[i] = (src[i].clamp(-1.0, 1.0) * 32767.0) as i16;
92 }
93}
94
95pub fn i16_to_f32_chunk(src: &[i16], dst: &mut [f32]) {
103 let len = src.len().min(dst.len());
104 let chunks = len / 4;
105
106 for chunk in 0..chunks {
107 let o = chunk * 4;
108 let v = ScalarVector4::load(&[
109 src[o] as f32 / 32768.0,
110 src[o + 1] as f32 / 32768.0,
111 src[o + 2] as f32 / 32768.0,
112 src[o + 3] as f32 / 32768.0,
113 ]);
114 v.store(&mut dst[o..o + 4]);
115 }
116
117 for i in chunks * 4..len {
118 dst[i] = src[i] as f32 / 32768.0;
119 }
120}
121
122pub fn deinterleave_stereo(stereo: &[f32], out_l: &mut [f32], out_r: &mut [f32]) {
130 let pairs = (stereo.len() / 2).min(out_l.len()).min(out_r.len());
131 let chunks = pairs / 4;
132
133 for chunk in 0..chunks {
134 let so = chunk * 8;
135 let mo = chunk * 4;
136
137 let v01 = ScalarVector4::load(&stereo[so..so + 4]);
138 let v23 = ScalarVector4::load(&stereo[so + 4..so + 8]);
139
140 let l = ScalarVector4::from_fn(|i| {
141 if i < 2 {
142 v01.extract(i * 2)
143 } else {
144 v23.extract((i - 2) * 2)
145 }
146 });
147
148 let r = ScalarVector4::from_fn(|i| {
149 if i < 2 {
150 v01.extract(i * 2 + 1)
151 } else {
152 v23.extract((i - 2) * 2 + 1)
153 }
154 });
155
156 l.store(&mut out_l[mo..mo + 4]);
157 r.store(&mut out_r[mo..mo + 4]);
158 }
159
160 for i in chunks * 4..pairs {
161 out_l[i] = stereo[i * 2];
162 out_r[i] = stereo[i * 2 + 1];
163 }
164}
165
166pub fn interleave_stereo(in_l: &[f32], in_r: &[f32], stereo: &mut [f32]) {
174 let pairs = in_l.len().min(in_r.len()).min(stereo.len() / 2);
175 let chunks = pairs / 4;
176
177 for chunk in 0..chunks {
178 let mo = chunk * 4;
179 let so = chunk * 8;
180
181 let l = ScalarVector4::load(&in_l[mo..mo + 4]);
182 let r = ScalarVector4::load(&in_r[mo..mo + 4]);
183
184 let out: [f32; 8] = std::array::from_fn(|i| {
185 if i % 2 == 0 {
186 l.extract(i / 2)
187 } else {
188 r.extract(i / 2)
189 }
190 });
191
192 stereo[so..so + 8].copy_from_slice(&out);
193 }
194
195 for i in chunks * 4..pairs {
196 stereo[i * 2] = in_l[i];
197 stereo[i * 2 + 1] = in_r[i];
198 }
199}