start using new keybinding stuff in step editor dialog
[ardour.git] / gtk2_ardour / step_entry.cc
1 /*
2     Copyright (C) 2010 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <iostream>
21
22 #include "pbd/filesystem.h"
23 #include "pbd/file_utils.h"
24
25 #include "gtkmm2ext/keyboard.h"
26 #include "gtkmm2ext/actions.h"
27 #include "gtkmm2ext/bindings.h"
28
29 #include "ardour/filesystem_paths.h"
30
31 #include "ardour_ui.h"
32 #include "midi_channel_selector.h"
33 #include "midi_time_axis.h"
34 #include "step_entry.h"
35 #include "utils.h"
36
37 #include "i18n.h"
38
39 using namespace std;
40 using namespace Gtk;
41 using namespace Gtkmm2ext;
42 using namespace PBD;
43 using namespace ARDOUR;
44
45 static void
46 _note_off_event_handler (GtkWidget* widget, int note, gpointer arg)
47 {
48         ((StepEntry*)arg)->note_off_event_handler (note);
49 }
50
51 static void
52 _rest_event_handler (GtkWidget* widget, gpointer arg)
53 {
54         ((StepEntry*)arg)->rest_event_handler ();
55 }
56
57 StepEntry::StepEntry (MidiTimeAxisView& mtv)
58         : ArdourDialog (string_compose (_("Step Entry: %1"), mtv.name()))
59         , triplet_button ("3")
60         , beat_resync_button (_(">beat"))
61         , bar_resync_button (_(">bar"))
62         , sustain_button (_("sustain"))
63         , rest_button (_("rest"))
64         , grid_rest_button (_("g-rest"))
65         , channel_adjustment (1, 1, 16, 1, 4) 
66         , channel_spinner (channel_adjustment)
67         , _piano (0)
68         , piano (0)
69         , _mtv (&mtv)
70 {
71         /* set channel selector to first selected channel. if none
72            are selected, it will remain at the value set in its
73            constructor, above (1)
74         */
75
76         uint16_t chn_mask = _mtv->channel_selector().get_selected_channels();
77         
78         for (uint32_t i = 0; i < 16; ++i) {
79                 if (chn_mask & (1<<i)) {
80                         channel_adjustment.set_value (i+1);
81                         break;
82                 }
83         }
84
85         RadioButtonGroup length_group = length_1_button.get_group();
86         length_2_button.set_group (length_group);
87         length_4_button.set_group (length_group);
88         length_8_button.set_group (length_group);
89         length_12_button.set_group (length_group);
90         length_16_button.set_group (length_group);
91         length_32_button.set_group (length_group);
92         length_64_button.set_group (length_group);
93
94         Widget* w;
95
96         w = manage (new Image (::get_icon (X_("wholenote"))));
97         w->show();
98         length_1_button.add (*w);
99         w = manage (new Image (::get_icon (X_("halfnote"))));
100         w->show();
101         length_2_button.add (*w);
102         w = manage (new Image (::get_icon (X_("quarternote"))));
103         w->show();
104         length_4_button.add (*w);
105         w = manage (new Image (::get_icon (X_("eighthnote"))));
106         w->show();
107         length_8_button.add (*w);
108         w = manage (new Image (::get_icon (X_("sixteenthnote"))));
109         w->show();
110         length_16_button.add (*w);
111         w = manage (new Image (::get_icon (X_("thirtysecondnote"))));
112         w->show();
113         length_32_button.add (*w);
114         w = manage (new Image (::get_icon (X_("sixtyfourthnote"))));
115         w->show();
116         length_64_button.add (*w);
117
118         length_1_button.property_draw_indicator() = false;
119         length_2_button.property_draw_indicator() = false;
120         length_4_button.property_draw_indicator() = false;
121         length_8_button.property_draw_indicator() = false;
122         length_16_button.property_draw_indicator() = false;
123         length_32_button.property_draw_indicator() = false;
124         length_64_button.property_draw_indicator() = false;
125
126         note_length_box.pack_start (length_1_button, false, false);
127         note_length_box.pack_start (length_2_button, false, false);
128         note_length_box.pack_start (length_4_button, false, false);
129         note_length_box.pack_start (length_8_button, false, false);
130         note_length_box.pack_start (length_16_button, false, false);
131         note_length_box.pack_start (length_32_button, false, false);
132         note_length_box.pack_start (length_64_button, false, false);
133
134         ARDOUR_UI::instance()->set_tip (&length_1_button, _("Set note length to a whole note"), "");
135         ARDOUR_UI::instance()->set_tip (&length_2_button, _("Set note length to a half note"), "");
136         ARDOUR_UI::instance()->set_tip (&length_4_button, _("Set note length to a quarter note"), "");
137         ARDOUR_UI::instance()->set_tip (&length_8_button, _("Set note length to a eighth note"), "");
138         ARDOUR_UI::instance()->set_tip (&length_16_button, _("Set note length to a sixteenth note"), "");
139         ARDOUR_UI::instance()->set_tip (&length_32_button, _("Set note length to a thirty-second note"), "");
140         ARDOUR_UI::instance()->set_tip (&length_64_button, _("Set note length to a sixty-fourth note"), "");
141
142         RadioButtonGroup velocity_group = velocity_ppp_button.get_group();
143         velocity_pp_button.set_group (velocity_group);
144         velocity_p_button.set_group (velocity_group);
145         velocity_mp_button.set_group (velocity_group);
146         velocity_mf_button.set_group (velocity_group);
147         velocity_f_button.set_group (velocity_group);
148         velocity_ff_button.set_group (velocity_group);
149         velocity_fff_button.set_group (velocity_group);
150
151         w = manage (new Image (::get_icon (X_("pianississimo"))));
152         w->show();
153         velocity_ppp_button.add (*w);
154         w = manage (new Image (::get_icon (X_("pianissimo"))));
155         w->show();
156         velocity_pp_button.add (*w);
157         w = manage (new Image (::get_icon (X_("piano"))));
158         w->show();
159         velocity_p_button.add (*w);
160         w = manage (new Image (::get_icon (X_("mezzopiano"))));
161         w->show();
162         velocity_mp_button.add (*w);
163         w = manage (new Image (::get_icon (X_("mezzoforte"))));
164         w->show();
165         velocity_mf_button.add (*w);
166         w = manage (new Image (::get_icon (X_("forte"))));
167         w->show();
168         velocity_f_button.add (*w);
169         w = manage (new Image (::get_icon (X_("fortissimo"))));
170         w->show();
171         velocity_ff_button.add (*w);
172         w = manage (new Image (::get_icon (X_("fortississimo"))));
173         w->show();
174         velocity_fff_button.add (*w);
175
176         velocity_ppp_button.property_draw_indicator() = false;
177         velocity_pp_button.property_draw_indicator() = false;
178         velocity_p_button.property_draw_indicator() = false;
179         velocity_mp_button.property_draw_indicator() = false;
180         velocity_mf_button.property_draw_indicator() = false;
181         velocity_f_button.property_draw_indicator() = false;
182         velocity_ff_button.property_draw_indicator() = false;
183         velocity_fff_button.property_draw_indicator() = false;
184
185         ARDOUR_UI::instance()->set_tip (&velocity_ppp_button, _("Set volume (velocity) to pianississimo"), "");
186         ARDOUR_UI::instance()->set_tip (&velocity_pp_button, _("Set volume (velocity) to pianissimo"), "");
187         ARDOUR_UI::instance()->set_tip (&velocity_p_button, _("Set volume (velocity) to piano"), "");
188         ARDOUR_UI::instance()->set_tip (&velocity_mp_button, _("Set volume (velocity) to mezzo-piano"), "");
189         ARDOUR_UI::instance()->set_tip (&velocity_mf_button, _("Set volume (velocity) to mezzo-forte"), "");
190         ARDOUR_UI::instance()->set_tip (&velocity_f_button, _("Set volume (velocity) to forte"), "");
191         ARDOUR_UI::instance()->set_tip (&velocity_ff_button, _("Set volume (velocity) to forteissimo"), "");
192         ARDOUR_UI::instance()->set_tip (&velocity_fff_button, _("Set volume (velocity) to forteississimo"), "");
193
194         note_velocity_box.pack_start (velocity_ppp_button, false, false);
195         note_velocity_box.pack_start (velocity_pp_button, false, false);
196         note_velocity_box.pack_start (velocity_p_button, false, false);
197         note_velocity_box.pack_start (velocity_mp_button, false, false);
198         note_velocity_box.pack_start (velocity_mf_button, false, false);
199         note_velocity_box.pack_start (velocity_f_button, false, false);
200         note_velocity_box.pack_start (velocity_ff_button, false, false);
201         note_velocity_box.pack_start (velocity_fff_button, false, false);
202
203         Label* l = manage (new Label);
204         l->set_markup ("<b><big>.</big></b>");
205         l->show ();
206         dot_button.add (*l);
207
208         w = manage (new Image (::get_icon (X_("chord"))));
209         w->show();
210         chord_button.add (*w);
211
212         rest_box.pack_start (rest_button, false, false);
213         rest_box.pack_start (grid_rest_button, false, false);
214
215         resync_box.pack_start (beat_resync_button, false, false);
216         resync_box.pack_start (bar_resync_button, false, false);
217
218         ARDOUR_UI::instance()->set_tip (&chord_button, _("Stack inserted notes to form a chord"), "");
219         ARDOUR_UI::instance()->set_tip (&sustain_button, _("Extend selected notes by note length"), "");
220         ARDOUR_UI::instance()->set_tip (&dot_button, _("Use dotted note lengths"), "");
221         ARDOUR_UI::instance()->set_tip (&rest_button, _("Insert a note-length's rest"), "");
222         ARDOUR_UI::instance()->set_tip (&grid_rest_button, _("Insert a grid-unit's rest"), "");
223         ARDOUR_UI::instance()->set_tip (&beat_resync_button, _("Insert a rest until the next beat"), "");
224         ARDOUR_UI::instance()->set_tip (&bar_resync_button, _("Insert a rest until the next bar"), "");
225
226         VBox* v = manage (new VBox);
227         l = manage (new Label (_("Channel")));
228         v->set_spacing (6);
229         v->pack_start (*l, false, false);
230         v->pack_start (channel_spinner, false, false);
231
232         upper_box.set_spacing (6);
233         upper_box.pack_start (chord_button, false, false);
234         upper_box.pack_start (note_length_box, false, false, 12);
235         upper_box.pack_start (triplet_button, false, false);
236         upper_box.pack_start (dot_button, false, false);
237         upper_box.pack_start (sustain_button, false, false);
238         upper_box.pack_start (rest_box, false, false);
239         upper_box.pack_start (resync_box, false, false);
240         upper_box.pack_start (note_velocity_box, false, false, 12);
241         upper_box.pack_start (*v, false, false);
242
243         _piano = (PianoKeyboard*) piano_keyboard_new ();
244         piano = Glib::wrap ((GtkWidget*) _piano);
245
246         piano->set_flags (Gtk::CAN_FOCUS);
247
248         g_signal_connect(G_OBJECT(_piano), "note-off", G_CALLBACK(_note_off_event_handler), this);
249         g_signal_connect(G_OBJECT(_piano), "rest", G_CALLBACK(_rest_event_handler), this);
250         
251         rest_button.signal_clicked().connect (sigc::mem_fun (*this, &StepEntry::rest_click));
252         grid_rest_button.signal_clicked().connect (sigc::mem_fun (*this, &StepEntry::grid_rest_click));
253         chord_button.signal_toggled().connect (sigc::mem_fun (*this, &StepEntry::chord_toggled));
254         triplet_button.signal_toggled().connect (sigc::mem_fun (*this, &StepEntry::triplet_toggled));
255         beat_resync_button.signal_clicked().connect (sigc::mem_fun (*this, &StepEntry::beat_resync_click));
256         bar_resync_button.signal_clicked().connect (sigc::mem_fun (*this, &StepEntry::bar_resync_click));
257
258         packer.set_spacing (6);
259         packer.pack_start (upper_box, false, false);
260         packer.pack_start (*piano, false, false);
261         packer.show_all ();
262
263         get_vbox()->add (packer);
264
265         register_actions ();
266         load_bindings ();
267 }
268
269 StepEntry::~StepEntry()
270 {
271 }
272
273 bool
274 StepEntry::on_key_press_event (GdkEventKey* ev)
275 {
276         KeyboardKey k (ev->state, ev->keyval);
277         
278         if (bindings.activate (k, KeyboardKey::Press)) {
279                 return true;
280         }
281         
282         if (!gtk_window_propagate_key_event (GTK_WINDOW(gobj()), ev)) {
283                 return gtk_window_activate_key (GTK_WINDOW(gobj()), ev);
284         }
285         return true;
286 }
287
288 bool
289 StepEntry::on_key_release_event (GdkEventKey* ev)
290 {
291         if (!gtk_window_propagate_key_event (GTK_WINDOW(gobj()), ev)) {
292                 return gtk_window_activate_key (GTK_WINDOW(gobj()), ev);
293         }
294         return true;
295 }
296
297 void
298 StepEntry::rest_event_handler ()
299 {
300         _mtv->step_edit_rest (0.0);
301 }
302
303 Evoral::MusicalTime
304 StepEntry::note_length () const
305 {
306         Evoral::MusicalTime length = 0.0;
307
308         if (length_64_button.get_active()) {
309                 length = 1.0/64.0;
310         } else if (length_32_button.get_active()) {
311                 length = 1.0/32.0;
312         } else if (length_16_button.get_active()) {
313                 length = 1.0/16.0;
314         } else if (length_8_button.get_active()) {
315                 length = 1.0/8.0;
316         } else if (length_4_button.get_active()) {
317                 length = 1.0/4.0;
318         } else if (length_2_button.get_active()) {
319                 length = 1.0/2.0;
320         } else if (length_1_button.get_active()) {
321                 length = 1.0/1.0;
322         }
323
324         if (dot_button.get_active()) {
325                 length *= 0.5;
326         }
327
328         if (_mtv->step_edit_within_triplet()) {
329                 length *= 2.0/3.0;
330         }
331
332         return length;
333 }
334
335 uint8_t
336 StepEntry::note_velocity () const
337 {
338         uint8_t velocity = 64;
339
340         if (velocity_ppp_button.get_active()) {
341                 velocity = 16;
342         } else if (velocity_pp_button.get_active()) {
343                 velocity = 32;
344         } else if (velocity_p_button.get_active()) {
345                 velocity = 48;
346         } else if (velocity_mp_button.get_active()) {
347                 velocity = 64;
348         } else if (velocity_mf_button.get_active()) {
349                 velocity = 80;
350         } else if (velocity_f_button.get_active()) {
351                 velocity = 96;
352         } else if (velocity_ff_button.get_active()) {
353                 velocity = 112;
354         } else if (velocity_fff_button.get_active()) {
355                 velocity = 127;
356         }
357
358         return velocity;
359 }
360
361 uint8_t 
362 StepEntry::note_channel() const
363 {
364         return channel_adjustment.get_value() - 1;
365 }
366
367 void
368 StepEntry::note_off_event_handler (int note)
369 {
370         _mtv->step_add_note (note_channel(), note, note_velocity(), note_length());
371 }
372
373 void
374 StepEntry::rest_click ()
375 {
376         _mtv->step_edit_rest (note_length());
377 }
378
379 void
380 StepEntry::grid_rest_click ()
381 {
382         _mtv->step_edit_rest (0.0);
383 }
384
385 void
386 StepEntry::triplet_toggled ()
387 {
388         if (triplet_button.get_active () != _mtv->step_edit_within_triplet()) {
389                 _mtv->step_edit_toggle_triplet ();
390         }
391 }
392
393 void
394 StepEntry::chord_toggled ()
395 {
396         if (chord_button.get_active() != _mtv->step_edit_within_chord ()) {
397                 _mtv->step_edit_toggle_chord ();
398         }
399 }
400
401 void
402 StepEntry::on_show ()
403 {
404         ArdourDialog::on_show ();
405         piano->grab_focus ();
406 }
407
408 void
409 StepEntry::beat_resync_click ()
410 {
411         _mtv->step_edit_beat_sync ();
412 }
413
414 void
415 StepEntry::bar_resync_click ()
416 {
417         _mtv->step_edit_bar_sync ();
418 }
419
420 void
421 StepEntry::register_actions ()
422 {
423         /* add named actions for the editor */
424
425         myactions.register_action ("StepEditing", "insert-a", _("Insert Note A"), sigc::mem_fun (*this, &StepEntry::insert_a));
426         myactions.register_action ("StepEditing", "insert-bsharp", _("Insert Note A-sharp"), sigc::mem_fun (*this, &StepEntry::insert_asharp));
427         myactions.register_action ("StepEditing", "insert-b", _("Insert Note B"), sigc::mem_fun (*this, &StepEntry::insert_b));
428         myactions.register_action ("StepEditing", "insert-bsharp", _("Insert Note B-sharp"), sigc::mem_fun (*this, &StepEntry::insert_bsharp));
429         myactions.register_action ("StepEditing", "insert-c", _("Insert Note C"), sigc::mem_fun (*this, &StepEntry::insert_c));
430         myactions.register_action ("StepEditing", "insert-csharp", _("Insert Note C-sharp"), sigc::mem_fun (*this, &StepEntry::insert_csharp));
431         myactions.register_action ("StepEditing", "insert-d", _("Insert Note D"), sigc::mem_fun (*this, &StepEntry::insert_d));
432         myactions.register_action ("StepEditing", "insert-dsharp", _("Insert Note D-sharp"), sigc::mem_fun (*this, &StepEntry::insert_dsharp));
433         myactions.register_action ("StepEditing", "insert-e", _("Insert Note E"), sigc::mem_fun (*this, &StepEntry::insert_e));
434         myactions.register_action ("StepEditing", "insert-f", _("Insert Note F"), sigc::mem_fun (*this, &StepEntry::insert_f));
435         myactions.register_action ("StepEditing", "insert-fsharp", _("Insert Note F-sharp"), sigc::mem_fun (*this, &StepEntry::insert_fsharp));
436         myactions.register_action ("StepEditing", "insert-g", _("Insert Note G"), sigc::mem_fun (*this, &StepEntry::insert_g));
437
438         RadioAction::Group note_length_group;
439
440         myactions.register_radio_action ("StepEditing", note_length_group, "note-length-whole", 
441                                               _("Set Note Length to Whole"), sigc::mem_fun (*this, &StepEntry::note_length_whole));
442         myactions.register_radio_action ("StepEditing", note_length_group, "note-length-half", 
443                                               _("Set Note Length to 1/2"), sigc::mem_fun (*this, &StepEntry::note_length_half));
444         myactions.register_radio_action ("StepEditing", note_length_group, "note-length-quarter",
445                                               _("Set Note Length to 1/4"), sigc::mem_fun (*this, &StepEntry::note_length_quarter));
446         myactions.register_radio_action ("StepEditing", note_length_group, "note-length-eighth",
447                                               _("Set Note Length to 1/8"), sigc::mem_fun (*this, &StepEntry::note_length_eighth));
448         myactions.register_radio_action ("StepEditing", note_length_group, "note-length-sixteenth",
449                                               _("Set Note Length to 1/16"), sigc::mem_fun (*this, &StepEntry::note_length_sixteenth));
450         myactions.register_radio_action ("StepEditing", note_length_group, "note-length-thirtysecond",
451                                               _("Set Note Length to 1/32"), sigc::mem_fun (*this, &StepEntry::note_length_thirtysecond));
452         myactions.register_radio_action ("StepEditing", note_length_group, "note-length-sixtyfourth",
453                                               _("Set Note Length to 1/64"), sigc::mem_fun (*this, &StepEntry::note_length_sixtyfourth));
454         
455         RadioAction::Group note_velocity_group;
456         
457         myactions.register_radio_action ("StepEditing", note_velocity_group, "note-velocity-ppp",
458                                               _("Set Note Velocity to Pianississimo"), sigc::mem_fun (*this, &StepEntry::note_velocity_ppp));
459         myactions.register_radio_action ("StepEditing", note_velocity_group, "note-velocity-pp",
460                                               _("Set Note Velocity to Pianissimo"), sigc::mem_fun (*this, &StepEntry::note_velocity_pp));
461         myactions.register_radio_action ("StepEditing", note_velocity_group, "note-velocity-p",
462                                               _("Set Note Velocity to Piano"), sigc::mem_fun (*this, &StepEntry::note_velocity_p));
463         myactions.register_radio_action ("StepEditing", note_velocity_group, "note-velocity-mp",
464                                               _("Set Note Velocity to Mezzo-Piano"), sigc::mem_fun (*this, &StepEntry::note_velocity_mp));
465         myactions.register_radio_action ("StepEditing", note_velocity_group, "note-velocity-mf",
466                                               _("Set Note Velocity to Mezzo-Forte"), sigc::mem_fun (*this, &StepEntry::note_velocity_mf));
467         myactions.register_radio_action ("StepEditing", note_velocity_group, "note-velocity-f",
468                                               _("Set Note Velocity to Forte"), sigc::mem_fun (*this, &StepEntry::note_velocity_f));
469         myactions.register_radio_action ("StepEditing", note_velocity_group, "note-velocity-ff",
470                                               _("Set Note Velocity to Fortississimo"), sigc::mem_fun (*this, &StepEntry::note_velocity_ff));
471         myactions.register_radio_action ("StepEditing", note_velocity_group, "note-velocity-fff",
472                                               _("Set Note Velocity to Fortississimo"), sigc::mem_fun (*this, &StepEntry::note_velocity_fff));
473 }
474
475 void
476 StepEntry::load_bindings ()
477 {
478         bindings.set_action_map (myactions);
479
480         sys::path binding_file;
481         SearchPath spath = ardour_search_path() + user_config_directory() + system_config_search_path();
482
483         if (find_file_in_search_path (spath, "step_editing.bindings", binding_file)) {
484                 bindings.load (binding_file.to_string());
485         }
486 }
487
488 void
489 StepEntry::insert_a ()
490 {
491 }
492 void
493 StepEntry::insert_asharp ()
494 {
495 }
496 void
497 StepEntry::insert_b ()
498 {
499 }
500 void
501 StepEntry::insert_bsharp ()
502 {
503 }
504 void
505 StepEntry::insert_c ()
506 {
507 }
508 void
509 StepEntry::insert_csharp ()
510 {
511 }
512 void
513 StepEntry::insert_d ()
514 {
515 }
516 void
517 StepEntry::insert_dsharp ()
518 {
519 }
520 void
521 StepEntry::insert_e ()
522 {
523 }
524 void
525 StepEntry::insert_f ()
526 {
527 }
528 void
529 StepEntry::insert_fsharp ()
530 {
531 }
532 void
533 StepEntry::insert_g ()
534 {
535 }
536
537 void
538 StepEntry::note_length_whole ()
539 {
540 }
541 void
542 StepEntry::note_length_half ()
543 {
544 }
545 void
546 StepEntry::note_length_quarter ()
547 {
548 }
549 void
550 StepEntry::note_length_eighth ()
551 {
552 }
553 void
554 StepEntry::note_length_sixteenth ()
555 {
556 }
557 void
558 StepEntry::note_length_thirtysecond ()
559 {
560 }
561 void
562 StepEntry::note_length_sixtyfourth ()
563 {
564 }
565
566 void
567 StepEntry::note_velocity_ppp ()
568 {
569 }
570 void
571 StepEntry::note_velocity_pp ()
572 {
573 }
574 void
575 StepEntry::note_velocity_p ()
576 {
577 }
578 void
579 StepEntry::note_velocity_mp ()
580 {
581 }
582 void
583 StepEntry::note_velocity_mf ()
584 {
585 }
586 void
587 StepEntry::note_velocity_f ()
588 {
589 }
590 void
591 StepEntry::note_velocity_ff ()
592 {
593 }
594 void
595 StepEntry::note_velocity_fff ()
596 {
597 }