Skip to content

Commit d012675

Browse files
committed
Merge branch 'rational'
2 parents 2843504 + 0c46eeb commit d012675

File tree

5 files changed

+163
-71
lines changed

5 files changed

+163
-71
lines changed

Cargo.lock

Lines changed: 46 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ repository = "https://github.com/DrPeaboss/simple_src"
99
keywords = ["audio", "dsp", "sample-rate"]
1010
exclude = ["*.py"]
1111

12+
[dependencies]
13+
num-rational = "0.4"
14+
1215
[dev-dependencies]
1316
divan = "0.1.14"
1417
hound = "3.5.1"

src/lib.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,17 +62,23 @@ pub trait Convert {
6262
}
6363
}
6464

65-
const MIN_RATIO: f64 = 0.01;
66-
const MAX_RATIO: f64 = 100.0;
67-
6865
#[derive(Debug)]
6966
pub enum Error {
70-
InvalidRatio,
67+
UnsupportedRatio,
7168
InvalidParam,
7269
}
7370

7471
pub type Result<T> = std::result::Result<T, Error>;
7572

73+
use num_rational::Rational64;
74+
75+
fn supported_ratio(ratio: Rational64) -> bool {
76+
ratio > Rational64::default()
77+
&& *ratio.numer() <= 1024
78+
&& ratio.ceil().to_integer() <= 16
79+
&& ratio.recip().ceil().to_integer() <= 16
80+
}
81+
7682
#[cfg(test)]
7783
mod tests {
7884
use super::*;

src/linear.rs

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
//! Linear converter
22
3+
use num_rational::Rational64;
4+
5+
use crate::supported_ratio;
6+
37
use super::{Convert, Error, Result};
48

59
enum State {
@@ -9,18 +13,28 @@ enum State {
913
}
1014

1115
pub struct Converter {
12-
step: f64,
13-
pos: f64,
16+
numer: usize,
17+
denom: usize,
18+
pos: usize,
19+
coefs: Vec<f64>,
1420
last_in: [f64; 2],
1521
state: State,
1622
}
1723

1824
impl Converter {
1925
#[inline]
20-
fn new(step: f64) -> Self {
26+
fn new(step: Rational64) -> Self {
27+
let numer = *step.numer() as usize;
28+
let denom = *step.denom() as usize;
29+
let mut coefs = Vec::with_capacity(denom);
30+
for i in 0..denom {
31+
coefs.push(i as f64 / denom as f64);
32+
}
2133
Self {
22-
step,
23-
pos: 0.0,
34+
numer,
35+
denom,
36+
pos: 0,
37+
coefs,
2438
last_in: [0.0; 2],
2539
state: State::First,
2640
}
@@ -38,15 +52,15 @@ impl Convert for Converter {
3852
State::First => {
3953
if let Some(s) = iter.next() {
4054
self.last_in[1] = s;
41-
self.pos = 1.0;
55+
self.pos = self.numer;
4256
self.state = State::Normal;
4357
} else {
4458
return None;
4559
}
4660
}
4761
State::Normal => {
48-
while self.pos >= 1.0 {
49-
self.pos -= 1.0;
62+
while self.pos >= self.denom {
63+
self.pos -= self.denom;
5064
self.last_in[0] = self.last_in[1];
5165
if let Some(s) = iter.next() {
5266
self.last_in[1] = s;
@@ -55,8 +69,9 @@ impl Convert for Converter {
5569
return None;
5670
}
5771
}
58-
let interp = self.last_in[0] + (self.last_in[1] - self.last_in[0]) * self.pos;
59-
self.pos += self.step;
72+
let coef = self.coefs[self.pos];
73+
let interp = self.last_in[0] + (self.last_in[1] - self.last_in[0]) * coef;
74+
self.pos += self.numer;
6075
return Some(interp);
6176
}
6277
State::Suspend => {
@@ -72,20 +87,19 @@ impl Convert for Converter {
7287
}
7388
}
7489

75-
use super::{MAX_RATIO, MIN_RATIO};
76-
7790
#[derive(Clone, Copy)]
7891
pub struct Manager {
79-
ratio: f64,
92+
ratio: Rational64,
8093
}
8194

8295
impl Manager {
8396
#[inline]
8497
pub fn new(ratio: f64) -> Result<Self> {
85-
if (MIN_RATIO..=MAX_RATIO).contains(&ratio) {
98+
let ratio = Rational64::approximate_float(ratio).unwrap_or_default();
99+
if supported_ratio(ratio) {
86100
Ok(Self { ratio })
87101
} else {
88-
Err(Error::InvalidRatio)
102+
Err(Error::UnsupportedRatio)
89103
}
90104
}
91105

@@ -101,7 +115,7 @@ mod tests {
101115

102116
#[test]
103117
fn test_manager_ok() {
104-
let ratio_ok = vec![0.01, 1.0, 10.0, 99.99, 100.0];
118+
let ratio_ok = vec![0.0625, 0.063, 1.0, 15.9, 16.0];
105119
for ratio in ratio_ok {
106120
assert!(Manager::new(ratio).is_ok());
107121
}
@@ -112,8 +126,9 @@ mod tests {
112126
let ratio_err = vec![
113127
-1.0,
114128
0.0,
115-
100.01,
116-
1000.0,
129+
0.0624,
130+
16.01,
131+
0.123456,
117132
f64::INFINITY,
118133
f64::NEG_INFINITY,
119134
f64::NAN,

0 commit comments

Comments
 (0)