Skip to content

Commit 94bfcb7

Browse files
committed
Add space inputs to some widgets
1 parent 26f68b4 commit 94bfcb7

File tree

15 files changed

+532
-79
lines changed

15 files changed

+532
-79
lines changed

caw/examples/live_example.rs

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ fn main() {
99
})
1010
.with_volume(volume.clone());
1111
volume.set(knob("volume").initial_value_01(0.5).build());
12-
let tempo_s = sv(knob("tempo s").build() * 0.5);
13-
let (cutoff_hz, res) = xy("lpf")
12+
let tempo_s = knob("tempo s").build();
13+
let (cutoff_hz, res, lpf_space) = xy_with_space("lpf")
1414
.axis_label_x("cutoff_hz")
1515
.axis_label_y("resonance")
1616
.build();
@@ -19,36 +19,40 @@ fn main() {
1919
let clock = sv(periodic_trig_s(tempo_s.clone())
2020
.build()
2121
.viz_blink("clock".to_string(), Default::default()));
22-
let ck = computer_keyboard("keys").start_note(note::B_0).build_();
23-
let space_button = ck.space_button().shared();
24-
let key_events = ck.key_events().shared();
22+
let keyboard = computer_keyboard("keys").start_note(note::B_1).build_();
23+
let space_button = keyboard.space_button().shared();
24+
let key_events = keyboard.key_events().shared();
25+
let length = 16;
2526
out.set_channel(|channel| {
2627
let voice = key_events.clone().mono_voice();
2728
let (note, gate) = key_looper(
2829
voice.gated_note(),
2930
clock.clone(),
3031
space_button.clone(),
31-
8,
32+
length,
3233
)
3334
.ungated();
35+
let cutoff_hz = value_looper(
36+
cutoff_hz.clone(),
37+
clock.clone(),
38+
lpf_space.clone(),
39+
length,
40+
);
3441
let env = adsr(gate)
3542
.key_press_trig(clock.clone())
36-
.a(tempo_s.clone() / 24.)
37-
.r(tempo_s.clone() / 2.)
38-
.s(0.25)
39-
.d(tempo_s.clone() / 2.)
43+
.a(tempo_s.clone() * knob("attack").build())
44+
.r(tempo_s.clone() * knob("release").build())
45+
.s(knob("sustain").build())
46+
.d(tempo_s.clone() * knob("decay").build())
4047
.build()
4148
.exp_01(1.)
4249
.shared();
43-
let voice = (super_saw(note.freq_hz()).build() * env.clone())
44-
.filter(
45-
low_pass::default(
46-
10. + (env.clone() * cutoff_hz.clone() * 15000.),
47-
)
50+
let voice = (super_saw(note.freq_hz()).build() * env.clone()).filter(
51+
low_pass::default(10. + (env.clone() * cutoff_hz * 15000.))
4852
.q(res.clone()),
49-
)
50-
.viz_oscilloscope_stereo("voice", channel, Default::default());
53+
);
5154
voice
55+
.viz_oscilloscope_stereo("voice", channel, Default::default())
5256
.filter(
5357
chorus()
5458
.lfo_rate_hz(0.1)

core/src/lib.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ mod arith;
22
mod sig;
33
pub mod sig_ops;
44
pub use sig::{
5-
Buf, Const, ConstBuf, Filter, GateToTrigRisingEdge, Sig, SigAbs, SigBoxed,
6-
SigBoxedVar, SigConst, SigCtx, SigSampleIntoBufT, SigShared, SigT, SigVar,
7-
Triggerable, Zip, Zip3, Zip4, sig_boxed, sig_boxed_var,
8-
sig_option_first_some, sig_shared, sig_var,
5+
Buf, Const, ConstBuf, Filter, GateToTrigRisingEdge, IsNegative, IsPositive,
6+
Sig, SigAbs, SigBoxed, SigBoxedVar, SigConst, SigCtx, SigSampleIntoBufT,
7+
SigShared, SigT, SigVar, Triggerable, Zip, Zip3, Zip4, sig_boxed,
8+
sig_boxed_var, sig_option_first_some, sig_shared, sig_var,
99
};
1010
pub mod stereo;
1111
pub use stereo::{Channel, Stereo, StereoPair};

core/src/sig.rs

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -824,12 +824,12 @@ where
824824
Sig(SigAbs(self.0))
825825
}
826826

827-
pub fn is_positive(self) -> Sig<impl SigT<Item = bool>> {
828-
self.map(|x| x > 0.0)
827+
pub fn is_positive(self) -> Sig<IsPositive<S>> {
828+
Sig(IsPositive(self.0))
829829
}
830830

831-
pub fn is_negative(self) -> Sig<impl SigT<Item = bool>> {
832-
self.map(|x| x < 0.0)
831+
pub fn is_negative(self) -> Sig<IsNegative<S>> {
832+
Sig(IsNegative(self.0))
833833
}
834834
}
835835

@@ -959,6 +959,13 @@ where
959959
ret
960960
})
961961
}
962+
963+
pub fn or<O>(self, other: O) -> Sig<impl SigT<Item = bool>>
964+
where
965+
O: SigT<Item = bool>,
966+
{
967+
self.zip(other).map(|(s, o)| s || o)
968+
}
962969
}
963970

