dasp_signal/interpolate.rs
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 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
//! The [**Converter**](./struct.Converter.html) type for interpolating the rate of a signal.
use crate::Signal;
use dasp_interpolate::Interpolator;
/// A signal type that converts the rate at which frames are yielded from some source signal to
/// some target rate.
///
/// Other names for `sample::interpolate::Converter` might include:
///
/// - Sample rate converter.
/// - {Up/Down}sampler.
/// - Sample interpolater.
/// - Sample decimator.
#[derive(Clone)]
pub struct Converter<S, I>
where
S: Signal,
I: Interpolator,
{
source: S,
interpolator: I,
interpolation_value: f64,
source_to_target_ratio: f64,
}
impl<S, I> Converter<S, I>
where
S: Signal,
I: Interpolator,
{
/// Construct a new `Converter` from the source frames and the source and target sample rates
/// (in Hz).
#[inline]
pub fn from_hz_to_hz(source: S, interpolator: I, source_hz: f64, target_hz: f64) -> Self {
Self::scale_playback_hz(source, interpolator, source_hz / target_hz)
}
/// Construct a new `Converter` from the source frames and the amount by which the current
/// ***playback*** **rate** (not sample rate) should be multiplied to reach the new playback
/// rate.
///
/// For example, if our `source_frames` is a sine wave oscillating at a frequency of 2hz and
/// we wanted to convert it to a frequency of 3hz, the given `scale` should be `1.5`.
#[inline]
pub fn scale_playback_hz(source: S, interpolator: I, scale: f64) -> Self {
assert!(
scale > 0.0,
"We can't yield any frames at 0 times a second!"
);
Converter {
source: source,
interpolator: interpolator,
interpolation_value: 0.0,
source_to_target_ratio: scale,
}
}
/// Construct a new `Converter` from the source frames and the amount by which the current
/// ***sample*** **rate** (not playback rate) should be multiplied to reach the new sample
/// rate.
///
/// If our `source_frames` are being sampled at a rate of 44_100hz and we want to
/// convert to a sample rate of 96_000hz, the given `scale` should be `96_000.0 / 44_100.0`.
///
/// This is the same as calling `Converter::scale_playback_hz(source_frames, 1.0 / scale)`.
#[inline]
pub fn scale_sample_hz(source: S, interpolator: I, scale: f64) -> Self {
Self::scale_playback_hz(source, interpolator, 1.0 / scale)
}
/// Update the `source_to_target_ratio` internally given the source and target hz.
///
/// This method might be useful for changing the sample rate during playback.
#[inline]
pub fn set_hz_to_hz(&mut self, source_hz: f64, target_hz: f64) {
self.set_playback_hz_scale(source_hz / target_hz)
}
/// Update the `source_to_target_ratio` internally given a new **playback rate** multiplier.
///
/// This method is useful for dynamically changing rates.
#[inline]
pub fn set_playback_hz_scale(&mut self, scale: f64) {
self.source_to_target_ratio = scale;
}
/// Update the `source_to_target_ratio` internally given a new **sample rate** multiplier.
///
/// This method is useful for dynamically changing rates.
#[inline]
pub fn set_sample_hz_scale(&mut self, scale: f64) {
self.set_playback_hz_scale(1.0 / scale);
}
/// Borrow the `source_frames` Interpolator from the `Converter`.
#[inline]
pub fn source(&self) -> &S {
&self.source
}
/// Mutably borrow the `source_frames` Iterator from the `Converter`.
#[inline]
pub fn source_mut(&mut self) -> &mut S {
&mut self.source
}
/// Drop `self` and return the internal `source_frames` Iterator.
#[inline]
pub fn into_source(self) -> S {
self.source
}
}
impl<S, I> Signal for Converter<S, I>
where
S: Signal,
I: Interpolator<Frame = S::Frame>,
{
type Frame = S::Frame;
fn next(&mut self) -> Self::Frame {
let Converter {
ref mut source,
ref mut interpolator,
ref mut interpolation_value,
source_to_target_ratio,
} = *self;
// Advance frames
while *interpolation_value >= 1.0 {
interpolator.next_source_frame(source.next());
*interpolation_value -= 1.0;
}
let out = interpolator.interpolate(*interpolation_value);
*interpolation_value += source_to_target_ratio;
out
}
fn is_exhausted(&self) -> bool {
self.source.is_exhausted() && self.interpolation_value >= 1.0
}
}