Something went wrong. Try again.
This repository has no description
Something went wrong. Try again.
5.5 kB · 178 lines
Rust
at sans-io
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179use std::{ fmt::Debug, iter::repeat_n, num::NonZero, ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign},};
use triomphe::ThinArc;
use crate::{audio_processing::Frame, project::note_event::Note};
// implemented for f32 and Framepub(crate) trait ProcessingFrame: Add<Self, Output = Self> + AddAssign<Self> + Sub<Self, Output = Self> + SubAssign<Self> + Mul<f32, Output = Self> + MulAssign<f32> + Div<f32, Output = Self> + DivAssign<f32> + Copy{ fn mul_add(self, mul: f32, add: Self) -> Self;}
impl ProcessingFrame for f32 { fn mul_add(self, mul: f32, add: Self) -> Self { f32::mul_add(self, mul, add) }}
pub(crate) trait ProcessingFunction<const N: usize, Fr: ProcessingFrame> { fn process(position: f32, data: &[Fr; N]) -> Fr;}
#[derive(Clone)]pub struct Sample { // also stores the mono state on the heap to make the packing in arrays more efficient data: ThinArc<bool, f32>,}
impl Sample { pub const MAX_LENGTH: usize = 16_000_000; pub const MAX_RATE: usize = 192_000; /// this many frames need to be put on the start and the end to ensure that the interpolation algorithms work correctly. pub const PAD_SIZE_EACH: usize = 4;
pub fn is_mono(&self) -> bool { self.data.header.header }
/// len in Frames pub fn len_with_pad(&self) -> usize { if self.is_mono() { self.data.header.length } else { self.data.header.length } }
/// This function also offsets the loaded sample data correctly, depending on the size of required processing data pub(crate) fn compute< const N: usize, // all implementations are generic over the ProcessingFrame type. here both possible ProcessingFrame types // are required, so that it can be decided at runtime which one to call. both are generated by the compiler // from the generic implementation Proc: ProcessingFunction<N, f32> + ProcessingFunction<N, Frame>, >( &self, position: (usize, f32), ) -> Frame { const { assert!(N / 2 <= Self::PAD_SIZE_EACH) }; let half = const { (N - 1) / 2 }; let start_idx = position.0 - half; let end_idx = start_idx + N; if self.is_mono() { let data: &[f32; N] = self.data.slice[start_idx..end_idx].try_into().unwrap(); Frame::from(Proc::process(position.1, data)) } else { let data: &[Frame; N] = Frame::from_interleaved(&self.data.slice[start_idx * 2..end_idx * 2]) .try_into() .unwrap(); Proc::process(position.1, data) } }
pub fn index(&self, idx: usize) -> Frame { if self.is_mono() { Frame::from(self.data.slice[idx]) } else { Frame::from([self.data.slice[idx * 2], self.data.slice[idx * 2 + 1]]) } }
pub(crate) fn strongcount(&self) -> usize { ThinArc::strong_count(&self.data) }
pub fn new_stereo_interpolated<I: IntoIterator<Item = f32>>(data: I) -> Self { Self::new_stereo_interpolated_padded( repeat_n(0f32, 2 * Self::PAD_SIZE_EACH) .chain(data) .chain(repeat_n(0f32, 2 * Self::PAD_SIZE_EACH)), ) }
/// Should only be called if the Iterator already includes enough padding pub fn new_stereo_interpolated_padded<I: IntoIterator<Item = f32>>(data: I) -> Self { let data = Vec::from_iter(data); Self { data: ThinArc::from_header_and_slice(false, &data), } }
// replace these with some kind of specialization as soon as it becomes available pub fn new_stereo_interpolated_padded_exact<I: Iterator<Item = f32> + ExactSizeIterator>( data: I, ) -> Self { Self { data: ThinArc::from_header_and_iter(false, data), } }
pub fn new_mono<I: IntoIterator<Item = f32>>(data: I) -> Self { Self::new_mono_padded( repeat_n(0f32, Self::PAD_SIZE_EACH) .chain(data) .chain(repeat_n(0f32, Self::PAD_SIZE_EACH)), ) }
pub fn new_mono_padded<I: IntoIterator<Item = f32>>(data: I) -> Self { let data = Vec::from_iter(data); Self { data: ThinArc::from_header_and_slice(true, &data), } }
// replace these with some kind of specialization as soon as it becomes available pub fn new_mono_padded_exact<I: Iterator<Item = f32> + ExactSizeIterator>(data: I) -> Self { Self { data: ThinArc::from_header_and_iter(true, data), } }}
impl Debug for Sample { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("Sample") .field("mono", &self.is_mono()) .field("data_len", &self.len_with_pad()) .finish_non_exhaustive() }}
#[derive(Debug, Default, Clone, Copy)]pub enum VibratoWave { #[default] Sine = 0, RampDown = 1, Square = 2, Random = 3,}
#[derive(Clone, Copy, Debug)]pub struct SampleMetaData { pub default_volume: u8, pub global_volume: u8, pub default_pan: Option<u8>, pub vibrato_speed: u8, pub vibrato_depth: u8, pub vibrato_rate: u8, pub vibrato_waveform: VibratoWave, pub sample_rate: NonZero<u32>, pub base_note: Note,}