reserved_io_names[_("Mackie")] = false;
reserved_io_names[_("FaderPort Recv")] = false;
reserved_io_names[_("FaderPort Send")] = false;
+ reserved_io_names[_("FaderPort2 Recv")] = false;
+ reserved_io_names[_("FaderPort2 Send")] = false;
reserved_io_names[_("FaderPort8 Recv")] = false;
reserved_io_names[_("FaderPort8 Send")] = false;
reserved_io_names[_("FaderPort16 Recv")] = false;
X_(".*FaderPort .*"),
X_(".*FaderPort8 .*"),
X_(".*FaderPort16 .*"),
+ X_(".*FaderPort2 .*"),
X_(".*US-2400 .*"),
X_(".*Mackie .*"),
};
#include "ardour/plugin_insert.h"
#include "ardour/session.h"
#include "ardour/session_configuration.h"
+#include "ardour/track.h"
#include "ardour/types.h"
#include "gtkmm2ext/actions.h"
#define BindMethod(ID, CB) \
_ctrls.button (FP8Controls::ID).released.connect_same_thread (button_connections, boost::bind (&FaderPort8:: CB, this));
+#define BindMethod2(ID, ACT, CB) \
+ _ctrls.button (FP8Controls::ID). ACT .connect_same_thread (button_connections, boost::bind (&FaderPort8:: CB, this));
+
#define BindFunction(ID, ACT, CB, ...) \
_ctrls.button (FP8Controls::ID). ACT .connect_same_thread (button_connections, boost::bind (&FaderPort8:: CB, this, __VA_ARGS__));
void
FaderPort8::setup_actions ()
{
- BindMethod (BtnPlay, button_play);
- BindMethod (BtnStop, button_stop);
- BindMethod (BtnLoop, button_loop);
- BindMethod (BtnRecord, button_record);
- BindMethod (BtnClick, button_metronom);
+ BindMethod2 (BtnPlay, pressed, button_play);
+ BindMethod2 (BtnStop, pressed, button_stop);
+ BindMethod2 (BtnLoop, pressed, button_loop);
+ BindMethod2 (BtnRecord, pressed, button_record);
+ BindMethod2 (BtnClick, pressed, button_metronom);
BindAction (BtnRedo, "Editor", "redo");
BindAction (BtnSave, "Common", "Save");
BindFunction (BtnALatch, released, button_automation, ARDOUR::Latch);
_ctrls.button (FP8Controls::BtnEncoder).pressed.connect_same_thread (button_connections, boost::bind (&FaderPort8::button_encoder, this));
+#ifdef FADERPORT2
+ _ctrls.button (FP8Controls::BtnParam).pressed.connect_same_thread (button_connections, boost::bind (&FaderPort8::button_encoder, this));
+#else
_ctrls.button (FP8Controls::BtnParam).pressed.connect_same_thread (button_connections, boost::bind (&FaderPort8::button_parameter, this));
+#endif
BindMethod (BtnBypass, button_bypass);
BindMethod (BtnLink, button_link);
BindMethod (BtnLock, button_lock);
+ BindMethod (BtnChanLock, button_chanlock); //FP2 only
+ BindMethod (BtnFlip, button_flip); //FP2 only
+
// user-specific
for (FP8Controls::UserButtonMap::const_iterator i = _ctrls.user_buttons ().begin ();
i != _ctrls.user_buttons ().end (); ++i) {
AccessAction ("Common", "addExistingAudioFiles");
}
}
+
+void
+FaderPort8::button_chanlock ()
+{
+ _chan_locked = !_chan_locked;
+
+ _ctrls.button (FP8Controls::BtnChannel).set_blinking (_chan_locked);
+}
+
+void
+FaderPort8::button_flip ()
+{
+}
+
void
FaderPort8::button_lock ()
{
switch (fadermode) {
case ModePlugins:
#if 0 // Plugin Control Automation Mode
- for ( std::list <ProcessorCtrl>::iterator i = _proc_params.begin(); i != _proc_params.end(); ++i) {
+ for (std::list <ProcessorCtrl>::iterator i = _proc_params.begin(); i != _proc_params.end(); ++i) {
((*i).ac)->set_automation_state (as);
}
#endif
void
FaderPort8::button_arm (bool press)
{
+#ifdef FADERPORT2
+ boost::shared_ptr<Stripable> s = first_selected_stripable();
+ if (press && s) {
+ boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(s);
+ if (t) {
+ t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), PBD::Controllable::UseGroup);
+ }
+ }
+#else
FaderMode fadermode = _ctrls.fader_mode ();
if (fadermode == ModeTrack || fadermode == ModePan) {
_ctrls.button (FP8Controls::BtnArm).set_active (press);
ARMButtonChange (press); /* EMIT SIGNAL */
}
+#endif
}
void
break;
case NavMaster:
case NavScroll:
+ case NavPan:
bank (!next, false);
break;
case NavBank:
}
}
break;
+ case NavPan:
+ break;
case NavSection:
// TODO nudge
break;
AccessAction ("Common", "nudge-playhead-forward");
}
break;
+ case NavPan:
+ abort(); /*NOTREACHED*/
+ break;
}
}
notify_mute_changed ();
notify_parameter_changed ("clicking");
- notify_automation_mode_changed (); // XXX (stip specific, see below)
+ notify_route_state_changed (); // XXX (stip specific, see below)
}
// TODO: AutomationState display of plugin & send automation
// TODO: link/lock control AS.
void
-FaderPort8::notify_automation_mode_changed ()
+FaderPort8::notify_route_state_changed ()
{
boost::shared_ptr<Stripable> s = first_selected_stripable();
boost::shared_ptr<AutomationControl> ac;
_ctrls.button (FP8Controls::BtnATouch).set_active (false);
_ctrls.button (FP8Controls::BtnARead).set_active (false);
_ctrls.button (FP8Controls::BtnAWrite).set_active (false);
+#ifdef FADERPORT2
+ _ctrls.button (FP8Controls::BtnArm).set_active (false);
+#endif
return;
}
_ctrls.button (FP8Controls::BtnARead).set_active (as == Play);
_ctrls.button (FP8Controls::BtnAWrite).set_active (as == Write);
_ctrls.button (FP8Controls::BtnALatch).set_active (as == Latch);
+
+#ifdef FADERPORT2
+ /* handle the Faderport's track-arm button */
+ ac = s->rec_enable_control ();
+ _ctrls.button (FP8Controls::BtnArm).set_active (ac ? ac->get_value() : false);
+#endif
}
void
--- /dev/null
+/*
+ * Copyright (C) 2017 Robin Gareus <robin@gareus.org>
+ * Copyright (C) 2015 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 <pbd/failed_constructor.h>
+
+#include "control_protocol/control_protocol.h"
+#include "faderport8.h"
+
+using namespace ARDOUR;
+using namespace ArdourSurface::FP_NAMESPACE;
+
+static ControlProtocol*
+new_faderport2_midi_protocol (ControlProtocolDescriptor* /*descriptor*/, Session* s)
+{
+ FaderPort8* fp;
+
+ try {
+ fp = new FaderPort8 (*s);
+ } catch (failed_constructor& err) {
+ return 0;
+ }
+
+ if (fp->set_active (true)) {
+ delete fp;
+ return 0;
+ }
+
+ return fp;
+}
+
+static void
+delete_faderport2_midi_protocol (ControlProtocolDescriptor* /*descriptor*/, ControlProtocol* cp)
+{
+ delete cp;
+}
+
+static bool
+probe_faderport2_midi_protocol (ControlProtocolDescriptor* /*descriptor*/)
+{
+ return FaderPort8::probe ();
+}
+
+static void*
+faderport2_request_buffer_factory (uint32_t num_requests)
+{
+ return FaderPort8::request_factory (num_requests);
+}
+
+static ControlProtocolDescriptor faderport2_midi_descriptor = {
+ /*name : */ "PreSonus FaderPort2",
+ /*id : */ "uri://ardour.org/surfaces/faderport2:0",
+ /*ptr : */ 0,
+ /*module : */ 0,
+ /*mandatory : */ 0,
+ /*supports_feedback : */ true,
+ /*probe : */ probe_faderport2_midi_protocol,
+ /*initialize : */ new_faderport2_midi_protocol,
+ /*destroy : */ delete_faderport2_midi_protocol,
+ /*request_buffer_factory */ faderport2_request_buffer_factory
+};
+
+extern "C" ARDOURSURFACE_API
+ControlProtocolDescriptor* protocol_descriptor () {
+ return &faderport2_midi_descriptor;
+}
FaderPort8::FaderPort8 (Session& s)
#ifdef FADERPORT16
: ControlProtocol (s, _("PreSonus FaderPort16"))
+#elif defined FADERPORT2
+ : ControlProtocol (s, _("PreSonus FaderPort2"))
#else
: ControlProtocol (s, _("PreSonus FaderPort8"))
#endif
, gui (0)
, _link_enabled (false)
, _link_locked (false)
+ , _chan_locked (false)
, _clock_mode (1)
, _scribble_mode (2)
, _two_line_text (false)
#ifdef FADERPORT16
inp = AudioEngine::instance()->register_input_port (DataType::MIDI, "FaderPort16 Recv", true);
outp = AudioEngine::instance()->register_output_port (DataType::MIDI, "FaderPort16 Send", true);
+#elif defined FADERPORT2
+ inp = AudioEngine::instance()->register_input_port (DataType::MIDI, "FaderPort2 Recv", true);
+ outp = AudioEngine::instance()->register_output_port (DataType::MIDI, "FaderPort2 Send", true);
#else
inp = AudioEngine::instance()->register_input_port (DataType::MIDI, "FaderPort8 Recv", true);
outp = AudioEngine::instance()->register_output_port (DataType::MIDI, "FaderPort8 Send", true);
#ifdef FADERPORT16
_input_bundle.reset (new ARDOUR::Bundle (_("FaderPort16 (Receive)"), true));
- _output_bundle.reset (new ARDOUR::Bundle (_("FaderPort16 (Send) "), false));
+ _output_bundle.reset (new ARDOUR::Bundle (_("FaderPort16 (Send)"), false));
+#elif defined FADERPORT2
+ _input_bundle.reset (new ARDOUR::Bundle (_("FaderPort2 (Receive)"), true));
+ _output_bundle.reset (new ARDOUR::Bundle (_("FaderPort2 (Send)"), false));
#else
_input_bundle.reset (new ARDOUR::Bundle (_("FaderPort8 (Receive)"), true));
- _output_bundle.reset (new ARDOUR::Bundle (_("FaderPort8 (Send) "), false));
+ _output_bundle.reset (new ARDOUR::Bundle (_("FaderPort8 (Send)"), false));
#endif
_input_bundle->add_channel (
DEBUG_TRACE (DEBUG::FaderPort8, "FaderPort8::close\n");
stop_midi_handling ();
session_connections.drop_connections ();
- automation_state_connections.drop_connections ();
+ route_state_connections.drop_connections ();
assigned_stripable_connections.drop_connections ();
_assigned_strips.clear ();
drop_ctrl_connections ();
encoder_navigate (tb->value & dir_mask ? true : false, tb->value & step_mask);
}
if (tb->controller_number == 0x10) {
+#ifdef FADERPORT2
+ if (_ctrls.nav_mode() == NavPan) {
+ encoder_parameter (tb->value & dir_mask ? true : false, tb->value & step_mask);
+ } else {
+ encoder_navigate (tb->value & dir_mask ? true : false, tb->value & step_mask);
+ }
+#else
encoder_parameter (tb->value & dir_mask ? true : false, tb->value & step_mask);
+#endif
}
}
set_periodic_display_mode (FP8Strip::Stripables);
}
+#ifdef FADERPORT2
+ boost::shared_ptr<Stripable> s = first_selected_stripable();
+ if (s) {
+ _ctrls.strip(0).set_stripable (s, _ctrls.fader_mode() == ModePan);
+ } else {
+ _ctrls.strip(0).unset_controllables ( FP8Strip::CTRL_ALL );
+ }
+ return;
+#endif
+
int n_strips = strips.size();
int channel_off = get_channel_off (_ctrls.mix_mode ());
channel_off = std::min (channel_off, n_strips - N_STRIPS);
break;
}
assign_strips ();
- notify_automation_mode_changed ();
+ notify_route_state_changed ();
}
void
}
}
+#ifdef FADERPORT2
+void
+FaderPort8::stripable_selection_changed ()
+{
+ if (!_device_active || _chan_locked) {
+ return;
+ }
+ route_state_connections.drop_connections ();
+ assign_stripables (false);
+ subscribe_to_strip_signals ();
+}
+
+#else
+
void
FaderPort8::stripable_selection_changed ()
{
*/
return;
}
- automation_state_connections.drop_connections();
+ route_state_connections.drop_connections();
switch (_ctrls.fader_mode ()) {
case ModePlugins:
_ctrls.strip(id).select_button ().set_blinking (sel && s == first_selected_stripable ());
}
- /* track automation-mode of primary selection */
+ subscribe_to_strip_signals ();
+}
+#endif
+
+void
+FaderPort8::subscribe_to_strip_signals ()
+{
+ /* keep track of automation-mode of primary selection, shared buttons */
boost::shared_ptr<Stripable> s = first_selected_stripable();
if (s) {
boost::shared_ptr<AutomationControl> ac;
ac = s->gain_control();
if (ac && ac->alist()) {
- ac->alist()->automation_state_changed.connect (automation_state_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort8::notify_automation_mode_changed, this), this);
+ ac->alist()->automation_state_changed.connect (route_state_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort8::notify_route_state_changed, this), this);
}
ac = s->pan_azimuth_control();
if (ac && ac->alist()) {
- ac->alist()->automation_state_changed.connect (automation_state_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort8::notify_automation_mode_changed, this), this);
+ ac->alist()->automation_state_changed.connect (route_state_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort8::notify_route_state_changed, this), this);
+ }
+#ifdef FADERPORT2
+ ac = s->rec_enable_control();
+ if (ac) {
+ ac->Changed.connect (route_state_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort8::notify_route_state_changed, this), this);
}
+#endif
}
/* set lights */
- notify_automation_mode_changed ();
+ notify_route_state_changed ();
}
void
FaderPort8::bank (bool down, bool page)
{
+#ifdef FADERPORT2
+ // XXX this should preferably be in actions.cc
+ AccessAction ("Editor", down ? "select-prev-stripable" : "select-next-stripable");
+ return;
+#endif
+
int dt = page ? N_STRIPS : 1;
if (down) {
dt *= -1;
void notify_pi_property_changed (const PBD::PropertyChange&);
void notify_stripable_property_changed (boost::weak_ptr<ARDOUR::Stripable>, const PBD::PropertyChange&);
void stripable_selection_changed ();
+ void subscribe_to_strip_signals ();
PBD::ScopedConnection selection_connection;
- PBD::ScopedConnectionList automation_state_connections;
+ PBD::ScopedConnectionList route_state_connections;
PBD::ScopedConnectionList modechange_connections;
/* **************************************************************************/
struct ProcessorCtrl {
void notify_history_changed ();
void notify_solo_changed ();
void notify_mute_changed ();
- void notify_automation_mode_changed ();
+ void notify_route_state_changed ();
void notify_plugin_active_changed ();
/* actions */
void button_prev_next (bool);
void button_action (const std::string& group, const std::string& item);
+ void button_chanlock (); /* FP2 only */
+ void button_flip (); /* FP2 only */
+
void button_encoder ();
void button_parameter ();
void encoder_navigate (bool, int);
bool _link_enabled;
bool _link_locked; // can only be true if _link_enabled
+ bool _chan_locked; /* FP2 only */
+
/* user prefs */
uint32_t _clock_mode;
uint32_t _scribble_mode;
#include "pbd/signals.h"
#ifdef FADERPORT16
-#define FP_NAMESPACE FP16
+# define FP_NAMESPACE FP16
+#elif defined FADERPORT2
+# define FP_NAMESPACE FP2
#else
-#define FP_NAMESPACE FP8
+# define FP_NAMESPACE FP8
#endif
namespace ArdourSurface { namespace FP_NAMESPACE {
NavBank,
NavMaster,
NavSection,
- NavMarker
+ NavMarker,
+ NavPan /* FP2 only */
};
enum MixMode {
FP8Controls::FP8Controls (FP8Base& b)
: _fadermode (ModeTrack)
+#ifdef FADERPORT2
+ , _navmode (NavScroll)
+#else
, _navmode (NavMaster)
+#endif
, _mixmode (MixAll)
, _display_timecode (false)
{
NEWBUTTON (0x5e, BtnPlay, false);
NEWBUTTON (0x5f, BtnRecord, false);
+#ifdef FADERPORT2
+
+ NEWSHIFTBUTTON (0x4a, BtnARead, BtnAOff, true);
+ NEWSHIFTBUTTON (0x4b, BtnAWrite, BtnATrim, true);
+ NEWSHIFTBUTTON (0x4d, BtnATouch, BtnALatch, true);
+
+ NEWSHIFTBUTTON (0x2e, BtnPrev, BtnUndo, false);
+ NEWSHIFTBUTTON (0x2f, BtnNext, BtnRedo, false);
+
+ NEWSHIFTBUTTON (0x2a, BtnPan, BtnFlip, true); //TODO: Flip Pan knob to fader ...?
+
+ NEWSHIFTBUTTON (0x36, BtnChannel, BtnChanLock, true);
+
+ NEWSHIFTBUTTON (0x38, BtnScroll, BtnZoom, true);
+
+ NEWSHIFTBUTTON (0x3a, BtnMaster, BtnF1, false);
+ NEWSHIFTBUTTON (0x3b, BtnClick, BtnF2, false);
+ NEWSHIFTBUTTON (0x3c, BtnSection, BtnF3, false);
+ NEWSHIFTBUTTON (0x3d, BtnMarker, BtnF4, false);
+
+ //these buttons do not exist in FP2, but they need to exist in the ctrlmap:
+ NEWBUTTON (0x71, BtnBank, false);
+ NEWBUTTON (0x72, BtnF5, false);
+ NEWBUTTON (0x73, BtnF6, false);
+ NEWBUTTON (0x74, BtnF7, false);
+ NEWBUTTON (0x75, BtnF8, false);
+ NEWBUTTON (0x76, BtnUser1, false);
+ NEWBUTTON (0x77, BtnUser2, false);
+ NEWBUTTON (0x78, BtnUser3, false);
+ NEWBUTTON (0x79, BtnSave, false);
+
+#else
NEWSHIFTBUTTON (0x4a, BtnARead, BtnUser3, true);
NEWSHIFTBUTTON (0x4b, BtnAWrite, BtnUser2, true);
NEWSHIFTBUTTON (0x4c, BtnATrim, BtnRedo, true);
NEWSHIFTBUTTON (0x3c, BtnSection, BtnF7, false);
NEWSHIFTBUTTON (0x3d, BtnMarker, BtnF8, false);
+ NEWBUTTON (0x2a, BtnPan, false);
+#endif
+
NEWSHIFTBUTTON (0x28, BtnTrack, BtnTimecode, false);
NEWBUTTON (0x2b, BtnPlugins, false);
NEWBUTTON (0x29, BtnSend, false);
- NEWBUTTON (0x2a, BtnPan, false);
NEWSHIFTBUTTON (0x00, BtnArm, BtnArmAll, false);
NEWBUTTON (0x01, BtnSoloClear, false);
BindNav (BtnMaster, NavMaster);
BindNav (BtnSection, NavSection);
BindNav (BtnMarker, NavMarker);
+#ifdef FADERPORT2
+ BindNav (BtnPan, NavPan);
+#endif
#define BindFader(BTN, MODE)\
button (BTN).released.connect_same_thread (button_connections, boost::bind (&FP8Controls::set_fader_mode, this, MODE))
BindFader (BtnTrack, ModeTrack);
BindFader (BtnPlugins, ModePlugins);
BindFader (BtnSend, ModeSend);
+#ifndef FADERPORT2
BindFader (BtnPan, ModePan);
+#endif
#define BindMix(BTN, MODE)\
button (BtnMFX).set_color (0x0000ffff);
button (BtnMUser).set_color (0x0000ffff);
+#ifdef FADERPORT2
+ /* encoder mode-switches are orange, to match the Master switch physical color */
+ button (BtnLink).set_color (0x000000ff);
+ button (BtnChannel).set_color (0x0000ffff);
+ button (BtnScroll).set_color (0x0000ffff);
+ button (BtnPan).set_color (0xffffffff);
+#endif
+
for (uint8_t id = 0; id < N_STRIPS; ++id) {
chanstrip[id]->initialize ();
}
all_lights_off ();
/* default modes */
+#ifdef FADERPORT2
+ button (BtnScroll).set_active (true);
+#else
button (BtnMaster).set_active (true);
+#endif
button (BtnTrack).set_active (true);
button (BtnMAll).set_active (true);
button (BtnTimecode).set_active (_display_timecode);
button (BtnMaster).set_active (m == NavMaster);
button (BtnSection).set_active (m == NavSection);
button (BtnMarker).set_active (m == NavMarker);
+#ifdef FADERPORT2
+ button (BtnPan).set_active (m == NavPan);
+#endif
_navmode = m;
}
BtnLink,
BtnLock,
+ /* FP2 only */
+ BtnChanLock,
+ BtnFlip
+
};
typedef std::map <ButtonId, std::string> UserButtonMap;
PBD::Signal0<void> FaderModeChanged;
PBD::Signal0<void> MixModeChanged;
+#ifdef FADERPORT2
+ FP8Types::FaderMode fader_mode () const { return FP8Types::ModeTrack; }
+ FP8Types::MixMode mix_mode () const { return FP8Types::MixUser; }
+#else
FP8Types::FaderMode fader_mode () const { return _fadermode; }
- FP8Types::NavigationMode nav_mode () const { return _navmode; }
FP8Types::MixMode mix_mode () const { return _mixmode; }
+#endif
+
+ FP8Types::NavigationMode nav_mode () const { return _navmode; }
bool display_timecode () const { return _display_timecode; }
FP8ButtonInterface& button (ButtonId id);
FP8Strip::periodic ()
{
periodic_update_fader ();
+#ifndef FADERPORT2
periodic_update_meter ();
if (_displaymode != PluginSelect && _displaymode != PluginParam) {
periodic_update_timecode (_base.clock_mode ());
}
+#endif
}
#ifdef FADERPORT16
# define N_STRIPS 16
+#elif defined FADERPORT2
+# define N_STRIPS 1
#else
# define N_STRIPS 8
#endif
std::string data_file_path;
#ifdef FADERPORT16
string name = "faderport16-small.png";
+#elif defined FADERPORT2
+ string name = ""; // TODO
#else
string name = "faderport8-small.png";
#endif
obj.use = 'libardour libardour_cp libgtkmm2ext libpbd'
obj.install_path = os.path.join(bld.env['LIBDIR'], 'surfaces')
+ obj = bld(features = 'cxx cxxshlib')
+ obj.source = list(fp8_16_sources)
+ obj.source += [ 'faderport2_interface.cc' ]
+ obj.defines = [ 'PACKAGE="ardour_faderport8"' ]
+ obj.defines += [ 'ARDOURSURFACE_DLL_EXPORTS' ]
+ obj.defines += [ 'FADERPORT2' ]
+ obj.includes = [ '.' ]
+ obj.name = 'libardour_faderport2'
+ obj.target = 'ardour_faderport2'
+ obj.uselib = 'GTKMM GTK GDK XML'
+ obj.use = 'libardour libardour_cp libgtkmm2ext libpbd'
+ obj.install_path = os.path.join(bld.env['LIBDIR'], 'surfaces')
+
def shutdown():
autowaf.shutdown()