Skip to content

Commit

Permalink
Finish out MVP level detector node + Various fixes
Browse files Browse the repository at this point in the history
 * Fix issue with oversampling in FM synth that was causing audio artifacts for sine waves and maybe others.
   * It sounds so much better now it's crazy...
   * Make the oversampling impl more unified across the board for the different waveforms
 * Build out level detector UI
   * Show cur detected level (if available) using `SharedArrayBuffer`
   * Show detected value as dB
 * Delete all the old equalizer code
   * It doesn't even work anymore and never worked well, and filter designer can do a decent job of providing that functionality anyway
 * Hide wavetable from the graph editor add module search since it's not meant to be used by itself
 * Add Jemalloc for the backend
  • Loading branch information
Ameobea committed Feb 14, 2024
1 parent 292fd76 commit 4fb09fe
Show file tree
Hide file tree
Showing 22 changed files with 214 additions and 1,174 deletions.
21 changes: 21 additions & 0 deletions backend/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions backend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,6 @@ base64 = "0.21"
rust-s3 = { version = "0.33", features = [] }
aws-region = { version = "0.25.0", features = ["serde"] }
urlencoding = "2.1"

[target.'cfg(not(target_env = "msvc"))'.dependencies]
tikv-jemallocator = "0.5"
7 changes: 7 additions & 0 deletions backend/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ use rocket::{
Request, Response,
};

#[cfg(not(target_env = "msvc"))]
use tikv_jemallocator::Jemalloc;

#[cfg(not(target_env = "msvc"))]
#[global_allocator]
static GLOBAL: Jemalloc = Jemalloc;

