old school music tracker audio backend
at main 142 lines 3.9 kB view raw
1use std::{ 2 fmt::Debug, 3 iter::repeat_n, 4 num::NonZero, 5 ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign}, 6 sync::Arc, 7}; 8 9use crate::{ 10 audio_processing::Frame, file::impulse_format::sample::VibratoWave, project::note_event::Note, 11}; 12 13pub(crate) trait ProcessingFrame: 14 Add<Self, Output = Self> 15 + AddAssign<Self> 16 + Sub<Self, Output = Self> 17 + SubAssign<Self> 18 + Mul<f32, Output = Self> 19 + MulAssign<f32> 20 + Copy 21{ 22} 23 24impl ProcessingFrame for Frame {} 25 26impl ProcessingFrame for f32 {} 27 28pub(crate) trait ProcessingFunction<const N: usize, Fr: ProcessingFrame> { 29 fn process(self, data: &[Fr; N]) -> Fr; 30} 31 32#[derive(Clone)] 33pub struct Sample { 34 mono: bool, 35 data: Arc<[f32]>, 36} 37 38impl Sample { 39 pub const MAX_LENGTH: usize = 16_000_000; 40 pub const MAX_RATE: usize = 192_000; 41 /// this many frames need to be put on the start and the end to ensure that the interpolation algorithms work correctly. 42 pub const PAD_SIZE_EACH: usize = 4; 43 44 pub fn is_mono(&self) -> bool { 45 self.mono 46 } 47 48 /// len in Frames 49 pub fn len_with_pad(&self) -> usize { 50 if self.mono { 51 self.data.len() 52 } else { 53 self.data.len() / 2 54 } 55 } 56 57 pub(crate) fn compute< 58 const N: usize, 59 // all implementations are generic over the ProcessingFrame type. here both possible ProcessingFrame types 60 // are required, so that it can be decided at runtime which one to call. both are generated by the compiler 61 // from the generic implementation 62 Proc: ProcessingFunction<N, f32> + ProcessingFunction<N, Frame>, 63 >( 64 &self, 65 index: usize, 66 proc: Proc, 67 ) -> Frame { 68 if self.is_mono() { 69 let data: &[f32; N] = self.data[index..index + N].try_into().unwrap(); 70 Frame::from(proc.process(data)) 71 } else { 72 let data: &[Frame; N] = Frame::from_interleaved(&self.data[index * 2..(index + N) * 2]) 73 .try_into() 74 .unwrap(); 75 proc.process(data) 76 } 77 } 78 79 pub fn index(&self, idx: usize) -> Frame { 80 if self.is_mono() { 81 Frame::from(self.data[idx]) 82 } else { 83 Frame::from([self.data[idx * 2], self.data[idx * 2 + 1]]) 84 } 85 } 86 87 pub(crate) fn strongcount(&self) -> usize { 88 Arc::strong_count(&self.data) 89 } 90 91 pub fn new_stereo_interpolated<I: IntoIterator<Item = f32>>(data: I) -> Self { 92 Self::new_stereo_interpolated_padded( 93 repeat_n(0f32, 2 * Self::PAD_SIZE_EACH) 94 .chain(data) 95 .chain(repeat_n(0f32, 2 * Self::PAD_SIZE_EACH)), 96 ) 97 } 98 99 pub fn new_stereo_interpolated_padded<I: IntoIterator<Item = f32>>(data: I) -> Self { 100 Self { 101 mono: false, 102 data: Arc::from_iter(data), 103 } 104 } 105 106 pub fn new_mono<I: IntoIterator<Item = f32>>(data: I) -> Self { 107 Self::new_mono_padded( 108 repeat_n(0f32, Self::PAD_SIZE_EACH) 109 .chain(data) 110 .chain(repeat_n(0f32, Self::PAD_SIZE_EACH)), 111 ) 112 } 113 114 pub fn new_mono_padded<I: IntoIterator<Item = f32>>(data: I) -> Self { 115 Self { 116 mono: true, 117 data: Arc::from_iter(data), 118 } 119 } 120} 121 122impl Debug for Sample { 123 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 124 f.debug_struct("Sample") 125 .field("mono", &self.mono) 126 .field("data_len", &self.len_with_pad()) 127 .finish_non_exhaustive() 128 } 129} 130 131#[derive(Clone, Copy, Debug)] 132pub struct SampleMetaData { 133 pub default_volume: u8, 134 pub global_volume: u8, 135 pub default_pan: Option<u8>, 136 pub vibrato_speed: u8, 137 pub vibrato_depth: u8, 138 pub vibrato_rate: u8, 139 pub vibrato_waveform: VibratoWave, 140 pub sample_rate: NonZero<u32>, 141 pub base_note: Note, 142}