rodio/source/
take.rs
1use std::time::Duration;
2
3use crate::{Sample, Source};
4
5use super::SeekError;
6
7pub fn take_duration<I>(input: I, duration: Duration) -> TakeDuration<I>
9where
10 I: Source,
11 I::Item: Sample,
12{
13 TakeDuration {
14 current_frame_len: input.current_frame_len(),
15 duration_per_sample: TakeDuration::get_duration_per_sample(&input),
16 input,
17 remaining_duration: duration,
18 requested_duration: duration,
19 filter: None,
20 }
21}
22
23#[derive(Clone, Debug)]
25enum DurationFilter {
26 FadeOut,
27}
28impl DurationFilter {
29 fn apply<I: Iterator>(
30 &self,
31 sample: <I as Iterator>::Item,
32 parent: &TakeDuration<I>,
33 ) -> <I as Iterator>::Item
34 where
35 I::Item: Sample,
36 {
37 use self::DurationFilter::*;
38 match self {
39 FadeOut => {
40 let remaining = parent.remaining_duration.as_millis() as f32;
41 let total = parent.requested_duration.as_millis() as f32;
42 sample.amplify(remaining / total)
43 }
44 }
45 }
46}
47
48const NANOS_PER_SEC: u64 = 1_000_000_000;
49
50#[derive(Clone, Debug)]
52pub struct TakeDuration<I> {
53 input: I,
54 remaining_duration: Duration,
55 requested_duration: Duration,
56 filter: Option<DurationFilter>,
57 current_frame_len: Option<usize>,
59 duration_per_sample: Duration,
61}
62
63impl<I> TakeDuration<I>
64where
65 I: Source,
66 I::Item: Sample,
67{
68 #[inline]
70 fn get_duration_per_sample(input: &I) -> Duration {
71 let ns = NANOS_PER_SEC / (input.sample_rate() as u64 * input.channels() as u64);
72 Duration::new(0, ns as u32)
74 }
75
76 #[inline]
78 pub fn inner(&self) -> &I {
79 &self.input
80 }
81
82 #[inline]
84 pub fn inner_mut(&mut self) -> &mut I {
85 &mut self.input
86 }
87
88 #[inline]
90 pub fn into_inner(self) -> I {
91 self.input
92 }
93
94 pub fn set_filter_fadeout(&mut self) {
97 self.filter = Some(DurationFilter::FadeOut);
98 }
99
100 pub fn clear_filter(&mut self) {
102 self.filter = None;
103 }
104}
105
106impl<I> Iterator for TakeDuration<I>
107where
108 I: Source,
109 I::Item: Sample,
110{
111 type Item = <I as Iterator>::Item;
112
113 fn next(&mut self) -> Option<<I as Iterator>::Item> {
114 if let Some(frame_len) = self.current_frame_len.take() {
115 if frame_len > 0 {
116 self.current_frame_len = Some(frame_len - 1);
117 } else {
118 self.current_frame_len = self.input.current_frame_len();
119 self.duration_per_sample = Self::get_duration_per_sample(&self.input);
121 }
122 }
123
124 if self.remaining_duration <= self.duration_per_sample {
125 None
126 } else if let Some(sample) = self.input.next() {
127 let sample = match &self.filter {
128 Some(filter) => filter.apply(sample, self),
129 None => sample,
130 };
131
132 self.remaining_duration -= self.duration_per_sample;
133
134 Some(sample)
135 } else {
136 None
137 }
138 }
139
140 }
142
143impl<I> Source for TakeDuration<I>
144where
145 I: Iterator + Source,
146 I::Item: Sample,
147{
148 #[inline]
149 fn current_frame_len(&self) -> Option<usize> {
150 let remaining_nanos = self.remaining_duration.as_secs() * NANOS_PER_SEC
151 + self.remaining_duration.subsec_nanos() as u64;
152 let nanos_per_sample = self.duration_per_sample.as_secs() * NANOS_PER_SEC
153 + self.duration_per_sample.subsec_nanos() as u64;
154 let remaining_samples = (remaining_nanos / nanos_per_sample) as usize;
155
156 self.input
157 .current_frame_len()
158 .filter(|value| *value < remaining_samples)
159 .or(Some(remaining_samples))
160 }
161
162 #[inline]
163 fn channels(&self) -> u16 {
164 self.input.channels()
165 }
166
167 #[inline]
168 fn sample_rate(&self) -> u32 {
169 self.input.sample_rate()
170 }
171
172 #[inline]
173 fn total_duration(&self) -> Option<Duration> {
174 if let Some(duration) = self.input.total_duration() {
175 if duration < self.requested_duration {
176 Some(duration)
177 } else {
178 Some(self.requested_duration)
179 }
180 } else {
181 None
182 }
183 }
184
185 #[inline]
186 fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
187 self.input.try_seek(pos)
188 }
189}