Skip to content

Commit 4b1c65f

Browse files
committed
Allow bypassing filter
1 parent f37ee3e commit 4b1c65f

File tree

5 files changed

+163
-68
lines changed

5 files changed

+163
-68
lines changed

caw/examples/live_example.rs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ fn main() {
2525
let length = 16;
2626
out.set_channel(|channel| {
2727
let voice = key_events.clone().mono_voice();
28-
let (note, gate) = key_looper(voice.gated_note(), clock.clone())
28+
let (note, gate) = key_looper(voice.triggered_note(), clock.clone())
2929
.clearing(space_button.clone())
3030
.length(length)
3131
.persist_with_name("keys")
@@ -38,10 +38,10 @@ fn main() {
3838
.build();
3939
let env = adsr(gate)
4040
.key_press_trig(clock.clone())
41-
.a(tempo_s.clone() * knob("attack").build())
42-
.r(tempo_s.clone() * knob("release").build())
41+
.a(tempo_s.clone() * knob("attack").build() * 4.)
42+
.r(tempo_s.clone() * knob("release").build() * 4.)
4343
.s(knob("sustain").build())
44-
.d(tempo_s.clone() * knob("decay").build())
44+
.d(tempo_s.clone() * knob("decay").build() * 4.)
4545
.build()
4646
.exp_01(1.)
4747
.shared();
@@ -58,15 +58,18 @@ fn main() {
5858
)
5959
.q(res.clone()),
6060
)
61-
.filter(band_pass_chebyshev_centered(
62-
knob("mid").build() * 10_000.,
63-
knob("width").build() * 4.,
64-
))
61+
.filter_enable(
62+
true,
63+
band_pass::centered::default(
64+
knob("mid").build() * 1_000.,
65+
knob("width").build() * 4.,
66+
),
67+
)
6568
.filter(
6669
compressor()
6770
.ratio(0.05)
6871
.threshold(1.0)
69-
.scale(knob("distort").build() * 100.),
72+
.scale(knob("distort").build() * 10.),
7073
);
7174
voice
7275
.viz_oscilloscope_stereo("voice", channel, Default::default())

core/src/sig.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,27 @@ where
689689
{
690690
self.zip(other).map(|(x, _)| x)
691691
}
692+
693+
pub fn filter_enable<E, F>(
694+
self,
695+
enable: E,
696+
filter: F,
697+
) -> impl SigT<Item = S::Item>
698+
where
699+
E: SigT<Item = bool>,
700+
F: Filter<ItemIn = S::Item>,
701+
F::Out<Sig<SigShared<S>>>: SigT<Item = S::Item>,
702+
{
703+
let shared = self.shared();
704+
let filtered = shared.clone().filter(filter);
705+
Sig(enable)
706+
.zip3(shared, filtered)
707+
.map(
708+
|(enable, shared, filtered)| {
709+
if enable { filtered } else { shared }
710+
},
711+
)
712+
}
692713
}
693714

694715
impl<S, A, B> Sig<S>

keyboard/src/mono_voice.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,15 @@ where
4646
} = self;
4747
note.gated(key_down_gate)
4848
}
49+
50+
pub fn triggered_note(self) -> Sig<impl SigT<Item = Option<crate::Note>>> {
51+
let Self {
52+
note,
53+
key_press_trig,
54+
..
55+
} = self;
56+
note.gated(key_press_trig)
57+
}
4958
}
5059

5160
/// Extracts a sequence of notes from a sequence of key events.

modules/src/band_pass_chebyshev.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,20 @@ builder! {
2323
}
2424
}
2525

26+
impl<L, U, R> Props<L, U, R>
27+
where
28+
L: SigT<Item = f32>,
29+
U: SigT<Item = f32>,
30+
R: SigT<Item = f32>,
31+
{
32+
pub fn q<X>(self, resonance: X) -> Props<L, U, X>
33+
where
34+
X: SigT<Item = f32>,
35+
{
36+
self.resonance(resonance)
37+
}
38+
}
39+
2640
impl<L, U, R> Filter for Props<L, U, R>
2741
where
2842
L: SigT<Item = f32>,
@@ -158,6 +172,21 @@ builder! {
158172
}
159173
}
160174

175+
impl<C, W, M, R> PropsCenteredBuilder<C, W, M, R>
176+
where
177+
C: SigT<Item = f32>,
178+
W: SigT<Item = f32>,
179+
M: SigT<Item = f32>,
180+
R: SigT<Item = f32>,
181+
{
182+
pub fn q<X>(self, resonance: X) -> PropsCenteredBuilder<C, W, M, X>
183+
where
184+
X: SigT<Item = f32>,
185+
{
186+
self.resonance(resonance)
187+
}
188+
}
189+
161190
impl<C, W, M, R> Filter for PropsCenteredBuilder<C, W, M, R>
162191
where
163192
C: SigT<Item = f32>,

viz-udp-app/src/main.rs

Lines changed: 92 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,91 @@ impl App {
208208
}
209209
}
210210