pub mod conf;
pub mod db_util;
pub mod models;
Expand Down
7 changes: 3 additions & 4 deletions engine/dsp/src/oscillator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub trait PhasedOscillator {

fn set_phase(&mut self, new_phase: f32);

#[inline(always)]
fn compute_new_phase(phase: f32, frequency: f32) -> f32 {
let mut new_phase = (phase + (1. / (SAMPLE_RATE as f32 / frequency))).fract();
if new_phase < 0. {
Expand All @@ -13,19 +14,17 @@ pub trait PhasedOscillator {
new_phase
}

#[inline(always)]
fn compute_new_phase_oversampled(phase: f32, oversample_multiplier: f32, frequency: f32) -> f32 {
Self::compute_new_phase(phase, frequency / oversample_multiplier)
}

#[inline(always)]
fn update_phase(&mut self, frequency: f32) {
// 1 phase corresponds to 1 period of the waveform. 1 phase is passed every (SAMPLE_RATE /
// frequency) samples.
let phase = self.get_phase();
let new_phase = Self::compute_new_phase(phase, frequency);
self.set_phase(new_phase);
}

fn update_phase_oversampled(&mut self, oversample_multiplier: f32, frequency: f32) {
self.update_phase(frequency / oversample_multiplier)
}
}
2 changes: 1 addition & 1 deletion engine/dsp/src/rms_level_detector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ impl<const TEND_TOWARDS_ZERO: bool> RMSLevelDetector<TEND_TOWARDS_ZERO> {

// To deal with floating point precision issues, we tend the sum towards zero slightly so
// that it doesn't get stuck at a non-zero value when the input is silent.
if TEND_TOWARDS_ZERO {
if TEND_TOWARDS_ZERO && sample.abs() < 0.001 {
self.sum *= 0.999999;
}

Expand Down
2 changes: 1 addition & 1 deletion engine/level_detector/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ impl Default for LevelDetectorCtx {
fn default() -> Self {
Self {
io_buffer: [0.0; FRAME_SIZE],
detector: RMSLevelDetector::new(10), // Will be set dynamically during processing
detector: RMSLevelDetector::new(10), // Window size will be set dynamically during processing
}
}
}
Expand Down
82 changes: 41 additions & 41 deletions engine/wavetable/src/fm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,26 +95,21 @@ impl Oscillator for SineOscillator {
_base_frequency: f32,
) -> f32 {
let sine_lookup_table = dsp::lookup_tables::get_sine_lookup_table();
if frequency.abs() < 1000. {
self.update_phase(frequency);
return dsp::read_interpolated(
sine_lookup_table,
self.phase * (sine_lookup_table.len() - 2) as f32,
);
}

// 2x oversampling to avoid aliasing
// 4x oversampling to avoid aliasing
let mut out = 0.;
let oversample_ratio = 2usize;
let mut phase = self.phase;
let oversample_ratio = 4usize;
for _ in 0..oversample_ratio {
self.update_phase_oversampled(oversample_ratio as f32, frequency);
phase = Self::compute_new_phase_oversampled(phase, oversample_ratio as f32, frequency);
out += dsp::read_interpolated(
sine_lookup_table,
self.phase * (sine_lookup_table.len() - 2) as f32,
) * (1. / (oversample_ratio as f32));
phase * (sine_lookup_table.len() - 2) as f32,
);
}

out
self.phase = phase;
out / oversample_ratio as f32
}
}

Expand All @@ -139,21 +134,20 @@ impl Oscillator for SquareOscillator {
_sample_ix_within_frame: usize,
_base_frequency: f32,
) -> f32 {
if frequency.abs() < 1000. {
self.update_phase(frequency);
return if self.phase < 0.5 { 1. } else { -1. };
}

// 4x oversampling to avoid aliasing
let mut out = 0.;
self.update_phase_oversampled(4., frequency);
out += if self.phase < 0.5 { 0.25 } else { -0.25 };
self.update_phase_oversampled(4., frequency);
out += if self.phase < 0.5 { 0.25 } else { -0.25 };
self.update_phase_oversampled(4., frequency);
out += if self.phase < 0.5 { 0.25 } else { -0.25 };
self.update_phase_oversampled(4., frequency);
out += if self.phase < 0.5 { 0.25 } else { -0.25 };
let mut phase = self.phase;

phase = Self::compute_new_phase_oversampled(phase, 4., frequency);
out += if phase < 0.5 { 0.25 } else { -0.25 };
phase = Self::compute_new_phase_oversampled(phase, 4., frequency);
out += if phase < 0.5 { 0.25 } else { -0.25 };
phase = Self::compute_new_phase_oversampled(phase, 4., frequency);
out += if phase < 0.5 { 0.25 } else { -0.25 };
phase = Self::compute_new_phase_oversampled(phase, 4., frequency);
out += if phase < 0.5 { 0.25 } else { -0.25 };

self.phase = phase;

out
}
Expand Down Expand Up @@ -181,10 +175,11 @@ impl Oscillator for TriangleOscillator {
_base_frequency: f32,
) -> f32 {
// 4x oversampling to avoid aliasing
let oversample_factor = 4usize;
let mut out = 0.;
let mut phase = self.phase;
for _ in 0..4 {
phase = Self::compute_new_phase_oversampled(phase, 4., frequency);
for _ in 0..oversample_factor {
phase = Self::compute_new_phase_oversampled(phase, oversample_factor as f32, frequency);
out += if phase < 0.25 {
4. * phase
} else if phase < 0.5 {
Expand All @@ -196,11 +191,11 @@ impl Oscillator for TriangleOscillator {
} else {
let adjusted_phase = phase - 0.75;
-1. + (adjusted_phase * 4.)
} * 0.25;
}
}

self.phase = phase;
out
out / oversample_factor as f32
}
}

Expand All @@ -226,19 +221,20 @@ impl Oscillator for SawtoothOscillator {
_base_frequency: f32,
) -> f32 {
// 4x oversampling to reduce aliasing
let oversample_factor = 4usize;
let mut out = 0.;
let mut phase = self.phase;
for _ in 0..4 {
phase = Self::compute_new_phase_oversampled(phase, 4., frequency);
out += if self.phase < 0.5 {
2. * self.phase
for _ in 0..oversample_factor {
phase = Self::compute_new_phase_oversampled(phase, oversample_factor as f32, frequency);
out += if phase < 0.5 {
2. * phase
} else {
-1. + (2. * (self.phase - 0.5))
} * 0.25;
-1. + (2. * (phase - 0.5))
};
}

self.phase = phase;
out
out / oversample_factor as f32
}
}

Expand Down Expand Up @@ -500,15 +496,19 @@ impl Oscillator for WaveTableHandle {
];

// 4x oversampling to avoid aliasing
let oversample_factor = 4usize;
let mut sample = 0.;
for _ in 0..4 {
self.update_phase_oversampled(4., frequency);
let mut phase = self.phase;
for _ in 0..oversample_factor {
phase = Self::compute_new_phase_oversampled(phase, oversample_factor as f32, frequency);
sample += wavetable.get_sample(
self.phase * (wavetable.settings.waveform_length - 1) as f32,
phase * (wavetable.settings.waveform_length - 1) as f32,
&mixes,
);
}
sample * 0.25

self.phase = phase;
sample / oversample_factor as f32
}
}

Expand Down
Loading

0 comments on commit 4fb09fe

Please sign in to comment.