1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
//! Add two streams.
//!
//! To add a constant value to a stream, instead use `AddConst`.
use crate::Sample;
use crate::stream::{ReadStream, WriteStream};
/// Adds two streams, sample wise.
///
/// Output tags are taken from the first stream. Tags from the other input
/// stream is discarded.
///
/// To add a constant value to a stream, instead use `AddConst`.
///
/// ```
/// use rustradio::graph::{Graph, GraphRunner};
/// use rustradio::blocks::{ConstantSource, SignalSourceFloat, Add, NullSink};
///
/// let mut graph = Graph::new();
///
/// // Add a constant value. Could just as well use AddConst instead of Add.
/// let (src1, src1_out) = ConstantSource::new(1.0);
/// let (src2, src2_out) = SignalSourceFloat::new(44100.0, 1000.0, 1.0);
///
/// // Sum up the streams.
/// let (sum, sum_out) = Add::new(src1_out, src2_out);
///
/// graph.add(Box::new(src1));
/// graph.add(Box::new(src2));
/// graph.add(Box::new(sum));
///
/// // Set up dummy sink.
/// let sink = NullSink::new(sum_out);
/// # return Ok(());
/// graph.run()?;
/// # Ok::<(), anyhow::Error>(())
/// ```
#[derive(rustradio_macros::Block)]
#[rustradio(crate, new, sync)]
pub struct Add<Ta, Tb, Tout>
where
Ta: Sample + std::ops::Add<Tb, Output = Tout>,
Tb: Sample,
Tout: Sample,
{
#[rustradio(in)]
a: ReadStream<Ta>,
#[rustradio(in)]
b: ReadStream<Tb>,
#[rustradio(out)]
dst: WriteStream<Tout>,
}
impl<Ta, Tb, Tout> Add<Ta, Tb, Tout>
where
Ta: Sample + std::ops::Add<Tb, Output = Tout>,
Tb: Sample,
Tout: Sample,
{
fn process_sync(&self, a: Ta, b: Tb) -> Tout {
a + b
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Float;
use crate::block::Block;
use crate::blocks::VectorSource;
use crate::stream::{Tag, TagValue};
#[test]
fn add_float() -> crate::Result<()> {
// Testing VectorSource too, because why not.
let input_a: Vec<_> = (0..10).map(|i| i as Float).collect();
let (mut ablock, a) = VectorSource::new(input_a);
ablock.work()?;
let input_b: Vec<_> = (0..20).map(|i| 2.0 * (i as Float)).collect();
let (mut bblock, b) = VectorSource::new(input_b);
bblock.work()?;
let (mut add, os) = Add::new(a, b);
add.work()?;
let (res, tags) = os.read_buf()?;
let want: Vec<_> = (0..10).map(|i| 3 * i).collect();
let got: Vec<_> = res.slice().iter().map(|f| *f as usize).collect();
assert_eq!(got, want);
assert_eq!(
tags,
&[
Tag::new(0, "VectorSource::start", TagValue::Bool(true)),
Tag::new(0, "VectorSource::repeat", TagValue::U64(0)),
Tag::new(0, "VectorSource::first", TagValue::Bool(true))
]
);
Ok(())
}
}
/* vim: textwidth=80
*/