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