Skip to content

Commit 2c60bf1

Browse files
committed
add tests for buffered, fix buffered parameters_changed
1 parent 39acf88 commit 2c60bf1

File tree

4 files changed

+144
-31
lines changed

4 files changed

+144
-31
lines changed

src/source/buffered.rs

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,25 @@
1+
/// A iterator that stores extracted data in memory while allowing
2+
/// concurrent reading in real time.
13
use std::mem;
24
use std::sync::{Arc, Mutex};
35
use std::time::Duration;
46

57
use super::SeekError;
68
use crate::common::{ChannelCount, SampleRate};
9+
use crate::math::PrevMultipleOf;
710
use crate::Source;
811

9-
/// Iterator that at the same time extracts data from the iterator and stores it in a buffer.
12+
/// Iterator that at the same time extracts data from the iterator and
13+
/// stores it in a buffer.
1014
pub struct Buffered<I>
1115
where
1216
I: Source,
1317
{
1418
/// Immutable reference to the next span of data. Cannot be `Span::Input`.
1519
current_span: Arc<Span<I>>,
1620

21+
parameters_changed: bool,
22+
1723
/// The position in number of samples of this iterator inside `current_span`.
1824
position_in_span: usize,
1925

@@ -30,6 +36,7 @@ impl<I: Source> Buffered<I> {
3036
current_span: first_span,
3137
position_in_span: 0,
3238
total_duration,
39+
parameters_changed: false,
3340
}
3441
}
3542

@@ -46,6 +53,7 @@ impl<I: Source> Buffered<I> {
4653
Span::End => next_span_ptr.clone(),
4754
Span::Input(input) => {
4855
let input = input.lock().unwrap().take().unwrap();
56+
dbg!();
4957
extract(input)
5058
}
5159
};
@@ -70,7 +78,7 @@ where
7078
let current_sample;
7179
let advance_span;
7280

73-
match &*self.current_span {
81+
match dbg!(&*self.current_span) {
7482
Span::Data(SpanData { data, .. }) => {
7583
current_sample = Some(data[self.position_in_span]);
7684
self.position_in_span += 1;
@@ -86,39 +94,31 @@ where
8694
};
8795

8896
if advance_span {
97+
dbg!();
98+
self.parameters_changed = true;
8999
self.next_span();
100+
} else {
101+
self.parameters_changed = false;
90102
}
91103

92104
current_sample
93105
}
94-
95-
#[inline]
96-
fn size_hint(&self) -> (usize, Option<usize>) {
97-
// TODO:
98-
(0, None)
99-
}
100106
}
101107

102-
// TODO: implement exactsize iterator when size_hint is done
103-
104108
impl<I> Source for Buffered<I>
105109
where
106110
I: Source,
107111
{
108112
#[inline]
109113
fn parameters_changed(&self) -> bool {
110-
match &*self.current_span {
111-
Span::Data(_) => false,
112-
Span::End => true,
113-
Span::Input(_) => unreachable!(),
114-
}
114+
self.parameters_changed
115115
}
116116

117117
#[inline]
118118
fn channels(&self) -> ChannelCount {
119119
match *self.current_span {
120120
Span::Data(SpanData { channels, .. }) => channels,
121-
Span::End => 1,
121+
Span::End => 0,
122122
Span::Input(_) => unreachable!(),
123123
}
124124
}
@@ -127,7 +127,7 @@ where
127127
fn sample_rate(&self) -> SampleRate {
128128
match *self.current_span {
129129
Span::Data(SpanData { rate, .. }) => rate,
130-
Span::End => 44100,
130+
Span::End => 0,
131131
Span::Input(_) => unreachable!(),
132132
}
133133
}
@@ -157,6 +157,7 @@ where
157157
current_span: self.current_span.clone(),
158158
position_in_span: self.position_in_span,
159159
total_duration: self.total_duration,
160+
parameters_changed: self.parameters_changed,
160161
}
161162
}
162163
}
@@ -165,8 +166,8 @@ enum Span<I>
165166
where
166167
I: Source,
167168
{
168-
/// Data that has already been extracted from the iterator. Also contains a pointer to the
169-
/// next span.
169+
/// Data that has already been extracted from the iterator.
170+
/// Also contains a pointer to the next span.
170171
Data(SpanData<I>),
171172

172173
/// No more data.
@@ -177,6 +178,16 @@ where
177178
Input(Mutex<Option<I>>),
178179
}
179180