964971
/// A counting gate, which is a gate which implements a counter each time it transitions to "on".
@@ -1336,6 +1343,36 @@ where
13361343
}
13371344
}
13381345

1346+
pub struct IsPositive<S>(S)
1347+
where
1348+
S: SigT<Item = f32>;
1349+
1350+
impl<S> SigT for IsPositive<S>
1351+
where
1352+
S: SigT<Item = f32>,
1353+
{
1354+
type Item = bool;
1355+
1356+
fn sample(&mut self, ctx: &SigCtx) -> impl Buf<Self::Item> {
1357+
MapBuf::new(self.0.sample(ctx), |x| x > 0.0)
1358+
}
1359+
}
1360+
1361+
pub struct IsNegative<S>(S)
1362+
where
1363+
S: SigT<Item = f32>;
1364+
1365+
impl<S> SigT for IsNegative<S>
1366+
where
1367+
S: SigT<Item = f32>,
1368+
{
1369+
type Item = bool;
1370+
1371+
fn sample(&mut self, ctx: &SigCtx) -> impl Buf<Self::Item> {
1372+
MapBuf::new(self.0.sample(ctx), |x| x < 0.0)
1373+
}
1374+
}
1375+
13391376
/// For signals yielding `f32`, this trait provides a general way of defining filters.
13401377
pub trait Filter {
13411378
/// The type of the item of the input signal to this filter.

midi-udp-widgets-app-lib/examples/midi_udp_widgets_app_lib_demo.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ fn sig() -> Sig<impl SigT<Item = f32>> {
88
adsr_linear_01(button("env gate").build().gate_to_trig_rising_edge())
99
.release_s(0.5)
1010
.build();
11-
let (chorus_depth_01, chorus_lfo_rate_01) = xy("chorus").build().unzip();
11+
let (chorus_depth_01, chorus_lfo_rate_01) = xy("chorus").build();
1212
super_saw(60.)
1313
.build()
1414
.filter(

midi-udp-widgets-app-lib/src/knob.rs

Lines changed: 50 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,33 @@ use crate::{
22
midi,
33
widget::{ByTitle, MidiController01Udp, Widget},
44
};
5-
use caw_core::{Sig, SigShared};
5+
use caw_core::{IsPositive, Sig, SigShared};
66
use caw_midi::MidiMessagesT;
77
use lazy_static::lazy_static;
88

9+
pub type KnobWithSpace = (
10+
Sig<SigShared<MidiController01Udp>>,
11+
Sig<SigShared<IsPositive<MidiController01Udp>>>,
12+
);
13+
914
lazy_static! {
1015
// Used to prevent multiple windows from opening at the same time with the same name. Note that
1116
// when using with evcxr this seems to get cleared when a cell is recomputed, but this is still
1217
// valuable in the context of stereo signals, where a function is evaluated once for the left
1318
// channel and once for the right channel. In such a case, this prevents each knob openned by
1419
// that function from being openned twice.
15-
static ref BY_TITLE: ByTitle<Sig<SigShared<MidiController01Udp>>> = Default::default();
20+
static ref BY_TITLE: ByTitle<KnobWithSpace> = Default::default();
1621
}
1722

18-
fn new_knob(
23+
fn new_knob_with_space(
1924
title: String,
2025
initial_value_01: f32,
2126
sensitivity: f32,
22-
) -> Sig<SigShared<MidiController01Udp>> {
27+
) -> KnobWithSpace {
2328
BY_TITLE.get_or_insert(title.as_str(), || {
2429
let channel = midi::alloc_channel();
2530
let controller = midi::alloc_controller(channel);
31+
let space_controller = midi::alloc_controller(channel);
2632
let widget = Widget::new(
2733
title.clone(),
2834
channel,
@@ -31,18 +37,31 @@ fn new_knob(
3137
format!("--controller={}", controller),
3238
format!("--initial-value={}", initial_value_01),
3339
format!("--sensitivity={}", sensitivity),
40+
format!("--space-controller={}", space_controller),
3441
],
3542
)
3643
.unwrap();
37-
widget
38-
.channel()
39-
.controllers()
44+
let controllers = widget.channel().controllers();
45+
let value = controllers
4046
.get_with_initial_value_01(controller.into(), initial_value_01)
41-
.shared()
47+
.shared();
48+
let space = controllers
49+
.get_with_initial_value_01(space_controller.into(), 0.0)
50+
.is_positive()
51+
.shared();
52+
(value, space)
4253
})
4354
}
4455

45-
mod knob_builder {
56+
fn new_knob(
57+
title: String,
58+
initial_value_01: f32,
59+
sensitivity: f32,
60+
) -> Sig<SigShared<MidiController01Udp>> {
61+
new_knob_with_space(title, initial_value_01, sensitivity).0
62+
}
63+
64+
mod builder {
4665
use super::*;
4766
use caw_builder_proc_macros::builder;
4867
use caw_core::{Sig, SigShared};
@@ -53,7 +72,7 @@ mod knob_builder {
5372
#[generic_setter_type_name = "X"]
5473
#[build_fn = "new_knob"]
5574
#[build_ty = "Sig<SigShared<MidiController01Udp>>"]
56-
pub struct Props {
75+
pub struct KnobProps {
5776
title: String,
5877
#[default = 0.5]
5978
initial_value_01: f32,
@@ -62,9 +81,28 @@ mod knob_builder {
6281
}
6382
}
6483

65-
pub fn knob(title: impl Into<String>) -> Props {
84+
pub fn knob(title: impl Into<String>) -> KnobProps {
6685
knob_(title.into())
6786
}
87+
88+
builder! {
89+
#[constructor = "knob_with_space_"]
90+
#[constructor_doc = "A visual knob in a new window"]
91+
#[generic_setter_type_name = "X"]
92+
#[build_fn = "new_knob_with_space"]
93+
#[build_ty = "KnobWithSpace"]
94+
pub struct KnobWithSpaceProps {
95+
title: String,
96+
#[default = 0.5]
97+
initial_value_01: f32,
98+
#[default = 0.2]
99+
sensitivity: f32,
100+
}
101+
}
102+
103+
pub fn knob_with_space(title: impl Into<String>) -> KnobWithSpaceProps {
104+
knob_with_space_(title.into())
105+
}
68106
}
69107

70-
pub use knob_builder::knob;
108+
pub use builder::{knob, knob_with_space};

midi-udp-widgets-app-lib/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ pub mod button;
22
pub use button::button;
33

44
pub mod knob;
5-
pub use knob::knob;
5+
pub use knob::{knob, knob_with_space};
66

77
pub mod xy;
8-
pub use xy::xy;
8+
pub use xy::{xy, xy_with_space};
99

1010
pub mod computer_keyboard;
1111
pub use computer_keyboard::computer_keyboard;

0 commit comments

Comments
 (0)