211+
fn tick_oscilloscope_time_domain_single_stereo(
212+
canvas: &mut Canvas<Window>,
213+
screen_size: Coord,
214+
scope_state: &ScopeState,
215+
ui_state: &OscilloscopeUiState,
216+
rgb: Rgb24,
217+
) {
218+
// A zero crossing of the left channel will be centered in an attempt to stabalize the
219+
// visualization over time.
220+
let num_samples_to_draw = screen_size.x as usize;
221+
// Take the mean so it can be used to identify the relative 0 crossing in case the waveform
222+
// has drifted above 0 mean.
223+
let left_mean = {
224+
let sum = scope_state.samples.iter().map(|(x, _)| x).sum::<f32>();
225+
sum / (scope_state.samples.len()) as f32
226+
};
227+
let mut samples_to_scan_for_zero_crossing = scope_state
228+
.samples
229+
.iter()
230+
.map(|(x, _)| *x)
231+
.enumerate()
232+
.rev()
233+
// skip half a screen worth of samples
234+
.skip(num_samples_to_draw / 2);
235+
let mut zero_crossing_index =
236+
scope_state.samples.len() - num_samples_to_draw / 2;
237+
if let Some((_, mut prev)) = samples_to_scan_for_zero_crossing.next() {
238+
for (i, sample) in samples_to_scan_for_zero_crossing {
239+
if prev > left_mean && sample <= left_mean {
240+
zero_crossing_index = i;
241+
break;
242+
}
243+
prev = sample;
244+
}
245+
}
246+
// Subtract half the screen width so that the crossing point is in the centre of the
247+
// screen.
248+
let left_most_sample = zero_crossing_index - num_samples_to_draw / 2;
249+
let make_sample_pair_iter =
250+
|| scope_state.samples.iter().skip(left_most_sample);
251+
let sample_left_iter = make_sample_pair_iter().map(|(x, _)| x);
252+
let sample_right_iter = make_sample_pair_iter().map(|(_, x)| x);
253+
canvas.set_draw_color(Color::RGBA(rgb.r, rgb.g, rgb.b, 255));
254+
let mut prev = None;
255+
for (x, sample) in sample_left_iter.enumerate() {
256+
let x = x as i32;
257+
let y = screen_size.y
258+
- ((sample * ui_state.scale) as i32
259+
+ ((2 * screen_size.y) / 3));
260+
let coord = Coord { x, y };
261+
if let Some(prev) = prev {
262+
for Coord { x, y } in line_2d::coords_between(prev, coord) {
263+
let rect = Rect::new(
264+
x,
265+
y,
266+
ui_state.line_width,
267+
ui_state.line_width,
268+
);
269+
let _ = canvas.fill_rect(rect);
270+
}
271+
}
272+
prev = Some(coord);
273+
}
274+
let mut prev = None;
275+
for (x, sample) in sample_right_iter.enumerate() {
276+
let x = x as i32;
277+
let y = screen_size.y
278+
- ((sample * ui_state.scale) as i32
279+
+ ((1 * screen_size.y) / 3));
280+
let coord = Coord { x, y };
281+
if let Some(prev) = prev {
282+
for Coord { x, y } in line_2d::coords_between(prev, coord) {
283+
let rect = Rect::new(
284+
x,
285+
y,
286+
ui_state.line_width,
287+
ui_state.line_width,
288+
);
289+
let _ = canvas.fill_rect(rect);
290+
}
291+
}
292+
prev = Some(coord);
293+
}
294+
}
295+
211296
fn run_oscilloscope(
212297
mut self,
213298
args: OscilloscopeCommand,
@@ -322,65 +407,13 @@ impl App {
322407
);
323408
}
324409
OscilloscopeStyle::TimeDomainStereo => {
325-
let num_samples_to_draw = screen_size.x as usize;
326-
let make_sample_pair_iter = || {
327-
scope_state
328-
.samples
329-
.iter()
330-
.rev()
331-
.take(num_samples_to_draw)
332-
.rev()
333-
};
334-
let sample_left_iter =
335-
make_sample_pair_iter().map(|(x, _)| x);
336-
let sample_right_iter =
337-
make_sample_pair_iter().map(|(_, x)| x);
338-
self.canvas
339-
.set_draw_color(Color::RGBA(rgb.r, rgb.g, rgb.b, 255));
340-
let mut prev = None;
341-
for (x, sample) in sample_left_iter.enumerate() {
342-
let x = x as i32;
343-
let y = screen_size.y
344-
- ((sample * ui_state.scale) as i32
345-
+ (screen_size.y / 3));
346-
let coord = Coord { x, y };
347-
if let Some(prev) = prev {
348-
for Coord { x, y } in
349-
line_2d::coords_between(prev, coord)
350-
{
351-
let rect = Rect::new(
352-
x,
353-
y,
354-
ui_state.line_width,
355-
ui_state.line_width,
356-
);
357-
let _ = self.canvas.fill_rect(rect);
358-
}
359-
}
360-
prev = Some(coord);
361-
}
362-
let mut prev = None;
363-
for (x, sample) in sample_right_iter.enumerate() {
364-
let x = x as i32;
365-
let y = screen_size.y
366-
- ((sample * ui_state.scale) as i32
367-
+ ((2 * screen_size.y) / 3));
368-
let coord = Coord { x, y };
369-
if let Some(prev) = prev {
370-
for Coord { x, y } in
371-
line_2d::coords_between(prev, coord)
372-
{
373-
let rect = Rect::new(
374-
x,
375-
y,
376-
ui_state.line_width,
377-
ui_state.line_width,
378-
);
379-
let _ = self.canvas.fill_rect(rect);
380-
}
381-
}
382-
prev = Some(coord);
383-
}
410+
Self::tick_oscilloscope_time_domain_single_stereo(
411+
&mut self.canvas,
412+
screen_size,
413+
&scope_state,
414+
&ui_state,
415+
rgb,
416+
);
384417
}
385418
OscilloscopeStyle::Xy => {
386419
let mut coord_iter =

0 commit comments

Comments
 (0)