1use std::time::Duration;
2
3use super::SeekError;
4use crate::common::{ChannelCount, SampleRate};
5use crate::math::nz;
6use crate::Source;
7
8pub fn track_position<I>(source: I) -> TrackPosition<I> {
11 TrackPosition {
12 input: source,
13 samples_counted: 0,
14 offset_duration: 0.0,
15 current_span_sample_rate: nz!(1),
16 current_span_channels: nz!(1),
17 current_span_len: None,
18 }
19}
20
21#[derive(Debug)]
23pub struct TrackPosition<I> {
24 input: I,
25 samples_counted: usize,
26 offset_duration: f64,
27 current_span_sample_rate: SampleRate,
28 current_span_channels: ChannelCount,
29 current_span_len: Option<usize>,
30}
31
32impl<I> TrackPosition<I> {
33 #[inline]
35 pub fn inner(&self) -> &I {
36 &self.input
37 }
38
39 #[inline]
41 pub fn inner_mut(&mut self) -> &mut I {
42 &mut self.input
43 }
44
45 #[inline]
47 pub fn into_inner(self) -> I {
48 self.input
49 }
50}
51
52impl<I> TrackPosition<I>
53where
54 I: Source,
55{
56 #[inline]
67 pub fn get_pos(&self) -> Duration {
68 let seconds = self.samples_counted as f64
69 / self.input.sample_rate().get() as f64
70 / self.input.channels().get() as f64
71 + self.offset_duration;
72 Duration::from_secs_f64(seconds)
73 }
74
75 #[inline]
76 fn set_current_span(&mut self) {
77 self.current_span_len = self.current_span_len();
78 self.current_span_sample_rate = self.sample_rate();
79 self.current_span_channels = self.channels();
80 }
81}
82
83impl<I> Iterator for TrackPosition<I>
84where
85 I: Source,
86{
87 type Item = I::Item;
88
89 #[inline]
90 fn next(&mut self) -> Option<I::Item> {
91 if self.current_span_len.is_none() {
93 self.set_current_span();
94 }
95
96 let item = self.input.next();
97 if item.is_some() {
98 self.samples_counted += 1;
99
100 if Some(self.samples_counted) == self.current_span_len() {
103 self.offset_duration += self.samples_counted as f64
104 / self.current_span_sample_rate.get() as f64
105 / self.current_span_channels.get() as f64;
106
107 self.samples_counted = 0;
109 self.set_current_span();
110 };
111 };
112 item
113 }
114
115 #[inline]
116 fn size_hint(&self) -> (usize, Option<usize>) {
117 self.input.size_hint()
118 }
119}
120
121impl<I> Source for TrackPosition<I>
122where
123 I: Source,
124{
125 #[inline]
126 fn current_span_len(&self) -> Option<usize> {
127 self.input.current_span_len()
128 }
129
130 #[inline]
131 fn channels(&self) -> ChannelCount {
132 self.input.channels()
133 }
134
135 #[inline]
136 fn sample_rate(&self) -> SampleRate {
137 self.input.sample_rate()
138 }
139
140 #[inline]
141 fn total_duration(&self) -> Option<Duration> {
142 self.input.total_duration()
143 }
144
145 #[inline]
146 fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
147 let result = self.input.try_seek(pos);
148 if result.is_ok() {
149 self.offset_duration = pos.as_secs_f64();
150 self.samples_counted = 0;
154 }
155 result
156 }
157}
158
159#[cfg(test)]
160mod tests {
161 use std::time::Duration;
162
163 use crate::buffer::SamplesBuffer;
164 use crate::math::nz;
165 use crate::source::Source;
166
167 #[test]
168 fn test_position() {
169 let inner = SamplesBuffer::new(nz!(1), nz!(1), vec![10.0, -10.0, 10.0, -10.0, 20.0, -20.0]);
170 let mut source = inner.track_position();
171
172 assert_eq!(source.get_pos().as_secs_f32(), 0.0);
173 source.next();
174 assert_eq!(source.get_pos().as_secs_f32(), 1.0);
175
176 source.next();
177 assert_eq!(source.get_pos().as_secs_f32(), 2.0);
178
179 assert!(source.try_seek(Duration::new(1, 0)).is_ok());
180 assert_eq!(source.get_pos().as_secs_f32(), 1.0);
181 }
182
183 #[test]
184 fn test_position_in_presence_of_speedup() {
185 let inner = SamplesBuffer::new(nz!(1), nz!(1), vec![10.0, -10.0, 10.0, -10.0, 20.0, -20.0]);
186 let mut source = inner.speed(2.0).track_position();
187
188 assert_eq!(source.get_pos().as_secs_f32(), 0.0);
189 source.next();
190 assert_eq!(source.get_pos().as_secs_f32(), 0.5);
191
192 source.next();
193 assert_eq!(source.get_pos().as_secs_f32(), 1.0);
194
195 assert!(source.try_seek(Duration::new(1, 0)).is_ok());
196 assert_eq!(source.get_pos().as_secs_f32(), 1.0);
197 }
198}