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
use super::{
PlayingTrack,
SampleTransform
};
/// Taken from rodio and modified (I will create my own later)
///
/// Iterator that converts from a certain sample rate to another.
pub struct RateConverter{
/// We convert chunks of `from` samples into chunks of `to` samples.
from: u32,
/// We convert chunks of `from` samples into chunks of `to` samples.
to: u32,
/// One sample per channel, extracted from `input`.
current_frame: Vec<f32>,
/// Position of `current_sample` modulo `from`.
current_frame_pos_in_chunk: u32,
/// The samples right after `current_sample` (one per channel), extracted from `input`.
next_frame: Vec<f32>,
/// The position of the next sample that the iterator should return, modulo `to`.
/// This counter is incremented (modulo `to`) every time the iterator is called.
next_output_frame_pos_in_chunk: u32,
}
impl RateConverter{
///
///
/// # Panic
///
/// Panicks if `from` or `to` are equal to 0.
///
pub fn new(
from:u32,
to:u32,
track:&mut PlayingTrack,
)->RateConverter{
assert!(from >= 1);
assert!(to >= 1);
// finding greatest common divisor
let gcd = {
fn gcd(a: u32, b: u32) -> u32 {
if b == 0 {
a
} else {
gcd(b, a % b)
}
}
gcd(from, to)
};
let channels=track.channels as usize;
let mut first_samples=Vec::with_capacity(channels);
let mut next_samples=Vec::with_capacity(channels);
if from!=to{
track.next(&mut first_samples);
track.next(&mut next_samples);
}
RateConverter {
from: from / gcd,
to: to / gcd,
current_frame_pos_in_chunk: 0,
next_output_frame_pos_in_chunk: 0,
current_frame:first_samples,
next_frame:next_samples,
}
}
fn next_input_frame(&mut self,track:&mut PlayingTrack){
self.current_frame_pos_in_chunk += 1;
std::mem::swap(&mut self.current_frame, &mut self.next_frame);
self.next_frame.clear();
track.next(&mut self.next_frame);
}
pub fn next(&mut self,track:&mut PlayingTrack,frame:&mut Vec<f32>){
if self.from==self.to{
return track.next(frame)
}
// The frame we are going to return from this function will be a linear interpolation
// between `self.current_frame` and `self.next_frame`.
if self.next_output_frame_pos_in_chunk == self.to {
// If we jump to the next frame, we reset the whole state.
self.next_output_frame_pos_in_chunk = 0;
self.next_input_frame(track);
while self.current_frame_pos_in_chunk != self.from {
self.next_input_frame(track);
}
self.current_frame_pos_in_chunk = 0;
} else {
// Finding the position of the first sample of the linear interpolation.
let req_left_sample =
(self.from * self.next_output_frame_pos_in_chunk / self.to) % self.from;
// Advancing `self.current_frame`, `self.next_frame` and
// `self.current_frame_pos_in_chunk` until the latter variable
// matches `req_left_sample`.
while self.current_frame_pos_in_chunk != req_left_sample {
self.next_input_frame(track);
debug_assert!(self.current_frame_pos_in_chunk < self.from);
}
}
// Merging `self.current_frame` and `self.next_frame` into `self.output_buffer`.
// Note that `self.output_buffer` can be truncated if there is not enough data in
// `self.next_frame`.
//let mut result = None;
let numerator = (self.from * self.next_output_frame_pos_in_chunk) % self.to;
for (off, (cur, next)) in self.current_frame
.iter()
.zip(self.next_frame.iter())
.enumerate()
{
let sample = SampleTransform::lerp(cur.clone(), next.clone(), numerator, self.to);
frame.push(sample);
}
// Incrementing the counter for the next iteration.
self.next_output_frame_pos_in_chunk += 1;
}
}