skeleton for launchpad pro support
This commit is contained in:
parent
6c44dbf9d6
commit
3fa15d9162
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
|
272
libs/surfaces/launchpad_pro/gui.cc
Normal file
272
libs/surfaces/launchpad_pro/gui.cc
Normal file
@ -0,0 +1,272 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Paul Davis <paul@linuxaudiosystems.com>
|
||||
*
|
||||
* 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 <gtkmm/alignment.h>
|
||||
#include <gtkmm/label.h>
|
||||
#include <gtkmm/liststore.h>
|
||||
|
||||
#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<LaunchPadPro*>(this)->build_gui ();
|
||||
}
|
||||
|
||||
static_cast<Gtk::VBox*>(_gui)->show_all();
|
||||
return _gui;
|
||||
}
|
||||
|
||||
void
|
||||
LaunchPadPro::tear_down_gui ()
|
||||
{
|
||||
if (_gui) {
|
||||
Gtk::Widget *w = static_cast<Gtk::VBox*>(_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 ("<span weight=\"bold\">%1</span>", _("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 ("<span weight=\"bold\">%1</span>", _("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<bool> ici (_ignore_active_change, true);
|
||||
|
||||
update_port_combos ();
|
||||
}
|
||||
|
||||
void
|
||||
LPPRO_GUI::update_port_combos ()
|
||||
{
|
||||
std::vector<std::string> midi_inputs;
|
||||
std::vector<std::string> 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<Gtk::ListStore> input = build_midi_port_list (midi_inputs, true);
|
||||
Glib::RefPtr<Gtk::ListStore> 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<Gtk::ListStore>
|
||||
LPPRO_GUI::build_midi_port_list (std::vector<std::string> const & ports, bool for_input)
|
||||
{
|
||||
Glib::RefPtr<Gtk::ListStore> 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<std::string>::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);
|
||||
}
|
||||
}
|
||||
}
|
101
libs/surfaces/launchpad_pro/gui.h
Normal file
101
libs/surfaces/launchpad_pro/gui.h
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Paul Davis <paul@linuxaudiosystems.com>
|
||||
*
|
||||
* 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 <vector>
|
||||
#include <string>
|
||||
|
||||
#include <gtkmm/box.h>
|
||||
#include <gtkmm/button.h>
|
||||
#include <gtkmm/combobox.h>
|
||||
#include <gtkmm/image.h>
|
||||
#include <gtkmm/table.h>
|
||||
#include <gtkmm/treestore.h>
|
||||
#include <gtkmm/spinbutton.h>
|
||||
#include <gtkmm/notebook.h>
|
||||
|
||||
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<std::string> short_name;
|
||||
Gtk::TreeModelColumn<std::string> full_name;
|
||||
};
|
||||
|
||||
MidiPortColumns _midi_port_columns;
|
||||
bool _ignore_active_change;
|
||||
|
||||
Glib::RefPtr<Gtk::ListStore> build_midi_port_list (std::vector<std::string> 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<Push2::PressureMode> mode;
|
||||
Gtk::TreeModelColumn<std::string> name;
|
||||
};
|
||||
|
||||
PressureModeColumns _pressure_mode_columns;
|
||||
Glib::RefPtr<Gtk::ListStore> build_pressure_mode_columns ();
|
||||
Gtk::ComboBox _pressure_mode_selector;
|
||||
Gtk::Label _pressure_mode_label;
|
||||
|
||||
void reprogram_pressure_mode ();
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* __ardour_lppro_gui_h__ */
|
82
libs/surfaces/launchpad_pro/interface.cc
Normal file
82
libs/surfaces/launchpad_pro/interface.cc
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Paul Davis <paul@linuxaudiosystems.com>
|
||||
*
|
||||
* 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 <stdexcept>
|
||||
|
||||
#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; }
|
280
libs/surfaces/launchpad_pro/lppro.cc
Normal file
280
libs/surfaces/launchpad_pro/lppro.cc
Normal file
@ -0,0 +1,280 @@
|
||||
/*
|
||||
* Copyright (C) 2016-2018 Paul Davis <paul@linuxaudiosystems.com>
|
||||
* Copyright (C) 2017-2018 Robin Gareus <robin@gareus.org>
|
||||
*
|
||||
* 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 <algorithm>
|
||||
#include <bitset>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#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<string> midi_inputs;
|
||||
vector<string> 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 ()
|
||||
{
|
||||
}
|
133
libs/surfaces/launchpad_pro/lppro.h
Normal file
133
libs/surfaces/launchpad_pro/lppro.h
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (C) 2016-2018 Paul Davis <paul@linuxaudiosystems.com>
|
||||
*
|
||||
* 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 <vector>
|
||||
#include <map>
|
||||
#include <stack>
|
||||
#include <list>
|
||||
#include <set>
|
||||
|
||||
#include <libusb.h>
|
||||
|
||||
#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__ */
|
34
libs/surfaces/launchpad_pro/wscript
Normal file
34
libs/surfaces/launchpad_pro/wscript
Normal file
@ -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()
|
@ -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')
|
||||
|
Loading…
Reference in New Issue
Block a user