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#[repr(C)]
146pub struct BiquadState {
147 pub x1: f32,
148 pub x2: f32,
149 pub y1: f32,
150 pub y2: f32,
151}
152
153impl BiquadState {
154 pub const fn new() -> Self {
155 Self { x1: 0.0, x2: 0.0, y1: 0.0, y2: 0.0 }
156 }
157}
158
159#[repr(u32)]
161#[derive(Clone, Copy)]
162pub enum EnvelopeMode {
163 Peak = 0,
165 Rms = 1,
167}
168
169#[repr(C)]
171pub struct EnvelopeState {
172 pub current: f32,
173}
174
175impl EnvelopeState {
176 pub const fn new() -> Self {
177 Self { current: 0.0 }
178 }
179}
180
181pub fn vec_copy(dst: &mut [f32], src: &[f32]) {
187 let len = dst.len().min(src.len());
188 dispatch!(
189 unsafe { sesh_vec_copy_host(dst.as_mut_ptr(), src.as_ptr(), len as u32) },
190 dst[..len].copy_from_slice(&src[..len])
191 );
192}
193
194pub fn vec_fill(dst: &mut [f32], value: f32) {
196 let len = dst.len();
197 dispatch!(
198 unsafe { sesh_vec_fill_host(dst.as_mut_ptr(), value, len as u32) },
199 for s in dst.iter_mut() { *s = value; }
200 );
201}
202
203pub fn vec_add(dst: &mut [f32], a: &[f32], b: &[f32]) {
205 let len = dst.len().min(a.len()).min(b.len());
206 dispatch!(
207 unsafe { sesh_vec_add_host(dst.as_mut_ptr(), a.as_ptr(), b.as_ptr(), len as u32) },
208 for i in 0..len { dst[i] = a[i] + b[i]; }
209 );
210}
211
212pub fn vec_add_scalar(dst: &mut [f32], value: f32) {
214 let len = dst.len();
215 dispatch!(
216 unsafe { sesh_vec_add_scalar_host(dst.as_mut_ptr(), value, len as u32) },
217 for s in dst.iter_mut() { *s += value; }
218 );
219}
220
221pub fn vec_mul(dst: &mut [f32], a: &[f32], b: &[f32]) {
223 let len = dst.len().min(a.len()).min(b.len());
224 dispatch!(
225 unsafe { sesh_vec_mul_host(dst.as_mut_ptr(), a.as_ptr(), b.as_ptr(), len as u32) },
226 for i in 0..len { dst[i] = a[i] * b[i]; }
227 );
228}
229
230pub fn vec_mul_scalar(dst: &mut [f32], value: f32) {
232 let len = dst.len();
233 dispatch!(
234 unsafe { sesh_vec_mul_scalar_host(dst.as_mut_ptr(), value, len as u32) },
235 for s in dst.iter_mut() { *s *= value; }
236 );
237}
238
239pub fn vec_mul_add(dst: &mut [f32], src: &[f32], gain: f32) {
241 let len = dst.len().min(src.len());
242 dispatch!(
243 unsafe { sesh_vec_mul_add_host(dst.as_mut_ptr(), src.as_ptr(), gain, len as u32) },
244 for i in 0..len { dst[i] += src[i] * gain; }
245 );
246}
247
248pub fn vec_clamp(dst: &mut [f32], src: &[f32], min: f32, max: f32) {
250 let len = dst.len().min(src.len());
251 dispatch!(
252 unsafe { sesh_vec_clamp_host(dst.as_mut_ptr(), src.as_ptr(), min, max, len as u32) },
253 for i in 0..len { dst[i] = src[i].clamp(min, max); }
254 );
255}
256
257pub fn vec_clamp_assign(dst: &mut [f32], min: f32, max: f32) {
259 let len = dst.len();
260 dispatch!(
261 unsafe { sesh_vec_clamp_host(dst.as_mut_ptr(), dst.as_ptr(), min, max, len as u32) },
262 for i in 0..len { dst[i] = dst[i].clamp(min, max); }
263 );
264}
265
266pub fn vec_ring_write(buf: &mut [f32], pos: &mut usize, src: &[f32]) {
273 let buf_len = buf.len();
274 let frames = src.len();
275 dispatch!(
276 {
277 let mut pos32 = *pos as u32;
278 unsafe {
279 sesh_vec_ring_write_host(
280 buf.as_mut_ptr(), buf_len as u32, &mut pos32, src.as_ptr(), frames as u32,
281 );
282 }
283 *pos = pos32 as usize;
284 },
285 {
286 for i in 0..frames {
287 buf[(*pos + i) % buf_len] = src[i];
288 }
289 *pos = (*pos + frames) % buf_len;
290 }
291 );
292}
293
294pub fn vec_ring_read(buf: &[f32], pos: usize, dst: &mut [f32], offset: usize) {
296 let buf_len = buf.len();
297 let frames = dst.len();
298 dispatch!(
299 unsafe {
300 sesh_vec_ring_read_host(
301 buf.as_ptr(), buf_len as u32, pos as u32,
302 dst.as_mut_ptr(), offset as u32, frames as u32,
303 );
304 },
305 {
306 let start = (pos + buf_len - offset) % buf_len;
307 for i in 0..frames {
308 dst[i] = buf[(start + i) % buf_len];
309 }
310 }
311 );
312}
313
314pub fn vec_delay_read(buf: &[f32], pos: usize, dst: &mut [f32], time: &[f32]) {
324 let buf_len = buf.len();
325 let frames = dst.len().min(time.len());
326 dispatch!(
327 unsafe {
328 sesh_vec_delay_read_host(
329 buf.as_ptr(), buf_len as u32, pos as u32,
330 dst.as_mut_ptr(), time.as_ptr(), frames as u32,
331 );
332 },
333 {
334 for i in 0..frames {
335 let write_pos_at_i = (pos + buf_len - frames + i) % buf_len;
337
338 let delay_int = time[i] as usize;
339 let delay_frac = time[i] - delay_int as f32;
340
341 let idx1 = (write_pos_at_i + buf_len - delay_int) % buf_len;
342 let idx2 = (idx1 + buf_len - 1) % buf_len;
343
344 dst[i] = buf[idx1] + delay_frac * (buf[idx2] - buf[idx1]);
345 }
346 }
347 );
348}
349
350pub fn vec_schroeder_allpass(
362 buf: &mut [f32],
363 pos: &mut usize,
364 dst: &mut [f32],
365 src: &[f32],
366 delay: usize,
367 g: f32,
368) {
369 let buf_len = buf.len();
370 let frames = dst.len().min(src.len());
371 dispatch!(
372 {
373 let mut pos32 = *pos as u32;
374 unsafe {
375 sesh_vec_schroeder_allpass_host(
376 buf.as_mut_ptr(), buf_len as u32, &mut pos32,
377 dst.as_mut_ptr(), src.as_ptr(),
378 delay as u32, g, frames as u32,
379 );
380 }
381 *pos = pos32 as usize;
382 },
383 {
384 let mut wp = *pos;
385 for i in 0..frames {
386 let read_idx = (wp + buf_len - delay) % buf_len;
387 let buf_out = buf[read_idx];
388
389 let v = src[i] + g * buf_out;
390 dst[i] = buf_out - g * v;
391
392 buf[wp] = v;
393 wp = (wp + 1) % buf_len;
394 }
395 *pos = wp;
396 }
397 );
398}
399
400pub fn vec_osc(
406 phase: &mut f32,
407 dst: &mut [f32],
408 freq: f32,
409 waveform: Waveform,
410 sample_rate: f32,
411) {
412 let frames = dst.len();
413 dispatch!(
414 unsafe {
415 sesh_vec_osc_host(
416 phase as *mut f32, dst.as_mut_ptr(),
417 freq, waveform as u32, sample_rate, frames as u32,
418 );
419 },
420 {
421 let phase_inc = freq / sample_rate;
422 for i in 0..frames {
423 dst[i] = match waveform {
424 Waveform::Sine => (*phase * std::f32::consts::TAU).sin(),
425 Waveform::Triangle => 4.0 * (*phase - (*phase + 0.5).floor()).abs() - 1.0,
426 Waveform::Saw => 2.0 * (*phase - (*phase + 0.5).floor()),
427 Waveform::Square => if *phase % 1.0 < 0.5 { 1.0 } else { -1.0 },
428 };
429 *phase += phase_inc;
430 if *phase >= 1.0 {
431 *phase -= 1.0;
432 }
433 }
434 }
435 );
436}
437
438pub fn vec_biquad(
447 state: &mut BiquadState,
448 dst: &mut [f32],
449 src: &[f32],
450 cutoff: &[f32],
451 q: &[f32],
452 gain: &[f32],
453 filter_type: FilterType,
454 sample_rate: f32,
455) {
456 let frames = dst.len().min(src.len()).min(cutoff.len()).min(q.len()).min(gain.len());
457 dispatch!(
458 unsafe {
459 sesh_vec_biquad_host(
460 state as *mut BiquadState as *mut f32,
461 dst.as_mut_ptr(), src.as_ptr(),
462 cutoff.as_ptr(), q.as_ptr(), gain.as_ptr(),
463 filter_type as u32, sample_rate, frames as u32,
464 );
465 },
466 {
467 for i in 0..frames {
468 let w0 = std::f32::consts::TAU * cutoff[i] / sample_rate;
469 let cos_w0 = w0.cos();
470 let sin_w0 = w0.sin();
471 let alpha = sin_w0 / (2.0 * q[i]);
472 let a_db = gain[i];
473 let a_lin = 10.0f32.powf(a_db / 40.0);
474
475 let (b0, b1, b2, a0, a1, a2) = match filter_type {
476 FilterType::Lowpass => {
477 let b1 = 1.0 - cos_w0;
478 let b0 = b1 / 2.0;
479 (b0, b1, b0, 1.0 + alpha, -2.0 * cos_w0, 1.0 - alpha)
480 }
481 FilterType::Highpass => {
482 let b1 = -(1.0 + cos_w0);
483 let b0 = (1.0 + cos_w0) / 2.0;
484 (b0, b1, b0, 1.0 + alpha, -2.0 * cos_w0, 1.0 - alpha)
485 }
486 FilterType::Bandpass => {
487 (alpha, 0.0, -alpha, 1.0 + alpha, -2.0 * cos_w0, 1.0 - alpha)
488 }
489 FilterType::Notch => {
490 (1.0, -2.0 * cos_w0, 1.0, 1.0 + alpha, -2.0 * cos_w0, 1.0 - alpha)
491 }
492 FilterType::Peak => {
493 (
494 1.0 + alpha * a_lin,
495 -2.0 * cos_w0,
496 1.0 - alpha * a_lin,
497 1.0 + alpha / a_lin,
498 -2.0 * cos_w0,
499 1.0 - alpha / a_lin,
500 )
501 }
502 FilterType::LowShelf => {
503 let two_sqrt_a_alpha = 2.0 * a_lin.sqrt() * alpha;
504 (
505 a_lin * ((a_lin + 1.0) - (a_lin - 1.0) * cos_w0 + two_sqrt_a_alpha),
506 2.0 * a_lin * ((a_lin - 1.0) - (a_lin + 1.0) * cos_w0),
507 a_lin * ((a_lin + 1.0) - (a_lin - 1.0) * cos_w0 - two_sqrt_a_alpha),
508 (a_lin + 1.0) + (a_lin - 1.0) * cos_w0 + two_sqrt_a_alpha,
509 -2.0 * ((a_lin - 1.0) + (a_lin + 1.0) * cos_w0),
510 (a_lin + 1.0) + (a_lin - 1.0) * cos_w0 - two_sqrt_a_alpha,
511 )
512 }
513 FilterType::HighShelf => {
514 let two_sqrt_a_alpha = 2.0 * a_lin.sqrt() * alpha;
515 (
516 a_lin * ((a_lin + 1.0) + (a_lin - 1.0) * cos_w0 + two_sqrt_a_alpha),
517 -2.0 * a_lin * ((a_lin - 1.0) + (a_lin + 1.0) * cos_w0),
518 a_lin * ((a_lin + 1.0) + (a_lin - 1.0) * cos_w0 - two_sqrt_a_alpha),
519 (a_lin + 1.0) - (a_lin - 1.0) * cos_w0 + two_sqrt_a_alpha,
520 2.0 * ((a_lin - 1.0) - (a_lin + 1.0) * cos_w0),
521 (a_lin + 1.0) - (a_lin - 1.0) * cos_w0 - two_sqrt_a_alpha,
522 )
523 }
524 FilterType::Allpass => {
525 (1.0 - alpha, -2.0 * cos_w0, 1.0 + alpha, 1.0 + alpha, -2.0 * cos_w0, 1.0 - alpha)
526 }
527 };
528
529 let b0 = b0 / a0;
531 let b1 = b1 / a0;
532 let b2 = b2 / a0;
533 let a1 = a1 / a0;
534 let a2 = a2 / a0;
535
536 let x0 = src[i];
537 let y0 = b0 * x0 + b1 * state.x1 + b2 * state.x2
538 - a1 * state.y1 - a2 * state.y2;
539
540 state.x2 = state.x1;
541 state.x1 = x0;
542 state.y2 = state.y1;
543 state.y1 = y0;
544
545 dst[i] = y0;
546 }
547 }
548 );
549}
550
551pub fn vec_envelope(
560 state: &mut EnvelopeState,
561 dst: &mut [f32],
562 src: &[f32],
563 attack: &[f32],
564 release: &[f32],
565 mode: EnvelopeMode,
566 sample_rate: f32,
567) {
568 let frames = dst.len().min(src.len()).min(attack.len()).min(release.len());
569 dispatch!(
570 unsafe {
571 sesh_vec_envelope_host(
572 state as *mut EnvelopeState as *mut f32,
573 dst.as_mut_ptr(), src.as_ptr(),
574 attack.as_ptr(), release.as_ptr(),
575 mode as u32, sample_rate, frames as u32,
576 );
577 },
578 {
579 for i in 0..frames {
580 let input_level = match mode {
581 EnvelopeMode::Peak => src[i].abs(),
582 EnvelopeMode::Rms => src[i] * src[i],
583 };
584
585 let att_coeff = (-1.0 / (attack[i] * sample_rate)).exp();
586 let rel_coeff = (-1.0 / (release[i] * sample_rate)).exp();
587
588 let coeff = if input_level > state.current { att_coeff } else { rel_coeff };
589 state.current = coeff * state.current + (1.0 - coeff) * input_level;
590
591 dst[i] = match mode {
592 EnvelopeMode::Peak => state.current,
593 EnvelopeMode::Rms => state.current.sqrt(),
594 };
595 }
596 }
597 );
598}
599
600pub fn vec_tanh(dst: &mut [f32], src: &[f32], drive: &[f32]) {
606 let len = dst.len().min(src.len()).min(drive.len());
607 dispatch!(
608 unsafe { sesh_vec_tanh_host(dst.as_mut_ptr(), src.as_ptr(), drive.as_ptr(), len as u32) },
609 for i in 0..len { dst[i] = (src[i] * drive[i]).tanh(); }
610 );
611}
612
613pub fn vec_hard_clip(dst: &mut [f32], src: &[f32], threshold: &[f32]) {
615 let len = dst.len().min(src.len()).min(threshold.len());
616 dispatch!(
617 unsafe { sesh_vec_hard_clip_host(dst.as_mut_ptr(), src.as_ptr(), threshold.as_ptr(), len as u32) },
618 for i in 0..len { dst[i] = src[i].clamp(-threshold[i], threshold[i]); }
619 );
620}
621
622pub fn vec_abs(dst: &mut [f32], src: &[f32]) {
628 let len = dst.len().min(src.len());
629 dispatch!(
630 unsafe { sesh_vec_abs_host(dst.as_mut_ptr(), src.as_ptr(), len as u32) },
631 for i in 0..len { dst[i] = src[i].abs(); }
632 );
633}
634
635pub fn vec_neg(dst: &mut [f32], src: &[f32]) {
637 let len = dst.len().min(src.len());
638 dispatch!(
639 unsafe { sesh_vec_neg_host(dst.as_mut_ptr(), src.as_ptr(), len as u32) },
640 for i in 0..len { dst[i] = -src[i]; }
641 );
642}
643
644pub fn vec_sqrt(dst: &mut [f32], src: &[f32]) {
646 let len = dst.len().min(src.len());
647 dispatch!(
648 unsafe { sesh_vec_sqrt_host(dst.as_mut_ptr(), src.as_ptr(), len as u32) },
649 for i in 0..len { dst[i] = src[i].sqrt(); }
650 );
651}
652
653pub fn vec_recip(dst: &mut [f32], src: &[f32]) {
655 let len = dst.len().min(src.len());
656 dispatch!(
657 unsafe { sesh_vec_recip_host(dst.as_mut_ptr(), src.as_ptr(), len as u32) },
658 for i in 0..len { dst[i] = 1.0 / src[i]; }
659 );
660}
661
662pub fn vec_div(dst: &mut [f32], a: &[f32], b: &[f32]) {
664 let len = dst.len().min(a.len()).min(b.len());
665 dispatch!(
666 unsafe { sesh_vec_div_host(dst.as_mut_ptr(), a.as_ptr(), b.as_ptr(), len as u32) },
667 for i in 0..len { dst[i] = a[i] / b[i]; }
668 );
669}
670
671pub fn vec_pow(dst: &mut [f32], src: &[f32], exp: &[f32]) {
673 let len = dst.len().min(src.len()).min(exp.len());
674 dispatch!(
675 unsafe { sesh_vec_pow_host(dst.as_mut_ptr(), src.as_ptr(), exp.as_ptr(), len as u32) },
676 for i in 0..len { dst[i] = src[i].powf(exp[i]); }
677 );
678}
679
680pub fn vec_add_assign(dst: &mut [f32], src: &[f32]) {
690 let len = dst.len().min(src.len());
691 dispatch!(
692 unsafe { sesh_vec_add_host(dst.as_mut_ptr(), dst.as_ptr(), src.as_ptr(), len as u32) },
693 for i in 0..len { dst[i] += src[i]; }
694 );
695}
696
697pub fn vec_mul_assign(dst: &mut [f32], src: &[f32]) {
699 let len = dst.len().min(src.len());
700 dispatch!(
701 unsafe { sesh_vec_mul_host(dst.as_mut_ptr(), dst.as_ptr(), src.as_ptr(), len as u32) },
702 for i in 0..len { dst[i] *= src[i]; }
703 );
704}
705
706pub fn vec_tanh_assign(dst: &mut [f32], drive: &[f32]) {
708 let len = dst.len().min(drive.len());
709 dispatch!(
710 unsafe { sesh_vec_tanh_host(dst.as_mut_ptr(), dst.as_ptr(), drive.as_ptr(), len as u32) },
711 for i in 0..len { dst[i] = (dst[i] * drive[i]).tanh(); }
712 );
713}
714
715pub fn vec_hard_clip_assign(dst: &mut [f32], threshold: &[f32]) {
717 let len = dst.len().min(threshold.len());
718 dispatch!(
719 unsafe { sesh_vec_hard_clip_host(dst.as_mut_ptr(), dst.as_ptr(), threshold.as_ptr(), len as u32) },
720 for i in 0..len { dst[i] = dst[i].clamp(-threshold[i], threshold[i]); }
721 );
722}
723
724pub fn vec_abs_assign(dst: &mut [f32]) {
726 let len = dst.len();
727 dispatch!(
728 unsafe { sesh_vec_abs_host(dst.as_mut_ptr(), dst.as_ptr(), len as u32) },
729 for i in 0..len { dst[i] = dst[i].abs(); }
730 );
731}
732
733pub fn vec_neg_assign(dst: &mut [f32]) {
735 let len = dst.len();
736 dispatch!(
737 unsafe { sesh_vec_neg_host(dst.as_mut_ptr(), dst.as_ptr(), len as u32) },
738 for i in 0..len { dst[i] = -dst[i]; }
739 );
740}
741
742pub fn vec_sqrt_assign(dst: &mut [f32]) {
744 let len = dst.len();
745 dispatch!(
746 unsafe { sesh_vec_sqrt_host(dst.as_mut_ptr(), dst.as_ptr(), len as u32) },
747 for i in 0..len { dst[i] = dst[i].sqrt(); }
748 );
749}
750
751pub fn vec_recip_assign(dst: &mut [f32]) {
753 let len = dst.len();
754 dispatch!(
755 unsafe { sesh_vec_recip_host(dst.as_mut_ptr(), dst.as_ptr(), len as u32) },
756 for i in 0..len { dst[i] = 1.0 / dst[i]; }
757 );
758}
759
760pub fn vec_div_assign(dst: &mut [f32], src: &[f32]) {
762 let len = dst.len().min(src.len());
763 dispatch!(
764 unsafe { sesh_vec_div_host(dst.as_mut_ptr(), dst.as_ptr(), src.as_ptr(), len as u32) },
765 for i in 0..len { dst[i] /= src[i]; }
766 );
767}
768
769pub fn vec_pow_assign(dst: &mut [f32], exp: &[f32]) {
771 let len = dst.len().min(exp.len());
772 dispatch!(
773 unsafe { sesh_vec_pow_host(dst.as_mut_ptr(), dst.as_ptr(), exp.as_ptr(), len as u32) },
774 for i in 0..len { dst[i] = dst[i].powf(exp[i]); }
775 );
776}