use super::common::WAVENET_MAX_NUM_FRAMES;
use super::layer_array_dyn::WaveNetLayerArrayDyn;
use super::post_stack_head::PostStackHead;
use crate::math::common::{AlignedVec, SimdMath};
use crate::models::{NamModel, StaticModel};
pub struct WaveNetModelDyn {
pub ch: usize,
pub k: usize,
pub head: usize,
pub arrays: Vec<WaveNetLayerArrayDyn>,
pub head_scale: f32,
pub receptive_field_size: usize,
pub condition_dsp: Option<Box<StaticModel>>,
pub condition_dsp_output: AlignedVec<f32>,
pub post_stack_head: Option<PostStackHead>,
pub head_output_scratch: AlignedVec<f32>,
pub prewarm_on_reset: bool,
}
impl Clone for WaveNetModelDyn {
fn clone(&self) -> Self {
let condition_dsp = crate::models::clone_condition_dsp(&self.condition_dsp);
Self {
ch: self.ch,
k: self.k,
head: self.head,
arrays: self.arrays.clone(),
head_scale: self.head_scale,
receptive_field_size: self.receptive_field_size,
condition_dsp,
condition_dsp_output: self.condition_dsp_output.clone(),
post_stack_head: self.post_stack_head.clone(),
head_output_scratch: self.head_output_scratch.clone(),
prewarm_on_reset: self.prewarm_on_reset,
}
}
}
impl WaveNetModelDyn {
#[inline(always)]
pub fn set_effective_layers(&mut self, n: usize) {
for array in &mut self.arrays {
array.set_effective_layers(n);
}
}
#[inline(always)]
pub fn backup_buffer_starts(&self, starts: &mut [usize], offset: &mut usize) {
for array in &self.arrays {
for state in &array.states {
if *offset < starts.len() {
starts[*offset] = state.buffer_start;
*offset += 1;
}
}
}
}
#[inline(always)]
pub fn restore_buffer_starts(&mut self, starts: &[usize], offset: &mut usize) {
for array in &mut self.arrays {
for state in &mut array.states {
if *offset < starts.len() {
state.buffer_start = starts[*offset];
*offset += 1;
}
}
}
}
pub fn slice_channels(&self, new_ch: usize) -> std::io::Result<Self> {
crate::models::slimmable::slice_wavenet_model(self, new_ch)
}
pub fn process(&mut self, input: &[f32], output: &mut [f32]) {
unsafe { crate::math::common::dispatch_simd!(self, process_internal, input, output) };
}
#[inline(always)]
unsafe fn process_internal<M: SimdMath>(&mut self, input: &[f32], output: &mut [f32]) {
let total_frames = input.len();
if total_frames == 0 {
return;
}
let cond = self.arrays[0].cond;
let mut pos = 0;
while pos < total_frames {
let num_frames = (total_frames - pos).min(WAVENET_MAX_NUM_FRAMES);
let in_slice = &input[pos..pos + num_frames];
let condition_slice: &[f32] = if let Some(ref mut cond_dsp) = self.condition_dsp {
let cond_out = &mut self.condition_dsp_output[0..num_frames * cond];
cond_dsp.process(in_slice, cond_out);
let dsp_ch = cond_dsp.num_output_channels();
if dsp_ch > 0 && dsp_ch < cond {
for f in (0..num_frames).rev() {
let val = cond_out[f];
for c in 1..cond {
cond_out[f * cond + c] = val;
}
}
}
cond_out
} else {
in_slice
};
unsafe {
let num_arrays = self.arrays.len();
let arrays_ptr = self.arrays.as_mut_ptr();
(*arrays_ptr).process_block_internal::<M, false>(
in_slice,
condition_slice,
num_frames,
None,
);
for i in 1..num_arrays {
let prev = &*arrays_ptr.add(i - 1);
let curr = &mut *arrays_ptr.add(i);
let prev_head_out = &prev.head_outputs[0..num_frames * prev.head];
let prev_outputs = &prev.array_outputs[0..num_frames * prev.ch];
curr.process_block_internal::<M, false>(
prev_outputs,
condition_slice,
num_frames,
Some(prev_head_out),
);
}
}
let last = &self.arrays[self.arrays.len() - 1];
let head_dim = last.head;
let last_head = &last.head_outputs[0..num_frames * head_dim];
if let Some(ref mut head_proc) = self.post_stack_head {
let out_ch = head_proc.out_channels();
let scratch = &mut self.head_output_scratch[0..num_frames * out_ch];
unsafe {
head_proc.process_block(last_head, scratch, num_frames);
}
let out_start = pos * out_ch;
let out_slice = &mut output[out_start..out_start + num_frames * out_ch];
unsafe {
core::ptr::copy_nonoverlapping(
scratch.as_ptr(),
out_slice.as_mut_ptr(),
num_frames * out_ch,
);
}
unsafe {
M::apply_gain(out_slice, self.head_scale);
}
} else {
let out_start = pos * head_dim;
let out_slice = &mut output[out_start..out_start + num_frames * head_dim];
unsafe {
core::ptr::copy_nonoverlapping(
last_head.as_ptr(),
out_slice.as_mut_ptr(),
num_frames * head_dim,
);
}
unsafe {
M::apply_gain(out_slice, self.head_scale);
}
}
pos += num_frames;
}
}
#[cold]
pub fn prewarm(&mut self) {
unsafe {
crate::math::common::dispatch_simd!(self, prewarm_internal);
}
}
#[target_feature(enable = "avx512f,avx512vl")]
#[cold]
pub unsafe fn prewarm_avx512(&mut self) {
unsafe { self.prewarm_internal::<crate::math::common::Avx512Math>() };
}
#[cold]
pub unsafe fn prewarm_avx2(&mut self) {
unsafe { self.prewarm_internal::<crate::math::common::Avx2Math>() };
}
#[inline(always)]
#[cold]
unsafe fn prewarm_internal<M: SimdMath>(&mut self) {
if let Some(ref mut cond_dsp) = self.condition_dsp {
cond_dsp.prewarm(cond_dsp.prewarm_samples());
}
let zero_input = [0.0f32];
let cond = self.arrays[0].cond;
let condition: &[f32] = if let Some(ref mut cond_dsp) = self.condition_dsp {
cond_dsp.process(&zero_input, &mut self.condition_dsp_output[0..cond]);
let dsp_ch = cond_dsp.num_output_channels();
if dsp_ch > 0 && dsp_ch < cond {
let val = self.condition_dsp_output[0];
for c in 1..cond {
self.condition_dsp_output[c] = val;
}
}
&self.condition_dsp_output[0..cond]
} else {
&zero_input
};
unsafe {
let num_arrays = self.arrays.len();
let arrays_ptr = self.arrays.as_mut_ptr();
(*arrays_ptr).prewarm_internal::<M>(&zero_input, condition, None);
for i in 1..num_arrays {
let prev = &*arrays_ptr.add(i - 1);
let curr = &mut *arrays_ptr.add(i);
let prev_outputs = &prev.array_outputs[0..prev.ch];
let prev_head_out = &prev.head_outputs[0..prev.head];
curr.prewarm_internal::<M>(prev_outputs, condition, Some(prev_head_out));
}
}
if let Some(ref mut head_proc) = self.post_stack_head {
head_proc.prewarm();
}
}
}