1pub const DEFAULT_AMP_EPSILON: f32 = 0.00001;
2pub const DEFAULT_DB_EPSILON: f32 = -100.0;
3
4use crate::{
5 diff::{Diff, Patch},
6 event::ParamData,
7};
8
9#[derive(Debug, Clone, Copy, PartialEq)]
11pub enum Volume {
12 Linear(f32),
14 Decibels(f32),
16}
17
18impl Volume {
19 pub const UNITY_GAIN: Self = Self::Linear(1.0);
21 pub const SILENT: Self = Self::Linear(0.0);
23
24 pub fn amp(&self) -> f32 {
26 match *self {
27 Self::Linear(volume) => linear_volume_to_amp_clamped(volume, 0.0),
28 Self::Decibels(db) => db_to_amp(db),
29 }
30 }
31
32 pub fn amp_clamped(&self, amp_epsilon: f32) -> f32 {
36 match *self {
37 Self::Linear(volume) => linear_volume_to_amp_clamped(volume, amp_epsilon),
38 Self::Decibels(db) => {
39 if db == f32::NEG_INFINITY {
40 0.0
41 } else {
42 let amp = db_to_amp(db);
43 if amp <= amp_epsilon {
44 0.0
45 } else {
46 amp
47 }
48 }
49 }
50 }
51 }
52
53 pub fn decibels(&self) -> f32 {
55 match *self {
56 Self::Linear(volume) => {
57 if volume == 0.0 {
58 f32::NEG_INFINITY
59 } else {
60 let amp = linear_volume_to_amp_clamped(volume, 0.0);
61 amp_to_db(amp)
62 }
63 }
64 Self::Decibels(db) => db,
65 }
66 }
67
68 pub fn decibels_clamped(&self, db_epsilon: f32) -> f32 {
73 match *self {
74 Self::Linear(volume) => {
75 if volume == 0.0 {
76 f32::NEG_INFINITY
77 } else {
78 let amp = linear_volume_to_amp_clamped(volume, 0.0);
79 let db = amp_to_db(amp);
80 if db <= db_epsilon {
81 f32::NEG_INFINITY
82 } else {
83 db
84 }
85 }
86 }
87 Self::Decibels(db) => {
88 if db <= db_epsilon {
89 f32::NEG_INFINITY
90 } else {
91 db
92 }
93 }
94 }
95 }
96
97 pub fn linear(&self) -> f32 {
99 match *self {
100 Self::Linear(volume) => volume,
101 Self::Decibels(db) => amp_to_linear_volume_clamped(db_to_amp(db), 0.0),
102 }
103 }
104
105 pub fn as_linear_variant(&self) -> Self {
107 Self::Linear(self.linear())
108 }
109
110 pub fn as_decibel_variant(&self) -> Self {
112 Self::Decibels(self.decibels())
113 }
114}
115
116impl Default for Volume {
117 fn default() -> Self {
118 Self::UNITY_GAIN
119 }
120}
121
122impl Diff for Volume {
123 fn diff<E: crate::diff::EventQueue>(
124 &self,
125 baseline: &Self,
126 path: crate::diff::PathBuilder,
127 event_queue: &mut E,
128 ) {
129 if self != baseline {
130 event_queue.push_param(*self, path);
131 }
132 }
133}
134
135impl Patch for Volume {
136 type Patch = Self;
137
138 fn patch(data: &ParamData, _path: &[u32]) -> Result<Self::Patch, crate::diff::PatchError> {
139 data.try_into()
140 }
141
142 fn apply(&mut self, patch: Self::Patch) {
143 *self = patch;
144 }
145}
146
147impl core::ops::Add<Self> for Volume {
148 type Output = Self;
149
150 fn add(self, rhs: Self) -> Self {
151 use Volume::{Decibels, Linear};
152
153 match (self, rhs) {
154 (Linear(a), Linear(b)) => Linear(a + b),
155 (Decibels(a), Decibels(b)) => Decibels(amp_to_db(db_to_amp(a) + db_to_amp(b))),
156 (Linear(..), Decibels(..)) => self + rhs.as_linear_variant(),
160 (Decibels(..), Linear(..)) => self + rhs.as_decibel_variant(),
161 }
162 }
163}
164
165impl core::ops::Sub<Self> for Volume {
166 type Output = Self;
167
168 fn sub(self, rhs: Self) -> Self {
169 use Volume::{Decibels, Linear};
170
171 match (self, rhs) {
172 (Linear(a), Linear(b)) => Linear(a - b),
173 (Decibels(a), Decibels(b)) => Decibels(amp_to_db(db_to_amp(a) - db_to_amp(b))),
174 (Linear(..), Decibels(..)) => self - rhs.as_linear_variant(),
178 (Decibels(..), Linear(..)) => self - rhs.as_decibel_variant(),
179 }
180 }
181}
182
183impl core::ops::Mul<Self> for Volume {
184 type Output = Self;
185
186 fn mul(self, rhs: Self) -> Self {
187 use Volume::{Decibels, Linear};
188
189 match (self, rhs) {
190 (Linear(a), Linear(b)) => Linear(a * b),
191 (Decibels(a), Decibels(b)) => Decibels(amp_to_db(db_to_amp(a) * db_to_amp(b))),
192 (Linear(..), Decibels(..)) => self * rhs.as_linear_variant(),
196 (Decibels(..), Linear(..)) => self * rhs.as_decibel_variant(),
197 }
198 }
199}
200
201impl core::ops::Div<Self> for Volume {
202 type Output = Self;
203
204 fn div(self, rhs: Self) -> Self {
205 use Volume::{Decibels, Linear};
206
207 match (self, rhs) {
208 (Linear(a), Linear(b)) => Linear(a / b),
209 (Decibels(a), Decibels(b)) => Decibels(amp_to_db(db_to_amp(a) / db_to_amp(b))),
210 (Linear(..), Decibels(..)) => self / rhs.as_linear_variant(),
214 (Decibels(..), Linear(..)) => self / rhs.as_decibel_variant(),
215 }
216 }
217}
218
219impl core::ops::AddAssign<Self> for Volume {
220 fn add_assign(&mut self, rhs: Self) {
221 *self = *self + rhs;
222 }
223}
224
225impl core::ops::SubAssign<Self> for Volume {
226 fn sub_assign(&mut self, rhs: Self) {
227 *self = *self - rhs;
228 }
229}
230
231impl core::ops::MulAssign<Self> for Volume {
232 fn mul_assign(&mut self, rhs: Self) {
233 *self = *self * rhs;
234 }
235}
236
237impl core::ops::DivAssign<Self> for Volume {
238 fn div_assign(&mut self, rhs: Self) {
239 *self = *self / rhs;
240 }
241}
242
243#[inline]
245pub fn db_to_amp(db: f32) -> f32 {
246 if db == f32::NEG_INFINITY {
247 0.0
248 } else {
249 10.0f32.powf(0.05 * db)
250 }
251}
252
253#[inline]
255pub fn amp_to_db(amp: f32) -> f32 {
256 if amp == 0.0 {
257 f32::NEG_INFINITY
258 } else {
259 20.0 * amp.log10()
260 }
261}
262
263#[inline]
268pub fn db_to_amp_clamped(db: f32, db_epsilon: f32) -> f32 {
269 if db == f32::NEG_INFINITY || db <= db_epsilon {
270 0.0
271 } else {
272 db_to_amp(db)
273 }
274}
275
276#[inline]
280pub fn amp_to_db_clamped(amp: f32, amp_epsilon: f32) -> f32 {
281 if amp <= amp_epsilon {
282 f32::NEG_INFINITY
283 } else {
284 amp_to_db(amp)
285 }
286}
287
288#[inline]
295pub fn linear_volume_to_amp_clamped(linear_volume: f32, amp_epsilon: f32) -> f32 {
296 let v = linear_volume * linear_volume;
297 if v <= amp_epsilon {
298 0.0
299 } else {
300 v
301 }
302}
303
304#[inline]
310pub fn amp_to_linear_volume_clamped(amp: f32, amp_epsilon: f32) -> f32 {
311 if amp <= amp_epsilon {
312 0.0
313 } else {
314 amp.sqrt()
315 }
316}
317
318#[derive(Debug, Clone, Copy, PartialEq)]
321pub struct DbMeterNormalizer {
322 min_db: f32,
323 range_recip: f32,
324 factor: f32,
325}
326
327impl DbMeterNormalizer {
328 pub fn new(min_db: f32, max_db: f32, center_db: f32) -> Self {
334 assert!(max_db > min_db);
335 assert!(center_db > min_db && center_db < max_db);
336
337 let range_recip = (max_db - min_db).recip();
338 let center_normalized = ((center_db - min_db) * range_recip).clamp(0.0, 1.0);
339
340 Self {
341 min_db,
342 range_recip,
343 factor: 0.5_f32.log(center_normalized),
344 }
345 }
346
347 #[inline]
348 pub fn normalize(&self, db: f32) -> f32 {
349 ((db - self.min_db) * self.range_recip)
350 .clamp(0.0, 1.0)
351 .powf(self.factor)
352 }
353}
354
355impl Default for DbMeterNormalizer {
356 fn default() -> Self {
357 Self::new(-100.0, 0.0, -22.0)
358 }
359}