Skip to content

Commit cb93c10

Browse files
committed
Widgets are less of a mess
1 parent 1b990b4 commit cb93c10

File tree

11 files changed

+499
-515
lines changed

11 files changed

+499
-515
lines changed

caw/examples/live_example.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use caw::prelude::*;
22
use std::thread;
33

44
fn main() {
5+
env_logger::init();
56
let volume = sv_default();
67
let out: LiveStereoOut = live_stereo_viz_udp(oscilloscope::Config {
78
..Default::default()

midi-udp-widgets-app-lib/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ caw_keyboard = { version = "0.4", path = "../keyboard" }
1818
lazy_static = "1.5"
1919
anyhow = "1.0"
2020
midly = "0.5"
21+
log = "0.4"
2122

2223
[dev-dependencies]
2324
env_logger = "0.11"
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
use crate::{
2+
midi,
3+
server::MidiChannelUdp,
4+
widget::{ByTitle, Widget},
5+
};
6+
use caw_core::{Buf, Sig, SigShared, SigT};
7+
use caw_keyboard::Note;
8+
use caw_midi::{MidiKeyPress, MidiMessagesT};
9+
use lazy_static::lazy_static;
10+
11+
pub struct Button {
12+
sig: Sig<MidiKeyPress<MidiChannelUdp>>,
13+
}
14+
15+
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+
}
34+
}
35+
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+
}
42+
}
43+
44+
mod button_builder {
45+
use super::Button;
46+
use caw_builder_proc_macros::builder;
47+
use caw_core::{Sig, SigShared};
48+
49+
builder! {
50+
#[constructor = "button_"]
51+
#[constructor_doc = "A visual button in a new window"]
52+
#[generic_setter_type_name = "X"]
53+
#[build_fn = "Button::new"]
54+
#[build_ty = "Sig<SigShared<Button>>"]
55+
pub struct Props {
56+
title: String,
57+
}
58+
}
59+
60+
pub fn button(title: impl Into<String>) -> Props {
61+
button_(title.into())
62+
}
63+
}
64+
65+
pub use button_builder::button;
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
use crate::{
2+
midi,
3+
server::MidiChannelUdp,
4+
widget::{ByTitle, Widget},
5+
};
6+
use caw_core::{Buf, Sig, SigShared, SigT};
7+
use caw_keyboard::Note;
8+
use caw_midi::MidiMessages;
9+
use lazy_static::lazy_static;
10+
11+
pub struct ComputerKeyboard {
12+
sig: Sig<MidiChannelUdp>,
13+
}
14+
15+
lazy_static! {
16+
static ref BY_TITLE: ByTitle<ComputerKeyboard> = Default::default();
17+
}
18+
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+
}
34+
}
35+
36+
impl SigT for ComputerKeyboard {
37+
type Item = MidiMessages;
38+
39+
fn sample(&mut self, ctx: &caw_core::SigCtx) -> impl Buf<Self::Item> {
40+
self.sig.sample(ctx)
41+
}
42+
}
43+
44+
mod computer_keyboard_builder {
45+
use super::ComputerKeyboard;
46+
use caw_builder_proc_macros::builder;
47+
use caw_core::{Sig, SigShared};
48+
use caw_keyboard::Note;
49+
50+
builder! {
51+
#[constructor = "computer_keyboard_"]
52+
#[constructor_doc = "Generate midi events with a computer keyboard when this widget is focused"]
53+
#[generic_setter_type_name = "X"]
54+
#[build_fn = "ComputerKeyboard::new"]
55+
#[build_ty = "Sig<SigShared<ComputerKeyboard>>"]
56+
pub struct Props {
57+
title: String,
58+
#[default = Note::B_1]
59+
start_note: Note,
60+
}
61+
}
62+
63+
pub fn computer_keyboard(title: impl Into<String>) -> Props {
64+
computer_keyboard_(title.into())
65+
}
66+
}
67+
68+
pub use computer_keyboard_builder::computer_keyboard;
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
use crate::{
2+
midi,
3+
server::MidiChannelUdp,
4+
widget::{ByTitle, Widget},
5+
};
6+
use caw_core::{Buf, Sig, SigShared, SigT};
7+
use caw_midi::{MidiController01, MidiMessagesT};
8+
use lazy_static::lazy_static;
9+
10+
pub struct Knob {
11+
sig: Sig<MidiController01<MidiChannelUdp>>,
12+
}
13+
14+
lazy_static! {
15+
// Used to prevent multiple windows from opening at the same time with the same name. Note that
16+
// when using with evcxr this seems to get cleared when a cell is recomputed, but this is still
17+
// valuable in the context of stereo signals, where a function is evaluated once for the left
18+
// channel and once for the right channel. In such a case, this prevents each knob openned by
19+
// that function from being openned twice.
20+
static ref BY_TITLE: ByTitle<Knob> = Default::default();
21+
}
22+
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+
}
58+
}
59+
60+
mod knob_builder {
61+
use super::Knob;
62+
use caw_builder_proc_macros::builder;
63+
use caw_core::{Sig, SigShared};
64+
65+
builder! {
66+
#[constructor = "knob_"]
67+
#[constructor_doc = "A visual knob in a new window"]
68+
#[generic_setter_type_name = "X"]
69+
#[build_fn = "Knob::new"]
70+
#[build_ty = "Sig<SigShared<Knob>>"]
71+
pub struct Props {
72+
title: String,
73+
#[default = 0.5]
74+
initial_value_01: f32,
75+
#[default = 0.2]
76+
sensitivity: f32,
77+
}
78+
}
79+
80+
pub fn knob(title: impl Into<String>) -> Props {
81+
knob_(title.into())
82+
}
83+
}
84+
85+
pub use knob_builder::knob;

0 commit comments

Comments
 (0)