use super::spherical_harmonics::*;
use crate::building_blocks::{
Modulator, Panner, SampleBuffer, SynthParameterLabel, SynthParameterValue,
};
pub struct Encoder<const BUFSIZE: usize, const NCHAN: usize> {
pub order: usize,
azimuth: f32,
elevation: f32,
azimuth_mod: Option<Modulator<BUFSIZE>>,
elevation_mod: Option<Modulator<BUFSIZE>>,
coefs: [[f32; BUFSIZE]; NCHAN],
}
impl<const BUFSIZE: usize, const NCHAN: usize> Default for Encoder<BUFSIZE, NCHAN> {
fn default() -> Self {
Self::new()
}
}
impl<const BUFSIZE: usize, const NCHAN: usize> Encoder<BUFSIZE, NCHAN> {
pub fn new() -> Self {
Encoder {
order: NCHAN.isqrt() - 1,
azimuth: 0.0,
elevation: 0.0,
azimuth_mod: None,
elevation_mod: None,
coefs: [[0.0; BUFSIZE]; NCHAN],
}
}
}
impl<const BUFSIZE: usize, const NCHAN: usize> Panner<BUFSIZE, NCHAN> for Encoder<BUFSIZE, NCHAN> {
fn set_modulator(
&mut self,
par: SynthParameterLabel,
init: f32,
modulator: Modulator<BUFSIZE>,
) {
match par {
SynthParameterLabel::AmbisonicAzimuth => {
self.azimuth = init; self.azimuth_mod = Some(modulator);
}
SynthParameterLabel::AmbisonicElevation => {
self.elevation = init; self.elevation_mod = Some(modulator);
}
_ => {}
}
}
fn set_parameter(&mut self, par: SynthParameterLabel, value: &SynthParameterValue) {
if let SynthParameterValue::ScalarF32(val) = value {
match par {
SynthParameterLabel::AmbisonicAzimuth => self.azimuth = *val,
SynthParameterLabel::AmbisonicElevation => {
self.elevation = *val;
}
_ => {}
};
let sin_a = self.azimuth.sin();
let cos_a = self.azimuth.cos();
let sin_e = self.elevation.sin();
let cos_e = self.elevation.cos();
self.coefs[0] = [1.0; BUFSIZE];
self.coefs[1] = [SH_ACN_1 * sin_a * cos_e; BUFSIZE];
self.coefs[2] = [SH_ACN_2 * sin_e; BUFSIZE];
self.coefs[3] = [SH_ACN_3 * cos_a * cos_e; BUFSIZE];
if self.order >= 2 {
let sin_a2 = (self.azimuth * 2.0).sin();
let cos_a2 = (self.azimuth * 2.0).cos();
let sin_e2 = (self.elevation * 2.0).sin();
let sin2_e = sin_e * sin_e;
let cos2_e = cos_e * cos_e;
self.coefs[4] = [SH_ACN_4 * sin_a2 * cos2_e; BUFSIZE];
self.coefs[5] = [SH_ACN_5 * sin_a * sin_e2; BUFSIZE];
self.coefs[6] = [SH_ACN_6 * (3.0 * sin2_e - 1.0); BUFSIZE];
self.coefs[7] = [SH_ACN_7 * cos_a * sin_e2; BUFSIZE];
self.coefs[8] = [SH_ACN_8 * cos_a2 * cos2_e; BUFSIZE];
if self.order >= 3 {
let sin_a3 = (self.azimuth * 3.0).sin();
let cos3_e = cos2_e * cos_e;
let cos_a3 = (self.azimuth * 3.0).cos();
self.coefs[9] = [SH_ACN_9 * sin_a3 * cos3_e; BUFSIZE];
self.coefs[10] = [SH_ACN_10 * sin_a2 * sin_e * cos2_e; BUFSIZE];
self.coefs[11] = [SH_ACN_11 * sin_a * cos_e * (5.0 * sin2_e - 1.0); BUFSIZE];
self.coefs[12] = [SH_ACN_12 * sin_e * (5.0 * sin2_e - 3.0); BUFSIZE];
self.coefs[13] = [SH_ACN_13 * cos_a * cos_e * (5.0 * sin2_e - 1.0); BUFSIZE];
self.coefs[14] = [SH_ACN_14 * cos_a2 * sin_e * cos2_e; BUFSIZE];
self.coefs[15] = [SH_ACN_15 * cos_a3 * cos3_e; BUFSIZE];
if self.order >= 4 {
let sin_a4 = (self.azimuth * 4.0).sin();
let cos_a4 = (self.azimuth * 4.0).cos();
let cos4_e = cos3_e * cos_e;
let sin4_e = sin2_e * sin2_e;
self.coefs[16] = [SH_ACN_16 * sin_a4 * cos4_e; BUFSIZE];
self.coefs[17] = [SH_ACN_17 * sin_a3 * sin_e * cos3_e; BUFSIZE];
self.coefs[18] =
[SH_ACN_18 * sin_a2 * cos2_e * (7.0 * sin2_e - 1.0); BUFSIZE];
self.coefs[19] =
[SH_ACN_19 * sin_a * sin_e2 * (7.0 * sin2_e - 3.0); BUFSIZE];
self.coefs[20] =
[SH_ACN_20 * (35.0 * sin4_e - 30.0 * sin2_e + 3.0); BUFSIZE];
self.coefs[21] =
[SH_ACN_21 * cos_a * sin_e2 * (7.0 * sin2_e - 3.0); BUFSIZE];
self.coefs[22] =
[SH_ACN_22 * cos_a2 * cos2_e * (7.0 * sin2_e - 1.0); BUFSIZE];
self.coefs[23] = [SH_ACN_23 * cos_a3 * sin_e * cos3_e; BUFSIZE];
self.coefs[24] = [SH_ACN_24 * cos_a4 * cos4_e; BUFSIZE];
}
}
}
}
}
fn process_block(
&mut self,
input: [f32; BUFSIZE],
start_sample: usize,
in_buffers: &[SampleBuffer],
) -> [[f32; BUFSIZE]; NCHAN] {
let mut enc_block = [[0.0; BUFSIZE]; NCHAN];
if self.azimuth_mod.is_some() || self.elevation_mod.is_some() {
let azi_buf = if let Some(azi_mod) = self.azimuth_mod.as_mut() {
azi_mod.process(self.azimuth, start_sample, in_buffers)
} else {
[self.azimuth; BUFSIZE]
};
let ele_buf = if let Some(ele_mod) = self.elevation_mod.as_mut() {
ele_mod.process(self.elevation, start_sample, in_buffers)
} else {
[self.elevation; BUFSIZE]
};
self.coefs[0] = [1.0; BUFSIZE];
if self.order == 1 {
for s in 0..BUFSIZE {
let sin_a = azi_buf[s].sin();
let cos_a = azi_buf[s].cos();
let sin_e = ele_buf[s].sin();
let cos_e = ele_buf[s].cos();
self.coefs[1][s] = SH_ACN_1 * sin_a * cos_e;
self.coefs[2][s] = SH_ACN_2 * sin_e;
self.coefs[3][s] = SH_ACN_3 * cos_a * cos_e;
}
}
if self.order == 2 {
for s in 0..BUFSIZE {
let sin_a = azi_buf[s].sin();
let cos_a = azi_buf[s].cos();
let sin_e = ele_buf[s].sin();
let cos_e = ele_buf[s].cos();
let sin_a2 = (azi_buf[s] * 2.0).sin();
let cos_a2 = (azi_buf[s] * 2.0).cos();
let sin2_e = sin_e * sin_e;
let sin_e2 = (ele_buf[s] * 2.0).sin();
let cos2_e = cos_e * cos_e;
self.coefs[1][s] = SH_ACN_1 * sin_a * cos_e;
self.coefs[2][s] = SH_ACN_2 * sin_e;
self.coefs[3][s] = SH_ACN_3 * cos_a * cos_e;
self.coefs[4][s] = SH_ACN_4 * sin_a2 * cos2_e;
self.coefs[5][s] = SH_ACN_5 * sin_a * sin_e2;
self.coefs[6][s] = SH_ACN_6 * (3.0 * sin2_e - 1.0);
self.coefs[7][s] = SH_ACN_7 * cos_a * sin_e2;
self.coefs[8][s] = SH_ACN_8 * cos_a2 * cos2_e;
}
}
if self.order == 3 {
for s in 0..BUFSIZE {
let sin_a = azi_buf[s].sin();
let cos_a = azi_buf[s].cos();
let sin_e = ele_buf[s].sin();
let cos_e = ele_buf[s].cos();
let sin_a2 = (azi_buf[s] * 2.0).sin();
let cos_a2 = (azi_buf[s] * 2.0).cos();
let sin2_e = sin_e * sin_e;
let cos2_e = cos_e * cos_e;
let sin_a3 = (azi_buf[s] * 3.0).sin();
let cos3_e = cos2_e * cos_e;
let cos_a3 = (azi_buf[s] * 3.0).cos();
let sin_e2 = (ele_buf[s] * 2.0).sin();
self.coefs[1][s] = SH_ACN_1 * sin_a * cos_e;
self.coefs[2][s] = SH_ACN_2 * sin_e;
self.coefs[3][s] = SH_ACN_3 * cos_a * cos_e;
self.coefs[4][s] = SH_ACN_4 * sin_a2 * cos2_e;
self.coefs[5][s] = SH_ACN_5 * sin_a * sin_e2;
self.coefs[6][s] = SH_ACN_6 * (3.0 * sin2_e - 1.0);
self.coefs[7][s] = SH_ACN_7 * cos_a * sin_e2;
self.coefs[8][s] = SH_ACN_8 * cos_a2 * cos2_e;
self.coefs[9][s] = SH_ACN_9 * sin_a3 * cos3_e;
self.coefs[10][s] = SH_ACN_10 * sin_a2 * sin_e * cos2_e;
self.coefs[11][s] = SH_ACN_11 * sin_a * cos_e * (5.0 * sin2_e - 1.0);
self.coefs[12][s] = SH_ACN_12 * sin_e * (5.0 * sin2_e - 3.0);
self.coefs[13][s] = SH_ACN_13 * cos_a * cos_e * (5.0 * sin2_e - 1.0);
self.coefs[14][s] = SH_ACN_14 * cos_a2 * sin_e * cos2_e;
self.coefs[15][s] = SH_ACN_15 * cos_a3 * cos3_e;
}
}
if self.order == 4 {
for s in 0..BUFSIZE {
let sin_a = azi_buf[s].sin();
let cos_a = azi_buf[s].cos();
let sin_e = ele_buf[s].sin();
let cos_e = ele_buf[s].cos();
let sin_a2 = (azi_buf[s] * 2.0).sin();
let cos_a2 = (azi_buf[s] * 2.0).cos();
let sin2_e = sin_e * sin_e;
let cos2_e = cos_e * cos_e;
let sin_a3 = (azi_buf[s] * 3.0).sin();
let cos3_e = cos2_e * cos_e;
let cos_a3 = (azi_buf[s] * 3.0).cos();
let sin_e2 = (ele_buf[s] * 2.0).sin();
let sin_a4 = (azi_buf[s] * 4.0).sin();
let cos_a4 = (azi_buf[s] * 4.0).cos();
let cos4_e = cos3_e * cos_e;
let sin4_e = sin2_e * sin2_e;
self.coefs[1][s] = SH_ACN_1 * sin_a * cos_e;
self.coefs[2][s] = SH_ACN_2 * sin_e;
self.coefs[3][s] = SH_ACN_3 * cos_a * cos_e;
self.coefs[4][s] = SH_ACN_4 * sin_a2 * cos2_e;
self.coefs[5][s] = SH_ACN_5 * sin_a * sin_e2;
self.coefs[6][s] = SH_ACN_6 * (3.0 * sin2_e - 1.0);
self.coefs[7][s] = SH_ACN_7 * cos_a * sin_e2;
self.coefs[8][s] = SH_ACN_8 * cos_a2 * cos2_e;
self.coefs[9][s] = SH_ACN_9 * sin_a3 * cos3_e;
self.coefs[10][s] = SH_ACN_10 * sin_a2 * sin_e * cos2_e;
self.coefs[11][s] = SH_ACN_11 * sin_a * cos_e * (5.0 * sin2_e - 1.0);
self.coefs[12][s] = SH_ACN_12 * sin_e * (5.0 * sin2_e - 3.0);
self.coefs[13][s] = SH_ACN_13 * cos_a * cos_e * (5.0 * sin2_e - 1.0);
self.coefs[14][s] = SH_ACN_14 * cos_a2 * sin_e * cos2_e;
self.coefs[15][s] = SH_ACN_15 * cos_a3 * cos3_e;
self.coefs[16][s] = SH_ACN_16 * sin_a4 * cos4_e;
self.coefs[17][s] = SH_ACN_17 * sin_a3 * sin_e * cos3_e;
self.coefs[18][s] = SH_ACN_18 * sin_a2 * cos2_e * (7.0 * sin2_e - 1.0);
self.coefs[19][s] = SH_ACN_19 * sin_a * sin_e2 * (7.0 * sin2_e - 3.0);
self.coefs[20][s] = SH_ACN_20 * (35.0 * sin4_e - 30.0 * sin2_e + 3.0);
self.coefs[21][s] = SH_ACN_21 * cos_a * sin_e2 * (7.0 * sin2_e - 3.0);
self.coefs[22][s] = SH_ACN_22 * cos_a2 * cos2_e * (7.0 * sin2_e - 1.0);
self.coefs[23][s] = SH_ACN_23 * cos_a3 * sin_e * cos3_e;
self.coefs[24][s] = SH_ACN_24 * cos_a4 * cos4_e;
}
}
}
if self.order == 1 {
for (i, input_sample) in input.iter().enumerate().take(BUFSIZE) {
enc_block[0][i] = input_sample * self.coefs[0][i];
enc_block[1][i] = input_sample * self.coefs[1][i];
enc_block[2][i] = input_sample * self.coefs[2][i];
enc_block[3][i] = input_sample * self.coefs[3][i];
}
}
if self.order == 2 {
for (i, input_sample) in input.iter().enumerate().take(BUFSIZE) {
enc_block[0][i] = input_sample * self.coefs[0][i];
enc_block[1][i] = input_sample * self.coefs[1][i];
enc_block[2][i] = input_sample * self.coefs[2][i];
enc_block[3][i] = input_sample * self.coefs[3][i];
enc_block[4][i] = input_sample * self.coefs[4][i];
enc_block[5][i] = input_sample * self.coefs[5][i];
enc_block[6][i] = input_sample * self.coefs[6][i];
enc_block[7][i] = input_sample * self.coefs[7][i];
enc_block[8][i] = input_sample * self.coefs[8][i];
}
}
if self.order == 3 {
for (i, input_sample) in input.iter().enumerate().take(BUFSIZE) {
enc_block[0][i] = input_sample * self.coefs[0][i];
enc_block[1][i] = input_sample * self.coefs[1][i];
enc_block[2][i] = input_sample * self.coefs[2][i];
enc_block[3][i] = input_sample * self.coefs[3][i];
enc_block[4][i] = input_sample * self.coefs[4][i];
enc_block[5][i] = input_sample * self.coefs[5][i];
enc_block[6][i] = input_sample * self.coefs[6][i];
enc_block[7][i] = input_sample * self.coefs[7][i];
enc_block[8][i] = input_sample * self.coefs[8][i];
enc_block[9][i] = input_sample * self.coefs[9][i];
enc_block[10][i] = input_sample * self.coefs[10][i];
enc_block[11][i] = input_sample * self.coefs[11][i];
enc_block[12][i] = input_sample * self.coefs[12][i];
enc_block[13][i] = input_sample * self.coefs[13][i];
enc_block[14][i] = input_sample * self.coefs[14][i];
enc_block[15][i] = input_sample * self.coefs[15][i];
}
}
if self.order == 4 {
for (i, input_sample) in input.iter().enumerate().take(BUFSIZE) {
enc_block[0][i] = input_sample * self.coefs[0][i];
enc_block[1][i] = input_sample * self.coefs[1][i];
enc_block[2][i] = input_sample * self.coefs[2][i];
enc_block[3][i] = input_sample * self.coefs[3][i];
enc_block[4][i] = input_sample * self.coefs[4][i];
enc_block[5][i] = input_sample * self.coefs[5][i];
enc_block[6][i] = input_sample * self.coefs[6][i];
enc_block[7][i] = input_sample * self.coefs[7][i];
enc_block[8][i] = input_sample * self.coefs[8][i];
enc_block[9][i] = input_sample * self.coefs[9][i];
enc_block[10][i] = input_sample * self.coefs[10][i];
enc_block[11][i] = input_sample * self.coefs[11][i];
enc_block[12][i] = input_sample * self.coefs[12][i];
enc_block[13][i] = input_sample * self.coefs[13][i];
enc_block[14][i] = input_sample * self.coefs[14][i];
enc_block[15][i] = input_sample * self.coefs[15][i];
enc_block[16][i] = input_sample * self.coefs[16][i];
enc_block[17][i] = input_sample * self.coefs[17][i];
enc_block[18][i] = input_sample * self.coefs[18][i];
enc_block[19][i] = input_sample * self.coefs[19][i];
enc_block[20][i] = input_sample * self.coefs[20][i];
enc_block[21][i] = input_sample * self.coefs[21][i];
enc_block[22][i] = input_sample * self.coefs[22][i];
enc_block[23][i] = input_sample * self.coefs[23][i];
enc_block[24][i] = input_sample * self.coefs[24][i];
}
}
enc_block
}
}