Skip to content

Commit

Permalink
Fix waveform renderer division precision issue
Browse files Browse the repository at this point in the history
 * or something like that
  • Loading branch information
Ameobea committed Feb 5, 2024
1 parent 5bf82ea commit a661870
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 19 deletions.
38 changes: 21 additions & 17 deletions engine/waveform_renderer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use wasm_bindgen::prelude::*;
const BYTES_PER_PX: usize = 4; // RGBA

pub struct WaveformRendererCtx {
pub sample_rate: u32,
pub sample_rate: f32,
pub width_px: u32,
pub height_px: u32,
pub waveform_buf: Vec<f32>,
Expand All @@ -14,18 +14,22 @@ pub struct WaveformRendererCtx {
impl WaveformRendererCtx {
pub fn new(
waveform_length_samples: u32,
sample_rate: u32,
sample_rate: f32,
width_px: u32,
height_px: u32,
) -> Self {
let mut image_data_buf =
Vec::with_capacity(width_px as usize * height_px as usize * BYTES_PER_PX);
unsafe { image_data_buf.set_len(width_px as usize * height_px as usize * BYTES_PER_PX) };

let mut waveform_buf = Vec::with_capacity(waveform_length_samples as usize);
unsafe { waveform_buf.set_len(waveform_length_samples as usize) };

WaveformRendererCtx {
sample_rate,
width_px,
height_px,
waveform_buf: Vec::with_capacity(waveform_length_samples as usize),
waveform_buf,
image_data_buf,
}
}
Expand All @@ -35,27 +39,20 @@ impl WaveformRendererCtx {
#[wasm_bindgen]
pub fn create_waveform_renderer_ctx(
waveform_length_samples: u32,
sample_rate: u32,
sample_rate: f32,
width_px: u32,
height_px: u32,
) -> *mut WaveformRendererCtx {
common::maybe_init(None);

wbg_logging::maybe_init();

let mut ctx = Box::new(WaveformRendererCtx::new(
Box::into_raw(Box::new(WaveformRendererCtx::new(
waveform_length_samples,
sample_rate,
width_px,
height_px,
));
unsafe {
ctx.waveform_buf.set_len(waveform_length_samples as usize);
ctx
.image_data_buf
.set_len(width_px as usize * height_px as usize * BYTES_PER_PX);
}
Box::into_raw(ctx)
)))
}

#[cfg(feature = "bindgen")]
Expand All @@ -79,7 +76,7 @@ pub fn get_waveform_buf_ptr(ctx: *mut WaveformRendererCtx) -> *mut f32 {
}

#[inline(always)]
fn ms_to_samples(sample_rate: u32, ms: u32) -> u32 { (ms * sample_rate) / 1000 }
fn ms_to_samples(sample_rate: f32, ms: f32) -> u32 { ((ms * sample_rate) / 1000.) as u32 }

#[inline(always)]
fn sample_to_y_val(sample: f32, half_height: f32, max_distance_from_0: f32) -> u32 {
Expand All @@ -88,7 +85,7 @@ fn sample_to_y_val(sample: f32, half_height: f32, max_distance_from_0: f32) -> u
}

#[cfg_attr(feature = "bindgen", wasm_bindgen)]
pub fn render_waveform(ctx: *mut WaveformRendererCtx, start_ms: u32, end_ms: u32) -> *const u8 {
pub fn render_waveform(ctx: *mut WaveformRendererCtx, start_ms: f32, end_ms: f32) -> *const u8 {
let ctx = unsafe { &mut *ctx };

if ctx.waveform_buf.is_empty() {
Expand Down Expand Up @@ -117,11 +114,18 @@ pub fn render_waveform(ctx: *mut WaveformRendererCtx, start_ms: u32, end_ms: u32

let start_sample_ix = ms_to_samples(ctx.sample_rate, start_ms).min(ctx.waveform_buf.len() as u32);
let end_sample_ix = ms_to_samples(ctx.sample_rate, end_ms).min(ctx.waveform_buf.len() as u32);
debug_assert!(end_sample_ix > start_sample_ix);
assert!(
end_sample_ix > start_sample_ix,
"Start sample after end? start_ms={}, end_ms={}, start_sample_ix={}, end_sample_ix={}",
start_ms,
end_ms,
start_sample_ix,
end_sample_ix
);

let len_samples = end_sample_ix - start_sample_ix;
let samples_per_px = (len_samples / ctx.width_px).max(1);
debug_assert_eq!(ctx.height_px % 2, 0, "Height must be divisible by 2");
assert_eq!(ctx.height_px % 2, 0, "Height must be divisible by 2");

let max_distance_from_0 = ctx.waveform_buf[start_sample_ix as usize..end_sample_ix as usize]
.iter()
Expand Down
4 changes: 2 additions & 2 deletions engine/wavegen/src/bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ fn get_waveform_renderer_ctx() -> &'static mut WaveformRendererCtx {

let ctx = Box::into_raw(Box::new(WaveformRendererCtx::new(
WAVEFORM_LENGTH_SAMPLES as u32,
SAMPLE_RATE,
SAMPLE_RATE as f32,
WAVEFORM_WIDTH_PX,
WAVEFORM_HEIGHT_PX,
)));
Expand Down Expand Up @@ -100,7 +100,7 @@ pub extern "C" fn wavegen_render_waveform() -> *const u8 {
dsp::lookup_tables::maybe_init_lookup_tables();
}
build_waveform(&mut ctx.waveform_buf, magnitudes, phases, fast);
waveform_renderer::render_waveform(ctx, 0, 100_000_000)
waveform_renderer::render_waveform(ctx, 0., 100_000_000.)
}

#[no_mangle]
Expand Down
5 changes: 5 additions & 0 deletions src/granulator/GranulatorUI/WaveformRendererWorker.worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ export class WaveformRendererWorker {
}

public async render(bounds: WaveformBounds, widthPx: number, heightPx: number) {
if (bounds.endMs <= bounds.startMs) {
console.error('Invalid bounds:', bounds);
return new Uint8ClampedArray(widthPx * heightPx * BYTES_PER_PX);
}

const inst = await this.inst;
const imageDataPtr = inst.render_waveform(this.ctxPtr, bounds.startMs, bounds.endMs);
return new Uint8ClampedArray(
Expand Down

0 comments on commit a661870

Please sign in to comment.