Add Pianokeyboard + Velocity Control to PC Dialog
authorRobin Gareus <robin@gareus.org>
Fri, 8 Sep 2017 01:32:31 +0000 (03:32 +0200)
committerRobin Gareus <robin@gareus.org>
Fri, 8 Sep 2017 02:32:43 +0000 (04:32 +0200)
gtk2_ardour/patch_change_widget.cc
gtk2_ardour/patch_change_widget.h

index 75bb3b342eda98db8b58afabb4a90724da00cb50..b7aa2cfc12725bbff800ff0d80575428cc2d6a1a 100644 (file)
@@ -52,10 +52,11 @@ PatchChangeWidget::PatchChangeWidget (boost::shared_ptr<ARDOUR::Route> r)
        , _audition_enable (_("Audition on Change"), ArdourWidgets::ArdourButton::led_default_elements)
        , _audition_start_spin (*manage (new Adjustment (48, 0, 127, 1, 16)))
        , _audition_end_spin (*manage (new Adjustment (60, 0, 127, 1, 16)))
+       , _audition_velocity (*manage (new Adjustment (100, 1, 127, 1, 16)))
        , _audition_note_on (false)
+       , _piano ((PianoKeyboard*)piano_keyboard_new())
+       , _pianomm (Glib::wrap((GtkWidget*)_piano))
 {
-       assert (boost::dynamic_pointer_cast<MidiTrack> (r));
-
        Box* box;
        box = manage (new HBox ());
        box->set_border_width (2);
@@ -74,18 +75,22 @@ PatchChangeWidget::PatchChangeWidget (boost::shared_ptr<ARDOUR::Route> r)
        _program_table.set_spacings (1);
        pack_start (_program_table, true, true);
 
-       box = manage (new HBox ());
-       box->set_spacing (4);
-       box->pack_start (_audition_enable, false, false);
-       box->pack_start (*manage (new Label (_("Start Note:"))), false, false);
-       box->pack_start (_audition_start_spin, false, false);
-       box->pack_start (*manage (new Label (_("End Note:"))), false, false);
-       box->pack_start (_audition_end_spin, false, false);
-
-       Box* box2 = manage (new HBox ());
-       box2->pack_start (*box, true, false);
-       box2->set_border_width (2);
-       pack_start (*box2, false, false);
+       if (boost::dynamic_pointer_cast<MidiTrack> (_route)) {
+               box = manage (new HBox ());
+               box->set_spacing (4);
+               box->pack_start (_audition_enable, false, false);
+               box->pack_start (*manage (new Label (_("Start Note:"))), false, false);
+               box->pack_start (_audition_start_spin, false, false);
+               box->pack_start (*manage (new Label (_("End Note:"))), false, false);
+               box->pack_start (_audition_end_spin, false, false);
+               box->pack_start (*manage (new Label (_("Velocity:"))), false, false);
+               box->pack_start (_audition_velocity, false, false);
+
+               Box* box2 = manage (new HBox ());
+               box2->pack_start (*box, true, false);
+               box2->set_border_width (2);
+               pack_start (*box2, false, false);
+       }
 
        for (uint8_t pgm = 0; pgm < 128; ++pgm) {
                _program_btn[pgm].set_text_ellipsize (Pango::ELLIPSIZE_END);
@@ -103,6 +108,14 @@ PatchChangeWidget::PatchChangeWidget (boost::shared_ptr<ARDOUR::Route> r)
                _channel_select.AddMenuElem (MenuElem (buf, sigc::bind (sigc::mem_fun (*this, &PatchChangeWidget::select_channel), chn)));
        }
 
+       if (boost::dynamic_pointer_cast<MidiTrack> (_route)) {
+               piano_keyboard_set_monophonic (_piano, TRUE);
+               g_signal_connect (G_OBJECT (_piano), "note-on", G_CALLBACK (PatchChangeWidget::_note_on_event_handler), this);
+               g_signal_connect (G_OBJECT (_piano), "note-off", G_CALLBACK (PatchChangeWidget::_note_off_event_handler), this);
+               _pianomm->set_flags(Gtk::CAN_FOCUS);
+               pack_start (*_pianomm, false, false);
+       }
+
        _audition_start_spin.set_sensitive (false);
        _audition_end_spin.set_sensitive (false);
 
@@ -122,6 +135,7 @@ PatchChangeWidget::PatchChangeWidget (boost::shared_ptr<ARDOUR::Route> r)
 PatchChangeWidget::~PatchChangeWidget ()
 {
        cancel_audition ();
+       delete _pianomm;
 }
 
 void
@@ -160,7 +174,7 @@ PatchChangeWidget::select_channel (uint8_t chn)
 
        boost::shared_ptr<AutomationControl> bank_msb = _route->automation_control(Evoral::Parameter (MidiCCAutomation, chn, MIDI_CTL_MSB_BANK), true);
        boost::shared_ptr<AutomationControl> bank_lsb = _route->automation_control(Evoral::Parameter (MidiCCAutomation, chn, MIDI_CTL_LSB_BANK), true);
-       boost::shared_ptr<AutomationControl> program = _route->automation_control(Evoral::Parameter (MidiPgmChangeAutomation, chn), true); 
+       boost::shared_ptr<AutomationControl> program = _route->automation_control(Evoral::Parameter (MidiPgmChangeAutomation, chn), true);
 
        bank_msb->Changed.connect (_ac_connections, invalidator (*this),
                        boost::bind (&PatchChangeWidget::bank_changed, this), gui_context ());
@@ -228,9 +242,6 @@ PatchChangeWidget::refill_program_list ()
                        boost::replace_all (n, "_", " ");
                        MIDI::Name::PatchPrimaryKey const& key = (*i)->patch_primary_key ();
 
-                       assert (key.program () < 128);
-                       assert (key.bank () == bank (_channel));
-
                        const uint8_t pgm = key.program();
                        _program_btn[pgm].set_text (n);
                        set_tooltip (_program_btn[pgm], string_compose (_("%1 (Pgm-%2)"), n, (int)(pgm +1)));
@@ -342,7 +353,8 @@ PatchChangeWidget::cancel_audition ()
                event[0] = (MIDI_CMD_NOTE_OFF | _channel);
                event[1] = _audition_note_num;
                event[2] = 0;
-               mt->write_immediate_event(3, event);
+               mt->write_immediate_event (3, event);
+               piano_keyboard_set_note_off (_piano, _audition_note_num);
        }
        _audition_note_on = false;
 }
