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(ParamData::Volume(*self), path);
131 }
132 }
133}
134
135impl Patch for Volume {
136 fn patch(&mut self, data: &ParamData, _path: &[u32]) -> Result<(), crate::diff::PatchError> {
137 *self = data.try_into()?;
138 Ok(())
139 }
140}
141
142impl core::ops::Add<Self> for Volume {
143 type Output = Self;
144
145 fn add(self, rhs: Self) -> Self {
146 use Volume::{Decibels, Linear};
147
148 match (self, rhs) {
149 (Linear(a), Linear(b)) => Linear(a + b),
150 (Decibels(a), Decibels(b)) => Decibels(amp_to_db(db_to_amp(a) + db_to_amp(b))),
151 (Linear(..), Decibels(..)) => self + rhs.as_linear_variant(),
155 (Decibels(..), Linear(..)) => self + rhs.as_decibel_variant(),
156 }
157 }
158}
159
160impl core::ops::Sub<Self> for Volume {
161 type Output = Self;
162
163 fn sub(self, rhs: Self) -> Self {
164 use Volume::{Decibels, Linear};
165
166 match (self, rhs) {
167 (Linear(a), Linear(b)) => Linear(a - b),
168 (Decibels(a), Decibels(b)) => Decibels(amp_to_db(db_to_amp(a) - db_to_amp(b))),
169 (Linear(..), Decibels(..)) => self - rhs.as_linear_variant(),
173 (Decibels(..), Linear(..)) => self - rhs.as_decibel_variant(),
174 }
175 }
176}
177
178impl core::ops::Mul<Self> for Volume {
179 type Output = Self;
180
181 fn mul(self, rhs: Self) -> Self {
182 use Volume::{Decibels, Linear};
183
184 match (self, rhs) {
185 (Linear(a), Linear(b)) => Linear(a * b),
186 (Decibels(a), Decibels(b)) => Decibels(amp_to_db(db_to_amp(a) * db_to_amp(b))),
187 (Linear(..), Decibels(..)) => self * rhs.as_linear_variant(),
191 (Decibels(..), Linear(..)) => self * rhs.as_decibel_variant(),
192 }
193 }
194}
195
196impl core::ops::Div<Self> for Volume {
197 type Output = Self;
198
199 fn div(self, rhs: Self) -> Self {
200 use Volume::{Decibels, Linear};
201
202 match (self, rhs) {
203 (Linear(a), Linear(b)) => Linear(a / b),
204 (Decibels(a), Decibels(b)) => Decibels(amp_to_db(db_to_amp(a) / db_to_amp(b))),
205 (Linear(..), Decibels(..)) => self / rhs.as_linear_variant(),
209 (Decibels(..), Linear(..)) => self / rhs.as_decibel_variant(),
210 }
211 }
212}
213
214impl core::ops::AddAssign<Self> for Volume {
215 fn add_assign(&mut self, rhs: Self) {
216 *self = *self + rhs;
217 }
218}
219
220impl core::ops::SubAssign<Self> for Volume {
221 fn sub_assign(&mut self, rhs: Self) {
222 *self = *self - rhs;
223 }
224}
225
226impl core::ops::MulAssign<Self> for Volume {
227 fn mul_assign(&mut self, rhs: Self) {
228 *self = *self * rhs;
229 }
230}
231
232impl core::ops::DivAssign<Self> for Volume {
233 fn div_assign(&mut self, rhs: Self) {
234 *self = *self / rhs;
235 }
236}
237
238#[inline]
240pub fn db_to_amp(db: f32) -> f32 {
241 if db == f32::NEG_INFINITY {
242 0.0
243 } else {
244 10.0f32.powf(0.05 * db)
245 }
246}
247
248#[inline]
250pub fn amp_to_db(amp: f32) -> f32 {
251 if amp == 0.0 {
252 f32::NEG_INFINITY
253 } else {
254 20.0 * amp.log10()
255 }
256}
257
258#[inline]
263pub fn db_to_amp_clamped(db: f32, db_epsilon: f32) -> f32 {
264 if db == f32::NEG_INFINITY || db <= db_epsilon {
265 0.0
266 } else {
267 db_to_amp(db)
268 }
269}
270
271#[inline]
275pub fn amp_to_db_clamped(amp: f32, amp_epsilon: f32) -> f32 {
276 if amp <= amp_epsilon {
277 f32::NEG_INFINITY
278 } else {
279 amp_to_db(amp)
280 }
281}
282
283#[inline]
290pub fn linear_volume_to_amp_clamped(linear_volume: f32, amp_epsilon: f32) -> f32 {
291 let v = linear_volume * linear_volume;
292 if v <= amp_epsilon {
293 0.0
294 } else {
295 v
296 }
297}
298
299#[inline]
305pub fn amp_to_linear_volume_clamped(amp: f32, amp_epsilon: f32) -> f32 {
306 if amp <= amp_epsilon {
307 0.0
308 } else {
309 amp.sqrt()
310 }
311}
312
313#[derive(Debug, Clone, Copy, PartialEq)]
316pub struct DbMeterNormalizer {
317 min_db: f32,
318 range_recip: f32,
319 factor: f32,
320}
321
322impl DbMeterNormalizer {
323 pub fn new(min_db: f32, max_db: f32, center_db: f32) -> Self {
329 assert!(max_db > min_db);
330 assert!(center_db > min_db && center_db < max_db);
331
332 let range_recip = (max_db - min_db).recip();
333 let center_normalized = ((center_db - min_db) * range_recip).clamp(0.0, 1.0);
334
335 Self {
336 min_db,
337 range_recip,
338 factor: 0.5_f32.log(center_normalized),
339 }
340 }
341
342 #[inline]
343 pub fn normalize(&self, db: f32) -> f32 {
344 ((db - self.min_db) * self.range_recip)
345 .clamp(0.0, 1.0)
346 .powf(self.factor)
347 }
348}
349
350impl Default for DbMeterNormalizer {
351 fn default() -> Self {
352 Self::new(-100.0, 0.0, -22.0)
353 }
354}