Skip to content

Commit f37ee3e

Browse files
committed
Center plot, safety limit for band pass ranges
1 parent 7b1b6ac commit f37ee3e

File tree

3 files changed

+97
-35
lines changed

3 files changed

+97
-35
lines changed

caw/examples/live_example.rs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,28 @@ fn main() {
4545
.build()
4646
.exp_01(1.)
4747
.shared();
48-
let voice = (super_saw(note.freq_hz()).build() * env.clone()).filter(
49-
low_pass::default(10. + (env.clone() * cutoff_hz * 15000.))
50-
.q(res.clone()),
48+
let voice = (saw(note.freq_hz())
49+
.reset_offset_01(channel.circle_phase_offset_01())
50+
.build()
51+
* env.clone())
52+
.filter(
53+
low_pass::default(
54+
10. + (env.clone()
55+
* cutoff_hz
56+
* 15000.
57+
* knob("cutoff_scale").build()),
58+
)
59+
.q(res.clone()),
60+
)
61+
.filter(band_pass_chebyshev_centered(
62+
knob("mid").build() * 10_000.,
63+
knob("width").build() * 4.,
64+
))
65+
.filter(
66+
compressor()
67+
.ratio(0.05)
68+
.threshold(1.0)
69+
.scale(knob("distort").build() * 100.),
5170
);
5271
voice
5372
.viz_oscilloscope_stereo("voice", channel, Default::default())

modules/src/low_level/biquad_band_pass_filter.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ pub mod butterworth {
9292
) -> f64 {
9393
let lower_half_power_frequency_hz =
9494
lower_half_power_frequency_hz.max(0.0);
95+
let upper_half_power_frequency_hz =
96+
upper_half_power_frequency_hz.min(20_000.);
9597
let upper_half_power_frequency_hz = upper_half_power_frequency_hz
9698
.max(lower_half_power_frequency_hz);
9799
if self.buffer.entries.is_empty() {
@@ -199,6 +201,8 @@ pub mod chebyshev {
199201
if self.buffer.entries.is_empty() {
200202
return sample;
201203
}
204+
let lower_cutoff_hz = lower_cutoff_hz.max(0.);
205+
let upper_cutoff_hz = upper_cutoff_hz.min(20_000.);
202206
let epsilon = epsilon.max(EPSILON_MIN);
203207
if lower_cutoff_hz != self.prev_lower_cutoff_hz
204208
|| upper_cutoff_hz != self.prev_upper_cutoff_hz

viz-udp-app/src/main.rs

Lines changed: 71 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,70 @@ impl App {
144144
}
145145
}
146146

147+
fn tick_oscilloscope_time_domain_single(
148+
canvas: &mut Canvas<Window>,
149+
screen_size: Coord,
150+
scope_state: &ScopeState,
151+
ui_state: &OscilloscopeUiState,
152+
rgb: Rgb24,
153+
) {
154+
let num_samples_to_draw = screen_size.x as usize;
155+
// Take the mean so it can be used to identify the relative 0 crossing in case the waveform
156+
// has drifted above 0 mean.
157+
let mean = {
158+
let sum =
159+
scope_state.samples.iter().map(|(x, y)| x + y).sum::<f32>();
160+
sum / (scope_state.samples.len() * 2) as f32
161+
};
162+
let mut samples_to_scan_for_zero_crossing = scope_state
163+
.samples
164+
.iter()
165+
.map(|(x, y)| x + y / 2.)
166+
.enumerate()
167+
.rev()
168+
// skip half a screen worth of samples
169+
.skip(num_samples_to_draw / 2);
170+
let mut zero_crossing_index =
171+
scope_state.samples.len() - num_samples_to_draw / 2;
172+
if let Some((_, mut prev)) = samples_to_scan_for_zero_crossing.next() {
173+
for (i, sample) in samples_to_scan_for_zero_crossing {
174+
if prev > mean && sample <= mean {
175+
zero_crossing_index = i;
176+
break;
177+
}
178+
prev = sample;
179+
}
180+
}
181+
// Subtract half the screen width so that the crossing point is in the centre of the
182+
// screen.
183+
let left_most_sample = zero_crossing_index - num_samples_to_draw / 2;
184+
let sample_mean_iter = scope_state
185+
.samples
186+
.iter()
187+
.skip(left_most_sample)
188+
.map(|(left, right)| (left + right) / 2.);
189+
canvas.set_draw_color(Color::RGBA(rgb.r, rgb.g, rgb.b, 255));
190+
let mut prev = None;
191+
for (x, sample) in sample_mean_iter.enumerate() {
192+
let x = x as i32;
193+
let y = screen_size.y
194+
- ((sample * ui_state.scale) as i32 + (screen_size.y / 2));
195+
let coord = Coord { x, y };
196+
if let Some(prev) = prev {
197+
for Coord { x, y } in line_2d::coords_between(prev, coord) {
198+
let rect = Rect::new(
199+
x,
200+
y,
201+
ui_state.line_width,
202+
ui_state.line_width,
203+
);
204+
let _ = canvas.fill_rect(rect);
205+
}
206+
}
207+
prev = Some(coord);
208+
}
209+
}
210+
147211
fn run_oscilloscope(
148212
mut self,
149213
args: OscilloscopeCommand,
@@ -249,38 +313,13 @@ impl App {
249313
};
250314
match ui_state.style {
251315
OscilloscopeStyle::TimeDomain => {
252-
let num_samples_to_draw = screen_size.x as usize;
253-
let sample_mean_iter = scope_state
254-
.samples
255-
.iter()
256-
.rev()
257-
.take(num_samples_to_draw)
258-
.rev()
259-
.map(|(left, right)| (left + right) / 2.0);
260-
self.canvas
261-
.set_draw_color(Color::RGBA(rgb.r, rgb.g, rgb.b, 255));
262-
let mut prev = None;
263-
for (x, sample) in sample_mean_iter.enumerate() {
264-
let x = x as i32;
265-
let y = screen_size.y
266-
- ((sample * ui_state.scale) as i32
267-
+ (screen_size.y / 2));
268-
let coord = Coord { x, y };
269-
if let Some(prev) = prev {
270-
for Coord { x, y } in
271-
line_2d::coords_between(prev, coord)
272-
{
273-
let rect = Rect::new(
274-
x,
275-
y,
276-
ui_state.line_width,
277-
ui_state.line_width,
278-
);
279-
let _ = self.canvas.fill_rect(rect);
280-
}
281-
}
282-
prev = Some(coord);
283-
}
316+
Self::tick_oscilloscope_time_domain_single(
317+
&mut self.canvas,
318+
screen_size,
319+
&scope_state,
320+
&ui_state,
321+
rgb,
322+
);
284323
}
285324
OscilloscopeStyle::TimeDomainStereo => {
286325
let num_samples_to_draw = screen_size.x as usize;

0 commit comments

Comments
 (0)