-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsample.rs
More file actions
153 lines (136 loc) · 4.42 KB
/
sample.rs
File metadata and controls
153 lines (136 loc) · 4.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
use std::{
fmt::Debug,
iter::repeat_n,
num::NonZero,
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign},
sync::Arc,
};
use crate::{
audio_processing::Frame, file::impulse_format::sample::VibratoWave, project::note_event::Note,
};
// implemented for f32 and Frame
pub(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 {
mono: bool,
data: Arc<[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.mono
}
/// len in Frames
pub fn len_with_pad(&self) -> usize {
if self.mono {
self.data.len()
} else {
self.data.len() / 2
}
}
/// 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[start_idx..end_idx].try_into().unwrap();
Frame::from(Proc::process(position.1, data))
} else {
let data: &[Frame; N] = Frame::from_interleaved(&self.data[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[idx])
} else {
Frame::from([self.data[idx * 2], self.data[idx * 2 + 1]])
}
}
pub(crate) fn strongcount(&self) -> usize {
Arc::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 {
Self {
mono: false,
data: Arc::from_iter(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 {
Self {
mono: true,
data: Arc::from_iter(data),
}
}
}
impl Debug for Sample {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Sample")
.field("mono", &self.mono)
.field("data_len", &self.len_with_pad())
.finish_non_exhaustive()
}
}
#[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,
}