@@ -380,20 +392,61 @@ PatchChangeWidget::audition_next ()
        if (_audition_note_on) {
                event[0] = (MIDI_CMD_NOTE_OFF | _channel);
                event[1] = _audition_note_num;
-               event[2] = 100;
-               mt->write_immediate_event(3, event);
+               event[2] = 0;
+               mt->write_immediate_event (3, event);
                _audition_note_on = false;
+               piano_keyboard_set_note_off (_piano, _audition_note_num);
                return ++_audition_note_num <= _audition_end_spin.get_value_as_int() && _audition_enable.get_active ();
        } else {
                event[0] = (MIDI_CMD_NOTE_ON | _channel);
                event[1] = _audition_note_num;
-               event[2] = 100;
-               mt->write_immediate_event(3, event);
+               event[2] = _audition_velocity.get_value_as_int ();
+               mt->write_immediate_event (3, event);
                _audition_note_on = true;
+               piano_keyboard_set_note_on (_piano, _audition_note_num);
                return true;
        }
 }
 
+void
+PatchChangeWidget::_note_on_event_handler(GtkWidget*, int note, gpointer arg)
+{
+       ((PatchChangeWidget*)arg)->note_on_event_handler(note);
+}
+
+void
+PatchChangeWidget::_note_off_event_handler(GtkWidget*, int note, gpointer arg)
+{
+       ((PatchChangeWidget*)arg)->note_off_event_handler(note);
+}
+
+void
+PatchChangeWidget::note_on_event_handler (int note)
+{
+       cancel_audition ();
+       _pianomm->grab_focus ();
+       boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (_route);
+       uint8_t event[3];
+       event[0] = (MIDI_CMD_NOTE_ON | _channel);
+       event[1] = note;
+       event[2] = _audition_velocity.get_value_as_int ();
+       mt->write_immediate_event (3, event);
+       _audition_note_on = true;
+       _audition_note_num = note;
+}
+
+void
+PatchChangeWidget::note_off_event_handler (int note)
+{
+       boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (_route);
+       uint8_t event[3];
+       event[0] = (MIDI_CMD_NOTE_OFF | _channel);
+       event[1] = note;
+       event[2] = 0;
+       mt->write_immediate_event (3, event);
+       _audition_note_on = false;
+}
+
 /* ***** query info *****/
 
 int
@@ -405,10 +458,10 @@ PatchChangeWidget::bank (uint8_t chn) const
        return ((int)bank_msb->get_value () << 7) + (int)bank_lsb->get_value();
 }
 
-uint8_t 
+uint8_t
 PatchChangeWidget::program (uint8_t chn) const
 {
-       boost::shared_ptr<AutomationControl> program = _route->automation_control(Evoral::Parameter (MidiPgmChangeAutomation, chn), true); 
+       boost::shared_ptr<AutomationControl> program = _route->automation_control(Evoral::Parameter (MidiPgmChangeAutomation, chn), true);
        return program->get_value();
 }
 
index 47661982fa54e1bdd7ccf66a57faf3414425a08b..f3f78985082b732e4d3be40a7b8f9a9b5e951295 100644 (file)
@@ -31,6 +31,7 @@
 #include "widgets/ardour_dropdown.h"
 
 #include "ardour_dialog.h"
+#include "gtk_pianokeyboard.h"
 
 class PatchChangeWidget : public Gtk::VBox
 {
@@ -88,8 +89,17 @@ private:
        ArdourWidgets::ArdourButton _audition_enable;
        Gtk::SpinButton             _audition_start_spin; // Consider a click-box w/note-names
        Gtk::SpinButton             _audition_end_spin;
+       Gtk::SpinButton             _audition_velocity;
        uint8_t                     _audition_note_num;
        bool                        _audition_note_on;
+
+       PianoKeyboard* _piano;
+       Gtk::Widget*   _pianomm;
+
+       static void _note_on_event_handler (GtkWidget*, int, gpointer);
+       static void _note_off_event_handler (GtkWidget*, int, gpointer);
+       void note_on_event_handler (int);
+       void note_off_event_handler (int);
 };
 
 class PatchChangeGridDialog : public ArdourDialog