181+
impl<I: Source> std::fmt::Debug for Span<I> {
182+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
183+
match self {
184+
Span::Data(_) => f.write_str("Span::Data"),
185+
Span::End => f.write_str("Span::End"),
186+
Span::Input(_) => f.write_str("Span::Input"),
187+
}
188+
}
189+
}
190+
180191
struct SpanData<I>
181192
where
182193
I: Source,
@@ -221,26 +232,23 @@ fn extract<I>(mut input: I) -> Arc<Span<I>>
221232
where
222233
I: Source,
223234
{
224-
if input.parameters_changed() {
225-
return Arc::new(Span::End);
226-
}
227-
228235
let channels = input.channels();
229236
let rate = input.sample_rate();
230237

231238
let mut data = Vec::new();
232239
loop {
233-
let Some(element) = input.next() else { break };
234-
data.push(element);
240+
let Some(sample) = input.next() else { break };
241+
data.push(sample);
242+
dbg!(sample);
235243
if input.parameters_changed() {
236244
break;
237245
}
238-
if data.len() > 32768 {
246+
if data.len() > 32768.prev_multiple_of(channels) {
239247
break;
240248
}
241249
}
242250

243-
if data.is_empty() {
251+
if dbg!(data.is_empty()) {
244252
return Arc::new(Span::End);
245253
}
246254

tests/buffered.rs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
mod test_support;
2+
use rodio::Source;
3+
use test_support::{TestSource, TestSpan};
4+
5+
#[test]
6+
fn parameters_change_correct() {
7+
let mut source = TestSource::new()
8+
.with_span(TestSpan::silence().with_sample_count(10))
9+
.with_span(TestSpan::silence().with_sample_count(10))
10+
.buffered();
11+
12+
assert_eq!(source.by_ref().take(10).count(), 10);
13+
assert!(source.parameters_changed());
14+
15+
assert!(source.next().is_some());
16+
assert!(!source.parameters_changed());
17+
18+
assert_eq!(source.count(), 9);
19+
}
20+
21+
#[test]
22+
fn channel_count_changes() {
23+
let mut source = TestSource::new()
24+
.with_span(
25+
TestSpan::silence()
26+
.with_channel_count(1)
27+
.with_sample_count(10),
28+
)
29+
.with_span(
30+
TestSpan::silence()
31+
.with_channel_count(2)
32+
.with_sample_count(10),
33+
)
34+
.buffered();
35+
36+
assert_eq!(source.channels(), 1);
37+
assert_eq!(source.by_ref().take(10).count(), 10);
38+
assert_eq!(source.channels(), 2);
39+
}
40+
41+
#[test]
42+
fn buffered_sample_rate_changes() {
43+
let mut source = TestSource::new()
44+
.with_span(
45+
TestSpan::silence()
46+
.with_sample_rate(10)
47+
.with_sample_count(10),
48+
)
49+
.with_span(
50+
TestSpan::silence()
51+
.with_sample_rate(20)
52+
.with_sample_count(10),
53+
)
54+
.buffered();
55+
56+
assert_eq!(source.sample_rate(), 10);
57+
assert_eq!(source.by_ref().take(10).count(), 10);
58+
assert_eq!(source.sample_rate(), 20);
59+
}
60+
61+
#[test]
62+
fn equals_unbuffered() {
63+
let mut source = TestSource::new()
64+
.with_span(
65+
TestSpan::from_samples((0..10).into_iter().map(|n| n as f32))
66+
.with_sample_rate(10)
67+
.with_sample_count(10),
68+
)
69+
.with_span(
70+
TestSpan::silence()
71+
.with_sample_rate(20)
72+
.with_sample_count(10),
73+
);
74+
75+
let mut buffered = source.clone().buffered();
76+
for (sample, expected) in buffered.by_ref().zip(source.by_ref()) {
77+
assert_eq!(sample, expected);
78+
}
79+
80+
assert!(buffered.next().is_none());
81+
assert!(source.next().is_none());
82+
}

tests/peekable.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ use test_support::{TestSource, TestSpan};
66
fn peeked_matches_next() {
77
let source = TestSource::new()
88
.with_span(
9-
TestSpan::from_samples(&(0..10).map(|n| n as f32).collect::<Vec<_>>())
9+
TestSpan::from_samples((0..10).map(|n| n as f32))
1010
.with_sample_count(10),
1111
)
1212
.with_span(
13-
TestSpan::from_samples(&(10..20).map(|n| n as f32).collect::<Vec<_>>())
13+
TestSpan::from_samples((10..20).map(|n| n as f32))
1414
.with_sample_count(10),
1515
);
1616

tests/test_support/mod.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,8 @@ impl TestSpan {
9292
channels: 1,
9393
}
9494
}
95-
pub fn from_samples<'a>(samples: impl IntoIterator<Item = &'a f32>) -> TestSpanBuilder {
96-
let samples = samples.into_iter().copied().collect::<Vec<f32>>();
95+
pub fn from_samples<'a>(samples: impl IntoIterator<Item = Sample>) -> TestSpanBuilder {
96+
let samples = samples.into_iter().collect::<Vec<Sample>>();
9797
TestSpanBuilder {
9898
sample_source: SampleSource::List(samples),
9999
sample_rate: 1,
@@ -306,6 +306,7 @@ impl rodio::Source for TestSource {
306306

307307
// test for your tests of course. Leave these in, they guard regression when we
308308
// expand the functionally which we probably will.
309+
#[test]
309310
fn parameters_change_correct() {
310311
let mut source = TestSource::new()
311312
.with_span(TestSpan::silence().with_sample_count(10))
@@ -381,3 +382,25 @@ fn sine_abs_avg_not_zero() {
381382
let avg = sine.clone().map(f32::abs).sum::<f32>() / sine.spans[0].len() as f32;
382383
assert!(avg > 0.5);
383384
}
385+
386+
#[test]
387+
fn size_hint() {
388+
let mut source = TestSource::new()
389+
.with_span(
390+
TestSpan::silence()
391+
.with_sample_rate(10)
392+
.with_sample_count(10),
393+
)
394+
.with_span(
395+
TestSpan::silence()
396+
.with_sample_rate(20)
397+
.with_sample_count(10),
398+
);
399+
400+
assert_eq!(source.len(), 20);
401+
assert_eq!(source.by_ref().take(10).count(), 10);
402+
assert_eq!(source.len(), 10);
403+
assert_eq!(source.by_ref().take(10).count(), 10);
404+
assert_eq!(source.len(), 0);
405+
assert!(source.next().is_none())
406+
}

0 commit comments

Comments
 (0)