1
2use {
3 crate::{
4 makepad_draw::*,
5 makepad_widgets::*,
6 }
7};
8
9live_design!{
10 use link::shaders::*;
11
12 DrawKey= {{DrawKey}} {
13
14 fn height_map(self, pos: vec2) -> float {
15 let fx = 1 - pow(1.2 - sin(pos.x * PI), 10.8);
16 let fy = 1 - pow(1.2 - self.pressed * 0.2 - cos(pos.y * 0.5 * PI), 25.8)
17 return fx + fy
18 }
19
20 fn black_key(self) -> vec4 {
21 let delta = 0.001;
22 let d = self.height_map(self.pos)
24 let dy = self.height_map(self.pos + vec2(0, delta))
25 let dx = self.height_map(self.pos + vec2(delta, 0))
26 let normal = normalize(cross(vec3(delta, 0, dx - d), vec3(0, delta, dy - d)))
27 let light = normalize(vec3(0.65, 0.5, 0.5))
29 let light_hover = normalize(vec3(0.75, 0.5, 1.5))
30 let diff = pow(max(dot(mix(light, light_hover, self.hover * (1 - self.pressed)), normal), 0), 3)
31 return mix(#181818, #bc, diff)
32 }
33
34 fn white_key(self) -> vec4 {
35 return mix(
36 #DEDAD3FF,
37 mix(
38 mix(
39 #EAE7E2FF,
40 #ff,
41 self.hover
42 ),
43 mix(#96989CFF, #131820FF, pow(1.0 - sin(self.pos.x * PI), 1.8)),
44 self.pressed
45 ),
46 self.pos.y
47 )
48 }
49
50 fn pixel(self) -> vec4 {
51 let sdf = Sdf2d::viewport(self.pos * self.rect_size);
53 if self.is_black > 0.5 {
54 sdf.box(0., -4, self.rect_size.x, self.rect_size.y + 4, 1);
55 sdf.fill_keep(self.black_key())
56 }
57 else {
58 sdf.box(0., -4.0, self.rect_size.x, self.rect_size.y + 4.0, 2.0);
59 sdf.fill_keep(self.white_key())
60 }
61 return sdf.result
62 }
63 }
64
65 PianoKey= {{PianoKey}} {
66
67 animator: {
68 hover = {
69 default: off,
70 off = {
71 from: {all: Forward {duration: 0.2}}
72 apply: {draw_key: {hover: 0.0}}
73 }
74
75 on = {
76 from: {all: Snap}
77 apply: {draw_key: {hover: 1.0}}
78 }
79 }
80
81 focus = {
82 default: off
83
84 off = {
85 from: {all: Snap}
86 apply: {draw_key: {focussed: 1.0}}
87 }
88
89 on = {
90 from: {all: Forward {duration: 0.05}}
91 apply: {draw_key: {focussed: 0.0}}
92 }
93 }
94 pressed = {
95 default: off
96 off = {
97 from: {all: Forward {duration: 0.05}}
98 apply: {draw_key: {pressed: 0.0}}
99 }
100
101 on = {
102 from: {all: Snap}
103 apply: {draw_key: {pressed: 1.0}}
104 }
105 }
106 }
107 }
108
109 pub Piano= {{Piano}} {
110 piano_key: <PianoKey> {}
111 white_size: vec2(20.0, 75.0),
112 black_size: vec2(15.0, 50.0),
113 width: Fit,
114 height: Fit
115 }
116}
117
118#[derive(Live, LiveHook, LiveRegister)]#[repr(C)]
120struct DrawKey {
121 #[deref] draw_super: DrawQuad,
122 #[live] is_black: f32,
123 #[live] pressed: f32,
124 #[live] focussed: f32,
125 #[live] hover: f32,
126}
127
128#[derive(Live, LiveHook, LiveRegister)]
129pub struct PianoKey {
130 #[live] draw_key: DrawKey,
131 #[animator] animator: Animator,
132}
133
134#[derive(Live, Widget)]
135pub struct Piano {
136 #[redraw] #[rust] area: Area,
137 #[walk] walk: Walk,
138 #[live] piano_key: Option<LivePtr>,
139
140 #[rust([0; 20])]
141 keyboard_keys_down: [u8; 20],
142
143 #[rust(4)]
144 keyboard_octave: u8,
145
146 #[rust(100)]
147 keyboard_velocity: u8,
148
149 #[live] black_size: Vec2,
150 #[live] white_size: Vec2,
151
152 #[rust] white_keys: ComponentMap<PianoKeyId, PianoKey>,
153 #[rust] black_keys: ComponentMap<PianoKeyId, PianoKey>,
154}
155
156impl LiveHook for Piano {
157 fn after_apply(&mut self, cx: &mut Cx, apply: &mut Apply, index: usize, nodes: &[LiveNode]) {
158 for piano_key in self.white_keys.values_mut().chain(self.black_keys.values_mut()) {
159 if let Some(index) = nodes.child_by_name(index, live_id!(piano_key).as_field()) {
160 piano_key.apply(cx, apply, index, nodes);
161 }
162 }
163 self.area.redraw(cx);
164 }
165}
166
167#[derive(Clone, Debug)]
168pub struct PianoNote {
169 pub is_on: bool,
170 pub note_number: u8,
171 pub velocity: u8
172}
173
174#[derive(Clone, Debug, DefaultNone)]
175pub enum PianoAction {
176 Note(PianoNote),
177 None
178}
179
180pub enum PianoKeyAction {
181 Pressed(u8),
182 Up,
183}
184
185impl PianoKey {
186
187 pub fn draw_abs(&mut self, cx: &mut Cx2d, depth: f32, is_black: f32, rect: Rect) {
188 self.draw_key.draw_depth = depth;
189 self.draw_key.is_black = is_black;
190 self.draw_key.draw_abs(cx, rect);
191 }
192
193 fn set_is_pressed(&mut self, cx: &mut Cx, is: bool, animate: Animate) {
194 self.animator_toggle(cx, is, animate, id!(pressed.on), id!(pressed.off))
195 }
196
197 fn set_is_focussed(&mut self, cx: &mut Cx, is: bool, animate: Animate) {
198 self.animator_toggle(cx, is, animate, id!(focus.on), id!(focus.off))
199 }
200
201 pub fn handle_event(
202 &mut self,
203 cx: &mut Cx,
204 event: &Event,
205 sweep_area: Area,
206 key_id: PianoKeyId,
207 actions: &mut Vec<(PianoKeyId, PianoKeyAction)>
208 ) {
209 if self.animator_handle_event(cx, event).must_redraw() {
210 self.draw_key.area().redraw(cx);
211 }
212 match event.hits_with_sweep_area(cx, self.draw_key.area(), sweep_area) {
213 Hit::FingerHoverIn(_) => {
214 cx.set_cursor(MouseCursor::Hand);
215 self.animator_play(cx, id!(hover.on));
216 }
217 Hit::FingerHoverOut(_) => {
218 self.animator_play(cx, id!(hover.off));
219 }
220 Hit::FingerDown(_) => {
221 self.animator_play(cx, id!(hover.on));
222 self.animator_play(cx, id!(pressed.on));
223 actions.push((key_id, PianoKeyAction::Pressed(127)));
224 }
225 Hit::FingerUp(e) => {
226 if !e.is_sweep && e.device.has_hovers(){
227 self.animator_play(cx, id!(hover.on));
228 }
229 else{
230 self.animator_play(cx, id!(hover.off));
231 }
232 self.animator_play(cx, id!(pressed.off));
233 actions.push((key_id, PianoKeyAction::Up));
234 }
235 _ => {}
236 }
237 }
238}
239
240impl Piano {
241
242 pub fn set_key_focus(&self, cx: &mut Cx) {
243 cx.set_key_focus(self.area);
244 }
245
246 pub fn set_note(&mut self, cx: &mut Cx, is_on: bool, note_number: u8) {
247 let id = LiveId(note_number as u64).into();
248 if let Some(key) = self.black_keys.get_mut(&id) {
249 key.set_is_pressed(cx, is_on, Animate::No)
250 }
251 if let Some(key) = self.white_keys.get_mut(&id) {
252 key.set_is_pressed(cx, is_on, Animate::No)
253 }
254 }
255
256}
257
258impl Widget for Piano{
259 fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope){
260
261 let uid = self.widget_uid();
262 let mut key_actions = Vec::new();
263
264 for (key_id, piano_key) in self.black_keys.iter_mut().chain(self.white_keys.iter_mut()) {
265 piano_key.handle_event(cx, event, self.area, *key_id, &mut key_actions);
266 }
267
268 for (node_id, action) in key_actions {
269 match action {
270 PianoKeyAction::Pressed(velocity) => {
271 self.set_key_focus(cx);
272 cx.widget_action(uid, &scope.path, PianoAction::Note(PianoNote {
273 is_on: true,
274 note_number: node_id.0.0 as u8,
275 velocity
276 }));
277 }
278 PianoKeyAction::Up => {
279 cx.widget_action(uid, &scope.path, PianoAction::Note(PianoNote {
280 is_on: false,
281 note_number: node_id.0.0 as u8,
282 velocity: 127
283 }));
284 }
285 }
286 }
287
288 fn key_map(kk: KeyCode) -> Option<u8> {
291 match kk {
292 KeyCode::KeyA => Some(0),
293 KeyCode::KeyW => Some(1),
294 KeyCode::KeyS => Some(2),
295 KeyCode::KeyE => Some(3),
296 KeyCode::KeyD => Some(4),
297 KeyCode::KeyF => Some(5),
298 KeyCode::KeyT => Some(6),
299 KeyCode::KeyG => Some(7),
300 KeyCode::KeyY => Some(8),
301 KeyCode::KeyH => Some(9),
302 KeyCode::KeyU => Some(10),
303 KeyCode::KeyJ => Some(11),
304 KeyCode::KeyK => Some(12),
305 KeyCode::KeyO => Some(13),
306 KeyCode::KeyL => Some(14),
307 KeyCode::KeyP => Some(15),
308 KeyCode::Semicolon => Some(16),
309 KeyCode::Quote => Some(17),
310 _ => None
311 }
312 }
313
314 match event {
315 Event::KeyDown(ke) => if !ke.is_repeat {
316 if let Some(nn) = key_map(ke.key_code) {
317 let note_number = nn + self.keyboard_octave * 12;
318 self.keyboard_keys_down[nn as usize] = note_number;
319 self.set_note(cx, true, note_number);
320 cx.widget_action(uid, &scope.path, PianoAction::Note(PianoNote {
321 is_on: true,
322 note_number,
323 velocity: self.keyboard_velocity
324 }));
325 }
326 else {match ke.key_code {
327 KeyCode::KeyZ => {
328 self.keyboard_octave -= 1;
329 self.keyboard_octave = self.keyboard_octave.max(1);
330 }
331 KeyCode::KeyX => {
332 self.keyboard_octave += 1;
333 self.keyboard_octave = self.keyboard_octave.min(7);
334 }
335 KeyCode::KeyC => {
336 self.keyboard_velocity -= 16;
337 self.keyboard_velocity = self.keyboard_velocity.max(16);
338 }
339 KeyCode::KeyV => {
340 self.keyboard_velocity += 16;
341 self.keyboard_velocity = self.keyboard_velocity.min(127);
342 }
343 _ => ()
344 }}
345 },
346 Event::KeyUp(ke) => if let Some(nn) = key_map(ke.key_code) {
347 let note_number = self.keyboard_keys_down[nn as usize];
348 self.keyboard_keys_down[nn as usize] = 0;
349 self.set_note(cx, false, note_number);
350 cx.widget_action(uid, &scope.path, PianoAction::Note(PianoNote {
351 is_on: false,
352 note_number,
353 velocity: self.keyboard_velocity
354 }));
355 },
356 _ => ()
357 }
358
359 match event.hits(cx, self.area) {
360 Hit::KeyFocus(_) => {
361 for piano_key in self.white_keys.values_mut().chain(self.black_keys.values_mut()) {
362 piano_key.set_is_focussed(cx, true, Animate::Yes)
363 }
364 }
365 Hit::KeyFocusLost(_) => {
366 for piano_key in self.white_keys.values_mut().chain(self.black_keys.values_mut()) {
367 piano_key.set_is_focussed(cx, true, Animate::No)
368 }
369 }
370 _ => ()
371 }
372 }
373
374 fn draw_walk(&mut self, cx: &mut Cx2d, _scope: &mut Scope, walk: Walk) -> DrawStep {
375
376 cx.begin_turtle(walk, Layout::default());
377
378 let start_pos = cx.turtle().pos(); let mut pos = start_pos;
380
381 let midi_a0 = 21;
382 let midi_c8 = 108+24;
383
384 fn black_key_shift(key: u32) -> Option<f64> {
385 match key % 12 {
386 0 => None, 1 => Some(0.6), 2 => None, 3 => Some(0.4), 4 => None, 5 => None, 6 => Some(0.7), 7 => None, 8 => Some(0.5), 9 => None, 10 => Some(0.3), 11 => None, _ => None
399 }
400 }
401
402 let white_size:DVec2 = self.white_size.into();let black_size:DVec2 = self.black_size.into();let piano_key = self.piano_key;
405 let mut depth = 1.0;
407 for i in midi_a0..midi_c8 {
408 if black_key_shift(i).is_some() {
409 continue;
410 }
411 let key_id = LiveId(i as u64).into();
412 let key = self.white_keys.get_or_insert(cx, key_id, | cx | {
413 PianoKey::new_from_ptr(cx, piano_key)
414 });
415 key.draw_abs(cx, depth, 0.0, Rect {pos: pos, size: white_size});
416 depth += cx.micro_zbias_step();
417 pos.x += white_size.x;
418 }
419 let mut pos = start_pos;
421for i in midi_a0..midi_c8 {
422 if let Some(shift) = black_key_shift(i) {
423 let key_id = LiveId(i as u64).into();
424 let key = self.black_keys.get_or_insert(cx, key_id, | cx | {
425 PianoKey::new_from_ptr(cx, piano_key)
426 });
427 key.draw_abs(cx, depth, 1.0, Rect {
428 pos: pos - dvec2(black_size.x * shift, 0.),
429 size: black_size
430 });
431 depth += cx.micro_zbias_step();
432 }
433 else {
434 pos.x += white_size.x;
435 }
436 }
437 cx.turtle_mut().set_used(white_size.x * (midi_c8 - midi_a0) as f64, white_size.y);
438 cx.end_turtle_with_area(&mut self.area);
439 self.white_keys.retain_visible();
440 self.black_keys.retain_visible();
441
442 DrawStep::done()
443 }
444}
445
446#[derive(Clone, Debug, Default, Eq, Hash, Copy, PartialEq, FromLiveId)]
447pub struct PianoKeyId(pub LiveId);
448
449impl PianoRef {
450 pub fn notes_played(&self, actions:&Actions) -> Vec<PianoNote> {
451 let mut notes = Vec::new();
452 for action in actions {
453 match action.as_widget_action().widget_uid_eq(self.widget_uid()).cast() {
454 PianoAction::Note(note) => {
455 notes.push(note)
456 }
457 PianoAction::None=>()
458 }
459 }
460 notes
461 }
462
463 pub fn set_note(&self, cx: &mut Cx, is_on: bool, note_number: u8) {
464 if let Some(mut inner) = self.borrow_mut() {
465 inner.set_note(cx, is_on, note_number)
466 }
467 }
468
469 pub fn set_key_focus(&self, cx: &mut Cx) {
470 if let Some(inner) = self.borrow_mut() {
471 inner.set_key_focus(cx)
472 }
473 }
474}
475
476impl PianoSet {
477 pub fn notes_played(&self, actions:&Actions) -> Vec<PianoNote> {
478 let mut notes = Vec::new();
479 for item in self.iter() {
480 for action in actions {
481 match action.as_widget_action().widget_uid_eq(item.widget_uid()).cast() {
482 PianoAction::Note(note) =>{
483 notes.push(note)
484 }
485 PianoAction::None=>()
486 }
487 }
488 }
489 notes
490 }
491
492 pub fn set_note(&self, cx: &mut Cx, is_on: bool, note_number: u8) {
493 for item in self.iter(){
494 item.set_note(cx, is_on, note_number);
495 }
496 }
497}