Skip to content

Commit b072893

Browse files
fix: make block-driven events audio-driven so that they are consistent across framerates, etc.
Signed-off-by: Maika Namuo <httpworldview@gmail.com>
1 parent 45bc076 commit b072893

13 files changed

Lines changed: 253 additions & 212 deletions

File tree

‎src/dsp.rs‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,10 @@ impl<'a> AudioBlock<'a> {
234234
self.samples.len() / self.channels
235235
}
236236

237+
pub fn duration(&self) -> f32 {
238+
self.frame_count() as f32 / self.sample_rate
239+
}
240+
237241
pub fn stereo_frames(
238242
&self,
239243
) -> impl ExactSizeIterator<Item = [f32; 2]> + DoubleEndedIterator + '_ {

‎src/persistence/visuals.rs‎

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -214,16 +214,23 @@ visual_configs! {
214214
Stereometer(StereometerSettings),
215215
}
216216

217-
fn finite_averaging_or(value: AveragingMode, default: AveragingMode) -> AveragingMode {
218-
let parameter = match value {
219-
AveragingMode::None => return value,
220-
AveragingMode::Exponential { factor } => factor,
221-
AveragingMode::PeakHold { decay_per_second } => decay_per_second,
222-
};
223-
if parameter.is_finite() {
224-
value
225-
} else {
226-
default
217+
// Bounds hand-edited settings so new input keeps showing.
218+
const MAX_TIME_CONSTANT: f32 = 10.0;
219+
220+
fn time_constant_or(value: f32, default: f32) -> f32 {
221+
finite_or(value, default).clamp(0.0, MAX_TIME_CONSTANT)
222+
}
223+
224+
fn averaging_or(value: AveragingMode, default: AveragingMode) -> AveragingMode {
225+
match value {
226+
AveragingMode::None => value,
227+
AveragingMode::Exponential { time_constant } if time_constant.is_finite() => {
228+
AveragingMode::Exponential {
229+
time_constant: time_constant.clamp(0.0, MAX_TIME_CONSTANT),
230+
}
231+
}
232+
AveragingMode::PeakHold { decay_per_second } if decay_per_second.is_finite() => value,
233+
_ => default,
227234
}
228235
}
229236

@@ -273,7 +280,7 @@ visual_settings!(OscilloscopeSettings from OscilloscopeConfig {
273280
segment_duration: f32 => finite_or, trigger_mode: TriggerMode, trigger_source: Channel,
274281
channel_1: Channel, channel_2: Channel,
275282
} extra {
276-
persistence: f32 = 0.0 => finite_or,
283+
persistence_time_constant: f32 = 0.0 => time_constant_or,
277284
stacked: bool = false,
278285
});
279286

@@ -289,7 +296,7 @@ visual_settings!(WaveformSettings from WaveformConfig {
289296

290297
visual_settings!(SpectrumSettings from SpectrumConfig {
291298
fft_size: usize, hop_size: usize, window: WindowKind,
292-
averaging: AveragingMode => finite_averaging_or,
299+
averaging: AveragingMode => averaging_or,
293300
source: Channel, secondary_source: Channel, floor_db: f32 => sanitize_negative_db,
294301
} extra {
295302
frequency_scale: FrequencyScale = FrequencyScale::Logarithmic,
@@ -315,7 +322,7 @@ visual_settings!(SpectrogramSettings from SpectrogramConfig {
315322

316323
visual_settings!(StereometerSettings from StereometerConfig {
317324
segment_duration: f32 => finite_or, target_sample_count: usize,
318-
correlation_window: f32 => finite_or,
325+
correlation_window: f32 => time_constant_or,
319326
} extra {
320327
dot_radius: f32 = 1.0 => finite_or, mode: StereometerMode = StereometerMode::default(),
321328
scale: StereometerScale = StereometerScale::default(), rotation: i8 = -1, flip: bool = true,

‎src/ui/settings/oscilloscope.rs‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ impl fmt::Display for TriggerSourceChoice {
4646

4747
settings_messages!(pane, settings, value {
4848
SegmentDuration(f32) => set_f32(&mut settings.segment_duration, value);
49-
Persistence(f32) => set_f32(&mut settings.persistence, value);
49+
Persistence(f32) => set_f32(&mut settings.persistence_time_constant, value);
5050
Preset(TriggerPreset) => {
5151
let mode = match value {
5252
TriggerPreset::Stable => TriggerMode::Stable { num_cycles: pane.num_cycles },
@@ -101,7 +101,10 @@ settings_view! {
101101
"Trigger" => trigger;
102102
"Display" => form!(
103103
toggle("Stacked", settings.stacked, Stacked);
104-
slider!("Persistence", settings.persistence, PERSISTENCE_RANGE, Persistence, "{:.2}");
104+
slider!(
105+
"Persistence", settings.persistence_time_constant, PERSISTENCE_RANGE, Persistence,
106+
format!("{:.0} ms", settings.persistence_time_constant * 1000.0)
107+
);
105108
);
106109
}
107110

‎src/ui/settings/spectrum.rs‎

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,16 @@ use crate::ui::widgets::{SliderRange, chip, pick, split, toggle};
1111
use crate::util::audio::{Channel, FrequencyScale};
1212
use crate::visuals::options::{SpectrumDisplayMode, SpectrumWeightingMode as WeightingMode};
1313
use crate::visuals::spectrum::processor::{
14-
AveragingMode, DEFAULT_SPECTRUM_EXP_FACTOR, DEFAULT_SPECTRUM_PEAK_DECAY, MAX_SPECTRUM_DB_FLOOR,
15-
MAX_SPECTRUM_EXP_FACTOR, MAX_SPECTRUM_PEAK_DECAY, MIN_SPECTRUM_DB_FLOOR,
16-
MIN_SPECTRUM_EXP_FACTOR, MIN_SPECTRUM_PEAK_DECAY,
14+
AveragingMode, DEFAULT_SPECTRUM_PEAK_DECAY, DEFAULT_SPECTRUM_TIME_CONSTANT,
15+
MAX_SPECTRUM_DB_FLOOR, MAX_SPECTRUM_PEAK_DECAY, MAX_SPECTRUM_TIME_CONSTANT,
16+
MIN_SPECTRUM_DB_FLOOR, MIN_SPECTRUM_PEAK_DECAY, MIN_SPECTRUM_TIME_CONSTANT,
1717
};
1818

19-
const EXP_R: SliderRange = SliderRange::new(MIN_SPECTRUM_EXP_FACTOR, MAX_SPECTRUM_EXP_FACTOR, 0.01);
19+
const TIME_CONSTANT_R: SliderRange = SliderRange::new(
20+
MIN_SPECTRUM_TIME_CONSTANT,
21+
MAX_SPECTRUM_TIME_CONSTANT,
22+
0.005,
23+
);
2024
const DECAY_R: SliderRange =
2125
SliderRange::new(MIN_SPECTRUM_PEAK_DECAY, MAX_SPECTRUM_PEAK_DECAY, 0.5);
2226
const BARS_R: SliderRange = SliderRange::new(8.0, 128.0, 1.0);
@@ -36,7 +40,7 @@ crate::macros::choice_enum!(pub(in crate::ui) enum FrequencyDirection {
3640

3741
struct AveragingControls {
3842
mode: AvgMode,
39-
factor: f32,
43+
time_constant: f32,
4044
peak_decay: f32,
4145
}
4246

@@ -61,7 +65,9 @@ settings_messages!(pane, settings, value {
6165
Weighting(WeightingMode) => set(&mut settings.weighting_mode, value);
6266
SecondaryWeighting(WeightingMode) => set(&mut settings.secondary_weighting_mode, value);
6367
Averaging(AvgMode) => pane.update_avg(|average| set(&mut average.mode, value));
64-
AvgFactor(f32) => pane.update_avg(|average| set_f32(&mut average.factor, value));
68+
AvgTimeConstant(f32) => {
69+
pane.update_avg(|average| set_f32(&mut average.time_constant, value))
70+
};
6571
PeakDecay(f32) => pane.update_avg(|average| set_f32(&mut average.peak_decay, value));
6672
ShowGrid(bool) => set(&mut settings.show_grid, value);
6773
ShowPeakLabel(bool) => set(&mut settings.show_peak_label, value);
@@ -96,7 +102,8 @@ settings_view! {
96102
);
97103
let averaging = match pane.averaging.mode {
98104
AvgMode::Exponential => Some(slider!(
99-
"Exp factor", pane.averaging.factor, EXP_R, AvgFactor, "{:.2}"
105+
"Time constant", pane.averaging.time_constant, TIME_CONSTANT_R, AvgTimeConstant,
106+
format!("{:.0} ms", pane.averaging.time_constant * 1000.0)
100107
)),
101108
AvgMode::PeakHold => Some(slider!(
102109
"Peak decay", pane.averaging.peak_decay, DECAY_R, PeakDecay, "{:.1} dB/s"
@@ -161,7 +168,7 @@ impl Pane {
161168
self.settings.averaging = match self.averaging.mode {
162169
AvgMode::None => AveragingMode::None,
163170
AvgMode::Exponential => AveragingMode::Exponential {
164-
factor: self.averaging.factor,
171+
time_constant: self.averaging.time_constant,
165172
},
166173
AvgMode::PeakHold => AveragingMode::PeakHold {
167174
decay_per_second: self.averaging.peak_decay,
@@ -172,18 +179,20 @@ impl Pane {
172179
}
173180

174181
fn split_averaging(avg: AveragingMode) -> AveragingControls {
175-
let default_factor = DEFAULT_SPECTRUM_EXP_FACTOR;
182+
let default_time_constant = DEFAULT_SPECTRUM_TIME_CONSTANT;
176183
let default_peak_decay = DEFAULT_SPECTRUM_PEAK_DECAY;
177-
let (mode, factor, peak_decay) = match avg {
178-
AveragingMode::None => (AvgMode::None, default_factor, default_peak_decay),
179-
AveragingMode::Exponential { factor } => (AvgMode::Exponential, factor, default_peak_decay),
184+
let (mode, time_constant, peak_decay) = match avg {
185+
AveragingMode::None => (AvgMode::None, default_time_constant, default_peak_decay),
186+
AveragingMode::Exponential { time_constant } => {
187+
(AvgMode::Exponential, time_constant, default_peak_decay)
188+
}
180189
AveragingMode::PeakHold { decay_per_second } => {
181-
(AvgMode::PeakHold, default_factor, decay_per_second)
190+
(AvgMode::PeakHold, default_time_constant, decay_per_second)
182191
}
183192
};
184193
AveragingControls {
185194
mode,
186-
factor,
195+
time_constant,
187196
peak_decay,
188197
}
189198
}

‎src/util/audio.rs‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,14 @@ pub fn sanitize_sample_rate(sample_rate: f32) -> f32 {
5050
.clamp(1.0, MAX_SAMPLE_RATE)
5151
}
5252

53+
pub fn smoothing_weight(elapsed: f32, time_constant: f32) -> f32 {
54+
if time_constant > 0.0 {
55+
-(-elapsed / time_constant).exp_m1()
56+
} else {
57+
1.0
58+
}
59+
}
60+
5361
pub fn fmt_freq(frequency: f32) -> String {
5462
match frequency {
5563
99_950.0.. => format!("{:.0}kHz", frequency / 1_000.0),

0 commit comments

Comments
 (0)