1use std::time::Duration;
2
3use super::SeekError;
4use crate::common::{ChannelCount, SampleRate};
5use crate::Source;
6
7pub fn periodic<I, F>(source: I, period: Duration, modifier: F) -> PeriodicAccess<I, F>
9where
10 I: Source,
11{
12 let update_ms = period.as_secs() as u32 * 1_000 + period.subsec_millis();
15 let update_frequency = (update_ms * source.sample_rate()) / 1000 * source.channels() as u32;
16
17 PeriodicAccess {
18 input: source,
19 modifier,
20 update_frequency: if update_frequency == 0 {
22 1
23 } else {
24 update_frequency
25 },
26 samples_until_update: 1,
27 }
28}
29
30#[derive(Clone, Debug)]
32pub struct PeriodicAccess<I, F> {
33 input: I,
35
36 modifier: F,
38
39 update_frequency: u32,
41
42 samples_until_update: u32,
44}
45
46impl<I, F> PeriodicAccess<I, F>
47where
48 I: Source,
49
50 F: FnMut(&mut I),
51{
52 #[inline]
54 pub fn inner(&self) -> &I {
55 &self.input
56 }
57
58 #[inline]
60 pub fn inner_mut(&mut self) -> &mut I {
61 &mut self.input
62 }
63
64 #[inline]
66 pub fn into_inner(self) -> I {
67 self.input
68 }
69}
70
71impl<I, F> Iterator for PeriodicAccess<I, F>
72where
73 I: Source,
74
75 F: FnMut(&mut I),
76{
77 type Item = I::Item;
78
79 #[inline]
80 fn next(&mut self) -> Option<I::Item> {
81 self.samples_until_update -= 1;
82 if self.samples_until_update == 0 {
83 (self.modifier)(&mut self.input);
84 self.samples_until_update = self.update_frequency;
85 }
86
87 self.input.next()
88 }
89
90 #[inline]
91 fn size_hint(&self) -> (usize, Option<usize>) {
92 self.input.size_hint()
93 }
94}
95
96impl<I, F> Source for PeriodicAccess<I, F>
97where
98 I: Source,
99
100 F: FnMut(&mut I),
101{
102 #[inline]
103 fn current_span_len(&self) -> Option<usize> {
104 self.input.current_span_len()
105 }
106
107 #[inline]
108 fn channels(&self) -> ChannelCount {
109 self.input.channels()
110 }
111
112 #[inline]
113 fn sample_rate(&self) -> SampleRate {
114 self.input.sample_rate()
115 }
116
117 #[inline]
118 fn total_duration(&self) -> Option<Duration> {
119 self.input.total_duration()
120 }
121
122 #[inline]
123 fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
124 self.input.try_seek(pos)
125 }
126}
127
128#[cfg(test)]
129mod tests {
130 use std::cell::RefCell;
131 use std::time::Duration;
132
133 use crate::buffer::SamplesBuffer;
134 use crate::source::Source;
135
136 #[test]
137 fn stereo_access() {
138 let inner = SamplesBuffer::new(2, 1, vec![10.0, -10.0, 10.0, -10.0, 20.0, -20.0]);
140
141 let cnt = RefCell::new(0);
142
143 let mut source = inner.periodic_access(Duration::from_millis(1000), |_src| {
144 *cnt.borrow_mut() += 1;
145 });
146
147 assert_eq!(*cnt.borrow(), 0);
148 assert_eq!(source.next(), Some(10.0));
150 assert_eq!(*cnt.borrow(), 1);
151 assert_eq!(source.next(), Some(-10.0));
153 assert_eq!(*cnt.borrow(), 1);
154 assert_eq!(source.next(), Some(10.0));
155 assert_eq!(*cnt.borrow(), 2);
156 assert_eq!(source.next(), Some(-10.0));
157 assert_eq!(*cnt.borrow(), 2);
158 assert_eq!(source.next(), Some(20.0));
159 assert_eq!(*cnt.borrow(), 3);
160 assert_eq!(source.next(), Some(-20.0));
161 assert_eq!(*cnt.borrow(), 3);
162 }
163
164 #[test]
165 fn fast_access_overflow() {
166 let inner = SamplesBuffer::new(1, 1, vec![10.0, -10.0, 10.0, -10.0, 20.0, -20.0]);
168 let mut source = inner.periodic_access(Duration::from_millis(5), |_src| {});
169
170 source.next();
171 source.next(); }
173}