-
-
Save mkalte666/9797eb7e0eb31cdbe208fce994d3e45b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// Recursive function for mipmap creation | |
/// makes some assumptions about the size relationship of in_samp and out_samp | |
/// that is, in_samp should be == out_samp except in the recursion abort case (in_samp<2); out_samp should then be zero | |
/// Then performs two things: | |
/// IIR filtering with f_c = 0.5 of in_samp | |
/// And then downsamples it (every second part) into out samp | |
/// Then, it splits out samp in half: | |
/// First half becomes the new input, second half becomes new output, and recursion happens | |
fn make_mipmap_slice(in_samp: &[f32], out_samp: &mut [f32]) { | |
// done? | |
if in_samp.len() < 2 || out_samp.is_empty() { | |
return; | |
} | |
// single pole low pass | |
let x = (-2.0 * std::f32::consts::PI * 0.5).exp(); | |
let a0 = 1.0 - x; | |
let b1 = x; | |
let mut last = 0.0; | |
for i in 0..in_samp.len() / 2 { | |
let first = in_samp[i * 2] * a0 + last * b1; | |
let second = in_samp[i * 2 + 1] * a0 + first * b1; | |
out_samp[i] = second; | |
last = second; | |
} | |
let (new_input, new_output) = out_samp.split_at_mut(in_samp.len() / 2); | |
make_mipmap_slice(new_input, new_output); | |
} | |
/// take a bunch of input data and make a mipmap for it | |
fn make_mipmap(samples: Vec<f32>) -> Vec<f32> { | |
let mut res = samples; | |
res.resize(res.len() * 2, 0.0); | |
let mid = res.len() / 2; | |
let (inp, outp) = res.split_at_mut(mid); | |
make_mipmap_slice(inp, outp); | |
res | |
} | |
/// Get `count` samples out of the mipmap+ | |
/// The mipmap is just a slice of len()/2 points, followed by len()/4 points with half the resolution, and so on | |
/// This function goes deeper and deeper, until the requested range (start_top..end_top) is smaller or equal to the requested samples | |
/// Then, because im lazy, it does just nearest pick to fill the output vector. I should probably interpolate here with the next mip level or something | |
/// But whatever, it works well enough | |
fn sample_mipmap(mipmap: &[f32], count: usize, start_top: usize, end_top: usize) -> Vec<f32> { | |
if (end_top - start_top) > count { | |
sample_mipmap( | |
&mipmap[mipmap.len() / 2..], | |
count, | |
start_top / 2, | |
end_top / 2, | |
) | |
} else { | |
let mut res = vec![0.0; count]; | |
for i in 0..count { | |
// sample nearest for now? | |
let data_i = i * (end_top - start_top) / count + start_top; | |
if data_i >= mipmap.len() / 2 { | |
res[i] = 0.0; | |
} else { | |
res[i] = mipmap[data_i]; | |
} | |
} | |
res | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment