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