1#![allow(unused_variables)]
2use smallvec::SmallVec;
9
10#[cfg(target_arch = "wasm32")]
11use std::sync::atomic::{AtomicU32, Ordering};
12
13#[cfg(target_arch = "wasm32")]
18extern "C" {
19 fn sesh_vec_version() -> u32;
20}
21
22#[cfg(target_arch = "wasm32")]
24static HOST_VEC_VERSION: AtomicU32 = AtomicU32::new(0);
25
26#[cfg(target_arch = "wasm32")]
27fn host_version() -> u32 {
28 let v = HOST_VEC_VERSION.load(Ordering::Relaxed);
29 if v != 0 {
30 return v;
31 }
32 let v = unsafe { sesh_vec_version() };
33 let store = if v == 0 { u32::MAX } else { v };
35 HOST_VEC_VERSION.store(store, Ordering::Relaxed);
36 v
37}
38
39#[inline]
40#[allow(dead_code)]
41fn use_host_ops() -> bool {
42 #[cfg(target_arch = "wasm32")]
43 { host_version() > 0 && host_version() != u32::MAX }
44 #[cfg(not(target_arch = "wasm32"))]
45 { false }
46}
47
48macro_rules! dispatch {
53 ($host:expr, $fallback:expr) => {{
54 #[cfg(target_arch = "wasm32")]
55 {
56 if use_host_ops() { $host } else { $fallback }
57 }
58 #[cfg(not(target_arch = "wasm32"))]
59 { $fallback }
60 }};
61}
62
63#[cfg(target_arch = "wasm32")]
68extern "C" {
69 fn sesh_vec_copy_host(dst: *mut f32, src: *const f32, len: u32);
70 fn sesh_vec_fill_host(dst: *mut f32, value: f32, len: u32);
71 fn sesh_vec_add_host(dst: *mut f32, a: *const f32, b: *const f32, len: u32);
72 fn sesh_vec_add_scalar_host(dst: *mut f32, value: f32, len: u32);
73 fn sesh_vec_mul_host(dst: *mut f32, a: *const f32, b: *const f32, len: u32);
74 fn sesh_vec_mul_scalar_host(dst: *mut f32, value: f32, len: u32);
75 fn sesh_vec_mul_add_host(dst: *mut f32, src: *const f32, gain: f32, len: u32);
76 fn sesh_vec_clamp_host(dst: *mut f32, src: *const f32, min: f32, max: f32, len: u32);
77 fn sesh_vec_ring_write_host(
78 buf: *mut f32, buf_len: u32, pos: *mut u32, src: *const f32, len: u32,
79 );
80 fn sesh_vec_ring_read_host(
81 buf: *const f32, buf_len: u32, pos: u32, dst: *mut f32, offset: u32, len: u32,
82 );
83 fn sesh_vec_delay_read_host(
84 buf: *const f32, buf_len: u32, pos: u32, dst: *mut f32, time: *const f32, len: u32,
85 );
86 fn sesh_vec_osc_host(
87 phase: *mut f32, dst: *mut f32, freq: f32, waveform: u32, sample_rate: f32, len: u32,
88 );
89 fn sesh_vec_biquad_host(
90 state: *mut f32, dst: *mut f32, src: *const f32,
91 cutoff: *const f32, q: *const f32, gain: *const f32,
92 filter_type: u32, sample_rate: f32, len: u32,
93 );
94 fn sesh_vec_envelope_host(
95 state: *mut f32, dst: *mut f32, src: *const f32,
96 attack: *const f32, release: *const f32,
97 mode: u32, sample_rate: f32, len: u32,
98 );
99 fn sesh_vec_tanh_host(dst: *mut f32, src: *const f32, drive: *const f32, len: u32);
100 fn sesh_vec_hard_clip_host(dst: *mut f32, src: *const f32, threshold: *const f32, len: u32);
101 fn sesh_vec_abs_host(dst: *mut f32, src: *const f32, len: u32);
102 fn sesh_vec_neg_host(dst: *mut f32, src: *const f32, len: u32);
103 fn sesh_vec_sqrt_host(dst: *mut f32, src: *const f32, len: u32);
104 fn sesh_vec_recip_host(dst: *mut f32, src: *const f32, len: u32);
105 fn sesh_vec_div_host(dst: *mut f32, a: *const f32, b: *const f32, len: u32);
106 fn sesh_vec_pow_host(dst: *mut f32, src: *const f32, exp: *const f32, len: u32);
107 fn sesh_vec_log_host(dst: *mut f32, src: *const f32, len: u32);
108 fn sesh_vec_exp_host(dst: *mut f32, src: *const f32, len: u32);
109 fn sesh_vec_schroeder_allpass_host(
110 buf: *mut f32, buf_len: u32, pos: *mut u32,
111 dst: *mut f32, src: *const f32,
112 delay: u32, g: f32, len: u32,
113 );
114 fn sesh_vec_one_pole_host(
115 state: *mut f32, dst: *mut f32, src: *const f32,
116 coefficient: f32, len: u32,
117 );
118 fn sesh_vec_comb_host(
119 buf: *mut f32, buf_len: u32, pos: *mut u32, damp: *mut f32,
120 dst: *mut f32, src: *const f32, time: *const f32,
121 feedback: f32, damping: f32, len: u32,
122 );
123 fn sesh_vec_comb_parallel_host(
124 bufs: *const *mut f32, buf_lens: *const u32, positions: *mut u32, damp: *mut f32,
125 dst: *const *mut f32, src: *const f32, time: *const *const f32,
126 feedback: f32, damping: f32, n: u32, len: u32,
127 );
128 fn sesh_vec_comb_coupled_host(
129 bufs: *const *mut f32, buf_lens: *const u32, positions: *mut u32, damp: *mut f32,
130 dst: *const *mut f32, src: *const *const f32, time: *const *const f32,
131 matrix: *const f32, damping: f32, n: u32, len: u32,
132 );
133}
134
135#[repr(u32)]
141#[derive(Clone, Copy)]
142pub enum Waveform {
143 Sine = 0,
144 Triangle = 1,
145 Saw = 2,
146 Square = 3,
147}
148
149#[repr(u32)]
151#[derive(Clone, Copy)]
152pub enum FilterType {
153 Lowpass = 0,
154 Highpass = 1,
155 Bandpass = 2,
156 Notch = 3,
157 Peak = 4,
159 LowShelf = 5,
161 HighShelf = 6,
163 Allpass = 7,
165}
166
167#[derive(Clone, Copy)]
169#[repr(C)]
170pub struct BiquadState {
171 pub x1: f32,
172 pub x2: f32,
173 pub y1: f32,
174 pub y2: f32,
175}
176
177impl BiquadState {
178 pub const fn new() -> Self {
179 Self { x1: 0.0, x2: 0.0, y1: 0.0, y2: 0.0 }
180 }
181}
182
183#[repr(u32)]
185#[derive(Clone, Copy)]
186pub enum EnvelopeMode {
187 Peak = 0,
189 Rms = 1,
191}
192
193#[derive(Clone, Copy)]
195#[repr(C)]
196pub struct EnvelopeState {
197 pub current: f32,
198}
199
200impl EnvelopeState {
201 pub const fn new() -> Self {
202 Self { current: 0.0 }
203 }
204}
205
206#[derive(Clone, Copy)]
208#[repr(C)]
209pub struct OnePoleState {
210 pub y1: f32,
211}
212
213impl OnePoleState {
214 pub const fn new() -> Self {
215 Self { y1: 0.0 }
216 }
217}
218
219pub fn vec_copy(dst: &mut [f32], src: &[f32]) {
225 let len = dst.len().min(src.len());
226 dispatch!(
227 unsafe { sesh_vec_copy_host(dst.as_mut_ptr(), src.as_ptr(), len as u32) },
228 dst[..len].copy_from_slice(&src[..len])
229 );
230}
231
232pub fn vec_fill(dst: &mut [f32], value: f32) {
234 let len = dst.len();
235 dispatch!(
236 unsafe { sesh_vec_fill_host(dst.as_mut_ptr(), value, len as u32) },
237 for s in dst.iter_mut() { *s = value; }
238 );
239}
240
241pub fn vec_add(dst: &mut [f32], a: &[f32], b: &[f32]) {
243 let len = dst.len().min(a.len()).min(b.len());
244 dispatch!(
245 unsafe { sesh_vec_add_host(dst.as_mut_ptr(), a.as_ptr(), b.as_ptr(), len as u32) },
246 for i in 0..len { dst[i] = a[i] + b[i]; }
247 );
248}
249
250pub fn vec_add_scalar(dst: &mut [f32], value: f32) {
252 let len = dst.len();
253 dispatch!(
254 unsafe { sesh_vec_add_scalar_host(dst.as_mut_ptr(), value, len as u32) },
255 for s in dst.iter_mut() { *s += value; }
256 );
257}
258
259pub fn vec_mul(dst: &mut [f32], a: &[f32], b: &[f32]) {
261 let len = dst.len().min(a.len()).min(b.len());
262 dispatch!(
263 unsafe { sesh_vec_mul_host(dst.as_mut_ptr(), a.as_ptr(), b.as_ptr(), len as u32) },
264 for i in 0..len { dst[i] = a[i] * b[i]; }
265 );
266}
267
268pub fn vec_mul_scalar(dst: &mut [f32], value: f32) {
270 let len = dst.len();
271 dispatch!(
272 unsafe { sesh_vec_mul_scalar_host(dst.as_mut_ptr(), value, len as u32) },
273 for s in dst.iter_mut() { *s *= value; }
274 );
275}
276
277pub fn vec_mul_add(dst: &mut [f32], src: &[f32], gain: f32) {
279 let len = dst.len().min(src.len());
280 dispatch!(
281 unsafe { sesh_vec_mul_add_host(dst.as_mut_ptr(), src.as_ptr(), gain, len as u32) },
282 for i in 0..len { dst[i] += src[i] * gain; }
283 );
284}
285
286pub fn vec_clamp(dst: &mut [f32], src: &[f32], min: f32, max: f32) {
288 let len = dst.len().min(src.len());
289 dispatch!(
290 unsafe { sesh_vec_clamp_host(dst.as_mut_ptr(), src.as_ptr(), min, max, len as u32) },
291 for i in 0..len { dst[i] = src[i].clamp(min, max); }
292 );
293}
294
295pub fn vec_clamp_assign(dst: &mut [f32], min: f32, max: f32) {
297 let len = dst.len();
298 dispatch!(
299 unsafe { sesh_vec_clamp_host(dst.as_mut_ptr(), dst.as_ptr(), min, max, len as u32) },
300 for i in 0..len { dst[i] = dst[i].clamp(min, max); }
301 );
302}
303
304pub fn vec_ring_write(buf: &mut [f32], pos: &mut usize, src: &[f32]) {
311 let buf_len = buf.len();
312 let frames = src.len();
313 dispatch!(
314 {
315 let mut pos32 = *pos as u32;
316 unsafe {
317 sesh_vec_ring_write_host(
318 buf.as_mut_ptr(), buf_len as u32, &mut pos32, src.as_ptr(), frames as u32,
319 );
320 }
321 *pos = pos32 as usize;
322 },
323 {
324 for i in 0..frames {
325 buf[(*pos + i) % buf_len] = src[i];
326 }
327 *pos = (*pos + frames) % buf_len;
328 }
329 );
330}
331
332pub fn vec_ring_read(buf: &[f32], pos: usize, dst: &mut [f32], offset: usize) {
334 let buf_len = buf.len();
335 let frames = dst.len();
336 dispatch!(
337 unsafe {
338 sesh_vec_ring_read_host(
339 buf.as_ptr(), buf_len as u32, pos as u32,
340 dst.as_mut_ptr(), offset as u32, frames as u32,
341 );
342 },
343 {
344 let start = (pos + buf_len - offset) % buf_len;
345 for i in 0..frames {
346 dst[i] = buf[(start + i) % buf_len];
347 }
348 }
349 );
350}
351
352pub fn vec_delay_read(buf: &[f32], pos: usize, dst: &mut [f32], time: &[f32]) {
362 let buf_len = buf.len();
363 let frames = dst.len().min(time.len());
364 dispatch!(
365 unsafe {
366 sesh_vec_delay_read_host(
367 buf.as_ptr(), buf_len as u32, pos as u32,
368 dst.as_mut_ptr(), time.as_ptr(), frames as u32,
369 );
370 },
371 {
372 for i in 0..frames {
373 let write_pos_at_i = (pos + buf_len - frames + i) % buf_len;
375
376 let delay_int = time[i] as usize;
377 let delay_frac = time[i] - delay_int as f32;
378
379 let idx1 = (write_pos_at_i + buf_len - delay_int) % buf_len;
380 let idx2 = (idx1 + buf_len - 1) % buf_len;
381
382 dst[i] = buf[idx1] + delay_frac * (buf[idx2] - buf[idx1]);
383 }
384 }
385 );
386}
387
388pub fn vec_schroeder_allpass(
400 buf: &mut [f32],
401 pos: &mut usize,
402 dst: &mut [f32],
403 src: &[f32],
404 delay: usize,
405 g: f32,
406) {
407 let buf_len = buf.len();
408 let frames = dst.len().min(src.len());
409 dispatch!(
410 {
411 let mut pos32 = *pos as u32;
412 unsafe {
413 sesh_vec_schroeder_allpass_host(
414 buf.as_mut_ptr(), buf_len as u32, &mut pos32,
415 dst.as_mut_ptr(), src.as_ptr(),
416 delay as u32, g, frames as u32,
417 );
418 }
419 *pos = pos32 as usize;
420 },
421 {
422 let mut wp = *pos;
423 for i in 0..frames {
424 let read_idx = (wp + buf_len - delay) % buf_len;
425 let buf_out = buf[read_idx];
426
427 let v = src[i] + g * buf_out;
428 dst[i] = buf_out - g * v;
429
430 buf[wp] = v;
431 wp = (wp + 1) % buf_len;
432 }
433 *pos = wp;
434 }
435 );
436}
437
438pub fn vec_one_pole(
448 state: &mut OnePoleState,
449 dst: &mut [f32],
450 src: &[f32],
451 coefficient: f32,
452) {
453 let frames = dst.len().min(src.len());
454 dispatch!(
455 {
456 unsafe {
457 sesh_vec_one_pole_host(
458 &mut state.y1 as *mut f32, dst.as_mut_ptr(), src.as_ptr(),
459 coefficient, frames as u32,
460 );
461 }
462 },
463 {
464 let mut y = state.y1;
465 for i in 0..frames {
466 y = src[i] + coefficient * (y - src[i]);
467 dst[i] = y;
468 }
469 state.y1 = y;
470 }
471 );
472}
473
474pub fn vec_comb(
504 buf: &mut [f32],
505 pos: &mut usize,
506 damp: &mut OnePoleState,
507 dst: &mut [f32],
508 src: &[f32],
509 time: &[f32],
510 feedback: f32,
511 damping: f32,
512) {
513 let buf_len = buf.len();
514 let frames = dst.len().min(src.len()).min(time.len());
515 dispatch!(
516 {
517 let mut pos32 = *pos as u32;
518 unsafe {
519 sesh_vec_comb_host(
520 buf.as_mut_ptr(), buf_len as u32, &mut pos32, &mut damp.y1 as *mut f32,
521 dst.as_mut_ptr(), src.as_ptr(), time.as_ptr(),
522 feedback, damping, frames as u32,
523 );
524 }
525 *pos = pos32 as usize;
526 },
527 {
528 let mut wp = *pos;
529 let mut y = damp.y1;
530 for i in 0..frames {
531 let delay_int = time[i] as usize;
532 let delay_frac = time[i] - delay_int as f32;
533 let idx1 = (wp + buf_len - delay_int) % buf_len;
534 let idx2 = (idx1 + buf_len - 1) % buf_len;
535 let tap = buf[idx1] + delay_frac * (buf[idx2] - buf[idx1]);
536
537 y = tap + damping * (y - tap);
538
539 dst[i] = y;
540 buf[wp] = src[i] + feedback * y;
541 wp = (wp + 1) % buf_len;
542 }
543 *pos = wp;
544 damp.y1 = y;
545 }
546 );
547}
548
549pub fn vec_comb_parallel(
558 bufs: &mut [&mut [f32]],
559 positions: &mut [usize],
560 damp: &mut [OnePoleState],
561 dst: &mut [&mut [f32]],
562 src: &[f32],
563 time: &[&[f32]],
564 feedback: f32,
565 damping: f32,
566) {
567 let n = bufs.len();
568 let frames = src.len();
569 dispatch!(
570 {
571 let mut buf_ptrs: SmallVec<[*mut f32; 16]> = SmallVec::with_capacity(n);
572 let mut buf_lens: SmallVec<[u32; 16]> = SmallVec::with_capacity(n);
573 let mut pos32: SmallVec<[u32; 16]> = SmallVec::with_capacity(n);
574 let mut damp_vals: SmallVec<[f32; 16]> = SmallVec::with_capacity(n);
575 let mut dst_ptrs: SmallVec<[*mut f32; 16]> = SmallVec::with_capacity(n);
576 let mut time_ptrs: SmallVec<[*const f32; 16]> = SmallVec::with_capacity(n);
577 for i in 0..n {
578 buf_ptrs.push(bufs[i].as_mut_ptr());
579 buf_lens.push(bufs[i].len() as u32);
580 pos32.push(positions[i] as u32);
581 damp_vals.push(damp[i].y1);
582 dst_ptrs.push(dst[i].as_mut_ptr());
583 time_ptrs.push(time[i].as_ptr());
584 }
585 unsafe {
586 sesh_vec_comb_parallel_host(
587 buf_ptrs.as_ptr(), buf_lens.as_ptr(), pos32.as_mut_ptr(), damp_vals.as_mut_ptr(),
588 dst_ptrs.as_ptr(), src.as_ptr(), time_ptrs.as_ptr(),
589 feedback, damping, n as u32, frames as u32,
590 );
591 }
592 for i in 0..n {
593 positions[i] = pos32[i] as usize;
594 damp[i].y1 = damp_vals[i];
595 }
596 },
597 {
598 for line in 0..n {
599 vec_comb(
600 bufs[line], &mut positions[line], &mut damp[line],
601 dst[line], src, time[line], feedback, damping,
602 );
603 }
604 }
605 );
606}
607
608pub fn vec_comb_coupled(
624 bufs: &mut [&mut [f32]],
625 positions: &mut [usize],
626 damp: &mut [OnePoleState],
627 dst: &mut [&mut [f32]],
628 src: &[&[f32]],
629 time: &[&[f32]],
630 matrix: &[f32],
631 damping: f32,
632) {
633 let n = bufs.len();
634 assert!(matrix.len() >= n * n, "vec_comb_coupled: matrix must be N×N");
635
636 let frames = dst[0].len();
637 dispatch!(
638 {
639 let mut buf_ptrs: SmallVec<[*mut f32; 16]> = SmallVec::with_capacity(n);
640 let mut buf_lens: SmallVec<[u32; 16]> = SmallVec::with_capacity(n);
641 let mut pos32: SmallVec<[u32; 16]> = SmallVec::with_capacity(n);
642 let mut damp_vals: SmallVec<[f32; 16]> = SmallVec::with_capacity(n);
643 let mut dst_ptrs: SmallVec<[*mut f32; 16]> = SmallVec::with_capacity(n);
644 let mut src_ptrs: SmallVec<[*const f32; 16]> = SmallVec::with_capacity(n);
645 let mut time_ptrs: SmallVec<[*const f32; 16]> = SmallVec::with_capacity(n);
646 for i in 0..n {
647 buf_ptrs.push(bufs[i].as_mut_ptr());
648 buf_lens.push(bufs[i].len() as u32);
649 pos32.push(positions[i] as u32);
650 damp_vals.push(damp[i].y1);
651 dst_ptrs.push(dst[i].as_mut_ptr());
652 src_ptrs.push(src[i].as_ptr());
653 time_ptrs.push(time[i].as_ptr());
654 }
655 unsafe {
656 sesh_vec_comb_coupled_host(
657 buf_ptrs.as_ptr(), buf_lens.as_ptr(), pos32.as_mut_ptr(), damp_vals.as_mut_ptr(),
658 dst_ptrs.as_ptr(), src_ptrs.as_ptr(), time_ptrs.as_ptr(),
659 matrix.as_ptr(), damping, n as u32, frames as u32,
660 );
661 }
662 for i in 0..n {
663 positions[i] = pos32[i] as usize;
664 damp[i].y1 = damp_vals[i];
665 }
666 },
667 {
668 for i in 0..frames {
669 let mut taps = [0.0f32; 16];
670 let mut mixed = [0.0f32; 16];
671
672 for line in 0..n {
673 let buf_len = bufs[line].len();
674 let wp = positions[line];
675 let t = time[line][i];
676 let delay_int = t as usize;
677 let delay_frac = t - delay_int as f32;
678 let idx1 = (wp + buf_len - delay_int) % buf_len;
679 let idx2 = (idx1 + buf_len - 1) % buf_len;
680 taps[line] = bufs[line][idx1] + delay_frac * (bufs[line][idx2] - bufs[line][idx1]);
681 }
682
683 for line in 0..n {
684 damp[line].y1 = taps[line] + damping * (damp[line].y1 - taps[line]);
685 taps[line] = damp[line].y1;
686 }
687
688 for row in 0..n {
689 let mut sum = 0.0;
690 for col in 0..n {
691 sum += matrix[row * n + col] * taps[col];
692 }
693 mixed[row] = sum;
694 }
695
696 for line in 0..n {
697 dst[line][i] = taps[line];
698 bufs[line][positions[line]] = src[line][i] + mixed[line];
699 positions[line] = (positions[line] + 1) % bufs[line].len();
700 }
701 }
702 }
703 );
704}
705
706pub fn vec_osc(
712 phase: &mut f32,
713 dst: &mut [f32],
714 freq: f32,
715 waveform: Waveform,
716 sample_rate: f32,
717) {
718 let frames = dst.len();
719 dispatch!(
720 unsafe {
721 sesh_vec_osc_host(
722 phase as *mut f32, dst.as_mut_ptr(),
723 freq, waveform as u32, sample_rate, frames as u32,
724 );
725 },
726 {
727 let phase_inc = freq / sample_rate;
728 for i in 0..frames {
729 dst[i] = match waveform {
730 Waveform::Sine => (*phase * std::f32::consts::TAU).sin(),
731 Waveform::Triangle => 4.0 * (*phase - (*phase + 0.5).floor()).abs() - 1.0,
732 Waveform::Saw => 2.0 * (*phase - (*phase + 0.5).floor()),
733 Waveform::Square => if *phase % 1.0 < 0.5 { 1.0 } else { -1.0 },
734 };
735 *phase += phase_inc;
736 if *phase >= 1.0 {
737 *phase -= 1.0;
738 }
739 }
740 }
741 );
742}
743
744pub fn vec_biquad(
753 state: &mut BiquadState,
754 dst: &mut [f32],
755 src: &[f32],
756 cutoff: &[f32],
757 q: &[f32],
758 gain: &[f32],
759 filter_type: FilterType,
760 sample_rate: f32,
761) {
762 let frames = dst.len().min(src.len()).min(cutoff.len()).min(q.len()).min(gain.len());
763 dispatch!(
764 unsafe {
765 sesh_vec_biquad_host(
766 state as *mut BiquadState as *mut f32,
767 dst.as_mut_ptr(), src.as_ptr(),
768 cutoff.as_ptr(), q.as_ptr(), gain.as_ptr(),
769 filter_type as u32, sample_rate, frames as u32,
770 );
771 },
772 {
773 for i in 0..frames {
774 let w0 = std::f32::consts::TAU * cutoff[i] / sample_rate;
775 let cos_w0 = w0.cos();
776 let sin_w0 = w0.sin();
777 let alpha = sin_w0 / (2.0 * q[i]);
778 let a_db = gain[i];
779 let a_lin = 10.0f32.powf(a_db / 40.0);
780
781 let (b0, b1, b2, a0, a1, a2) = match filter_type {
782 FilterType::Lowpass => {
783 let b1 = 1.0 - cos_w0;
784 let b0 = b1 / 2.0;
785 (b0, b1, b0, 1.0 + alpha, -2.0 * cos_w0, 1.0 - alpha)
786 }
787 FilterType::Highpass => {
788 let b1 = -(1.0 + cos_w0);
789 let b0 = (1.0 + cos_w0) / 2.0;
790 (b0, b1, b0, 1.0 + alpha, -2.0 * cos_w0, 1.0 - alpha)
791 }
792 FilterType::Bandpass => {
793 (alpha, 0.0, -alpha, 1.0 + alpha, -2.0 * cos_w0, 1.0 - alpha)
794 }
795 FilterType::Notch => {
796 (1.0, -2.0 * cos_w0, 1.0, 1.0 + alpha, -2.0 * cos_w0, 1.0 - alpha)
797 }
798 FilterType::Peak => {
799 (
800 1.0 + alpha * a_lin,
801 -2.0 * cos_w0,
802 1.0 - alpha * a_lin,
803 1.0 + alpha / a_lin,
804 -2.0 * cos_w0,
805 1.0 - alpha / a_lin,
806 )
807 }
808 FilterType::LowShelf => {
809 let two_sqrt_a_alpha = 2.0 * a_lin.sqrt() * alpha;
810 (
811 a_lin * ((a_lin + 1.0) - (a_lin - 1.0) * cos_w0 + two_sqrt_a_alpha),
812 2.0 * a_lin * ((a_lin - 1.0) - (a_lin + 1.0) * cos_w0),
813 a_lin * ((a_lin + 1.0) - (a_lin - 1.0) * cos_w0 - two_sqrt_a_alpha),
814 (a_lin + 1.0) + (a_lin - 1.0) * cos_w0 + two_sqrt_a_alpha,
815 -2.0 * ((a_lin - 1.0) + (a_lin + 1.0) * cos_w0),
816 (a_lin + 1.0) + (a_lin - 1.0) * cos_w0 - two_sqrt_a_alpha,
817 )
818 }
819 FilterType::HighShelf => {
820 let two_sqrt_a_alpha = 2.0 * a_lin.sqrt() * alpha;
821 (
822 a_lin * ((a_lin + 1.0) + (a_lin - 1.0) * cos_w0 + two_sqrt_a_alpha),
823 -2.0 * a_lin * ((a_lin - 1.0) + (a_lin + 1.0) * cos_w0),
824 a_lin * ((a_lin + 1.0) + (a_lin - 1.0) * cos_w0 - two_sqrt_a_alpha),
825 (a_lin + 1.0) - (a_lin - 1.0) * cos_w0 + two_sqrt_a_alpha,
826 2.0 * ((a_lin - 1.0) - (a_lin + 1.0) * cos_w0),
827 (a_lin + 1.0) - (a_lin - 1.0) * cos_w0 - two_sqrt_a_alpha,
828 )
829 }
830 FilterType::Allpass => {
831 (1.0 - alpha, -2.0 * cos_w0, 1.0 + alpha, 1.0 + alpha, -2.0 * cos_w0, 1.0 - alpha)
832 }
833 };
834
835 let b0 = b0 / a0;
837 let b1 = b1 / a0;
838 let b2 = b2 / a0;
839 let a1 = a1 / a0;
840 let a2 = a2 / a0;
841
842 let x0 = src[i];
843 let y0 = b0 * x0 + b1 * state.x1 + b2 * state.x2
844 - a1 * state.y1 - a2 * state.y2;
845
846 state.x2 = state.x1;
847 state.x1 = x0;
848 state.y2 = state.y1;
849 state.y1 = y0;
850
851 dst[i] = y0;
852 }
853 }
854 );
855}
856
857pub fn vec_envelope(
866 state: &mut EnvelopeState,
867 dst: &mut [f32],
868 src: &[f32],
869 attack: &[f32],
870 release: &[f32],
871 mode: EnvelopeMode,
872 sample_rate: f32,
873) {
874 let frames = dst.len().min(src.len()).min(attack.len()).min(release.len());
875 dispatch!(
876 unsafe {
877 sesh_vec_envelope_host(
878 state as *mut EnvelopeState as *mut f32,
879 dst.as_mut_ptr(), src.as_ptr(),
880 attack.as_ptr(), release.as_ptr(),
881 mode as u32, sample_rate, frames as u32,
882 );
883 },
884 {
885 for i in 0..frames {
886 let input_level = match mode {
887 EnvelopeMode::Peak => src[i].abs(),
888 EnvelopeMode::Rms => src[i] * src[i],
889 };
890
891 let att_coeff = (-1.0 / (attack[i] * sample_rate)).exp();
892 let rel_coeff = (-1.0 / (release[i] * sample_rate)).exp();
893
894 let coeff = if input_level > state.current { att_coeff } else { rel_coeff };
895 state.current = coeff * state.current + (1.0 - coeff) * input_level;
896
897 dst[i] = match mode {
898 EnvelopeMode::Peak => state.current,
899 EnvelopeMode::Rms => state.current.sqrt(),
900 };
901 }
902 }
903 );
904}
905
906pub fn vec_tanh(dst: &mut [f32], src: &[f32], drive: &[f32]) {
912 let len = dst.len().min(src.len()).min(drive.len());
913 dispatch!(
914 unsafe { sesh_vec_tanh_host(dst.as_mut_ptr(), src.as_ptr(), drive.as_ptr(), len as u32) },
915 for i in 0..len { dst[i] = (src[i] * drive[i]).tanh(); }
916 );
917}
918
919pub fn vec_hard_clip(dst: &mut [f32], src: &[f32], threshold: &[f32]) {
921 let len = dst.len().min(src.len()).min(threshold.len());
922 dispatch!(
923 unsafe { sesh_vec_hard_clip_host(dst.as_mut_ptr(), src.as_ptr(), threshold.as_ptr(), len as u32) },
924 for i in 0..len { dst[i] = src[i].clamp(-threshold[i], threshold[i]); }
925 );
926}
927
928pub fn vec_abs(dst: &mut [f32], src: &[f32]) {
934 let len = dst.len().min(src.len());
935 dispatch!(
936 unsafe { sesh_vec_abs_host(dst.as_mut_ptr(), src.as_ptr(), len as u32) },
937 for i in 0..len { dst[i] = src[i].abs(); }
938 );
939}
940
941pub fn vec_neg(dst: &mut [f32], src: &[f32]) {
943 let len = dst.len().min(src.len());
944 dispatch!(
945 unsafe { sesh_vec_neg_host(dst.as_mut_ptr(), src.as_ptr(), len as u32) },
946 for i in 0..len { dst[i] = -src[i]; }
947 );
948}
949
950pub fn vec_sqrt(dst: &mut [f32], src: &[f32]) {
952 let len = dst.len().min(src.len());
953 dispatch!(
954 unsafe { sesh_vec_sqrt_host(dst.as_mut_ptr(), src.as_ptr(), len as u32) },
955 for i in 0..len { dst[i] = src[i].sqrt(); }
956 );
957}
958
959pub fn vec_recip(dst: &mut [f32], src: &[f32]) {
961 let len = dst.len().min(src.len());
962 dispatch!(
963 unsafe { sesh_vec_recip_host(dst.as_mut_ptr(), src.as_ptr(), len as u32) },
964 for i in 0..len { dst[i] = 1.0 / src[i]; }
965 );
966}
967
968pub fn vec_div(dst: &mut [f32], a: &[f32], b: &[f32]) {
970 let len = dst.len().min(a.len()).min(b.len());
971 dispatch!(
972 unsafe { sesh_vec_div_host(dst.as_mut_ptr(), a.as_ptr(), b.as_ptr(), len as u32) },
973 for i in 0..len { dst[i] = a[i] / b[i]; }
974 );
975}
976
977pub fn vec_pow(dst: &mut [f32], src: &[f32], exp: &[f32]) {
979 let len = dst.len().min(src.len()).min(exp.len());
980 dispatch!(
981 unsafe { sesh_vec_pow_host(dst.as_mut_ptr(), src.as_ptr(), exp.as_ptr(), len as u32) },
982 for i in 0..len { dst[i] = src[i].powf(exp[i]); }
983 );
984}
985
986pub fn vec_log(dst: &mut [f32], src: &[f32]) {
988 let len = dst.len().min(src.len());
989 dispatch!(
990 unsafe { sesh_vec_log_host(dst.as_mut_ptr(), src.as_ptr(), len as u32) },
991 for i in 0..len { dst[i] = src[i].ln(); }
992 );
993}
994
995pub fn vec_exp(dst: &mut [f32], src: &[f32]) {
997 let len = dst.len().min(src.len());
998 dispatch!(
999 unsafe { sesh_vec_exp_host(dst.as_mut_ptr(), src.as_ptr(), len as u32) },
1000 for i in 0..len { dst[i] = src[i].exp(); }
1001 );
1002}
1003
1004pub fn vec_add_assign(dst: &mut [f32], src: &[f32]) {
1014 let len = dst.len().min(src.len());
1015 dispatch!(
1016 unsafe { sesh_vec_add_host(dst.as_mut_ptr(), dst.as_ptr(), src.as_ptr(), len as u32) },
1017 for i in 0..len { dst[i] += src[i]; }
1018 );
1019}
1020
1021pub fn vec_mul_assign(dst: &mut [f32], src: &[f32]) {
1023 let len = dst.len().min(src.len());
1024 dispatch!(
1025 unsafe { sesh_vec_mul_host(dst.as_mut_ptr(), dst.as_ptr(), src.as_ptr(), len as u32) },
1026 for i in 0..len { dst[i] *= src[i]; }
1027 );
1028}
1029
1030pub fn vec_tanh_assign(dst: &mut [f32], drive: &[f32]) {
1032 let len = dst.len().min(drive.len());
1033 dispatch!(
1034 unsafe { sesh_vec_tanh_host(dst.as_mut_ptr(), dst.as_ptr(), drive.as_ptr(), len as u32) },
1035 for i in 0..len { dst[i] = (dst[i] * drive[i]).tanh(); }
1036 );
1037}
1038
1039pub fn vec_hard_clip_assign(dst: &mut [f32], threshold: &[f32]) {
1041 let len = dst.len().min(threshold.len());
1042 dispatch!(
1043 unsafe { sesh_vec_hard_clip_host(dst.as_mut_ptr(), dst.as_ptr(), threshold.as_ptr(), len as u32) },
1044 for i in 0..len { dst[i] = dst[i].clamp(-threshold[i], threshold[i]); }
1045 );
1046}
1047
1048pub fn vec_abs_assign(dst: &mut [f32]) {
1050 let len = dst.len();
1051 dispatch!(
1052 unsafe { sesh_vec_abs_host(dst.as_mut_ptr(), dst.as_ptr(), len as u32) },
1053 for i in 0..len { dst[i] = dst[i].abs(); }
1054 );
1055}
1056
1057pub fn vec_neg_assign(dst: &mut [f32]) {
1059 let len = dst.len();
1060 dispatch!(
1061 unsafe { sesh_vec_neg_host(dst.as_mut_ptr(), dst.as_ptr(), len as u32) },
1062 for i in 0..len { dst[i] = -dst[i]; }
1063 );
1064}
1065
1066pub fn vec_sqrt_assign(dst: &mut [f32]) {
1068 let len = dst.len();
1069 dispatch!(
1070 unsafe { sesh_vec_sqrt_host(dst.as_mut_ptr(), dst.as_ptr(), len as u32) },
1071 for i in 0..len { dst[i] = dst[i].sqrt(); }
1072 );
1073}
1074
1075pub fn vec_recip_assign(dst: &mut [f32]) {
1077 let len = dst.len();
1078 dispatch!(
1079 unsafe { sesh_vec_recip_host(dst.as_mut_ptr(), dst.as_ptr(), len as u32) },
1080 for i in 0..len { dst[i] = 1.0 / dst[i]; }
1081 );
1082}
1083
1084pub fn vec_div_assign(dst: &mut [f32], src: &[f32]) {
1086 let len = dst.len().min(src.len());
1087 dispatch!(
1088 unsafe { sesh_vec_div_host(dst.as_mut_ptr(), dst.as_ptr(), src.as_ptr(), len as u32) },
1089 for i in 0..len { dst[i] /= src[i]; }
1090 );
1091}
1092
1093pub fn vec_pow_assign(dst: &mut [f32], exp: &[f32]) {
1095 let len = dst.len().min(exp.len());
1096 dispatch!(
1097 unsafe { sesh_vec_pow_host(dst.as_mut_ptr(), dst.as_ptr(), exp.as_ptr(), len as u32) },
1098 for i in 0..len { dst[i] = dst[i].powf(exp[i]); }
1099 );
1100}
1101
1102pub fn vec_log_assign(dst: &mut [f32]) {
1104 let len = dst.len();
1105 dispatch!(
1106 unsafe { sesh_vec_log_host(dst.as_mut_ptr(), dst.as_ptr(), len as u32) },
1107 for i in 0..len { dst[i] = dst[i].ln(); }
1108 );
1109}
1110
1111pub fn vec_exp_assign(dst: &mut [f32]) {
1113 let len = dst.len();
1114 dispatch!(
1115 unsafe { sesh_vec_exp_host(dst.as_mut_ptr(), dst.as_ptr(), len as u32) },
1116 for i in 0..len { dst[i] = dst[i].exp(); }
1117 );
1118}