dasp_signal/interpolate.rs
1//! The [**Converter**](./struct.Converter.html) type for interpolating the rate of a signal.
2
3use crate::Signal;
4use dasp_interpolate::Interpolator;
5
6/// A signal type that converts the rate at which frames are yielded from some source signal to
7/// some target rate.
8///
9/// Other names for `sample::interpolate::Converter` might include:
10///
11/// - Sample rate converter.
12/// - {Up/Down}sampler.
13/// - Sample interpolater.
14/// - Sample decimator.
15#[derive(Clone)]
16pub struct Converter<S, I>
17where
18 S: Signal,
19 I: Interpolator,
20{
21 source: S,
22 interpolator: I,
23 interpolation_value: f64,
24 source_to_target_ratio: f64,
25}
26
27impl<S, I> Converter<S, I>
28where
29 S: Signal,
30 I: Interpolator,
31{
32 /// Construct a new `Converter` from the source frames and the source and target sample rates
33 /// (in Hz).
34 #[inline]
35 pub fn from_hz_to_hz(source: S, interpolator: I, source_hz: f64, target_hz: f64) -> Self {
36 Self::scale_playback_hz(source, interpolator, source_hz / target_hz)
37 }
38
39 /// Construct a new `Converter` from the source frames and the amount by which the current
40 /// ***playback*** **rate** (not sample rate) should be multiplied to reach the new playback
41 /// rate.
42 ///
43 /// For example, if our `source_frames` is a sine wave oscillating at a frequency of 2hz and
44 /// we wanted to convert it to a frequency of 3hz, the given `scale` should be `1.5`.
45 #[inline]
46 pub fn scale_playback_hz(source: S, interpolator: I, scale: f64) -> Self {
47 assert!(
48 scale > 0.0,
49 "We can't yield any frames at 0 times a second!"
50 );
51 Converter {
52 source: source,
53 interpolator: interpolator,
54 interpolation_value: 0.0,
55 source_to_target_ratio: scale,
56 }
57 }
58
59 /// Construct a new `Converter` from the source frames and the amount by which the current
60 /// ***sample*** **rate** (not playback rate) should be multiplied to reach the new sample
61 /// rate.
62 ///
63 /// If our `source_frames` are being sampled at a rate of 44_100hz and we want to
64 /// convert to a sample rate of 96_000hz, the given `scale` should be `96_000.0 / 44_100.0`.
65 ///
66 /// This is the same as calling `Converter::scale_playback_hz(source_frames, 1.0 / scale)`.
67 #[inline]
68 pub fn scale_sample_hz(source: S, interpolator: I, scale: f64) -> Self {
69 Self::scale_playback_hz(source, interpolator, 1.0 / scale)
70 }
71
72 /// Update the `source_to_target_ratio` internally given the source and target hz.
73 ///
74 /// This method might be useful for changing the sample rate during playback.
75 #[inline]
76 pub fn set_hz_to_hz(&mut self, source_hz: f64, target_hz: f64) {
77 self.set_playback_hz_scale(source_hz / target_hz)
78 }
79
80 /// Update the `source_to_target_ratio` internally given a new **playback rate** multiplier.
81 ///
82 /// This method is useful for dynamically changing rates.
83 #[inline]
84 pub fn set_playback_hz_scale(&mut self, scale: f64) {
85 self.source_to_target_ratio = scale;
86 }
87
88 /// Update the `source_to_target_ratio` internally given a new **sample rate** multiplier.
89 ///
90 /// This method is useful for dynamically changing rates.
91 #[inline]
92 pub fn set_sample_hz_scale(&mut self, scale: f64) {
93 self.set_playback_hz_scale(1.0 / scale);
94 }
95
96 /// Borrow the `source_frames` Interpolator from the `Converter`.
97 #[inline]
98 pub fn source(&self) -> &S {
99 &self.source
100 }
101
102 /// Mutably borrow the `source_frames` Iterator from the `Converter`.
103 #[inline]
104 pub fn source_mut(&mut self) -> &mut S {
105 &mut self.source
106 }
107
108 /// Drop `self` and return the internal `source_frames` Iterator.
109 #[inline]
110 pub fn into_source(self) -> S {
111 self.source
112 }
113}
114
115impl<S, I> Signal for Converter<S, I>
116where
117 S: Signal,
118 I: Interpolator<Frame = S::Frame>,
119{
120 type Frame = S::Frame;
121
122 fn next(&mut self) -> Self::Frame {
123 let Converter {
124 ref mut source,
125 ref mut interpolator,
126 ref mut interpolation_value,
127 source_to_target_ratio,
128 } = *self;
129
130 // Advance frames
131 while *interpolation_value >= 1.0 {
132 interpolator.next_source_frame(source.next());
133 *interpolation_value -= 1.0;
134 }
135
136 let out = interpolator.interpolate(*interpolation_value);
137 *interpolation_value += source_to_target_ratio;
138 out
139 }
140
141 fn is_exhausted(&self) -> bool {
142 self.source.is_exhausted() && self.interpolation_value >= 1.0
143 }
144}