1use std::sync::atomic::{AtomicU32, Ordering};
8
9extern "C" {
14 fn sesh_vec_version() -> u32;
15}
16
17static HOST_VEC_VERSION: AtomicU32 = AtomicU32::new(0);
19
20fn host_version() -> u32 {
21 let v = HOST_VEC_VERSION.load(Ordering::Relaxed);
22 if v != 0 {
23 return v;
24 }
25 let v = unsafe { sesh_vec_version() };
26 let store = if v == 0 { u32::MAX } else { v };
28 HOST_VEC_VERSION.store(store, Ordering::Relaxed);
29 v
30}
31
32#[inline]
33fn use_host_ops() -> bool {
34 host_version() > 0 && host_version() != u32::MAX
35}
36
37extern "C" {
42 fn sesh_vec_copy_host(dst: *mut f32, src: *const f32, len: u32);
43 fn sesh_vec_fill_host(dst: *mut f32, value: f32, len: u32);
44 fn sesh_vec_add_host(dst: *mut f32, a: *const f32, b: *const f32, len: u32);
45 fn sesh_vec_add_scalar_host(dst: *mut f32, value: f32, len: u32);
46 fn sesh_vec_mul_host(dst: *mut f32, a: *const f32, b: *const f32, len: u32);
47 fn sesh_vec_mul_scalar_host(dst: *mut f32, value: f32, len: u32);
48 fn sesh_vec_mul_add_host(dst: *mut f32, src: *const f32, gain: f32, len: u32);
49 fn sesh_vec_clamp_host(dst: *mut f32, src: *const f32, min: f32, max: f32, len: u32);
50 fn sesh_vec_ring_write_host(
51 buf: *mut f32, buf_len: u32, pos: *mut u32, src: *const f32, len: u32,
52 );
53 fn sesh_vec_ring_read_host(
54 buf: *const f32, buf_len: u32, pos: u32, dst: *mut f32, offset: u32, len: u32,
55 );
56 fn sesh_vec_delay_read_host(
57 buf: *const f32, buf_len: u32, pos: u32, dst: *mut f32, time: *const f32, len: u32,
58 );
59 fn sesh_vec_osc_host(
60 phase: *mut f32, dst: *mut f32, freq: f32, waveform: u32, sample_rate: f32, len: u32,
61 );
62 fn sesh_vec_biquad_host(
63 state: *mut f32, dst: *mut f32, src: *const f32,
64 cutoff: *const f32, q: *const f32, gain: *const f32,
65 filter_type: u32, sample_rate: f32, len: u32,
66 );
67 fn sesh_vec_envelope_host(
68 state: *mut f32, dst: *mut f32, src: *const f32,
69 attack: *const f32, release: *const f32,
70 mode: u32, sample_rate: f32, len: u32,
71 );
72 fn sesh_vec_tanh_host(dst: *mut f32, src: *const f32, drive: *const f32, len: u32);
73 fn sesh_vec_hard_clip_host(dst: *mut f32, src: *const f32, threshold: *const f32, len: u32);
74 fn sesh_vec_abs_host(dst: *mut f32, src: *const f32, len: u32);
75 fn sesh_vec_neg_host(dst: *mut f32, src: *const f32, len: u32);
76 fn sesh_vec_sqrt_host(dst: *mut f32, src: *const f32, len: u32);
77 fn sesh_vec_recip_host(dst: *mut f32, src: *const f32, len: u32);
78 fn sesh_vec_div_host(dst: *mut f32, a: *const f32, b: *const f32, len: u32);
79 fn sesh_vec_pow_host(dst: *mut f32, src: *const f32, exp: *const f32, len: u32);
80 fn sesh_vec_schroeder_allpass_host(
81 buf: *mut f32, buf_len: u32, pos: *mut u32,
82 dst: *mut f32, src: *const f32,
83 delay: u32, g: f32, len: u32,
84 );
85}
86
87#[repr(u32)]
93#[derive(Clone, Copy)]
94pub enum Waveform {
95 Sine = 0,
96 Triangle = 1,
97 Saw = 2,
98 Square = 3,
99}
100
101#[repr(u32)]
103#[derive(Clone, Copy)]
104pub enum FilterType {
105 Lowpass = 0,
106 Highpass = 1,
107 Bandpass = 2,
108 Notch = 3,
109 Peak = 4,
111 LowShelf = 5,
113 HighShelf = 6,
115 Allpass = 7,
117}
118
119#[repr(C)]
121pub struct BiquadState {
122 pub x1: f32,
123 pub x2: f32,
124 pub y1: f32,
125 pub y2: f32,
126}
127
128impl BiquadState {
129 pub const fn new() -> Self {
130 Self { x1: 0.0, x2: 0.0, y1: 0.0, y2: 0.0 }
131 }
132}
133
134#[repr(u32)]
136#[derive(Clone, Copy)]
137pub enum EnvelopeMode {
138 Peak = 0,
140 Rms = 1,
142}
143
144#[repr(C)]
146pub struct EnvelopeState {
147 pub current: f32,
148}
149
150impl EnvelopeState {
151 pub const fn new() -> Self {
152 Self { current: 0.0 }
153 }
154}
155
156pub fn vec_copy(dst: &mut [f32], src: &[f32]) {
162 let len = dst.len().min(src.len());
163 if use_host_ops() {
164 unsafe { sesh_vec_copy_host(dst.as_mut_ptr(), src.as_ptr(), len as u32) }
165 } else {
166 dst[..len].copy_from_slice(&src[..len]);
167 }
168}
169
170pub fn vec_fill(dst: &mut [f32], value: f32) {
172 let len = dst.len();
173 if use_host_ops() {
174 unsafe { sesh_vec_fill_host(dst.as_mut_ptr(), value, len as u32) }
175 } else {
176 for s in dst.iter_mut() {
177 *s = value;
178 }
179 }
180}
181
182pub fn vec_add(dst: &mut [f32], a: &[f32], b: &[f32]) {
184 let len = dst.len().min(a.len()).min(b.len());
185 if use_host_ops() {
186 unsafe { sesh_vec_add_host(dst.as_mut_ptr(), a.as_ptr(), b.as_ptr(), len as u32) }
187 } else {
188 for i in 0..len {
189 dst[i] = a[i] + b[i];
190 }
191 }
192}
193
194pub fn vec_add_scalar(dst: &mut [f32], value: f32) {
196 let len = dst.len();
197 if use_host_ops() {
198 unsafe { sesh_vec_add_scalar_host(dst.as_mut_ptr(), value, len as u32) }
199 } else {
200 for s in dst.iter_mut() {
201 *s += value;
202 }
203 }
204}
205
206pub fn vec_mul(dst: &mut [f32], a: &[f32], b: &[f32]) {
208 let len = dst.len().min(a.len()).min(b.len());
209 if use_host_ops() {
210 unsafe { sesh_vec_mul_host(dst.as_mut_ptr(), a.as_ptr(), b.as_ptr(), len as u32) }
211 } else {
212 for i in 0..len {
213 dst[i] = a[i] * b[i];
214 }
215 }
216}
217
218pub fn vec_mul_scalar(dst: &mut [f32], value: f32) {
220 let len = dst.len();
221 if use_host_ops() {
222 unsafe { sesh_vec_mul_scalar_host(dst.as_mut_ptr(), value, len as u32) }
223 } else {
224 for s in dst.iter_mut() {
225 *s *= value;
226 }
227 }
228}
229
230pub fn vec_mul_add(dst: &mut [f32], src: &[f32], gain: f32) {
232 let len = dst.len().min(src.len());
233 if use_host_ops() {
234 unsafe { sesh_vec_mul_add_host(dst.as_mut_ptr(), src.as_ptr(), gain, len as u32) }
235 } else {
236 for i in 0..len {
237 dst[i] += src[i] * gain;
238 }
239 }
240}
241
242pub fn vec_clamp(dst: &mut [f32], src: &[f32], min: f32, max: f32) {
244 let len = dst.len().min(src.len());
245 if use_host_ops() {
246 unsafe { sesh_vec_clamp_host(dst.as_mut_ptr(), src.as_ptr(), min, max, len as u32) }
247 } else {
248 for i in 0..len {
249 dst[i] = src[i].clamp(min, max);
250 }
251 }
252}
253
254pub fn vec_clamp_assign(dst: &mut [f32], min: f32, max: f32) {
256 let len = dst.len();
257 if use_host_ops() {
258 unsafe { sesh_vec_clamp_host(dst.as_mut_ptr(), dst.as_ptr(), min, max, len as u32) }
259 } else {
260 for i in 0..len {
261 dst[i] = dst[i].clamp(min, max);
262 }
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 if use_host_ops() {
276 let mut pos32 = *pos as u32;
277 unsafe {
278 sesh_vec_ring_write_host(
279 buf.as_mut_ptr(), buf_len as u32, &mut pos32, src.as_ptr(), frames as u32,
280 );
281 }
282 *pos = pos32 as usize;
283 } else {
284 for i in 0..frames {
285 buf[(*pos + i) % buf_len] = src[i];
286 }
287 *pos = (*pos + frames) % buf_len;
288 }
289}
290
291pub fn vec_ring_read(buf: &[f32], pos: usize, dst: &mut [f32], offset: usize) {
293 let buf_len = buf.len();
294 let frames = dst.len();
295 if use_host_ops() {
296 unsafe {
297 sesh_vec_ring_read_host(
298 buf.as_ptr(), buf_len as u32, pos as u32,
299 dst.as_mut_ptr(), offset as u32, frames as u32,
300 );
301 }
302 } else {
303 let start = (pos + buf_len - offset) % buf_len;
304 for i in 0..frames {
305 dst[i] = buf[(start + i) % buf_len];
306 }
307 }
308}
309
310pub fn vec_delay_read(buf: &[f32], pos: usize, dst: &mut [f32], time: &[f32]) {
320 let buf_len = buf.len();
321 let frames = dst.len().min(time.len());
322 if use_host_ops() {
323 unsafe {
324 sesh_vec_delay_read_host(
325 buf.as_ptr(), buf_len as u32, pos as u32,
326 dst.as_mut_ptr(), time.as_ptr(), frames as u32,
327 );
328 }
329 } else {
330 for i in 0..frames {
331 let write_pos_at_i = (pos + buf_len - frames + i) % buf_len;
333
334 let delay_int = time[i] as usize;
335 let delay_frac = time[i] - delay_int as f32;
336
337 let idx1 = (write_pos_at_i + buf_len - delay_int) % buf_len;
338 let idx2 = (idx1 + buf_len - 1) % buf_len;
339
340 dst[i] = buf[idx1] + delay_frac * (buf[idx2] - buf[idx1]);
341 }
342 }
343}
344
345pub fn vec_schroeder_allpass(
357 buf: &mut [f32],
358 pos: &mut usize,
359 dst: &mut [f32],
360 src: &[f32],
361 delay: usize,
362 g: f32,
363) {
364 let buf_len = buf.len();
365 let frames = dst.len().min(src.len());
366 if use_host_ops() {
367 let mut pos32 = *pos as u32;
368 unsafe {
369 sesh_vec_schroeder_allpass_host(
370 buf.as_mut_ptr(), buf_len as u32, &mut pos32,
371 dst.as_mut_ptr(), src.as_ptr(),
372 delay as u32, g, frames as u32,
373 );
374 }
375 *pos = pos32 as usize;
376 } else {
377 let mut wp = *pos;
378 for i in 0..frames {
379 let read_idx = (wp + buf_len - delay) % buf_len;
380 let buf_out = buf[read_idx];
381
382 let v = src[i] + g * buf_out;
383 dst[i] = buf_out - g * v;
384
385 buf[wp] = v;
386 wp = (wp + 1) % buf_len;
387 }
388 *pos = wp;
389 }
390}
391
392pub fn vec_osc(
398 phase: &mut f32,
399 dst: &mut [f32],
400 freq: f32,
401 waveform: Waveform,
402 sample_rate: f32,
403) {
404 let frames = dst.len();
405 if use_host_ops() {
406 unsafe {
407 sesh_vec_osc_host(
408 phase as *mut f32, dst.as_mut_ptr(),
409 freq, waveform as u32, sample_rate, frames as u32,
410 );
411 }
412 } else {
413 let phase_inc = freq / sample_rate;
414 for i in 0..frames {
415 dst[i] = match waveform {
416 Waveform::Sine => (*phase * std::f32::consts::TAU).sin(),
417 Waveform::Triangle => 4.0 * (*phase - (*phase + 0.5).floor()).abs() - 1.0,
418 Waveform::Saw => 2.0 * (*phase - (*phase + 0.5).floor()),
419 Waveform::Square => if *phase % 1.0 < 0.5 { 1.0 } else { -1.0 },
420 };
421 *phase += phase_inc;
422 if *phase >= 1.0 {
423 *phase -= 1.0;
424 }
425 }
426 }
427}
428
429pub fn vec_biquad(
438 state: &mut BiquadState,
439 dst: &mut [f32],
440 src: &[f32],
441 cutoff: &[f32],
442 q: &[f32],
443 gain: &[f32],
444 filter_type: FilterType,
445 sample_rate: f32,
446) {
447 let frames = dst.len().min(src.len()).min(cutoff.len()).min(q.len()).min(gain.len());
448 if use_host_ops() {
449 unsafe {
450 sesh_vec_biquad_host(
451 state as *mut BiquadState as *mut f32,
452 dst.as_mut_ptr(), src.as_ptr(),
453 cutoff.as_ptr(), q.as_ptr(), gain.as_ptr(),
454 filter_type as u32, sample_rate, frames as u32,
455 );
456 }
457 } else {
458 for i in 0..frames {
459 let w0 = std::f32::consts::TAU * cutoff[i] / sample_rate;
460 let cos_w0 = w0.cos();
461 let sin_w0 = w0.sin();
462 let alpha = sin_w0 / (2.0 * q[i]);
463 let a_db = gain[i];
464 let a_lin = 10.0f32.powf(a_db / 40.0);
465
466 let (b0, b1, b2, a0, a1, a2) = match filter_type {
467 FilterType::Lowpass => {
468 let b1 = 1.0 - cos_w0;
469 let b0 = b1 / 2.0;
470 (b0, b1, b0, 1.0 + alpha, -2.0 * cos_w0, 1.0 - alpha)
471 }
472 FilterType::Highpass => {
473 let b1 = -(1.0 + cos_w0);
474 let b0 = (1.0 + cos_w0) / 2.0;
475 (b0, b1, b0, 1.0 + alpha, -2.0 * cos_w0, 1.0 - alpha)
476 }
477 FilterType::Bandpass => {
478 (alpha, 0.0, -alpha, 1.0 + alpha, -2.0 * cos_w0, 1.0 - alpha)
479 }
480 FilterType::Notch => {
481 (1.0, -2.0 * cos_w0, 1.0, 1.0 + alpha, -2.0 * cos_w0, 1.0 - alpha)
482 }
483 FilterType::Peak => {
484 (
485 1.0 + alpha * a_lin,
486 -2.0 * cos_w0,
487 1.0 - alpha * a_lin,
488 1.0 + alpha / a_lin,
489 -2.0 * cos_w0,
490 1.0 - alpha / a_lin,
491 )
492 }
493 FilterType::LowShelf => {
494 let two_sqrt_a_alpha = 2.0 * a_lin.sqrt() * alpha;
495 (
496 a_lin * ((a_lin + 1.0) - (a_lin - 1.0) * cos_w0 + two_sqrt_a_alpha),
497 2.0 * a_lin * ((a_lin - 1.0) - (a_lin + 1.0) * cos_w0),
498 a_lin * ((a_lin + 1.0) - (a_lin - 1.0) * cos_w0 - two_sqrt_a_alpha),
499 (a_lin + 1.0) + (a_lin - 1.0) * cos_w0 + two_sqrt_a_alpha,
500 -2.0 * ((a_lin - 1.0) + (a_lin + 1.0) * cos_w0),
501 (a_lin + 1.0) + (a_lin - 1.0) * cos_w0 - two_sqrt_a_alpha,
502 )
503 }
504 FilterType::HighShelf => {
505 let two_sqrt_a_alpha = 2.0 * a_lin.sqrt() * alpha;
506 (
507 a_lin * ((a_lin + 1.0) + (a_lin - 1.0) * cos_w0 + two_sqrt_a_alpha),
508 -2.0 * a_lin * ((a_lin - 1.0) + (a_lin + 1.0) * cos_w0),
509 a_lin * ((a_lin + 1.0) + (a_lin - 1.0) * cos_w0 - two_sqrt_a_alpha),
510 (a_lin + 1.0) - (a_lin - 1.0) * cos_w0 + two_sqrt_a_alpha,
511 2.0 * ((a_lin - 1.0) - (a_lin + 1.0) * cos_w0),
512 (a_lin + 1.0) - (a_lin - 1.0) * cos_w0 - two_sqrt_a_alpha,
513 )
514 }
515 FilterType::Allpass => {
516 (1.0 - alpha, -2.0 * cos_w0, 1.0 + alpha, 1.0 + alpha, -2.0 * cos_w0, 1.0 - alpha)
517 }
518 };
519
520 let b0 = b0 / a0;
522 let b1 = b1 / a0;
523 let b2 = b2 / a0;
524 let a1 = a1 / a0;
525 let a2 = a2 / a0;
526
527 let x0 = src[i];
528 let y0 = b0 * x0 + b1 * state.x1 + b2 * state.x2
529 - a1 * state.y1 - a2 * state.y2;
530
531 state.x2 = state.x1;
532 state.x1 = x0;
533 state.y2 = state.y1;
534 state.y1 = y0;
535
536 dst[i] = y0;
537 }
538 }
539}
540
541pub fn vec_envelope(
550 state: &mut EnvelopeState,
551 dst: &mut [f32],
552 src: &[f32],
553 attack: &[f32],
554 release: &[f32],
555 mode: EnvelopeMode,
556 sample_rate: f32,
557) {
558 let frames = dst.len().min(src.len()).min(attack.len()).min(release.len());
559 if use_host_ops() {
560 unsafe {
561 sesh_vec_envelope_host(
562 state as *mut EnvelopeState as *mut f32,
563 dst.as_mut_ptr(), src.as_ptr(),
564 attack.as_ptr(), release.as_ptr(),
565 mode as u32, sample_rate, frames as u32,
566 );
567 }
568 } else {
569 for i in 0..frames {
570 let input_level = match mode {
571 EnvelopeMode::Peak => src[i].abs(),
572 EnvelopeMode::Rms => src[i] * src[i],
573 };
574
575 let att_coeff = (-1.0 / (attack[i] * sample_rate)).exp();
576 let rel_coeff = (-1.0 / (release[i] * sample_rate)).exp();
577
578 let coeff = if input_level > state.current { att_coeff } else { rel_coeff };
579 state.current = coeff * state.current + (1.0 - coeff) * input_level;
580
581 dst[i] = match mode {
582 EnvelopeMode::Peak => state.current,
583 EnvelopeMode::Rms => state.current.sqrt(),
584 };
585 }
586 }
587}
588
589pub fn vec_tanh(dst: &mut [f32], src: &[f32], drive: &[f32]) {
595 let len = dst.len().min(src.len()).min(drive.len());
596 if use_host_ops() {
597 unsafe { sesh_vec_tanh_host(dst.as_mut_ptr(), src.as_ptr(), drive.as_ptr(), len as u32) }
598 } else {
599 for i in 0..len {
600 dst[i] = (src[i] * drive[i]).tanh();
601 }
602 }
603}
604
605pub fn vec_hard_clip(dst: &mut [f32], src: &[f32], threshold: &[f32]) {
607 let len = dst.len().min(src.len()).min(threshold.len());
608 if use_host_ops() {
609 unsafe {
610 sesh_vec_hard_clip_host(dst.as_mut_ptr(), src.as_ptr(), threshold.as_ptr(), len as u32)
611 }
612 } else {
613 for i in 0..len {
614 dst[i] = src[i].clamp(-threshold[i], threshold[i]);
615 }
616 }
617}
618
619pub fn vec_abs(dst: &mut [f32], src: &[f32]) {
625 let len = dst.len().min(src.len());
626 if use_host_ops() {
627 unsafe { sesh_vec_abs_host(dst.as_mut_ptr(), src.as_ptr(), len as u32) }
628 } else {
629 for i in 0..len {
630 dst[i] = src[i].abs();
631 }
632 }
633}
634
635pub fn vec_neg(dst: &mut [f32], src: &[f32]) {
637 let len = dst.len().min(src.len());
638 if use_host_ops() {
639 unsafe { sesh_vec_neg_host(dst.as_mut_ptr(), src.as_ptr(), len as u32) }
640 } else {
641 for i in 0..len {
642 dst[i] = -src[i];
643 }
644 }
645}
646
647pub fn vec_sqrt(dst: &mut [f32], src: &[f32]) {
649 let len = dst.len().min(src.len());
650 if use_host_ops() {
651 unsafe { sesh_vec_sqrt_host(dst.as_mut_ptr(), src.as_ptr(), len as u32) }
652 } else {
653 for i in 0..len {
654 dst[i] = src[i].sqrt();
655 }
656 }
657}
658
659pub fn vec_recip(dst: &mut [f32], src: &[f32]) {
661 let len = dst.len().min(src.len());
662 if use_host_ops() {
663 unsafe { sesh_vec_recip_host(dst.as_mut_ptr(), src.as_ptr(), len as u32) }
664 } else {
665 for i in 0..len {
666 dst[i] = 1.0 / src[i];
667 }
668 }
669}
670
671pub fn vec_div(dst: &mut [f32], a: &[f32], b: &[f32]) {
673 let len = dst.len().min(a.len()).min(b.len());
674 if use_host_ops() {
675 unsafe { sesh_vec_div_host(dst.as_mut_ptr(), a.as_ptr(), b.as_ptr(), len as u32) }
676 } else {
677 for i in 0..len {
678 dst[i] = a[i] / b[i];
679 }
680 }
681}
682
683pub fn vec_pow(dst: &mut [f32], src: &[f32], exp: &[f32]) {
685 let len = dst.len().min(src.len()).min(exp.len());
686 if use_host_ops() {
687 unsafe { sesh_vec_pow_host(dst.as_mut_ptr(), src.as_ptr(), exp.as_ptr(), len as u32) }
688 } else {
689 for i in 0..len {
690 dst[i] = src[i].powf(exp[i]);
691 }
692 }
693}
694
695pub fn vec_add_assign(dst: &mut [f32], src: &[f32]) {
705 let len = dst.len().min(src.len());
706 if use_host_ops() {
707 unsafe { sesh_vec_add_host(dst.as_mut_ptr(), dst.as_ptr(), src.as_ptr(), len as u32) }
708 } else {
709 for i in 0..len {
710 dst[i] += src[i];
711 }
712 }
713}
714
715pub fn vec_mul_assign(dst: &mut [f32], src: &[f32]) {
717 let len = dst.len().min(src.len());
718 if use_host_ops() {
719 unsafe { sesh_vec_mul_host(dst.as_mut_ptr(), dst.as_ptr(), src.as_ptr(), len as u32) }
720 } else {
721 for i in 0..len {
722 dst[i] *= src[i];
723 }
724 }
725}
726
727pub fn vec_tanh_assign(dst: &mut [f32], drive: &[f32]) {
729 let len = dst.len().min(drive.len());
730 if use_host_ops() {
731 unsafe { sesh_vec_tanh_host(dst.as_mut_ptr(), dst.as_ptr(), drive.as_ptr(), len as u32) }
732 } else {
733 for i in 0..len {
734 dst[i] = (dst[i] * drive[i]).tanh();
735 }
736 }
737}
738
739pub fn vec_hard_clip_assign(dst: &mut [f32], threshold: &[f32]) {
741 let len = dst.len().min(threshold.len());
742 if use_host_ops() {
743 unsafe { sesh_vec_hard_clip_host(dst.as_mut_ptr(), dst.as_ptr(), threshold.as_ptr(), len as u32) }
744 } else {
745 for i in 0..len {
746 dst[i] = dst[i].clamp(-threshold[i], threshold[i]);
747 }
748 }
749}
750
751pub fn vec_abs_assign(dst: &mut [f32]) {
753 let len = dst.len();
754 if use_host_ops() {
755 unsafe { sesh_vec_abs_host(dst.as_mut_ptr(), dst.as_ptr(), len as u32) }
756 } else {
757 for i in 0..len {
758 dst[i] = dst[i].abs();
759 }
760 }
761}
762
763pub fn vec_neg_assign(dst: &mut [f32]) {
765 let len = dst.len();
766 if use_host_ops() {
767 unsafe { sesh_vec_neg_host(dst.as_mut_ptr(), dst.as_ptr(), len as u32) }
768 } else {
769 for i in 0..len {
770 dst[i] = -dst[i];
771 }
772 }
773}
774
775pub fn vec_sqrt_assign(dst: &mut [f32]) {
777 let len = dst.len();
778 if use_host_ops() {
779 unsafe { sesh_vec_sqrt_host(dst.as_mut_ptr(), dst.as_ptr(), len as u32) }
780 } else {
781 for i in 0..len {
782 dst[i] = dst[i].sqrt();
783 }
784 }
785}
786
787pub fn vec_recip_assign(dst: &mut [f32]) {
789 let len = dst.len();
790 if use_host_ops() {
791 unsafe { sesh_vec_recip_host(dst.as_mut_ptr(), dst.as_ptr(), len as u32) }
792 } else {
793 for i in 0..len {
794 dst[i] = 1.0 / dst[i];
795 }
796 }
797}
798
799pub fn vec_div_assign(dst: &mut [f32], src: &[f32]) {
801 let len = dst.len().min(src.len());
802 if use_host_ops() {
803 unsafe { sesh_vec_div_host(dst.as_mut_ptr(), dst.as_ptr(), src.as_ptr(), len as u32) }
804 } else {
805 for i in 0..len {
806 dst[i] /= src[i];
807 }
808 }
809}
810
811pub fn vec_pow_assign(dst: &mut [f32], exp: &[f32]) {
813 let len = dst.len().min(exp.len());
814 if use_host_ops() {
815 unsafe { sesh_vec_pow_host(dst.as_mut_ptr(), dst.as_ptr(), exp.as_ptr(), len as u32) }
816 } else {
817 for i in 0..len {
818 dst[i] = dst[i].powf(exp[i]);
819 }
820 }
821}