torque_tracker_engine/
sample.rs

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}