1#![allow(unused_variables)]
2#[cfg(target_arch = "wasm32")]
9use std::sync::atomic::{AtomicU32, Ordering};
10
11#[cfg(target_arch = "wasm32")]
16extern "C" {
17 fn sesh_vec_version() -> u32;
18}
19
20#[cfg(target_arch = "wasm32")]
22static HOST_VEC_VERSION: AtomicU32 = AtomicU32::new(0);
23
24#[cfg(target_arch = "wasm32")]
25fn host_version() -> u32 {
26 let v = HOST_VEC_VERSION.load(Ordering::Relaxed);
27 if v != 0 {
28 return v;
29 }
30 let v = unsafe { sesh_vec_version() };
31 let store = if v == 0 { u32::MAX } else { v };
33 HOST_VEC_VERSION.store(store, Ordering::Relaxed);
34 v
35}
36
37#[inline]
38#[allow(dead_code)]
39fn use_host_ops() -> bool {
40 #[cfg(target_arch = "wasm32")]
41 { host_version() > 0 && host_version() != u32::MAX }
42 #[cfg(not(target_arch = "wasm32"))]
43 { false }
44}
45
46macro_rules! dispatch {
51 ($host:expr, $fallback:expr) => {{
52 #[cfg(target_arch = "wasm32")]
53 {
54 if use_host_ops() { $host } else { $fallback }
55 }
56 #[cfg(not(target_arch = "wasm32"))]
57 { $fallback }
58 }};
59}
60
61#[cfg(target_arch = "wasm32")]
66extern "C" {
67 fn sesh_vec_copy_host(dst: *mut f32, src: *const f32, len: u32);
68 fn sesh_vec_fill_host(dst: *mut f32, value: f32, len: u32);
69 fn sesh_vec_add_host(dst: *mut f32, a: *const f32, b: *const f32, len: u32);
70 fn sesh_vec_add_scalar_host(dst: *mut f32, value: f32, len: u32);
71 fn sesh_vec_mul_host(dst: *mut f32, a: *const f32, b: *const f32, len: u32);
72 fn sesh_vec_mul_scalar_host(dst: *mut f32, value: f32, len: u32);
73 fn sesh_vec_mul_add_host(dst: *mut f32, src: *const f32, gain: f32, len: u32);
74 fn sesh_vec_clamp_host(dst: *mut f32, src: *const f32, min: f32, max: f32, len: u32);
75 fn sesh_vec_ring_write_host(
76 buf: *mut f32, buf_len: u32, pos: *mut u32, src: *const f32, len: u32,
77 );
78 fn sesh_vec_ring_read_host(
79 buf: *const f32, buf_len: u32, pos: u32, dst: *mut f32, offset: u32, len: u32,
80 );
81 fn sesh_vec_delay_read_host(
82 buf: *const f32, buf_len: u32, pos: u32, dst: *mut f32, time: *const f32, len: u32,
83 );
84 fn sesh_vec_osc_host(
85 phase: *mut f32, dst: *mut f32, freq: f32, waveform: u32, sample_rate: f32, len: u32,
86 );
87 fn sesh_vec_biquad_host(
88 state: *mut f32, dst: *mut f32, src: *const f32,
89 cutoff: *const f32, q: *const f32, gain: *const f32,
90 filter_type: u32, sample_rate: f32, len: u32,
91 );
92 fn sesh_vec_envelope_host(
93 state: *mut f32, dst: *mut f32, src: *const f32,
94 attack: *const f32, release: *const f32,
95 mode: u32, sample_rate: f32, len: u32,
96 );
97 fn sesh_vec_tanh_host(dst: *mut f32, src: *const f32, drive: *const f32, len: u32);
98 fn sesh_vec_hard_clip_host(dst: *mut f32, src: *const f32, threshold: *const f32, len: u32);
99 fn sesh_vec_abs_host(dst: *mut f32, src: *const f32, len: u32);
100 fn sesh_vec_neg_host(dst: *mut f32, src: *const f32, len: u32);
101 fn sesh_vec_sqrt_host(dst: *mut f32, src: *const f32, len: u32);
102 fn sesh_vec_recip_host(dst: *mut f32, src: *const f32, len: u32);
103 fn sesh_vec_div_host(dst: *mut f32, a: *const f32, b: *const f32, len: u32);
104 fn sesh_vec_pow_host(dst: *mut f32, src: *const f32, exp: *const f32, len: u32);
105 fn sesh_vec_schroeder_allpass_host(
106 buf: *mut f32, buf_len: u32, pos: *mut u32,
107 dst: *mut f32, src: *const f32,
108 delay: u32, g: f32, len: u32,
109 );
110}
111
112#[repr(u32)]
118#[derive(Clone, Copy)]
119pub enum Waveform {
120 Sine = 0,
121 Triangle = 1,
122 Saw = 2,
123 Square = 3,
124}
125
126#[repr(u32)]
128#[derive(Clone, Copy)]
129pub enum FilterType {
130 Lowpass = 0,
131 Highpass = 1,
132 Bandpass = 2,
133 Notch = 3,
134 Peak = 4,
136 LowShelf = 5,
138 HighShelf = 6,
140 Allpass = 7,
142}
143
144#[derive(Clone, Copy)]
146#[repr(C)]
147pub struct BiquadState {
148 pub x1: f32,
149 pub x2: f32,
150 pub y1: f32,
151 pub y2: f32,
152}
153
154impl BiquadState {
155 pub const fn new() -> Self {
156 Self { x1: 0.0, x2: 0.0, y1: 0.0, y2: 0.0 }
157 }
158}
159
160#[repr(u32)]
162#[derive(Clone, Copy)]
163pub enum EnvelopeMode {
164 Peak = 0,
166 Rms = 1,
168}
169
170#[derive(Clone, Copy)]
172#[repr(C)]
173pub struct EnvelopeState {
174 pub current: f32,
175}
176
177impl EnvelopeState {
178 pub const fn new() -> Self {
179 Self { current: 0.0 }
180 }
181}
182
183#[derive(Clone, Copy)]
185#[repr(C)]
186pub struct OnePoleState {
187 pub y1: f32,
188}
189
190impl OnePoleState {
191 pub const fn new() -> Self {
192 Self { y1: 0.0 }
193 }
194}
195
196pub fn vec_copy(dst: &mut [f32], src: &[f32]) {
202 let len = dst.len().min(src.len());
203 dispatch!(
204 unsafe { sesh_vec_copy_host(dst.as_mut_ptr(), src.as_ptr(), len as u32) },
205 dst[..len].copy_from_slice(&src[..len])
206 );
207}
208
209pub fn vec_fill(dst: &mut [f32], value: f32) {
211 let len = dst.len();
212 dispatch!(
213 unsafe { sesh_vec_fill_host(dst.as_mut_ptr(), value, len as u32) },
214 for s in dst.iter_mut() { *s = value; }
215 );
216}
217
218pub fn vec_add(dst: &mut [f32], a: &[f32], b: &[f32]) {
220 let len = dst.len().min(a.len()).min(b.len());
221 dispatch!(
222 unsafe { sesh_vec_add_host(dst.as_mut_ptr(), a.as_ptr(), b.as_ptr(), len as u32) },
223 for i in 0..len { dst[i] = a[i] + b[i]; }
224 );
225}
226
227pub fn vec_add_scalar(dst: &mut [f32], value: f32) {
229 let len = dst.len();
230 dispatch!(
231 unsafe { sesh_vec_add_scalar_host(dst.as_mut_ptr(), value, len as u32) },
232 for s in dst.iter_mut() { *s += value; }
233 );
234}
235
236pub fn vec_mul(dst: &mut [f32], a: &[f32], b: &[f32]) {
238 let len = dst.len().min(a.len()).min(b.len());
239 dispatch!(
240 unsafe { sesh_vec_mul_host(dst.as_mut_ptr(), a.as_ptr(), b.as_ptr(), len as u32) },
241 for i in 0..len { dst[i] = a[i] * b[i]; }
242 );
243}
244
245pub fn vec_mul_scalar(dst: &mut [f32], value: f32) {
247 let len = dst.len();
248 dispatch!(
249 unsafe { sesh_vec_mul_scalar_host(dst.as_mut_ptr(), value, len as u32) },
250 for s in dst.iter_mut() { *s *= value; }
251 );
252}
253
254pub fn vec_mul_add(dst: &mut [f32], src: &[f32], gain: f32) {
256 let len = dst.len().min(src.len());
257 dispatch!(
258 unsafe { sesh_vec_mul_add_host(dst.as_mut_ptr(), src.as_ptr(), gain, len as u32) },
259 for i in 0..len { dst[i] += src[i] * gain; }
260 );
261}
262
263pub fn vec_clamp(dst: &mut [f32], src: &[f32], min: f32, max: f32) {
265 let len = dst.len().min(src.len());
266 dispatch!(
267 unsafe { sesh_vec_clamp_host(dst.as_mut_ptr(), src.as_ptr(), min, max, len as u32) },
268 for i in 0..len { dst[i] = src[i].clamp(min, max); }
269 );
270}
271
272pub fn vec_clamp_assign(dst: &mut [f32], min: f32, max: f32) {
274 let len = dst.len();
275 dispatch!(
276 unsafe { sesh_vec_clamp_host(dst.as_mut_ptr(), dst.as_ptr(), min, max, len as u32) },
277 for i in 0..len { dst[i] = dst[i].clamp(min, max); }
278 );
279}
280
281pub fn vec_ring_write(buf: &mut [f32], pos: &mut usize, src: &[f32]) {
288 let buf_len = buf.len();
289 let frames = src.len();
290 dispatch!(
291 {
292 let mut pos32 = *pos as u32;
293 unsafe {
294 sesh_vec_ring_write_host(
295 buf.as_mut_ptr(), buf_len as u32, &mut pos32, src.as_ptr(), frames as u32,
296 );
297 }
298 *pos = pos32 as usize;
299 },
300 {
301 for i in 0..frames {
302 buf[(*pos + i) % buf_len] = src[i];
303 }
304 *pos = (*pos + frames) % buf_len;
305 }
306 );
307}
308
309pub fn vec_ring_read(buf: &[f32], pos: usize, dst: &mut [f32], offset: usize) {
311 let buf_len = buf.len();
312 let frames = dst.len();
313 dispatch!(
314 unsafe {
315 sesh_vec_ring_read_host(
316 buf.as_ptr(), buf_len as u32, pos as u32,
317 dst.as_mut_ptr(), offset as u32, frames as u32,
318 );
319 },
320 {
321 let start = (pos + buf_len - offset) % buf_len;
322 for i in 0..frames {
323 dst[i] = buf[(start + i) % buf_len];
324 }
325 }
326 );
327}
328
329pub fn vec_delay_read(buf: &[f32], pos: usize, dst: &mut [f32], time: &[f32]) {
339 let buf_len = buf.len();
340 let frames = dst.len().min(time.len());
341 dispatch!(
342 unsafe {
343 sesh_vec_delay_read_host(
344 buf.as_ptr(), buf_len as u32, pos as u32,
345 dst.as_mut_ptr(), time.as_ptr(), frames as u32,
346 );
347 },
348 {
349 for i in 0..frames {
350 let write_pos_at_i = (pos + buf_len - frames + i) % buf_len;
352
353 let delay_int = time[i] as usize;
354 let delay_frac = time[i] - delay_int as f32;
355
356 let idx1 = (write_pos_at_i + buf_len - delay_int) % buf_len;
357 let idx2 = (idx1 + buf_len - 1) % buf_len;
358
359 dst[i] = buf[idx1] + delay_frac * (buf[idx2] - buf[idx1]);
360 }
361 }
362 );
363}
364
365pub fn vec_schroeder_allpass(
377 buf: &mut [f32],
378 pos: &mut usize,
379 dst: &mut [f32],
380 src: &[f32],
381 delay: usize,
382 g: f32,
383) {
384 let buf_len = buf.len();
385 let frames = dst.len().min(src.len());
386 dispatch!(
387 {
388 let mut pos32 = *pos as u32;
389 unsafe {
390 sesh_vec_schroeder_allpass_host(
391 buf.as_mut_ptr(), buf_len as u32, &mut pos32,
392 dst.as_mut_ptr(), src.as_ptr(),
393 delay as u32, g, frames as u32,
394 );
395 }
396 *pos = pos32 as usize;
397 },
398 {
399 let mut wp = *pos;
400 for i in 0..frames {
401 let read_idx = (wp + buf_len - delay) % buf_len;
402 let buf_out = buf[read_idx];
403
404 let v = src[i] + g * buf_out;
405 dst[i] = buf_out - g * v;
406
407 buf[wp] = v;
408 wp = (wp + 1) % buf_len;
409 }
410 *pos = wp;
411 }
412 );
413}
414
415pub fn vec_one_pole(
425 state: &mut OnePoleState,
426 dst: &mut [f32],
427 src: &[f32],
428 coefficient: f32,
429) {
430 let frames = dst.len().min(src.len());
431 let mut y = state.y1;
432 for i in 0..frames {
433 y = src[i] + coefficient * (y - src[i]);
434 dst[i] = y;
435 }
436 state.y1 = y;
437}
438
439const MAX_COMB_LINES: usize = 16;
462
463pub fn vec_comb(
472 buf: &mut [f32],
473 pos: &mut usize,
474 damp: &mut OnePoleState,
475 dst: &mut [f32],
476 src: &[f32],
477 time: &[f32],
478 feedback: f32,
479 damping: f32,
480) {
481 let buf_len = buf.len();
482 let frames = dst.len().min(src.len()).min(time.len());
483 let mut wp = *pos;
484 let mut y = damp.y1;
485 for i in 0..frames {
486 let delay_int = time[i] as usize;
487 let delay_frac = time[i] - delay_int as f32;
488 let idx1 = (wp + buf_len - delay_int) % buf_len;
489 let idx2 = (idx1 + buf_len - 1) % buf_len;
490 let tap = buf[idx1] + delay_frac * (buf[idx2] - buf[idx1]);
491
492 y = tap + damping * (y - tap);
493
494 dst[i] = y;
495 buf[wp] = src[i] + feedback * y;
496 wp = (wp + 1) % buf_len;
497 }
498 *pos = wp;
499 damp.y1 = y;
500}
501
502pub fn vec_comb_parallel(
511 bufs: &mut [&mut [f32]],
512 positions: &mut [usize],
513 damp: &mut [OnePoleState],
514 dst: &mut [&mut [f32]],
515 src: &[f32],
516 time: &[&[f32]],
517 feedback: f32,
518 damping: f32,
519) {
520 let n = bufs.len();
521 for line in 0..n {
522 vec_comb(
523 bufs[line], &mut positions[line], &mut damp[line],
524 dst[line], src, time[line], feedback, damping,
525 );
526 }
527}
528
529pub fn vec_comb_coupled(
545 bufs: &mut [&mut [f32]],
546 positions: &mut [usize],
547 damp: &mut [OnePoleState],
548 dst: &mut [&mut [f32]],
549 src: &[&[f32]],
550 time: &[&[f32]],
551 matrix: &[f32],
552 damping: f32,
553) {
554 let n = bufs.len();
555 assert!(n <= MAX_COMB_LINES, "vec_comb_coupled: max {MAX_COMB_LINES} lines");
556 assert!(matrix.len() >= n * n, "vec_comb_coupled: matrix must be N×N");
557
558 let frames = dst[0].len();
559
560 for i in 0..frames {
561 let mut taps = [0.0f32; MAX_COMB_LINES];
562 let mut mixed = [0.0f32; MAX_COMB_LINES];
563
564 for line in 0..n {
566 let buf_len = bufs[line].len();
567 let wp = positions[line];
568 let t = time[line][i];
569 let delay_int = t as usize;
570 let delay_frac = t - delay_int as f32;
571 let idx1 = (wp + buf_len - delay_int) % buf_len;
572 let idx2 = (idx1 + buf_len - 1) % buf_len;
573 taps[line] = bufs[line][idx1] + delay_frac * (bufs[line][idx2] - bufs[line][idx1]);
574 }
575
576 for line in 0..n {
578 damp[line].y1 = taps[line] + damping * (damp[line].y1 - taps[line]);
579 taps[line] = damp[line].y1;
580 }
581
582 for row in 0..n {
584 let mut sum = 0.0;
585 for col in 0..n {
586 sum += matrix[row * n + col] * taps[col];
587 }
588 mixed[row] = sum;
589 }
590
591 for line in 0..n {
593 dst[line][i] = taps[line];
594 bufs[line][positions[line]] = src[line][i] + mixed[line];
595 positions[line] = (positions[line] + 1) % bufs[line].len();
596 }
597 }
598}
599
600pub fn vec_osc(
606 phase: &mut f32,
607 dst: &mut [f32],
608 freq: f32,
609 waveform: Waveform,
610 sample_rate: f32,
611) {
612 let frames = dst.len();
613 dispatch!(
614 unsafe {
615 sesh_vec_osc_host(
616 phase as *mut f32, dst.as_mut_ptr(),
617 freq, waveform as u32, sample_rate, frames as u32,
618 );
619 },
620 {
621 let phase_inc = freq / sample_rate;
622 for i in 0..frames {
623 dst[i] = match waveform {
624 Waveform::Sine => (*phase * std::f32::consts::TAU).sin(),
625 Waveform::Triangle => 4.0 * (*phase - (*phase + 0.5).floor()).abs() - 1.0,
626 Waveform::Saw => 2.0 * (*phase - (*phase + 0.5).floor()),
627 Waveform::Square => if *phase % 1.0 < 0.5 { 1.0 } else { -1.0 },
628 };
629 *phase += phase_inc;
630 if *phase >= 1.0 {
631 *phase -= 1.0;
632 }
633 }
634 }
635 );
636}
637
638pub fn vec_biquad(
647 state: &mut BiquadState,
648 dst: &mut [f32],
649 src: &[f32],
650 cutoff: &[f32],
651 q: &[f32],
652 gain: &[f32],
653 filter_type: FilterType,
654 sample_rate: f32,
655) {
656 let frames = dst.len().min(src.len()).min(cutoff.len()).min(q.len()).min(gain.len());
657 dispatch!(
658 unsafe {
659 sesh_vec_biquad_host(
660 state as *mut BiquadState as *mut f32,
661 dst.as_mut_ptr(), src.as_ptr(),
662 cutoff.as_ptr(), q.as_ptr(), gain.as_ptr(),
663 filter_type as u32, sample_rate, frames as u32,
664 );
665 },
666 {
667 for i in 0..frames {
668 let w0 = std::f32::consts::TAU * cutoff[i] / sample_rate;
669 let cos_w0 = w0.cos();
670 let sin_w0 = w0.sin();
671 let alpha = sin_w0 / (2.0 * q[i]);
672 let a_db = gain[i];
673 let a_lin = 10.0f32.powf(a_db / 40.0);
674
675 let (b0, b1, b2, a0, a1, a2) = match filter_type {
676 FilterType::Lowpass => {
677 let b1 = 1.0 - cos_w0;
678 let b0 = b1 / 2.0;
679 (b0, b1, b0, 1.0 + alpha, -2.0 * cos_w0, 1.0 - alpha)
680 }
681 FilterType::Highpass => {
682 let b1 = -(1.0 + cos_w0);
683 let b0 = (1.0 + cos_w0) / 2.0;
684 (b0, b1, b0, 1.0 + alpha, -2.0 * cos_w0, 1.0 - alpha)
685 }
686 FilterType::Bandpass => {
687 (alpha, 0.0, -alpha, 1.0 + alpha, -2.0 * cos_w0, 1.0 - alpha)
688 }
689 FilterType::Notch => {
690 (1.0, -2.0 * cos_w0, 1.0, 1.0 + alpha, -2.0 * cos_w0, 1.0 - alpha)
691 }
692 FilterType::Peak => {
693 (
694 1.0 + alpha * a_lin,
695 -2.0 * cos_w0,
696 1.0 - alpha * a_lin,
697 1.0 + alpha / a_lin,
698 -2.0 * cos_w0,
699 1.0 - alpha / a_lin,
700 )
701 }
702 FilterType::LowShelf => {
703 let two_sqrt_a_alpha = 2.0 * a_lin.sqrt() * alpha;
704 (
705 a_lin * ((a_lin + 1.0) - (a_lin - 1.0) * cos_w0 + two_sqrt_a_alpha),
706 2.0 * a_lin * ((a_lin - 1.0) - (a_lin + 1.0) * cos_w0),
707 a_lin * ((a_lin + 1.0) - (a_lin - 1.0) * cos_w0 - two_sqrt_a_alpha),
708 (a_lin + 1.0) + (a_lin - 1.0) * cos_w0 + two_sqrt_a_alpha,
709 -2.0 * ((a_lin - 1.0) + (a_lin + 1.0) * cos_w0),
710 (a_lin + 1.0) + (a_lin - 1.0) * cos_w0 - two_sqrt_a_alpha,
711 )
712 }
713 FilterType::HighShelf => {
714 let two_sqrt_a_alpha = 2.0 * a_lin.sqrt() * alpha;
715 (
716 a_lin * ((a_lin + 1.0) + (a_lin - 1.0) * cos_w0 + two_sqrt_a_alpha),
717 -2.0 * a_lin * ((a_lin - 1.0) + (a_lin + 1.0) * cos_w0),
718 a_lin * ((a_lin + 1.0) + (a_lin - 1.0) * cos_w0 - two_sqrt_a_alpha),
719 (a_lin + 1.0) - (a_lin - 1.0) * cos_w0 + two_sqrt_a_alpha,
720 2.0 * ((a_lin - 1.0) - (a_lin + 1.0) * cos_w0),
721 (a_lin + 1.0) - (a_lin - 1.0) * cos_w0 - two_sqrt_a_alpha,
722 )
723 }
724 FilterType::Allpass => {
725 (1.0 - alpha, -2.0 * cos_w0, 1.0 + alpha, 1.0 + alpha, -2.0 * cos_w0, 1.0 - alpha)
726 }
727 };
728
729 let b0 = b0 / a0;
731 let b1 = b1 / a0;
732 let b2 = b2 / a0;
733 let a1 = a1 / a0;
734 let a2 = a2 / a0;
735
736 let x0 = src[i];
737 let y0 = b0 * x0 + b1 * state.x1 + b2 * state.x2
738 - a1 * state.y1 - a2 * state.y2;
739
740 state.x2 = state.x1;
741 state.x1 = x0;
742 state.y2 = state.y1;
743 state.y1 = y0;
744
745 dst[i] = y0;
746 }
747 }
748 );
749}
750
751pub fn vec_envelope(
760 state: &mut EnvelopeState,
761 dst: &mut [f32],
762 src: &[f32],
763 attack: &[f32],
764 release: &[f32],
765 mode: EnvelopeMode,
766 sample_rate: f32,
767) {
768 let frames = dst.len().min(src.len()).min(attack.len()).min(release.len());
769 dispatch!(
770 unsafe {
771 sesh_vec_envelope_host(
772 state as *mut EnvelopeState as *mut f32,
773 dst.as_mut_ptr(), src.as_ptr(),
774 attack.as_ptr(), release.as_ptr(),
775 mode as u32, sample_rate, frames as u32,
776 );
777 },
778 {
779 for i in 0..frames {
780 let input_level = match mode {
781 EnvelopeMode::Peak => src[i].abs(),
782 EnvelopeMode::Rms => src[i] * src[i],
783 };
784
785 let att_coeff = (-1.0 / (attack[i] * sample_rate)).exp();
786 let rel_coeff = (-1.0 / (release[i] * sample_rate)).exp();
787
788 let coeff = if input_level > state.current { att_coeff } else { rel_coeff };
789 state.current = coeff * state.current + (1.0 - coeff) * input_level;
790
791 dst[i] = match mode {
792 EnvelopeMode::Peak => state.current,
793 EnvelopeMode::Rms => state.current.sqrt(),
794 };
795 }
796 }
797 );
798}
799
800pub fn vec_tanh(dst: &mut [f32], src: &[f32], drive: &[f32]) {
806 let len = dst.len().min(src.len()).min(drive.len());
807 dispatch!(
808 unsafe { sesh_vec_tanh_host(dst.as_mut_ptr(), src.as_ptr(), drive.as_ptr(), len as u32) },
809 for i in 0..len { dst[i] = (src[i] * drive[i]).tanh(); }
810 );
811}
812
813pub fn vec_hard_clip(dst: &mut [f32], src: &[f32], threshold: &[f32]) {
815 let len = dst.len().min(src.len()).min(threshold.len());
816 dispatch!(
817 unsafe { sesh_vec_hard_clip_host(dst.as_mut_ptr(), src.as_ptr(), threshold.as_ptr(), len as u32) },
818 for i in 0..len { dst[i] = src[i].clamp(-threshold[i], threshold[i]); }
819 );
820}
821
822pub fn vec_abs(dst: &mut [f32], src: &[f32]) {
828 let len = dst.len().min(src.len());
829 dispatch!(
830 unsafe { sesh_vec_abs_host(dst.as_mut_ptr(), src.as_ptr(), len as u32) },
831 for i in 0..len { dst[i] = src[i].abs(); }
832 );
833}
834
835pub fn vec_neg(dst: &mut [f32], src: &[f32]) {
837 let len = dst.len().min(src.len());
838 dispatch!(
839 unsafe { sesh_vec_neg_host(dst.as_mut_ptr(), src.as_ptr(), len as u32) },
840 for i in 0..len { dst[i] = -src[i]; }
841 );
842}
843
844pub fn vec_sqrt(dst: &mut [f32], src: &[f32]) {
846 let len = dst.len().min(src.len());
847 dispatch!(
848 unsafe { sesh_vec_sqrt_host(dst.as_mut_ptr(), src.as_ptr(), len as u32) },
849 for i in 0..len { dst[i] = src[i].sqrt(); }
850 );
851}
852
853pub fn vec_recip(dst: &mut [f32], src: &[f32]) {
855 let len = dst.len().min(src.len());
856 dispatch!(
857 unsafe { sesh_vec_recip_host(dst.as_mut_ptr(), src.as_ptr(), len as u32) },
858 for i in 0..len { dst[i] = 1.0 / src[i]; }
859 );
860}
861
862pub fn vec_div(dst: &mut [f32], a: &[f32], b: &[f32]) {
864 let len = dst.len().min(a.len()).min(b.len());
865 dispatch!(
866 unsafe { sesh_vec_div_host(dst.as_mut_ptr(), a.as_ptr(), b.as_ptr(), len as u32) },
867 for i in 0..len { dst[i] = a[i] / b[i]; }
868 );
869}
870
871pub fn vec_pow(dst: &mut [f32], src: &[f32], exp: &[f32]) {
873 let len = dst.len().min(src.len()).min(exp.len());
874 dispatch!(
875 unsafe { sesh_vec_pow_host(dst.as_mut_ptr(), src.as_ptr(), exp.as_ptr(), len as u32) },
876 for i in 0..len { dst[i] = src[i].powf(exp[i]); }
877 );
878}
879
880pub fn vec_add_assign(dst: &mut [f32], src: &[f32]) {
890 let len = dst.len().min(src.len());
891 dispatch!(
892 unsafe { sesh_vec_add_host(dst.as_mut_ptr(), dst.as_ptr(), src.as_ptr(), len as u32) },
893 for i in 0..len { dst[i] += src[i]; }
894 );
895}
896
897pub fn vec_mul_assign(dst: &mut [f32], src: &[f32]) {
899 let len = dst.len().min(src.len());
900 dispatch!(
901 unsafe { sesh_vec_mul_host(dst.as_mut_ptr(), dst.as_ptr(), src.as_ptr(), len as u32) },
902 for i in 0..len { dst[i] *= src[i]; }
903 );
904}
905
906pub fn vec_tanh_assign(dst: &mut [f32], drive: &[f32]) {
908 let len = dst.len().min(drive.len());
909 dispatch!(
910 unsafe { sesh_vec_tanh_host(dst.as_mut_ptr(), dst.as_ptr(), drive.as_ptr(), len as u32) },
911 for i in 0..len { dst[i] = (dst[i] * drive[i]).tanh(); }
912 );
913}
914
915pub fn vec_hard_clip_assign(dst: &mut [f32], threshold: &[f32]) {
917 let len = dst.len().min(threshold.len());
918 dispatch!(
919 unsafe { sesh_vec_hard_clip_host(dst.as_mut_ptr(), dst.as_ptr(), threshold.as_ptr(), len as u32) },
920 for i in 0..len { dst[i] = dst[i].clamp(-threshold[i], threshold[i]); }
921 );
922}
923
924pub fn vec_abs_assign(dst: &mut [f32]) {
926 let len = dst.len();
927 dispatch!(
928 unsafe { sesh_vec_abs_host(dst.as_mut_ptr(), dst.as_ptr(), len as u32) },
929 for i in 0..len { dst[i] = dst[i].abs(); }
930 );
931}
932
933pub fn vec_neg_assign(dst: &mut [f32]) {
935 let len = dst.len();
936 dispatch!(
937 unsafe { sesh_vec_neg_host(dst.as_mut_ptr(), dst.as_ptr(), len as u32) },
938 for i in 0..len { dst[i] = -dst[i]; }
939 );
940}
941
942pub fn vec_sqrt_assign(dst: &mut [f32]) {
944 let len = dst.len();
945 dispatch!(
946 unsafe { sesh_vec_sqrt_host(dst.as_mut_ptr(), dst.as_ptr(), len as u32) },
947 for i in 0..len { dst[i] = dst[i].sqrt(); }
948 );
949}
950
951pub fn vec_recip_assign(dst: &mut [f32]) {
953 let len = dst.len();
954 dispatch!(
955 unsafe { sesh_vec_recip_host(dst.as_mut_ptr(), dst.as_ptr(), len as u32) },
956 for i in 0..len { dst[i] = 1.0 / dst[i]; }
957 );
958}
959
960pub fn vec_div_assign(dst: &mut [f32], src: &[f32]) {
962 let len = dst.len().min(src.len());
963 dispatch!(
964 unsafe { sesh_vec_div_host(dst.as_mut_ptr(), dst.as_ptr(), src.as_ptr(), len as u32) },
965 for i in 0..len { dst[i] /= src[i]; }
966 );
967}
968
969pub fn vec_pow_assign(dst: &mut [f32], exp: &[f32]) {
971 let len = dst.len().min(exp.len());
972 dispatch!(
973 unsafe { sesh_vec_pow_host(dst.as_mut_ptr(), dst.as_ptr(), exp.as_ptr(), len as u32) },
974 for i in 0..len { dst[i] = dst[i].powf(exp[i]); }
975 );
976}