dspk_ops/resampler/kernels/
poly.rs1use cubecl::prelude::*;
2use dspk_core::compute::{channel_position, element_position, sample_position};
3
4use crate::core::kernels::store_lanes;
5use crate::core::read_extended;
6use crate::core::edge::EDGE_ZEROS;
7
8#[cube(launch)]
10pub fn downsample_kernel<F: Float>(
11 input: &[F],
12 output: &mut [F],
13 num_channels: u32,
14 in_len: u32,
15 out_len: u32,
16 step: u32,
17 phase: u32,
18) {
19 let m = sample_position();
20 let ch = channel_position();
21 if m < out_len && ch < num_channels {
22 output[(ch * out_len + m) as usize] = input[(ch * in_len + phase + m * step) as usize];
23 }
24}
25
26#[cube(launch)]
32#[allow(clippy::too_many_arguments)]
33pub fn upfirdn_kernel<F: Float>(
34 input: &[F],
35 taps: &[F],
36 output: &mut [F],
37 num_channels: u32,
38 in_len: u32,
39 out_len: u32,
40 num_taps: u32,
41 up: u32,
42 down: u32,
43 start: i32,
44 ext_pad: u32,
45 #[comptime] edge: u32,
46) {
47 let m = sample_position();
48 let ch = channel_position();
49 if m < out_len && ch < num_channels {
50 let base = (ch * in_len) as usize;
51 let up_i = i32::cast_from(up);
52 let i0 = i32::cast_from(m) * i32::cast_from(down) + start;
53 let phase = ((i0 % up_i) + up_i) % up_i;
54 let n_taps = i32::cast_from(num_taps);
55 let len = i32::cast_from(in_len);
56 let mut acc = F::new(0.0f32);
57 let s0 = (i0 - phase) / up_i;
60 let visits = if phase < n_taps { (n_taps - phase + up_i - 1) / up_i } else { 0i32 };
61 let mut j = phase;
62 let mut s = s0;
63 if s0 < len && s0 - visits + 1 >= 0i32 {
64 let mut k = 0i32;
66 while k < visits {
67 acc += taps[u32::cast_from(j) as usize] * input[base + u32::cast_from(s) as usize];
68 j += up_i;
69 s -= 1i32;
70 k += 1i32;
71 }
72 } else {
73 while j < n_taps {
74 if s >= 0i32 && s < len {
75 acc += taps[u32::cast_from(j) as usize] * input[base + u32::cast_from(s) as usize];
76 } else if comptime!(edge != EDGE_ZEROS) {
77 let ext = u32::cast_from(s + i32::cast_from(ext_pad));
78 acc += taps[u32::cast_from(j) as usize] * read_extended::<F>(input, base, in_len, ext_pad, ext, edge);
79 }
80 j += up_i;
81 s -= 1i32;
82 }
83 }
84 output[(ch * out_len + m) as usize] = acc;
85 }
86}
87
88#[cube]
90fn floor_div(a: i32, b: i32) -> i32 {
91 let q = a / b;
92 if a % b != 0i32 && a < 0i32 { q - 1i32 } else { q }
93}
94
95#[cube]
102#[allow(clippy::too_many_arguments)]
103fn upfirdn_vector_at<F: Float, N: Size>(
104 input: &[F],
105 table: &[Vector<F, N>],
106 base: usize,
107 m: u32,
108 in_len: u32,
109 num_taps: u32,
110 up: u32,
111 down: u32,
112 start: i32,
113 ext_pad: u32,
114 #[comptime] edge: u32,
115) -> Vector<F, N> {
116 let n = N::value() as u32;
117 let up_i = i32::cast_from(up);
118 let down_i = i32::cast_from(down);
119 let len = i32::cast_from(in_len);
120 let i0 = i32::cast_from(m) * down_i + start;
121 let reach = i32::cast_from(n - 1u32) * down_i;
122 let s_hi = floor_div(i0 + reach, up_i);
124 let s_lo = 0i32 - floor_div(i32::cast_from(num_taps) - 1i32 - i0, up_i);
125 let mut acc = Vector::<F, N>::new(F::new(0.0f32));
126 let mut s = s_hi;
127 if s_lo >= 0i32 && s_hi < len {
128 while s >= s_lo {
129 let d = i0 - s * up_i + reach;
130 acc += table[u32::cast_from(d) as usize] * Vector::new(input[base + u32::cast_from(s) as usize]);
131 s -= 1i32;
132 }
133 } else {
134 while s >= s_lo {
135 let d = i0 - s * up_i + reach;
136 if s >= 0i32 && s < len {
137 acc += table[u32::cast_from(d) as usize] * Vector::new(input[base + u32::cast_from(s) as usize]);
138 } else if comptime!(edge != EDGE_ZEROS) {
139 let ext = u32::cast_from(s + i32::cast_from(ext_pad));
140 acc += table[u32::cast_from(d) as usize] * Vector::new(read_extended::<F>(input, base, in_len, ext_pad, ext, edge));
141 }
142 s -= 1i32;
143 }
144 }
145 acc
146}
147
148#[cube(launch)]
151#[allow(clippy::too_many_arguments)]
152pub fn upfirdn_vector_kernel<F: Float, N: Size>(
153 input: &[F],
154 table: &[Vector<F, N>],
155 output: &mut [Vector<F, N>],
156 in_len: u32,
157 out_len: u32,
158 num_taps: u32,
159 up: u32,
160 down: u32,
161 start: i32,
162 ext_pad: u32,
163 #[comptime] edge: u32,
164) {
165 let v = element_position();
166 if v < output.len() {
167 let n = N::value() as u32;
168 let per_row = out_len / n;
169 let m = (v as u32 % per_row) * n;
170 let base = ((v as u32 / per_row) * in_len) as usize;
171 output[v] = upfirdn_vector_at::<F, N>(input, table, base, m, in_len, num_taps, up, down, start, ext_pad, edge);
172 }
173}
174
175#[cube(launch)]
178#[allow(clippy::too_many_arguments)]
179pub fn upfirdn_vector_unaligned_kernel<F: Float, N: Size>(
180 input: &[F],
181 table: &[Vector<F, N>],
182 output: &mut [F],
183 in_len: u32,
184 out_len: u32,
185 num_taps: u32,
186 up: u32,
187 down: u32,
188 start: i32,
189 ext_pad: u32,
190 units_per_row: u32,
191 num_units: u32,
192 #[comptime] edge: u32,
193) {
194 let v = element_position() as u32;
195 if v < num_units {
196 let n = N::value() as u32;
197 let row = v / units_per_row;
198 let m = (v % units_per_row) * n;
199 let acc = upfirdn_vector_at::<F, N>(input, table, (row * in_len) as usize, m, in_len, num_taps, up, down, start, ext_pad, edge);
200 store_lanes::<F, N>(output, (row * out_len + m) as usize, acc, u32::min(n, out_len - m));
201 }
202}