1use std::collections::BTreeMap;
9
10fn python_sort_run(points: &mut [(f64, f64)]) -> usize {
11 if points.len() < 2 {
12 return points.len();
13 }
14 let mut n = 1;
15 while n < points.len()
16 && points[n].0.partial_cmp(&points[n - 1].0) != Some(std::cmp::Ordering::Less)
17 {
18 n += 1;
19 }
20 if n == points.len() {
21 return n;
22 }
23 if n > 1 {
24 if points[0].0 < points[n - 1].0 {
25 return n;
26 }
27 points[..n].reverse();
28 }
29 n += 1;
30 let mut equal_tail = 0;
31 while n < points.len() {
32 if points[n].0 < points[n - 1].0 {
33 if equal_tail != 0 {
34 points[n - equal_tail - 1..n].reverse();
35 equal_tail = 0;
36 }
37 } else if points[n - 1].0 < points[n].0 {
38 break;
39 } else {
40 equal_tail += 1;
41 }
42 n += 1;
43 }
44 if equal_tail != 0 {
45 points[n - equal_tail - 1..n].reverse();
46 }
47 points[..n].reverse();
48 while n < points.len()
49 && points[n].0.partial_cmp(&points[n - 1].0) != Some(std::cmp::Ordering::Less)
50 {
51 n += 1;
52 }
53 n
54}
55
56#[derive(Debug, Clone, PartialEq)]
58pub struct TargetCurve {
59 pub points: Vec<(f64, f64)>,
60}
61impl Default for TargetCurve {
62 fn default() -> Self {
63 Self::new(vec![
64 (25., 2.),
65 (80., 2.),
66 (200., 0.),
67 (1000., 0.),
68 (16000., -2.),
69 ])
70 }
71}
72impl TargetCurve {
73 pub fn new(points: Vec<(f64, f64)>) -> Self {
74 let mut s = Self { points };
75 s.sort();
76 s
77 }
78 pub fn sort(&mut self) {
79 let sorted = python_sort_run(&mut self.points);
83 for index in sorted..self.points.len() {
84 let point = self.points[index];
85 let mut lo = 0;
86 let mut hi = index;
87 while lo < hi {
88 let mid = (lo + hi) / 2;
89 if point.0 < self.points[mid].0 {
90 hi = mid;
91 } else {
92 lo = mid + 1;
93 }
94 }
95 self.points[lo..=index].rotate_right(1);
96 }
97 }
98 pub fn at(&self, f: f64) -> f64 {
99 if self.points.is_empty() {
100 return 0.;
101 }
102 if f <= self.points[0].0 {
103 return self.points[0].1;
104 }
105 if f >= self.points[self.points.len() - 1].0 {
106 return self.points[self.points.len() - 1].1;
107 }
108 for w in self.points.windows(2) {
109 let ((fa, da), (fb, db)) = (w[0], w[1]);
110 if fa <= f && f <= fb {
111 let t = (f.ln() - fa.ln()) / (fb.ln() - fa.ln());
112 let u = t * t * (3. - 2. * t);
113 return da + (db - da) * u;
114 }
115 }
116 0.
117 }
118 pub fn sample(&self, freqs: &[f64]) -> Vec<f64> {
119 freqs.iter().map(|&f| self.at(f)).collect()
120 }
121 pub fn presets() -> BTreeMap<&'static str, Self> {
122 [
123 (
124 "flat",
125 vec![(25., 0.), (200., 0.), (1000., 0.), (16000., 0.)],
126 ),
127 (
128 "harman",
129 vec![(25., 6.), (60., 5.), (120., 1.), (1000., 0.), (16000., -3.)],
130 ),
131 (
132 "cinema",
133 vec![
134 (25., 4.),
135 (80., 3.),
136 (200., 0.),
137 (1000., -1.),
138 (16000., -5.),
139 ],
140 ),
141 ]
142 .into_iter()
143 .map(|(k, v)| (k, Self::new(v)))
144 .collect()
145 }
146}