Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleanup chorus code #24

Merged
merged 1 commit into from
Dec 28, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 83 additions & 89 deletions src/chorus/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,13 @@ const MIN_SPEED_HZ: f32 = 0.29;
*/
const MAX_SAMPLES_LN2: usize = 12;
const MAX_SAMPLES: usize = 1 << (MAX_SAMPLES_LN2 - 1);
// const MAX_SAMPLES_ANDMASK: usize = MAX_SAMPLES - 1;
const MAX_SAMPLES_ANDMASK: usize = MAX_SAMPLES - 1;

const INTERPOLATION_SUBSAMPLES_LN2: usize = 8;
const INTERPOLATION_SUBSAMPLES: usize = 1 << (INTERPOLATION_SUBSAMPLES_LN2 - 1);
const INTERPOLATION_SUBSAMPLES_ANDMASK: usize = INTERPOLATION_SUBSAMPLES - 1;

const INTERPOLATION_SAMPLES: usize = 5;

#[derive(Clone)]
pub struct Chorus {
Expand Down Expand Up @@ -60,24 +66,21 @@ impl Chorus {
sample_rate,
sinc_table: [[0f32; 128]; 5],
};
for i in 0..5 {
for ii in 0..((1 as i32) << 8 as i32 - 1 as i32) {
let i_shifted: f64 = i as f64 - 5 as i32 as f64 / 2.0f64
+ ii as f64 / ((1 as i32) << 8 as i32 - 1 as i32) as f64;
if f64::abs(i_shifted) < 0.000001f64 {
chorus.sinc_table[i as usize][ii as usize] = 1.0f32
for i in 0..INTERPOLATION_SAMPLES {
for ii in 0..INTERPOLATION_SUBSAMPLES {
// Move the origin into the center of the table
let i_shifted = i as f32 - INTERPOLATION_SAMPLES as f32 / 2.0
+ ii as f32 / INTERPOLATION_SUBSAMPLES as f32;

if i_shifted.abs() < 0.000001 {
// sinc(0) cannot be calculated straightforward (limit needed for 0/0)
chorus.sinc_table[i][ii] = 1.0;
} else {
chorus.sinc_table[i as usize][ii as usize] =
(f64::sin(i_shifted * std::f64::consts::PI) as f32 as f64
/ (std::f64::consts::PI * i_shifted)) as f32;
chorus.sinc_table[i as usize][ii as usize] =
(chorus.sinc_table[i as usize][ii as usize] as f64
* (0.5f64
* (1.0f64
+ f64::cos(
2.0f64 * std::f64::consts::PI * i_shifted
/ 5 as i32 as f32 as f64,
)))) as f32
chorus.sinc_table[i][ii] = (i_shifted * std::f32::consts::PI).sin()
/ (std::f32::consts::PI * i_shifted);
// Hamming window
chorus.sinc_table[i][ii] *=
0.5 * (1.0 + (2.0 * std::f32::consts::PI * i_shifted / 5.0).cos());
}
}
}
Expand All @@ -87,60 +90,54 @@ impl Chorus {
}

fn init(&mut self) {
// Init
{
for i in 0..((1 as i32) << 12 as i32 - 1 as i32) {
self.chorusbuf[i as usize] = 0.0f32;
}
self.set_chorus(&Default::default());
self.update();
}
self.chorusbuf.fill(0.0);
self.set_chorus(&Default::default());
self.update();
}

fn update(&mut self) {
let mut modulation_depth_samples: i32;
if self.new_number_blocks > 99 {
log::warn!(
"chorus: number blocks larger than max. allowed! Setting value to {}.",
99
);
self.new_number_blocks = 99;
}
if (self.new_speed_hz as f64) < 0.29f64 {
if self.new_speed_hz < 0.29 {
log::warn!(
"chorus: speed is too low (min {})! Setting value to min.",
0.29f64
0.29
);
self.new_speed_hz = 0.29f32
} else if self.new_speed_hz > 5 as i32 as f32 {
self.new_speed_hz = 0.29;
} else if self.new_speed_hz > 5.0 {
log::warn!(
"chorus: speed must be below {} Hz! Setting value to max.",
5
);
self.new_speed_hz = 5 as i32 as f32
self.new_speed_hz = 5.0;
}
if (self.new_depth_ms as f64) < 0.0f64 {
if self.new_depth_ms < 0.0 {
log::warn!("chorus: depth must be positive! Setting value to 0.",);
self.new_depth_ms = 0.0f32
self.new_depth_ms = 0.0;
}
if (self.new_level as f64) < 0.0f64 {
if self.new_level < 0.0 {
log::warn!("chorus: level must be positive! Setting value to 0.",);
self.new_level = 0.0f32
} else if self.new_level > 10 as i32 as f32 {
self.new_level = 0.0;
} else if self.new_level > 10.0 {
log::warn!(
"chorus: level must be < 10. A reasonable level is << 1! Setting it to 0.1.",
);
self.new_level = 0.1f32
self.new_level = 0.1;
}
self.modulation_period_samples = (self.sample_rate / self.new_speed_hz) as isize;
modulation_depth_samples =
(self.new_depth_ms as f64 / 1000.0f64 * self.sample_rate as f64) as i32;
if modulation_depth_samples > (1 as i32) << 12 as i32 - 1 as i32 {

let mut modulation_depth_samples = (self.new_depth_ms / 1000.0 * self.sample_rate) as i32;
if modulation_depth_samples > MAX_SAMPLES as i32 {
log::warn!(
"chorus: Too high depth. Setting it to max ({}).",
(1) << 12 - 1
MAX_SAMPLES,
);
modulation_depth_samples = (1 as i32) << 12 as i32 - 1 as i32
modulation_depth_samples = MAX_SAMPLES as i32;
}
if self.type_0 == ChorusMode::Sine {
modulate_sine(
Expand All @@ -165,9 +162,9 @@ impl Chorus {
}
for i in 0..(self.number_blocks as usize) {
self.phase[i] = (self.modulation_period_samples as f64 * i as f64
/ self.number_blocks as f64) as i32 as isize;
/ self.number_blocks as f64) as isize;
}
self.counter = 0 as i32;
self.counter = 0;
self.type_0 = self.new_type;
self.depth_ms = self.new_depth_ms;
self.level = self.new_level;
Expand All @@ -182,25 +179,31 @@ impl Chorus {
right_out: &mut [f32; 64],
) {
for sample_index in 0..64 {
let d_in = in_0[sample_index as usize];
let mut d_out = 0.0f32;
let d_in = in_0[sample_index];
let mut d_out = 0.0;
self.chorusbuf[self.counter as usize] = d_in;

for i in 0..(self.number_blocks as usize) {
let mut pos_subsamples: i32 = ((1 as i32) << 8 as i32 - 1 as i32) * self.counter
- self.lookup_tab[self.phase[i as usize] as usize];
let mut pos_samples: i32 = pos_subsamples / ((1 as i32) << 8 as i32 - 1 as i32);
pos_subsamples &= ((1 as i32) << 8 as i32 - 1 as i32) - 1 as i32;
// Calculate the delay in subsamples for the delay line of chorus block nr. */
//
// The value in the lookup table is so, that this expression
// will always be positive. It will always include a number of
// full periods of MAX_SAMPLES*INTERPOLATION_SUBSAMPLES to
// remain positive at all times. */
let mut pos_subsamples = INTERPOLATION_SUBSAMPLES as i32 * self.counter
- self.lookup_tab[self.phase[i] as usize];

let mut pos_samples = pos_subsamples / INTERPOLATION_SUBSAMPLES as i32;
pos_subsamples &= INTERPOLATION_SUBSAMPLES_ANDMASK as i32;

for ii in 0..5 {
d_out += self.chorusbuf
[(pos_samples & ((1 as i32) << 12 as i32 - 1 as i32) - 1 as i32) as usize]
d_out += self.chorusbuf[(pos_samples & MAX_SAMPLES_ANDMASK as i32) as usize]
* self.sinc_table[ii as usize][pos_subsamples as usize];
pos_samples -= 1;
}

self.phase[i as usize] += 1;
self.phase[i as usize] %= self.modulation_period_samples;
self.phase[i] += 1;
self.phase[i] %= self.modulation_period_samples;
}

d_out *= self.level;
Expand All @@ -209,28 +212,28 @@ impl Chorus {
right_out[sample_index] += d_out;

self.counter += 1;
self.counter %= (1 as i32) << 12 as i32 - 1 as i32;
self.counter %= MAX_SAMPLES as i32;
}
}

pub(crate) fn process_replace(&mut self, left_out: &mut [f32; 64], right_out: &mut [f32; 64]) {
for sample_index in 0..64 {
// Don't ask me why only left buf is considered an input...
let d_in = left_out[sample_index];
let mut d_out = 0.0f32;
let mut d_out = 0.0;

self.chorusbuf[self.counter as usize] = d_in;

for i in 0..(self.number_blocks as usize) {
let mut pos_subsamples: i32 = ((1 as i32) << 8 as i32 - 1 as i32) * self.counter
- self.lookup_tab[self.phase[i as usize] as usize];
let mut pos_samples: i32 = pos_subsamples / ((1 as i32) << 8 as i32 - 1 as i32);
pos_subsamples &= ((1 as i32) << 8 as i32 - 1 as i32) - 1 as i32;
let mut pos_subsamples = INTERPOLATION_SUBSAMPLES as i32 * self.counter
- self.lookup_tab[self.phase[i] as usize];

for ii in 0..5 {
d_out += self.chorusbuf
[(pos_samples & ((1 as i32) << 12 as i32 - 1 as i32) - 1 as i32) as usize]
* self.sinc_table[ii as usize][pos_subsamples as usize];
let mut pos_samples = pos_subsamples / INTERPOLATION_SUBSAMPLES as i32;
pos_subsamples &= INTERPOLATION_SUBSAMPLES_ANDMASK as i32;

for ii in 0..INTERPOLATION_SAMPLES {
d_out += self.chorusbuf[(pos_samples & MAX_SAMPLES_ANDMASK as i32) as usize]
* self.sinc_table[ii][pos_subsamples as usize];
pos_samples -= 1;
}

Expand All @@ -239,11 +242,11 @@ impl Chorus {
}
d_out *= self.level;

left_out[sample_index as usize] = d_out;
right_out[sample_index as usize] = d_out;
left_out[sample_index] = d_out;
right_out[sample_index] = d_out;

self.counter += 1;
self.counter %= (1 as i32) << 12 as i32 - 1 as i32;
self.counter %= MAX_SAMPLES as i32;
}
}

Expand All @@ -253,33 +256,24 @@ impl Chorus {
}

fn modulate_sine(buf: &mut [i32], len: usize, depth: i32) {
let mut val: f64;
for i in 0..len {
val = f64::sin(i as f64 / len as f64 * 2.0f64 * std::f64::consts::PI);
buf[i] = ((1.0f64 + val) * depth as f64 / 2.0f64
* ((1 as i32) << 8 as i32 - 1 as i32) as f64) as i32;
buf[i] -=
3 as i32 * ((1 as i32) << 12 as i32 - 1 as i32) * ((1 as i32) << 8 as i32 - 1 as i32);
for (i, out) in buf.iter_mut().take(len).enumerate() {
let val = f64::sin(i as f64 / len as f64 * 2.0 * std::f64::consts::PI);
*out = ((1.0 + val) * depth as f64 / 2.0 * INTERPOLATION_SUBSAMPLES as f64) as i32;
*out -= 3 * MAX_SAMPLES as i32 * INTERPOLATION_SUBSAMPLES as i32;
}
}

fn modulate_triangle(buf: &mut [i32], len: i32, depth: i32) {
let mut i: i32 = 0 as i32;
let mut ii: i32 = len - 1 as i32;
let mut val: f64;
let mut val2: f64;
let mut i = 0;
let mut ii = len - 1;
while i <= ii {
val = i as f64 * 2.0f64 / len as f64
* depth as f64
* ((1 as i32) << 8 as i32 - 1 as i32) as f64;
val2 = ((val + 0.5f64) as i32
- 3 as i32 * ((1 as i32) << 12 as i32 - 1 as i32) * ((1 as i32) << 8 as i32 - 1 as i32))
as f64;
let val = i as f64 * 2.0 / len as f64 * depth as f64 * INTERPOLATION_SUBSAMPLES as f64;
let val2 = (val + 0.5) as i32 - 3 * MAX_SAMPLES as i32 * INTERPOLATION_SUBSAMPLES as i32;
let fresh2 = i;
i = i + 1;
buf[fresh2 as usize] = val2 as i32;
i += 1;
buf[fresh2 as usize] = val2;
let fresh3 = ii;
ii = ii - 1;
buf[fresh3 as usize] = val2 as i32
ii -= 1;
buf[fresh3 as usize] = val2;
}
}
Loading