Skip to content

Commit 0d13278

Browse files
committed
Tidy up widgets
1 parent cb93c10 commit 0d13278

File tree

7 files changed

+153
-185
lines changed

7 files changed

+153
-185
lines changed

caw/examples/live_example.rs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,15 @@ fn main() {
1313
let (cutoff_hz, res) = xy("lpf")
1414
.axis_label_x("cutoff_hz")
1515
.axis_label_y("resonance")
16-
.build()
17-
.unzip();
16+
.build();
1817
let cutoff_hz = sv(cutoff_hz);
1918
let res = sv(res * 2.);
2019
let clock = sv(periodic_trig_s(tempo_s.clone())
2120
.build()
2221
.viz_blink("clock".to_string(), Default::default()));
23-
let keys = computer_keyboard("keys")
24-
.start_note(note::B_0)
25-
.build()
26-
.shared();
27-
let space_button =
28-
keys.clone().controllers().get_01(0).is_positive().shared();
29-
let key_events = keys.clone().key_events().shared();
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();
3025
out.set_channel(|channel| {
3126
let voice = key_events.clone().mono_voice();
3227
let (note, gate) = key_looper(

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

Lines changed: 13 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,54 +3,37 @@ use crate::{
33
server::MidiChannelUdp,
44
widget::{ByTitle, Widget},
55
};
6-
use caw_core::{Buf, Sig, SigShared, SigT};
6+
use caw_core::{Sig, SigShared, sig_shared};
77
use caw_keyboard::Note;
88
use caw_midi::{MidiKeyPress, MidiMessagesT};
99
use lazy_static::lazy_static;
1010

11-
pub struct Button {
12-
sig: Sig<MidiKeyPress<MidiChannelUdp>>,
13-
}
11+
pub type Button = MidiKeyPress<MidiChannelUdp>;
1412

1513
lazy_static! {
16-
static ref BY_TITLE: ByTitle<Button> = Default::default();
17-
}
18-
19-
impl Button {
20-
pub fn new(title: String) -> Sig<SigShared<Self>> {
21-
BY_TITLE.get_or_insert(title.as_str(), || {
22-
let widget = Widget::new(
23-
title.clone(),
24-
midi::alloc_channel(),
25-
"button",
26-
vec![],
27-
)
28-
.unwrap();
29-
// The choice of note here is arbitrary.
30-
let sig = Sig(widget.channel().key_press(Note::default()));
31-
Self { sig }
32-
})
33-
}
14+
static ref BY_TITLE: ByTitle<Sig<SigShared<Button>>> = Default::default();
3415
}
3516

36-
impl SigT for Button {
37-
type Item = bool;
38-
39-
fn sample(&mut self, ctx: &caw_core::SigCtx) -> impl Buf<Self::Item> {
40-
self.sig.sample(ctx)
41-
}
17+
fn new_button(title: String) -> Sig<SigShared<Button>> {
18+
BY_TITLE.get_or_insert(title.as_str(), || {
19+
let widget =
20+
Widget::new(title.clone(), midi::alloc_channel(), "button", vec![])
21+
.unwrap();
22+
// The choice of note here is arbitrary.
23+
sig_shared(widget.channel().key_press(Note::default()))
24+
})
4225
}
4326

4427
mod button_builder {
45-
use super::Button;
28+
use super::*;
4629
use caw_builder_proc_macros::builder;
4730
use caw_core::{Sig, SigShared};
4831

4932
builder! {
5033
#[constructor = "button_"]
5134
#[constructor_doc = "A visual button in a new window"]
5235
#[generic_setter_type_name = "X"]
53-
#[build_fn = "Button::new"]
36+
#[build_fn = "new_button"]
5437
#[build_ty = "Sig<SigShared<Button>>"]
5538
pub struct Props {
5639
title: String,

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

Lines changed: 39 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,46 +3,49 @@ use crate::{
33
server::MidiChannelUdp,
44
widget::{ByTitle, Widget},
55
};
6-
use caw_core::{Buf, Sig, SigShared, SigT};
7-
use caw_keyboard::Note;
8-
use caw_midi::MidiMessages;
6+
use caw_core::{Sig, SigShared, SigT};
7+
use caw_keyboard::{KeyEvents, Note};
8+
use caw_midi::MidiMessagesT;
99
use lazy_static::lazy_static;
1010

11-
pub struct ComputerKeyboard {
12-
sig: Sig<MidiChannelUdp>,
11+
lazy_static! {
12+
static ref BY_TITLE: ByTitle<Sig<SigShared<MidiChannelUdp>>> =
13+
Default::default();
1314
}
1415

15-
lazy_static! {
16-
static ref BY_TITLE: ByTitle<ComputerKeyboard> = Default::default();
16+
fn new_computer_keyboard(
17+
title: String,
18+
start_note: Note,
19+
) -> Sig<SigShared<MidiChannelUdp>> {
20+
BY_TITLE.get_or_insert(title.as_str(), || {
21+
let channel = midi::alloc_channel();
22+
let widget = Widget::new(
23+
title.clone(),
24+
channel,
25+
"computer-keyboard",
26+
vec![format!("--start-note={}", start_note)],
27+
)
28+
.unwrap();
29+
widget.channel().shared()
30+
})
1731
}
1832

19-
impl ComputerKeyboard {
20-
pub fn new(title: String, start_note: Note) -> Sig<SigShared<Self>> {
21-
BY_TITLE.get_or_insert(title.as_str(), || {
22-
let channel = midi::alloc_channel();
23-
let widget = Widget::new(
24-
title.clone(),
25-
channel,
26-
"computer-keyboard",
27-
vec![format!("--start-note={}", start_note)],
28-
)
29-
.unwrap();
30-
let sig = widget.channel();
31-
Self { sig }
32-
})
33-
}
33+
pub struct ComputerKeyboard {
34+
sig: Sig<SigShared<MidiChannelUdp>>,
3435
}
3536

36-
impl SigT for ComputerKeyboard {
37-
type Item = MidiMessages;
37+
impl ComputerKeyboard {
38+
pub fn key_events(&self) -> Sig<impl SigT<Item = KeyEvents> + use<>> {
39+
self.sig.clone().key_events()
40+
}
3841

39-
fn sample(&mut self, ctx: &caw_core::SigCtx) -> impl Buf<Self::Item> {
40-
self.sig.sample(ctx)
42+
pub fn space_button(&self) -> Sig<impl SigT<Item = bool> + use<>> {
43+
self.sig.clone().controllers().get_01(0).is_positive()
4144
}
4245
}
4346

4447
mod computer_keyboard_builder {
45-
use super::ComputerKeyboard;
48+
use super::*;
4649
use caw_builder_proc_macros::builder;
4750
use caw_core::{Sig, SigShared};
4851
use caw_keyboard::Note;
@@ -51,15 +54,22 @@ mod computer_keyboard_builder {
5154
#[constructor = "computer_keyboard_"]
5255
#[constructor_doc = "Generate midi events with a computer keyboard when this widget is focused"]
5356
#[generic_setter_type_name = "X"]
54-
#[build_fn = "ComputerKeyboard::new"]
55-
#[build_ty = "Sig<SigShared<ComputerKeyboard>>"]
57+
#[build_fn = "new_computer_keyboard"]
58+
#[build_ty = "Sig<SigShared<MidiChannelUdp>>"]
5659
pub struct Props {
5760
title: String,
5861
#[default = Note::B_1]
5962
start_note: Note,
6063
}
6164
}
6265

66+
impl Props {
67+
/// Like `build` but returns a higher level object rather than a midi stream.
68+
pub fn build_(self) -> ComputerKeyboard {
69+
ComputerKeyboard { sig: self.build() }
70+
}
71+
}
72+
6373
pub fn computer_keyboard(title: impl Into<String>) -> Props {
6474
computer_keyboard_(title.into())
6575
}

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

Lines changed: 32 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,58 @@
11
use crate::{
22
midi,
3-
server::MidiChannelUdp,
4-
widget::{ByTitle, Widget},
3+
widget::{ByTitle, MidiController01Udp, Widget},
54
};
6-
use caw_core::{Buf, Sig, SigShared, SigT};
7-
use caw_midi::{MidiController01, MidiMessagesT};
5+
use caw_core::{Sig, SigShared};
6+
use caw_midi::MidiMessagesT;
87
use lazy_static::lazy_static;
98

10-
pub struct Knob {
11-
sig: Sig<MidiController01<MidiChannelUdp>>,
12-
}
13-
149
lazy_static! {
1510
// Used to prevent multiple windows from opening at the same time with the same name. Note that
1611
// when using with evcxr this seems to get cleared when a cell is recomputed, but this is still
1712
// valuable in the context of stereo signals, where a function is evaluated once for the left
1813
// channel and once for the right channel. In such a case, this prevents each knob openned by
1914
// that function from being openned twice.
20-
static ref BY_TITLE: ByTitle<Knob> = Default::default();
15+
static ref BY_TITLE: ByTitle<Sig<SigShared<MidiController01Udp>>> = Default::default();
2116
}
2217

23-
impl Knob {
24-
pub fn new(
25-
title: String,
26-
initial_value_01: f32,
27-
sensitivity: f32,
28-
) -> Sig<SigShared<Self>> {
29-
BY_TITLE.get_or_insert(title.as_str(), || {
30-
let channel = midi::alloc_channel();
31-
let controller = midi::alloc_controller(channel);
32-
let widget = Widget::new(
33-
title.clone(),
34-
channel,
35-
"knob",
36-
vec![
37-
format!("--controller={}", controller),
38-
format!("--initial-value={}", initial_value_01),
39-
format!("--sensitivity={}", sensitivity),
40-
],
41-
)
42-
.unwrap();
43-
let sig = widget
44-
.channel()
45-
.controllers()
46-
.get_with_initial_value_01(controller.into(), initial_value_01);
47-
Self { sig }
48-
})
49-
}
50-
}
51-
52-
impl SigT for Knob {
53-
type Item = f32;
54-
55-
fn sample(&mut self, ctx: &caw_core::SigCtx) -> impl Buf<Self::Item> {
56-
self.sig.sample(ctx)
57-
}
18+
fn new_knob(
19+
title: String,
20+
initial_value_01: f32,
21+
sensitivity: f32,
22+
) -> Sig<SigShared<MidiController01Udp>> {
23+
BY_TITLE.get_or_insert(title.as_str(), || {
24+
let channel = midi::alloc_channel();
25+
let controller = midi::alloc_controller(channel);
26+
let widget = Widget::new(
27+
title.clone(),
28+
channel,
29+
"knob",
30+
vec![
31+
format!("--controller={}", controller),
32+
format!("--initial-value={}", initial_value_01),
33+
format!("--sensitivity={}", sensitivity),
34+
],
35+
)
36+
.unwrap();
37+
widget
38+
.channel()
39+
.controllers()
40+
.get_with_initial_value_01(controller.into(), initial_value_01)
41+
.shared()
42+
})
5843
}
5944

6045
mod knob_builder {
61-
use super::Knob;
46+
use super::*;
6247
use caw_builder_proc_macros::builder;
6348
use caw_core::{Sig, SigShared};
6449

6550
builder! {
6651
#[constructor = "knob_"]
6752
#[constructor_doc = "A visual knob in a new window"]
6853
#[generic_setter_type_name = "X"]
69-
#[build_fn = "Knob::new"]
70-
#[build_ty = "Sig<SigShared<Knob>>"]
54+
#[build_fn = "new_knob"]
55+
#[build_ty = "Sig<SigShared<MidiController01Udp>>"]
7156
pub struct Props {
7257
title: String,
7358
#[default = 0.5]

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

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::server::{self, MidiChannelUdp};
2-
use caw_core::{Sig, SigShared, SigT, sig_shared};
2+
use caw_core::Sig;
3+
use caw_midi::MidiController01;
34
use midly::num::u4;
45
use std::{collections::HashMap, process::Command, sync::Mutex};
56

@@ -45,28 +46,30 @@ impl Widget {
4546
}
4647
}
4748

48-
pub struct ByTitle<T: SigT>(Mutex<HashMap<String, Sig<SigShared<T>>>>);
49+
pub struct ByTitle<T: Clone>(Mutex<HashMap<String, T>>);
4950

50-
impl<T: SigT> Default for ByTitle<T> {
51+
impl<T: Clone> Default for ByTitle<T> {
5152
fn default() -> Self {
5253
Self(Default::default())
5354
}
5455
}
5556

56-
impl<T: SigT> ByTitle<T> {
57+
impl<T: Clone> ByTitle<T> {
5758
pub fn get_or_insert<F: FnOnce() -> T>(
5859
&self,
5960
title: impl AsRef<str>,
6061
f: F,
61-
) -> Sig<SigShared<T>> {
62+
) -> T {
6263
let title = title.as_ref().to_string();
6364
let mut table = self.0.lock().unwrap();
64-
if let Some(t_shared) = table.get(&title) {
65-
t_shared.clone()
65+
if let Some(t) = table.get(&title) {
66+
t.clone()
6667
} else {
67-
let t_shared = sig_shared(f());
68-
table.insert(title, t_shared.clone());
69-
t_shared
68+
let t = f();
69+
table.insert(title, t.clone());
70+
t
7071
}
7172
}
7273
}
74+
75+
pub type MidiController01Udp = MidiController01<MidiChannelUdp>;

0 commit comments

Comments
 (0)