From 5ae72d574c27bfb4412ba8161918fb3c5d5745db Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Thu, 16 Jun 2016 17:45:41 -0400 Subject: [PATCH] only 1 MIDI port needed; more button functionality --- libs/surfaces/push2/buttons.cc | 25 +++++- libs/surfaces/push2/push2.cc | 140 ++++++++++++++++++--------------- libs/surfaces/push2/push2.h | 23 ++++-- 3 files changed, 118 insertions(+), 70 deletions(-) diff --git a/libs/surfaces/push2/buttons.cc b/libs/surfaces/push2/buttons.cc index 1db04f486e..84a6aee389 100644 --- a/libs/surfaces/push2/buttons.cc +++ b/libs/surfaces/push2/buttons.cc @@ -17,7 +17,6 @@ Push2::button_play () void Push2::button_recenable () { - std::cerr << "RE toggle\n"; rec_enable_toggle (); } @@ -32,3 +31,27 @@ Push2::button_down () { scroll_dn_1_track (); } + +void +Push2::button_right () +{ + ScrollTimeline (0.75); +} + +void +Push2::button_left () +{ + ScrollTimeline (-0.75); +} + +void +Push2::button_repeat () +{ + loop_toggle (); +} + +void +Push2::button_metronome () +{ + toggle_click (); +} diff --git a/libs/surfaces/push2/push2.cc b/libs/surfaces/push2/push2.cc index 9b6d84dbe3..263ac74dfb 100644 --- a/libs/surfaces/push2/push2.cc +++ b/libs/surfaces/push2/push2.cc @@ -57,6 +57,10 @@ Push2::Push2 (ARDOUR::Session& s) , device_buffer (0) , frame_buffer (Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, cols, rows)) { + if (open ()) { + throw failed_constructor (); + } + build_maps (); } @@ -70,6 +74,11 @@ Push2::open () { int err; + if (handle) { + /* already open */ + return 0; + } + if ((handle = libusb_open_device_with_vid_pid (NULL, ABLETON, PUSH2)) == 0) { return -1; } @@ -92,35 +101,15 @@ Push2::open () /* setup ports */ - _async_in[0] = AudioEngine::instance()->register_input_port (DataType::MIDI, X_("push2 in1"), true); - _async_out[0] = AudioEngine::instance()->register_output_port (DataType::MIDI, X_("push2 out1"), true); + _async_in = AudioEngine::instance()->register_input_port (DataType::MIDI, X_("push2 in"), true); + _async_out = AudioEngine::instance()->register_output_port (DataType::MIDI, X_("push2 out"), true); - if (_async_in[0] == 0 || _async_out[0] == 0) { + if (_async_in == 0 || _async_out == 0) { return -1; } - _input_port[0] = boost::dynamic_pointer_cast(_async_in[0]).get(); - _output_port[0] = boost::dynamic_pointer_cast(_async_out[0]).get(); - - _async_in[1] = AudioEngine::instance()->register_input_port (DataType::MIDI, X_("push2 in2"), true); - _async_out[1] = AudioEngine::instance()->register_output_port (DataType::MIDI, X_("push2 out2"), true); - - if (_async_in[1] == 0 || _async_out[1] == 0) { - return -1; - } - - _input_port[1] = boost::dynamic_pointer_cast(_async_in[1]).get(); - _output_port[1] = boost::dynamic_pointer_cast(_async_out[1]).get(); - - AsyncMIDIPort* asp; - - asp = dynamic_cast (_input_port[0]); - asp->xthread().set_receive_handler (sigc::bind (sigc::mem_fun (this, &Push2::midi_input_handler), _input_port[0])); - asp->xthread().attach (main_loop()->get_context()); - - asp = dynamic_cast (_input_port[1]); - asp->xthread().set_receive_handler (sigc::bind (sigc::mem_fun (this, &Push2::midi_input_handler), _input_port[1])); - asp->xthread().attach (main_loop()->get_context()); + _input_port = boost::dynamic_pointer_cast(_async_in).get(); + _output_port = boost::dynamic_pointer_cast(_async_out).get(); connect_to_parser (); @@ -130,15 +119,13 @@ Push2::open () int Push2::close () { - AudioEngine::instance()->unregister_port (_async_in[0]); - AudioEngine::instance()->unregister_port (_async_out[0]); - AudioEngine::instance()->unregister_port (_async_in[1]); - AudioEngine::instance()->unregister_port (_async_out[1]); + AudioEngine::instance()->unregister_port (_async_in); + AudioEngine::instance()->unregister_port (_async_out); - _async_in[0].reset ((ARDOUR::Port*) 0); - _async_out[0].reset ((ARDOUR::Port*) 0); - _async_in[1].reset ((ARDOUR::Port*) 0); - _async_out[1].reset ((ARDOUR::Port*) 0); + _async_in.reset ((ARDOUR::Port*) 0); + _async_out.reset ((ARDOUR::Port*) 0); + _input_port = 0; + _output_port = 0; vblank_connection.disconnect (); periodic_connection.disconnect (); @@ -147,6 +134,7 @@ Push2::close () if (handle) { libusb_release_interface (handle, 0x00); libusb_close (handle); + handle = 0; } delete [] device_frame_buffer[0]; @@ -304,20 +292,20 @@ Push2::set_active (bool yn) return -1; } + /* Connect input port to event loop */ + + AsyncMIDIPort* asp; + + asp = dynamic_cast (_input_port); + asp->xthread().set_receive_handler (sigc::bind (sigc::mem_fun (this, &Push2::midi_input_handler), _input_port)); + asp->xthread().attach (main_loop()->get_context()); + connect_session_signals (); /* say hello */ Cairo::RefPtr context = Cairo::Context::create (frame_buffer); - if (!context) { - cerr << "Cannot create context\n"; - return -1; - } Glib::RefPtr layout = Pango::Layout::create (context); - if (!layout) { - cerr << "Cannot create layout\n"; - return -1; - } layout->set_text ("hello, Ardour"); Pango::FontDescription fd ("Sans Bold 12"); @@ -364,11 +352,11 @@ Push2::set_active (bool yn) } void -Push2::write (int port, const MidiByteArray& data) +Push2::write (const MidiByteArray& data) { - /* immediate delivery */ cerr << data << endl; - _output_port[port]->write (&data[0], data.size(), 0); + /* immediate delivery */ + _output_port->write (&data[0], data.size(), 0); } bool @@ -405,9 +393,9 @@ Push2::periodic () void Push2::connect_to_parser () { - DEBUG_TRACE (DEBUG::Push2, string_compose ("Connecting to signals on port %2\n", _input_port[0]->name())); + DEBUG_TRACE (DEBUG::Push2, string_compose ("Connecting to signals on port %2\n", _input_port->name())); - MIDI::Parser* p = _input_port[0]->parser(); + MIDI::Parser* p = _input_port->parser(); /* Incoming sysex */ p->sysex.connect_same_thread (*this, boost::bind (&Push2::handle_midi_sysex, this, _1, _2, _3)); @@ -430,7 +418,6 @@ Push2::handle_midi_sysex (MIDI::Parser&, MIDI::byte* raw_bytes, size_t sz) void Push2::handle_midi_controller_message (MIDI::Parser&, MIDI::EventTwoBytes* ev) { - cerr << "controller " << (int) ev->controller_number << " = " << (int) ev->value << endl; CCButtonMap::iterator b = cc_button_map.find (ev->controller_number); if (b != cc_button_map.end()) { if (ev->value == 0) { @@ -575,7 +562,7 @@ Push2::build_maps () MAKE_COLOR_BUTTON (Fwd4trT, 37); MAKE_COLOR_BUTTON (Fwd4tr, 36); MAKE_COLOR_BUTTON (Automate, 89); - MAKE_COLOR_BUTTON_PRESS (RecordEnable, 86, &Push::button_recenable); + MAKE_COLOR_BUTTON_PRESS (RecordEnable, 86, &Push2::button_recenable); MAKE_COLOR_BUTTON_PRESS (Play, 85, &Push2::button_play); #define MAKE_WHITE_BUTTON(i,cc)\ @@ -588,7 +575,7 @@ Push2::build_maps () id_button_map.insert (make_pair (button->id, button)) MAKE_WHITE_BUTTON (TapTempo, 3); - MAKE_WHITE_BUTTON (Metronome, 9); + MAKE_WHITE_BUTTON_PRESS (Metronome, 9, &Push2::button_metronome); MAKE_WHITE_BUTTON (Setup, 30); MAKE_WHITE_BUTTON (User, 59); MAKE_WHITE_BUTTON (Delete, 118); @@ -605,10 +592,10 @@ Push2::build_maps () MAKE_WHITE_BUTTON (New, 87); MAKE_WHITE_BUTTON (FixedLength, 90); MAKE_WHITE_BUTTON_PRESS (Up, 46, &Push2::button_up); - MAKE_WHITE_BUTTON (Right, 45); + MAKE_WHITE_BUTTON_PRESS (Right, 45, &Push2::button_right); MAKE_WHITE_BUTTON_PRESS (Down, 47, &Push2::button_down); - MAKE_WHITE_BUTTON (Left, 44); - MAKE_WHITE_BUTTON (Repeat, 56); + MAKE_WHITE_BUTTON_PRESS (Left, 44, &Push2::button_left); + MAKE_WHITE_BUTTON_PRESS (Repeat, 56, &Push2::button_repeat); MAKE_WHITE_BUTTON (Accent, 57); MAKE_WHITE_BUTTON (Scale, 58); MAKE_WHITE_BUTTON (Layout, 31); @@ -667,36 +654,40 @@ Push2::notify_record_state_changed () return; } - if (session->actively_recording ()) { - b->second->set_state (LED::OneShot24th); - b->second->set_color (127); - } else { + b->second->set_color (LED::Red); + + switch (session->record_status ()) { + case Session::Disabled: b->second->set_state (LED::Off); + break; + case Session::Enabled: + b->second->set_state (LED::Blinking4th); + break; + case Session::Recording: + b->second->set_state (LED::OneShot24th); + break; } - write (0, b->second->state_msg()); + write (b->second->state_msg()); } void Push2::notify_transport_state_changed () { - cerr << "ts change, id button map holds " << id_button_map.size() << endl; - IDButtonMap::iterator b = id_button_map.find (Play); if (b == id_button_map.end()) { - cerr << " no button\n"; return; } if (session->transport_rolling()) { b->second->set_state (LED::OneShot24th); - b->second->set_color (125); + b->second->set_color (LED::Blue); } else { b->second->set_state (LED::Off); } - write (0, b->second->state_msg()); + write (b->second->state_msg()); } void @@ -724,15 +715,21 @@ Push2::notify_solo_active_changed (bool yn) b->second->set_state (LED::Off); } - write (0, b->second->state_msg()); + write (b->second->state_msg()); } XMLNode& Push2::get_state() { XMLNode& node (ControlProtocol::get_state()); + XMLNode* child; - DEBUG_TRACE (DEBUG::Push2, "Push2::get_state done\n"); + child = new XMLNode (X_("Input")); + child->add_child_nocopy (_async_in->get_state()); + node.add_child_nocopy (*child); + child = new XMLNode (X_("Output")); + child->add_child_nocopy (_async_out->get_state()); + node.add_child_nocopy (*child); return node; } @@ -748,6 +745,21 @@ Push2::set_state (const XMLNode & node, int version) return -1; } + XMLNode* child; + + if ((child = node.child (X_("Input"))) != 0) { + XMLNode* portnode = child->child (Port::state_node_name.c_str()); + if (portnode) { + _async_in->set_state (*portnode, version); + } + } + + if ((child = node.child (X_("Output"))) != 0) { + XMLNode* portnode = child->child (Port::state_node_name.c_str()); + if (portnode) { + _async_out->set_state (*portnode, version); + } + } return retval; } diff --git a/libs/surfaces/push2/push2.h b/libs/surfaces/push2/push2.h index 48359b6637..37be3b4809 100644 --- a/libs/surfaces/push2/push2.h +++ b/libs/surfaces/push2/push2.h @@ -169,6 +169,15 @@ class Push2 : public ARDOUR::ControlProtocol Blinking2th }; + enum Colors { + Red = 127, + Green = 126, + Blue = 125, + DarkGray = 124, + LightGray = 123, + White = 122 + }; + LED (uint8_t e) : _extra (e), _color_index (0), _state (Off) {} virtual ~LED() {} @@ -283,10 +292,10 @@ class Push2 : public ARDOUR::ControlProtocol void build_maps (); - MIDI::Port* _input_port[2]; - MIDI::Port* _output_port[2]; - boost::shared_ptr _async_in[2]; - boost::shared_ptr _async_out[2]; + MIDI::Port* _input_port; + MIDI::Port* _output_port; + boost::shared_ptr _async_in; + boost::shared_ptr _async_out; void connect_to_parser (); void handle_midi_pitchbend_message (MIDI::Parser&, MIDI::pitchbend_t); @@ -295,7 +304,7 @@ class Push2 : public ARDOUR::ControlProtocol void handle_midi_note_off_message (MIDI::Parser&, MIDI::EventTwoBytes*); void handle_midi_sysex (MIDI::Parser&, MIDI::byte *, size_t count); - void write (int port, const MidiByteArray&); + void write (const MidiByteArray&); bool midi_input_handler (Glib::IOCondition ioc, MIDI::Port* port); bool periodic (); @@ -314,6 +323,10 @@ class Push2 : public ARDOUR::ControlProtocol void button_recenable (); void button_up (); void button_down (); + void button_right (); + void button_left (); + void button_metronome (); + void button_repeat (); };