diff --git a/Cargo.lock b/Cargo.lock index 4887dc1..627bde8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1405,12 +1405,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" [[package]] name = "mach" @@ -1665,6 +1662,15 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "num-complex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" +dependencies = [ + "num-traits", +] + [[package]] name = "num-derive" version = "0.3.3" @@ -1676,6 +1682,16 @@ dependencies = [ "syn", ] +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.15" @@ -1914,7 +1930,9 @@ checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba" name = "pd-playback" version = "0.1.0" dependencies = [ + "log", "minimp3", + "rubato", ] [[package]] @@ -1980,6 +1998,15 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "primal-check" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9df7f93fd637f083201473dab4fee2db4c429d32e55e3299980ab3957ab916a0" +dependencies = [ + "num-integer", +] + [[package]] name = "proc-macro-crate" version = "1.2.1" @@ -2036,6 +2063,15 @@ dependencies = [ "cty", ] +[[package]] +name = "realfft" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953d9f7e5cdd80963547b456251296efc2626ed4e3cbf36c869d9564e0220571" +dependencies = [ + "rustfft", +] + [[package]] name = "redox_syscall" version = "0.2.16" @@ -2130,6 +2166,18 @@ dependencies = [ "minimp3", ] +[[package]] +name = "rubato" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6dd52e80cfc21894deadf554a5673002938ae4625f7a283e536f9cf7c17b0d5" +dependencies = [ + "num-complex", + "num-integer", + "num-traits", + "realfft", +] + [[package]] name = "rustc-hash" version = "1.1.0" @@ -2145,6 +2193,21 @@ dependencies = [ "semver", ] +[[package]] +name = "rustfft" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17d4f6cbdb180c9f4b2a26bbf01c4e647f1e1dea22fe8eb9db54198b32f9434" +dependencies = [ + "num-complex", + "num-integer", + "num-traits", + "primal-check", + "strength_reduce", + "transpose", + "version_check", +] + [[package]] name = "ryu" version = "1.0.12" @@ -2468,6 +2531,12 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0" +[[package]] +name = "strength_reduce" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe895eb47f22e2ddd4dabc02bce419d2e643c8e3b585c78158b349195bc24d82" + [[package]] name = "strsim" version = "0.10.0" @@ -2673,6 +2742,16 @@ dependencies = [ "once_cell", ] +[[package]] +name = "transpose" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6522d49d03727ffb138ae4cbc1283d3774f0d10aa7f9bf52e6784c45daf9b23" +dependencies = [ + "num-integer", + "strength_reduce", +] + [[package]] name = "try-lock" version = "0.2.4" diff --git a/pd-playback/Cargo.toml b/pd-playback/Cargo.toml index 42920ad..9da9c71 100644 --- a/pd-playback/Cargo.toml +++ b/pd-playback/Cargo.toml @@ -6,4 +6,6 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +log = "0.4.19" minimp3 = "0.5" +rubato = "0.14.1" diff --git a/pd-playback/src/lib.rs b/pd-playback/src/lib.rs index a8491b5..0c93808 100644 --- a/pd-playback/src/lib.rs +++ b/pd-playback/src/lib.rs @@ -1,4 +1,84 @@ -use minimp3::{Decoder, Frame} +use std::io::Read; +use minimp3::{ Decoder }; +use rubato::{ SincFixedIn, SincInterpolationParameters, SincInterpolationType, Resampler, WindowFunction }; + +struct Track { + sample_rate: i32, + samples: Vec, +} + +impl Track { + pub fn from_decoder(mut decoder: Decoder, target_sample_rate: i32) -> Self { + let frames = { + let mut accumulator = vec![]; + while let Ok(frame) = decoder.next_frame() { + accumulator.push(frame); + } + accumulator + }; + + let mut output_buffer = Vec::with_capacity(frames.len() * minimp3::MAX_SAMPLES_PER_FRAME); + let mut resampler = SincFixedIn::new( + target_sample_rate as f64 / frames[0].sample_rate as f64, + 10.0, + SincInterpolationParameters { + sinc_len: 256, + f_cutoff: 0.95, + oversampling_factor: 128, + interpolation: SincInterpolationType::Linear, + window: WindowFunction::BlackmanHarris2, + }, + 1152, + 2 + ).unwrap(); + + for frame in frames.iter() { + let mut deinterlaced_left = [0f32; 1152]; + let mut deinterlaced_right = [0f32; 1152]; + match frame.channels { + 1 => { + frame.data.iter() + .map(|&sample| sample as f32) + .enumerate() + .for_each(|(i, sample)| deinterlaced_left[i] = sample); + deinterlaced_right.copy_from_slice(&deinterlaced_left); + }, + + 2 => { + // if not fast enough, try the unsafe as_mut_ptr shit + // edit: unsafe stuff probably wont help actually bc iteration would have to + // happen anyway and also we still have to convert i32 to f32 + let (d_left_vec, d_right_vec): (Vec, Vec) + = frame.data.as_slice() + .chunks(2) + .map(|c| (c[0] as f32, c[1] as f32)) + .unzip(); + + deinterlaced_left[0..d_left_vec.len()] + .copy_from_slice(&d_left_vec); + deinterlaced_right[0..d_right_vec.len()] + .copy_from_slice(&d_right_vec); + }, + + _ => panic!("frame {} had {} channels, should only have 1 or 2", frames.len(), frame.channels) + } + + let mut frame_resampled = resampler + .process(&[deinterlaced_left, deinterlaced_right], None) + .unwrap(); + let frame_resampled_right = frame_resampled.pop().unwrap(); + let frame_resampled_left = frame_resampled.pop().unwrap(); + + let frame_resampled_interlaced = frame_resampled_left + .into_iter() + .zip(frame_resampled_right.into_iter()) + .flat_map(|(l, r)| [l, r]); + + output_buffer.extend(frame_resampled_interlaced); + } + todo!() + } +} #[cfg(test)] mod tests {