diff --git a/gtk2_ardour/ardev_common.sh.in b/gtk2_ardour/ardev_common.sh.in index 1934b90781..1edb62986c 100644 --- a/gtk2_ardour/ardev_common.sh.in +++ b/gtk2_ardour/ardev_common.sh.in @@ -19,7 +19,7 @@ export GTK2_RC_FILES=/nonexistent # can find all the components. # -export ARDOUR_SURFACES_PATH=$libs/surfaces/osc:$libs/surfaces/faderport8:$libs/surfaces/faderport:$libs/surfaces/generic_midi:$libs/surfaces/tranzport:$libs/surfaces/powermate:$libs/surfaces/mackie:$libs/surfaces/us2400:$libs/surfaces/wiimote:$libs/surfaces/push2:$libs/surfaces/maschine2:$libs/surfaces/cc121:$libs/surfaces/launch_control_xl:$libs/surfaces/contourdesign:$libs/surfaces/websockets:$libs/surfaces/console1 +export ARDOUR_SURFACES_PATH=$libs/surfaces/osc:$libs/surfaces/faderport8:$libs/surfaces/faderport:$libs/surfaces/generic_midi:$libs/surfaces/tranzport:$libs/surfaces/powermate:$libs/surfaces/mackie:$libs/surfaces/us2400:$libs/surfaces/wiimote:$libs/surfaces/push2:$libs/surfaces/maschine2:$libs/surfaces/cc121:$libs/surfaces/launch_control_xl:$libs/surfaces/contourdesign:$libs/surfaces/websockets:$libs/surfaces/console1:$libs/surfaces/launchpad_pro export ARDOUR_PANNER_PATH=$libs/panners export ARDOUR_DATA_PATH=$TOP/share:$TOP/build:$TOP/gtk2_ardour:$TOP/build/gtk2_ardour export ARDOUR_MIDIMAPS_PATH=$TOP/share/midi_maps diff --git a/libs/ardour/ardour/debug.h b/libs/ardour/ardour/debug.h index 9a682a8930..cd278625a1 100644 --- a/libs/ardour/ardour/debug.h +++ b/libs/ardour/ardour/debug.h @@ -88,6 +88,7 @@ namespace PBD { LIBARDOUR_API extern DebugBits ProcessThreads; LIBARDOUR_API extern DebugBits Processors; LIBARDOUR_API extern DebugBits Push2; + LIBARDOUR_API extern DebugBits Launchpad; LIBARDOUR_API extern DebugBits MIDISurface; LIBARDOUR_API extern DebugBits Selection; LIBARDOUR_API extern DebugBits SessionEvents; diff --git a/libs/ardour/debug.cc b/libs/ardour/debug.cc index d81138ae79..06a3237ce2 100644 --- a/libs/ardour/debug.cc +++ b/libs/ardour/debug.cc @@ -83,6 +83,7 @@ PBD::DebugBits PBD::DEBUG::Ports = PBD::new_debug_bit ("Ports"); PBD::DebugBits PBD::DEBUG::ProcessThreads = PBD::new_debug_bit ("processthreads"); PBD::DebugBits PBD::DEBUG::Processors = PBD::new_debug_bit ("processors"); PBD::DebugBits PBD::DEBUG::Push2 = PBD::new_debug_bit ("push2"); +PBD::DebugBits PBD::DEBUG::Launchpad = PBD::new_debug_bit ("launchpad"); PBD::DebugBits PBD::DEBUG::MIDISurface = PBD::new_debug_bit ("midisurface"); PBD::DebugBits PBD::DEBUG::Selection = PBD::new_debug_bit ("selection"); PBD::DebugBits PBD::DEBUG::SessionEvents = PBD::new_debug_bit ("sessionevents"); diff --git a/libs/surfaces/launchpad_pro/gui.cc b/libs/surfaces/launchpad_pro/gui.cc new file mode 100644 index 0000000000..7e1d29f782 --- /dev/null +++ b/libs/surfaces/launchpad_pro/gui.cc @@ -0,0 +1,272 @@ +/* + * Copyright (C) 2016 Paul Davis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include + +#include "pbd/unwind.h" +#include "pbd/strsplit.h" +#include "pbd/file_utils.h" + +#include "gtkmm2ext/bindings.h" +#include "gtkmm2ext/gui_thread.h" +#include "gtkmm2ext/utils.h" + +#include "ardour/audioengine.h" +#include "ardour/filesystem_paths.h" +#include "ardour/parameter_descriptor.h" + +#include "lppro.h" +#include "gui.h" + +#include "pbd/i18n.h" + +using namespace PBD; +using namespace ARDOUR; +using namespace ArdourSurface; +using namespace Gtk; +using namespace Gtkmm2ext; + +void* +LaunchPadPro::get_gui () const +{ + if (!_gui) { + const_cast(this)->build_gui (); + } + + static_cast(_gui)->show_all(); + return _gui; +} + +void +LaunchPadPro::tear_down_gui () +{ + if (_gui) { + Gtk::Widget *w = static_cast(_gui)->get_parent(); + if (w) { + w->hide(); + delete w; + } + } + delete _gui; + _gui = 0; +} + +void +LaunchPadPro::build_gui () +{ + _gui = new LPPRO_GUI (*this); +} + +/*--------------------*/ + +LPPRO_GUI::LPPRO_GUI (LaunchPadPro& p) + : _lp (p) + , _table (2, 5) + , _action_table (5, 4) + , _ignore_active_change (false) +{ + set_border_width (12); + + _table.set_row_spacings (4); + _table.set_col_spacings (6); + _table.set_border_width (12); + _table.set_homogeneous (false); + + std::string data_file_path; + std::string name = "push2-small.png"; + Searchpath spath(ARDOUR::ardour_data_search_path()); + spath.add_subdirectory_to_paths ("icons"); + find_file (spath, name, data_file_path); + if (!data_file_path.empty()) { + _image.set (data_file_path); + _hpacker.pack_start (_image, false, false); + } + + Gtk::Label* l; + int row = 0; + + _input_combo.pack_start (_midi_port_columns.short_name); + _output_combo.pack_start (_midi_port_columns.short_name); + + _input_combo.signal_changed().connect (sigc::bind (sigc::mem_fun (*this, &LPPRO_GUI::active_port_changed), &_input_combo, true)); + _output_combo.signal_changed().connect (sigc::bind (sigc::mem_fun (*this, &LPPRO_GUI::active_port_changed), &_output_combo, false)); + + l = manage (new Gtk::Label); + l->set_markup (string_compose ("%1", _("Incoming MIDI on:"))); + l->set_alignment (1.0, 0.5); + _table.attach (*l, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0)); + _table.attach (_input_combo, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0); + row++; + + l = manage (new Gtk::Label); + l->set_markup (string_compose ("%1", _("Outgoing MIDI on:"))); + l->set_alignment (1.0, 0.5); + _table.attach (*l, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0)); + _table.attach (_output_combo, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0); + row++; + + _hpacker.pack_start (_table, true, true); + + set_spacing (12); + + pack_start (_hpacker, false, false); + + /* update the port connection combos */ + + update_port_combos (); + + /* catch future changes to connection state */ + + ARDOUR::AudioEngine::instance()->PortRegisteredOrUnregistered.connect (_port_connections, invalidator (*this), boost::bind (&LPPRO_GUI::connection_handler, this), gui_context()); + ARDOUR::AudioEngine::instance()->PortPrettyNameChanged.connect (_port_connections, invalidator (*this), boost::bind (&LPPRO_GUI::connection_handler, this), gui_context()); + _lp.ConnectionChange.connect (_port_connections, invalidator (*this), boost::bind (&LPPRO_GUI::connection_handler, this), gui_context()); +} + +LPPRO_GUI::~LPPRO_GUI () +{ +} + +void +LPPRO_GUI::connection_handler () +{ + /* ignore all changes to combobox active strings here, because we're + updating them to match a new ("external") reality - we were called + because port connections have changed. + */ + + PBD::Unwinder ici (_ignore_active_change, true); + + update_port_combos (); +} + +void +LPPRO_GUI::update_port_combos () +{ + std::vector midi_inputs; + std::vector midi_outputs; + + if (!_lp.input_port() || !_lp.output_port()) { + return; + } + + ARDOUR::AudioEngine::instance()->get_ports ("", ARDOUR::DataType::MIDI, ARDOUR::PortFlags (ARDOUR::IsOutput|ARDOUR::IsTerminal), midi_inputs); + ARDOUR::AudioEngine::instance()->get_ports ("", ARDOUR::DataType::MIDI, ARDOUR::PortFlags (ARDOUR::IsInput|ARDOUR::IsTerminal), midi_outputs); + + Glib::RefPtr input = build_midi_port_list (midi_inputs, true); + Glib::RefPtr output = build_midi_port_list (midi_outputs, false); + bool input_found = false; + bool output_found = false; + int n; + + _input_combo.set_model (input); + _output_combo.set_model (output); + + Gtk::TreeModel::Children children = input->children(); + Gtk::TreeModel::Children::iterator i; + i = children.begin(); + ++i; /* skip "Disconnected" */ + + + for (n = 1; i != children.end(); ++i, ++n) { + std::string port_name = (*i)[_midi_port_columns.full_name]; + if (_lp.input_port()->connected_to (port_name)) { + _input_combo.set_active (n); + input_found = true; + break; + } + } + + if (!input_found) { + _input_combo.set_active (0); /* disconnected */ + } + + children = output->children(); + i = children.begin(); + ++i; /* skip "Disconnected" */ + + for (n = 1; i != children.end(); ++i, ++n) { + std::string port_name = (*i)[_midi_port_columns.full_name]; + if (_lp.output_port()->connected_to (port_name)) { + _output_combo.set_active (n); + output_found = true; + break; + } + } + + if (!output_found) { + _output_combo.set_active (0); /* disconnected */ + } +} + +Glib::RefPtr +LPPRO_GUI::build_midi_port_list (std::vector const & ports, bool for_input) +{ + Glib::RefPtr store = ListStore::create (_midi_port_columns); + TreeModel::Row row; + + row = *store->append (); + row[_midi_port_columns.full_name] = std::string(); + row[_midi_port_columns.short_name] = _("Disconnected"); + + for (std::vector::const_iterator p = ports.begin(); p != ports.end(); ++p) { + row = *store->append (); + row[_midi_port_columns.full_name] = *p; + std::string pn = ARDOUR::AudioEngine::instance()->get_pretty_name_by_name (*p); + if (pn.empty ()) { + pn = (*p).substr ((*p).find (':') + 1); + } + row[_midi_port_columns.short_name] = pn; + } + + return store; +} + +void +LPPRO_GUI::active_port_changed (Gtk::ComboBox* combo, bool for_input) +{ + if (_ignore_active_change) { + return; + } + + TreeModel::iterator active = combo->get_active (); + std::string new_port = (*active)[_midi_port_columns.full_name]; + + if (new_port.empty()) { + if (for_input) { + _lp.input_port()->disconnect_all (); + } else { + _lp.output_port()->disconnect_all (); + } + + return; + } + + if (for_input) { + if (!_lp.input_port()->connected_to (new_port)) { + _lp.input_port()->disconnect_all (); + _lp.input_port()->connect (new_port); + } + } else { + if (!_lp.output_port()->connected_to (new_port)) { + _lp.output_port()->disconnect_all (); + _lp.output_port()->connect (new_port); + } + } +} diff --git a/libs/surfaces/launchpad_pro/gui.h b/libs/surfaces/launchpad_pro/gui.h new file mode 100644 index 0000000000..4aa7033505 --- /dev/null +++ b/libs/surfaces/launchpad_pro/gui.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2016 Paul Davis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __ardour_lppro_gui_h__ +#define __ardour_lppro_gui_h__ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Gtk { + class ListStore; +} + +#include "ardour/mode.h" + +#include "lppro.h" + +namespace ArdourSurface { + +class LPPRO_GUI : public Gtk::VBox +{ +public: + LPPRO_GUI (LaunchPadPro&); + ~LPPRO_GUI (); + +private: + LaunchPadPro& _lp; + Gtk::HBox _hpacker; + Gtk::Table _table; + Gtk::Table _action_table; + Gtk::ComboBox _input_combo; + Gtk::ComboBox _output_combo; + Gtk::Image _image; + + void update_port_combos (); + void connection_handler (); + + PBD::ScopedConnectionList _port_connections; + + struct MidiPortColumns : public Gtk::TreeModel::ColumnRecord { + MidiPortColumns() { + add (short_name); + add (full_name); + } + Gtk::TreeModelColumn short_name; + Gtk::TreeModelColumn full_name; + }; + + MidiPortColumns _midi_port_columns; + bool _ignore_active_change; + + Glib::RefPtr build_midi_port_list (std::vector const & ports, bool for_input); + + void active_port_changed (Gtk::ComboBox*,bool for_input); + +#if 0 + struct PressureModeColumns : public Gtk::TreeModel::ColumnRecord { + PressureModeColumns() { + add (mode); + add (name); + } + Gtk::TreeModelColumn mode; + Gtk::TreeModelColumn name; + }; + + PressureModeColumns _pressure_mode_columns; + Glib::RefPtr build_pressure_mode_columns (); + Gtk::ComboBox _pressure_mode_selector; + Gtk::Label _pressure_mode_label; + + void reprogram_pressure_mode (); +#endif +}; + +} + +#endif /* __ardour_lppro_gui_h__ */ diff --git a/libs/surfaces/launchpad_pro/interface.cc b/libs/surfaces/launchpad_pro/interface.cc new file mode 100644 index 0000000000..b944a2733c --- /dev/null +++ b/libs/surfaces/launchpad_pro/interface.cc @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2016 Paul Davis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +#include "pbd/error.h" + +#include "ardour/rc_configuration.h" + +#include "control_protocol/control_protocol.h" +#include "lppro.h" + +using namespace ARDOUR; +using namespace PBD; +using namespace ArdourSurface; + +static ControlProtocol* +new_lppro (Session* s) +{ + LaunchPadPro * p2 = 0; + + try { + p2 = new LaunchPadPro (*s); + /* do not set active here - wait for set_state() */ + } + catch (std::exception & e) { + error << "Error instantiating LaunchPad Pro support: " << e.what() << endmsg; + delete p2; + p2 = 0; + } + + return p2; +} + +static void +delete_lppro (ControlProtocol* cp) +{ + try + { + delete cp; + } + catch ( std::exception & e ) + { + std::cout << "Exception caught trying to finalize LaunchPad Pro support: " << e.what() << std::endl; + } +} + +static bool +probe_lppro_midi_protocol () +{ + std::string i, o; + return LaunchPadPro::probe (i, o); +} + + +static ControlProtocolDescriptor lppro_descriptor = { + /* name */ "Novation LaunchPad Pro", + /* id */ "uri://ardour.org/surfaces/lppro:0", + /* module */ 0, + /* available */ LaunchPadPro::available, + /* probe_port */ probe_lppro_midi_protocol, + /* match usb */ 0, // LaunchPadPro::match_usb, + /* initialize */ new_lppro, + /* destroy */ delete_lppro, +}; + +extern "C" ARDOURSURFACE_API ControlProtocolDescriptor* protocol_descriptor () { return &lppro_descriptor; } diff --git a/libs/surfaces/launchpad_pro/lppro.cc b/libs/surfaces/launchpad_pro/lppro.cc new file mode 100644 index 0000000000..61a8671749 --- /dev/null +++ b/libs/surfaces/launchpad_pro/lppro.cc @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2016-2018 Paul Davis + * Copyright (C) 2017-2018 Robin Gareus + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include + +#include +#include + +#include "pbd/compose.h" +#include "pbd/convert.h" +#include "pbd/debug.h" +#include "pbd/failed_constructor.h" +#include "pbd/file_utils.h" +#include "pbd/search_path.h" +#include "pbd/enumwriter.h" + +#include "midi++/parser.h" + +#include "temporal/time.h" +#include "temporal/bbt_time.h" + +#include "ardour/amp.h" +#include "ardour/async_midi_port.h" +#include "ardour/audioengine.h" +#include "ardour/debug.h" +#include "ardour/midiport_manager.h" +#include "ardour/midi_track.h" +#include "ardour/midi_port.h" +#include "ardour/session.h" +#include "ardour/tempo.h" +#include "ardour/types_convert.h" + +#include "gtkmm2ext/gui_thread.h" +#include "gtkmm2ext/rgb_macros.h" + +#include "gtkmm2ext/colors.h" + +#include "gui.h" +#include "lppro.h" + +#include "pbd/i18n.h" + +#ifdef PLATFORM_WINDOWS +#define random() rand() +#endif + +using namespace ARDOUR; +using namespace PBD; +using namespace Glib; +using namespace ArdourSurface; +using namespace Gtkmm2ext; + +#include "pbd/abstract_ui.cc" // instantiate template + +#define NOVATION 0x1235 +#define LAUNCHPADPROMK3 0x0123 + +bool +LaunchPadPro::available () +{ + bool rv = LIBUSB_SUCCESS == libusb_init (0); + if (rv) { + libusb_exit (0); + } + return rv; +} + +bool +LaunchPadPro::match_usb (uint16_t vendor, uint16_t device) +{ + return vendor == NOVATION && device == LAUNCHPADPROMK3; +} + +bool +LaunchPadPro::probe (std::string& i, std::string& o) +{ + vector midi_inputs; + vector midi_outputs; + AudioEngine::instance()->get_ports ("", DataType::MIDI, PortFlags (IsOutput|IsTerminal), midi_inputs); + AudioEngine::instance()->get_ports ("", DataType::MIDI, PortFlags (IsInput|IsTerminal), midi_outputs); + + auto has_lppro = [](string const& s) { + std::string pn = AudioEngine::instance()->get_hardware_port_name_by_name (s); + return pn.find ("Launchpad Pro MK3 MIDI 1") != string::npos; + }; + + auto pi = std::find_if (midi_inputs.begin (), midi_inputs.end (), has_lppro); + auto po = std::find_if (midi_outputs.begin (), midi_outputs.end (), has_lppro); + + if (pi == midi_inputs.end () || po == midi_outputs.end ()) { + return false; + } + + i = *pi; + o = *po; + return true; +} + +LaunchPadPro::LaunchPadPro (ARDOUR::Session& s) + : MIDISurface (s, X_("Novation Launchpad Pro"), X_("Launchpad Pro"), true) +{ + run_event_loop (); + port_setup (); + + std::string pn_in, pn_out; + if (probe (pn_in, pn_out)) { + _async_in->connect (pn_in); + _async_out->connect (pn_out); + } +} + +LaunchPadPro::~LaunchPadPro () +{ + DEBUG_TRACE (DEBUG::Launchpad, "push2 control surface object being destroyed\n"); + + stop_event_loop (); + + MIDISurface::drop (); +} + +int +LaunchPadPro::set_active (bool yn) +{ + DEBUG_TRACE (DEBUG::Launchpad, string_compose("Launchpad Pro::set_active init with yn: '%1'\n", yn)); + + if (yn == active()) { + return 0; + } + + if (yn) { + + if (device_acquire ()) { + return -1; + } + + if ((_connection_state & (InputConnected|OutputConnected)) == (InputConnected|OutputConnected)) { + begin_using_device (); + } else { + /* begin_using_device () will get called once we're connected */ + } + + } else { + /* Control Protocol Manager never calls us with false, but + * insteads destroys us. + */ + } + + ControlProtocol::set_active (yn); + + DEBUG_TRACE (DEBUG::Launchpad, string_compose("Launchpad Pro::set_active done with yn: '%1'\n", yn)); + + return 0; +} + +void +LaunchPadPro::run_event_loop () +{ + DEBUG_TRACE (DEBUG::Launchpad, "start event loop\n"); + BaseUI::run (); +} + +void +LaunchPadPro::stop_event_loop () +{ + DEBUG_TRACE (DEBUG::Launchpad, "stop event loop\n"); + BaseUI::quit (); +} + +int +LaunchPadPro::begin_using_device () +{ + DEBUG_TRACE (DEBUG::Launchpad, "begin using device\n"); + +#if 0 + init_buttons (true); + init_touch_strip (false); + reset_pad_colors (); + splash (); + + /* catch current selection, if any so that we can wire up the pads if appropriate */ + stripable_selection_changed (); + + request_pressure_mode (); +#endif + + return MIDISurface::begin_using_device (); +} + +int +LaunchPadPro::stop_using_device () +{ + DEBUG_TRACE (DEBUG::Launchpad, "stop using device\n"); + + if (!_in_use) { + DEBUG_TRACE (DEBUG::Launchpad, "nothing to do, device not in use\n"); + return 0; + } +#if 0 + init_buttons (false); + strip_buttons_off (); + + for (auto & pad : _xy_pad_map) { + pad->set_color (LED::Black); + pad->set_state (LED::NoTransition); + write (pad->state_msg()); + } + +#endif + return MIDISurface::stop_using_device (); +} + +XMLNode& +LaunchPadPro::get_state() const +{ + XMLNode& node (MIDISurface::get_state()); + + return node; +} + +int +LaunchPadPro::set_state (const XMLNode & node, int version) +{ + DEBUG_TRACE (DEBUG::Launchpad, string_compose ("LaunchPadPro::set_state: active %1\n", active())); + + int retval = 0; + + if (MIDISurface::set_state (node, version)) { + return -1; + } + + return retval; +} + +std::string +LaunchPadPro::input_port_name () const +{ +#ifdef __APPLE__ + /* the origin of the numeric magic identifiers is known only to Novation + and may change in time. This is part of how CoreMIDI works. + */ + return X_("system:midi_capture_1319078870"); +#else + return X_("Launchpad Pro MK3 MIDI 1 in"); +#endif +} + +std::string +LaunchPadPro::output_port_name () const +{ +#ifdef __APPLE__ + /* the origin of the numeric magic identifiers is known only to Novation + and may change in time. This is part of how CoreMIDI works. + */ + return X_("system:midi_playback_3409210341"); +#else + return X_("Launchpad Pro MK3 MIDI 1 out"); +#endif +} + +void +LaunchPadPro::stripable_selection_changed () +{ +} diff --git a/libs/surfaces/launchpad_pro/lppro.h b/libs/surfaces/launchpad_pro/lppro.h new file mode 100644 index 0000000000..5a06cc2019 --- /dev/null +++ b/libs/surfaces/launchpad_pro/lppro.h @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2016-2018 Paul Davis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __ardour_lppro_h__ +#define __ardour_lppro_h__ + +#include +#include +#include +#include +#include + +#include + +#define ABSTRACT_UI_EXPORTS +#include "pbd/abstract_ui.h" + +#include "midi++/types.h" + +#include "ardour/mode.h" +#include "ardour/types.h" + +#include "control_protocol/control_protocol.h" +#include "control_protocol/types.h" + +#include "gtkmm2ext/colors.h" + +#include "midi_surface/midi_byte_array.h" +#include "midi_surface/midi_surface.h" + +namespace MIDI { + class Parser; + class Port; +} + +namespace ARDOUR { + class Port; + class MidiBuffer; + class MidiTrack; +} + +namespace ArdourSurface { + +class LPPRO_GUI; + +class LaunchPadPro : public MIDISurface +{ + public: + enum ButtonID { + Left, + Right, + Session, + Note, + Chord, + Custom, + Sequencer, + Projects, + Patterns, + Steps, + PatternSettings, + Velocity, + Probability, + Mutation, + MicroStep, + PrintToClip, + StopClip, + Device, + Sends, + Pan, + Volume, + Solo, + Mute, + RecordArm, + CaptureMIDI, + Play, + FixedLength, + Quantize, + Duplicate, + Clear, + Down, + Up + }; + + LaunchPadPro (ARDOUR::Session&); + ~LaunchPadPro (); + + static bool available (); + static bool match_usb (uint16_t, uint16_t); + static bool probe (std::string&, std::string&); + + std::string input_port_name () const; + std::string output_port_name () const; + + bool has_editor () const { return true; } + void* get_gui () const; + void tear_down_gui (); + + int set_active (bool yn); + XMLNode& get_state() const; + int set_state (const XMLNode & node, int version); + + private: + int begin_using_device (); + int stop_using_device (); + int device_acquire () { return 0; } + void device_release () { } + void run_event_loop (); + void stop_event_loop (); + + void stripable_selection_changed (); + + mutable LPPRO_GUI* _gui; + void build_gui (); +}; + +} /* namespace */ + +#endif /* __ardour_lppro_h__ */ diff --git a/libs/surfaces/launchpad_pro/wscript b/libs/surfaces/launchpad_pro/wscript new file mode 100644 index 0000000000..b71f9fb6af --- /dev/null +++ b/libs/surfaces/launchpad_pro/wscript @@ -0,0 +1,34 @@ +#!/usr/bin/env python +from waflib.extras import autowaf as autowaf +import os + +# Mandatory variables +top = '.' +out = 'build' + +def options(opt): + autowaf.set_options(opt) + +def configure(conf): + autowaf.check_pkg(conf, 'pangomm-1.4', uselib_store='PANGOMM', atleast_version='1.4', mandatory=True) + autowaf.check_pkg(conf, 'cairomm-1.0', uselib_store='CAIROMM', atleast_version='1.8.4', mandatory=True) + +def build(bld): + obj = bld(features = 'cxx cxxshlib') + obj.source = ''' + lppro.cc + interface.cc + gui.cc + ''' + obj.defines = [ 'PACKAGE="ardour_launchpad_pro"' ] + obj.defines += [ 'ARDOURSURFACE_DLL_EXPORTS' ] + obj.defines += [ 'VERSIONSTRING="' + bld.env['VERSION'] + '"' ] + obj.includes = ['.', '..', './launchpad_pro'] + obj.name = 'libardour_launchpad_pro' + obj.target = 'ardour_launchpad_pro' + obj.uselib = 'CAIROMM PANGOMM USB GTKMM SIGCPP XML OSX' + obj.use = 'libardour libardour_cp libardour_midisurface libgtkmm2ext libpbd libevoral libcanvas libtemporal' + obj.install_path = os.path.join(bld.env['LIBDIR'], 'surfaces') + +def shutdown(): + autowaf.shutdown() diff --git a/libs/surfaces/wscript b/libs/surfaces/wscript index 2ca75b131f..c4c9382586 100644 --- a/libs/surfaces/wscript +++ b/libs/surfaces/wscript @@ -28,7 +28,8 @@ children = [ 'us2400', 'launch_control_xl', 'osc', - 'console1' + 'console1', + 'launchpad_pro' ] def options(opt): @@ -89,6 +90,7 @@ def build(bld): bld.recurse('launch_control_xl') bld.recurse('osc') bld.recurse('console1') + bld.recurse('launchpad_pro') if bld.is_defined('BUILD_WIIMOTE'): bld.recurse('wiimote')