use crate::math::common::{AlignedVec, SimdMath};
use super::WaveNetA2Dyn;
impl WaveNetA2Dyn {
#[inline(always)]
pub(crate) fn cascade_layer_loop<M: SimdMath>(
&mut self,
nf: usize,
input: &[f32],
pos: usize,
use_cond_dsp: bool,
cond_size: usize,
is_first_array: bool,
) {
let head_wp = self.advance_head_ring(nf);
for li in 0..self.num_layers {
self.layer_forward_dispatch::<M>(
li,
nf,
input,
pos,
head_wp,
use_cond_dsp,
cond_size,
is_first_array,
);
}
self.head_write_pos = (head_wp + nf) & self.head_ring_mask;
}
#[inline(always)]
pub(crate) fn cascade_head_finalize(&mut self, nf: usize, output: &mut [f32]) {
let head_size = self.head_size;
if head_size == 1 {
if let Some(ref head) = self.head_conv {
head.process(
&self.head_accum,
self.head_write_pos,
self.head_ring_mask,
nf,
output,
);
}
} else {
let channels = self.head_accum_size;
let k = crate::models::a2::params::A2_HEAD_KERNEL_SIZE;
let hw = &self.head_rechannel_w;
let hb = &self.head_rechannel_b;
let hs = &self.head_rechannel_scale;
let ha = &self.head_accum;
let wp = self.head_write_pos;
let mask = self.head_ring_mask;
let base = wp.wrapping_sub(nf);
for f in 0..nf {
let col_base = base.wrapping_add(f);
let out_off = f * head_size;
for oc in 0..head_size {
let w_base = oc * k * channels;
let mut y = hb[oc];
for t in 0..k {
let col = col_base.wrapping_sub(k - 1 - t) & mask;
let ha_off = col * channels;
let w_off = w_base + t * channels;
for ic in 0..channels {
y += hw[w_off + ic] * ha[ha_off + ic];
}
}
output[out_off + oc] = y * hs[oc];
}
}
}
}
#[inline(always)]
pub(crate) fn cascade_write_mono_input(&mut self, input: &[f32], pos: usize, nf: usize) {
let channels = self.channels;
for f in 0..nf {
let base = f * channels;
let x = input[pos + f];
for c in 0..channels {
self.layer_in[base + c] = self.rechannel_w_f32[c] * x;
}
}
}
#[inline(always)]
pub(crate) fn cascade_write_residual_input(
&mut self,
residual: &[f32],
nf: usize,
src_channels: usize,
) {
let channels = self.channels;
let in_ch = self.input_channels;
assert_eq!(in_ch, src_channels, "input_channels mismatch in cascade");
for f in 0..nf {
let base = f * channels;
let rbase = f * src_channels;
for c in 0..channels {
let mut sum = 0.0f32;
for ic in 0..src_channels {
sum += residual[rbase + ic] * self.rechannel_w_f32[ic * channels + c];
}
self.layer_in[base + c] = sum;
}
}
}
#[inline(always)]
pub(crate) fn cascade_set_condition(&mut self, cond_buf: &[f32], nf: usize, cond_size: usize) {
let dest = &mut self.condition_dsp_output;
if dest.len() < nf * cond_size {
*dest = AlignedVec::new(nf * cond_size, 0.0f32)
.expect("allocation should succeed for test-sized buffers");
}
dest[0..nf * cond_size].copy_from_slice(&cond_buf[0..nf * cond_size]);
}
#[inline(always)]
pub(crate) fn cascade_seed_head_from_output(
&mut self,
prev_head_output: &[f32],
nf: usize,
prev_head_size: usize,
) {
let copy_ch = prev_head_size.min(self.head_accum_size);
let curr_wp = self.head_write_pos;
let curr_head = &mut self.head_accum;
for f in 0..nf {
let prev_off = f * prev_head_size;
let curr_off = ((curr_wp + f) & self.head_ring_mask) * self.head_accum_size;
for c in 0..copy_ch {
curr_head[curr_off + c] = prev_head_output[prev_off + c];
}
for c in copy_ch..self.head_accum_size {
curr_head[curr_off + c] = 0.0;
}
}
}
}