#include "ardour/automation_control.h"
#include "ardour/gain_control.h"
#include "ardour/meter.h"
-#include "ardour/mute_control.h"
#include "ardour/plugin_insert.h"
#include "ardour/session.h"
-#include "ardour/solo_control.h"
#include "ardour/stripable.h"
#include "ardour/track.h"
#include "ardour/value_as_string.h"
using namespace ArdourSurface;
using namespace ArdourSurface::FP8Types;
+uint8_t /* static */
+FP8Strip::midi_ctrl_id (CtrlElement type, uint8_t id)
+{
+ assert (id < N_STRIPS);
+ if (id < 8) {
+ switch (type) {
+ case BtnSolo:
+ return 0x08 + id;
+ case BtnMute:
+ return 0x10 + id;
+ case BtnSelect:
+ return 0x18 + id;
+ case Fader:
+ return 0xe0 + id;
+ case Meter:
+ return 0xd0 + id;
+ case Redux:
+ return 0xd8 + id;
+ case BarVal:
+ return 0x30 + id;
+ case BarMode:
+ return 0x38 + id;
+ }
+ } else {
+ id -= 8;
+ switch (type) {
+ case BtnSolo:
+ return 0x50 + id;
+ case BtnMute:
+ return 0x78 + id;
+ case BtnSelect:
+ if (id == 0) { // strip 8
+ return 0x07;
+ } else {
+ return 0x21 + id;
+ }
+ case Fader:
+ return 0xe8 + id;
+ case Meter:
+ return 0xc0 + id;
+ case Redux:
+ return 0xc8 + id;
+ case BarVal:
+ return 0x40 + id;
+ case BarMode:
+ return 0x48 + id;
+ }
+ }
+ assert (0);
+ return 0;
+}
+
FP8Strip::FP8Strip (FP8Base& b, uint8_t id)
: _base (b)
, _id (id)
- , _solo (b, 0x08 + id)
- , _mute (b, 0x10 + id)
- , _selrec (b, 0x18 + id, true)
+ , _solo (b, midi_ctrl_id (BtnSolo, id))
+ , _mute (b, midi_ctrl_id (BtnMute, id))
+ , _selrec (b, midi_ctrl_id (BtnSelect, id), true)
, _touching (false)
, _strip_mode (0)
, _bar_mode (0)
, _displaymode (Stripables)
{
- assert (id < 8);
+ assert (id < N_STRIPS);
_last_fader = 65535;
_last_meter = _last_redux = _last_barpos = 0xff;
}
FP8Strip::~FP8Strip ()
+{
+ drop_automation_controls ();
+ _base_connection.disconnect ();
+ _button_connections.drop_connections ();
+}
+
+void
+FP8Strip::drop_automation_controls ()
{
_fader_connection.disconnect ();
_mute_connection.disconnect ();
_solo_connection.disconnect ();
_rec_connection.disconnect ();
_pan_connection.disconnect ();
+ _x_select_connection.disconnect ();
_fader_ctrl.reset ();
_mute_ctrl.reset ();
_solo_ctrl.reset ();
_rec_ctrl.reset ();
_pan_ctrl.reset ();
-
- _base_connection.disconnect ();
- _button_connections.drop_connections ();
+ _x_select_ctrl.reset ();
+ _peak_meter.reset ();
+ _redux_ctrl.reset ();
+ _select_plugin_functor.clear ();
}
void
* ie from FaderPort8::connected()
*/
_solo.set_active (false);
+ _solo.set_blinking (false);
_mute.set_active (false);
/* reset momentary button state */
_mute.reset ();
_solo.reset ();
- /* clear cached values */
- _last_fader = 65535;
- _last_meter = _last_redux = _last_barpos = 0xff;
+ drop_automation_controls ();
select_button ().set_color (0xffffffff);
select_button ().set_active (false);
set_bar_mode (4); // off
- _base.tx_midi2 (0xd0 + _id, 0); // reset meter
- _base.tx_midi2 (0xd8 + _id, 0); // reset redux
+ _base.tx_midi2 (midi_ctrl_id (Meter, _id), 0); // reset meter
+ _base.tx_midi2 (midi_ctrl_id (Redux, _id), 0); // reset redux
+
+ _base.tx_midi3 (midi_ctrl_id (Fader, _id), 0, 0); // fader
- _base.tx_midi3 (0xe0 + _id, 0, 0); // fader
+ /* clear cached values */
+ _last_fader = 65535;
+ _last_meter = _last_redux = _last_barpos = 0xff;
}
{
_peak_meter = boost::shared_ptr<ARDOUR::PeakMeter>();
_redux_ctrl = boost::shared_ptr<ARDOUR::ReadOnlyControl>();
+ _stripable_name.clear ();
if (which & CTRL_FADER) {
set_fader_controllable (boost::shared_ptr<AutomationControl>());
select_button ().set_blinking (false);
}
if (which & CTRL_TEXT0) {
- set_text_line (0x00, "");
+ set_text_line (0, "");
}
if (which & CTRL_TEXT1) {
- set_text_line (0x01, "");
+ set_text_line (1, "");
}
if (which & CTRL_TEXT2) {
- set_text_line (0x02, "");
+ set_text_line (2, "");
}
if (which & CTRL_TEXT3) {
- set_text_line (0x03, "");
+ set_text_line (3, "");
}
set_bar_mode (4); // Off
}
+void
+FP8Strip::set_strip_name ()
+{
+ size_t lb = _base.show_meters () ? 6 : 9;
+ set_text_line (0, _stripable_name.substr (0, lb));
+ set_text_line (1, _stripable_name.length() > lb ? _stripable_name.substr (lb) : "");
+}
+
void
FP8Strip::set_stripable (boost::shared_ptr<Stripable> s, bool panmode)
{
assert (s);
+ if (_base.show_meters () && _base.show_panner ()) {
+ set_strip_mode (5, true);
+ } else if (_base.show_meters ()) {
+ set_strip_mode (4, true);
+ } else {
+ set_strip_mode (0, true);
+ }
+ if (!_base.show_panner ()) {
+ set_bar_mode (4, true); // Off
+ }
+
if (panmode) {
set_fader_controllable (s->pan_azimuth_control ());
} else {
select_button ().set_color (s->presentation_info ().color());
//select_button ().set_blinking (false);
- set_strip_mode (0x05);
- set_text_line (0x00, s->name ());
- set_text_line (0x01, _pan_ctrl ? _pan_ctrl->get_user_string () : "");
- set_text_line (0x02, "");
- set_text_line (0x03, "");
+ _stripable_name = s->name ();
+
+ if (_base.twolinetext ()) {
+ set_strip_name ();
+ } else {
+ set_text_line (0, s->name ());
+ set_text_line (1, _pan_ctrl ? _pan_ctrl->get_user_string () : "");
+ }
+ set_text_line (2, "");
+ set_text_line (3, "");
}
/* *****************************************************************************
return false;
}
if (t) {
- if (!ac->touching ()) {
- ac->start_touch (ac->session().transport_frame());
- }
+ ac->start_touch (ac->session().transport_sample());
} else {
- ac->stop_touch (true, ac->session().transport_frame());
+ ac->stop_touch (ac->session().transport_sample());
}
return true;
}
if (!ac) {
return false;
}
- if (!ac->touching ()) {
- ac->start_touch (ac->session().transport_frame());
- }
+ ac->start_touch (ac->session().transport_sample());
ac->set_value (ac->interface_to_internal (val), group_mode ());
return true;
}
void
FP8Strip::set_mute (bool on)
{
- if (_mute_ctrl) {
- if (!_mute_ctrl->touching ()) {
- _mute_ctrl->start_touch (_mute_ctrl->session().transport_frame());
- }
- _mute_ctrl->set_value (on ? 1.0 : 0.0, group_mode ());
+ if (!_mute_ctrl) {
+ return;
}
+ _mute_ctrl->start_touch (_mute_ctrl->session().transport_sample());
+ _mute_ctrl->set_value (on ? 1.0 : 0.0, group_mode ());
}
void
FP8Strip::set_solo (bool on)
{
- if (_solo_ctrl) {
- if (!_solo_ctrl->touching ()) {
- _solo_ctrl->start_touch (_solo_ctrl->session().transport_frame());
- }
- _solo_ctrl->set_value (on ? 1.0 : 0.0, group_mode ());
+ if (!_solo_ctrl) {
+ return;
}
+ _solo_ctrl->start_touch (_solo_ctrl->session().transport_sample());
+ _solo_ctrl->set_value (on ? 1.0 : 0.0, group_mode ());
}
void
FP8Strip::set_recarm ()
{
- if (_rec_ctrl) {
- const bool on = !recarm_button ().is_active();
- _rec_ctrl->set_value (on ? 1.0 : 0.0, group_mode ());
+ if (!_rec_ctrl) {
+ return;
}
+ const bool on = !recarm_button ().is_active();
+ _rec_ctrl->set_value (on ? 1.0 : 0.0, group_mode ());
}
void
assert (!_x_select_ctrl);
_select_plugin_functor ();
} else if (_x_select_ctrl) {
- if (!_x_select_ctrl->touching ()) {
- _x_select_ctrl->start_touch (_x_select_ctrl->session().transport_frame());
- }
+ _x_select_ctrl->start_touch (_x_select_ctrl->session().transport_sample());
const bool on = !select_button ().is_active();
_x_select_ctrl->set_value (on ? 1.0 : 0.0, group_mode ());
}
}
float val = 0;
if (ac) {
- val = ac->internal_to_interface (ac->get_value()) * 16368.f; /* 16 * 1023 */
+ val = ac->internal_to_interface (ac->get_value());
+ val = std::max (0.f, std::min (1.f, val)) * 16368.f; /* 16 * 1023 */
}
unsigned short mv = lrintf (val);
if (mv == _last_fader) {
return;
}
_last_fader = mv;
- _base.tx_midi3 (0xe0 + _id, (mv & 0x7f), (mv >> 7) & 0x7f);
+ _base.tx_midi3 (midi_ctrl_id (Fader, _id), (mv & 0x7f), (mv >> 7) & 0x7f);
}
void
FP8Strip::notify_solo_changed ()
{
if (_solo_ctrl) {
- _solo.set_active (_solo_ctrl->get_value () > 0);
+ boost::shared_ptr<SoloControl> sc = boost::dynamic_pointer_cast<SoloControl> (_solo_ctrl);
+ if (sc) {
+ _solo.set_blinking (sc->soloed_by_others () && !sc->self_soloed ());
+ _solo.set_active (sc->self_soloed ());
+ } else {
+ _solo.set_blinking (false);
+ _solo.set_active (_solo_ctrl->get_value () > 0);
+ }
} else {
+ _solo.set_blinking (false);
_solo.set_active (false);
}
}
select_button ().set_active (_x_select_ctrl->get_value() > 0.);
select_button ().set_color (0xffff00ff);
select_button ().set_blinking (false);
- } else {
- ; // leave alone.
}
}
return;
}
- ARDOUR::AutoState state = ac->automation_state();
- if (state == Touch || state == Play) {
- notify_fader_changed ();
+ if (!ac->automation_playback ()) {
+ return;
}
+ notify_fader_changed ();
}
void
void
FP8Strip::periodic_update_meter ()
{
+ bool show_meters = _base.show_meters ();
bool have_meter = false;
bool have_panner = false;
- if (_peak_meter) {
+ if (_peak_meter && show_meters) {
have_meter = true;
float dB = _peak_meter->meter_level (0, MeterMCP);
// TODO: deflect meter
int val = std::min (127.f, std::max (0.f, 2.f * dB + 127.f));
if (val != _last_meter || val > 0) {
- _base.tx_midi2 (0xd0 + _id, val & 0x7f); // falls off automatically
+ _base.tx_midi2 (midi_ctrl_id (Meter, _id), val & 0x7f); // falls off automatically
_last_meter = val;
}
- } else {
+ } else if (show_meters) {
if (0 != _last_meter) {
- _base.tx_midi2 (0xd0 + _id, 0);
+ _base.tx_midi2 (midi_ctrl_id (Meter, _id), 0);
_last_meter = 0;
}
}
// show redux only if there's a meter, too (strip display mode 5)
- if (_peak_meter && _redux_ctrl) {
+ if (_peak_meter && _redux_ctrl && show_meters) {
float rx = (1.f - _redux_ctrl->get_parameter ()) * 127.f;
// TODO: deflect redux
int val = std::min (127.f, std::max (0.f, rx));
if (val != _last_redux) {
- _base.tx_midi2 (0xd8 + _id, val & 0x7f);
+ _base.tx_midi2 (midi_ctrl_id (Redux, _id), val & 0x7f);
_last_redux = val;
}
- } else {
+ } else if (show_meters) {
if (0 != _last_redux) {
- _base.tx_midi2 (0xd8 + _id, 0);
+ _base.tx_midi2 (midi_ctrl_id (Redux, _id), 0);
_last_redux = 0;
}
}
if (_displaymode == PluginParam) {
if (_fader_ctrl) {
set_bar_mode (2); // Fill
- set_text_line (0x01, value_as_string(_fader_ctrl->desc(), _fader_ctrl->get_value()));
+ set_text_line (2, value_as_string(_fader_ctrl->desc(), _fader_ctrl->get_value()));
float barpos = _fader_ctrl->internal_to_interface (_fader_ctrl->get_value());
int val = std::min (127.f, std::max (0.f, barpos * 128.f));
if (val != _last_barpos) {
- _base.tx_midi3 (0xb0, 0x30 + _id, val & 0x7f);
+ _base.tx_midi3 (0xb0, midi_ctrl_id (BarVal, _id), val & 0x7f);
_last_barpos = val;
}
} else {
set_bar_mode (4); // Off
- set_text_line (0x01, "");
+ set_text_line (2, "");
}
}
+ else if (_displaymode == PluginSelect) {
+ set_bar_mode (4); // Off
+ }
else if (_displaymode == SendDisplay) {
set_bar_mode (4); // Off
if (_fader_ctrl) {
- set_text_line (0x01, value_as_string(_fader_ctrl->desc(), _fader_ctrl->get_value()));
+ set_text_line (1, value_as_string(_fader_ctrl->desc(), _fader_ctrl->get_value()));
} else {
- set_text_line (0x01, "");
+ set_text_line (1, "");
}
} else if (_pan_ctrl) {
- have_panner = true;
+ have_panner = _base.show_panner ();
float panpos = _pan_ctrl->internal_to_interface (_pan_ctrl->get_value());
int val = std::min (127.f, std::max (0.f, panpos * 128.f));
- set_bar_mode (1); // Bipolar
- if (val != _last_barpos) {
- _base.tx_midi3 (0xb0, 0x30 + _id, val & 0x7f);
+ set_bar_mode (have_panner ? 1 : 4); // Bipolar or Off
+ if (val != _last_barpos && have_panner) {
+ _base.tx_midi3 (0xb0, midi_ctrl_id (BarVal, _id), val & 0x7f);
_last_barpos = val;
}
- set_text_line (0x01, _pan_ctrl->get_user_string ());
+ if (_base.twolinetext ()) {
+ set_strip_name ();
+ } else {
+ set_text_line (1, _pan_ctrl->get_user_string ());
+ }
} else {
set_bar_mode (4); // Off
+ if (_base.twolinetext ()) {
+ set_strip_name ();
+ } else {
+ set_text_line (1, "");
+ }
}
if (_displaymode == SendDisplay || _displaymode == PluginParam) {
set_strip_mode (4); // big meters + 3 lines of text (3rd line is large)
}
else if (have_panner) {
- set_strip_mode (0); // 3 lines of text (3rd line is large) + value-bar
+ set_strip_mode (0); // 3 lines of text (3rd line is large + long) + value-bar
} else {
- set_strip_mode (0); // 3 lines of text (3rd line is large) + value-bar
+ set_strip_mode (0); // 3 lines of text (3rd line is large + long) + value-bar
}
}
if (strip_mode == _strip_mode && !clear) {
return;
}
+
_strip_mode = strip_mode;
_base.tx_sysex (3, 0x13, _id, (_strip_mode & 0x07) | (clear ? 0x10 : 0));
- //_base.tx_midi3 (0xb0, 0x38 + _id, _bar_mode);
+
+ if (clear) {
+ /* work-around, when swiching modes, the FP8 may not
+ * properly redraw long lines. Only update lines 0, 1
+ * (line 2 is timecode, line 3 may be inverted)
+ */
+ _base.tx_text (_id, 0, 0x00, _last_line[0]);
+ _base.tx_text (_id, 1, 0x00, _last_line[1]);
+ }
}
void
-FP8Strip::set_bar_mode (uint8_t bar_mode)
+FP8Strip::set_bar_mode (uint8_t bar_mode, bool force)
{
- if (bar_mode == _bar_mode) {
+ if (bar_mode == _bar_mode && !force) {
return;
}
+
+ if (bar_mode == 4) {
+ _base.tx_midi3 (0xb0, midi_ctrl_id (BarVal, _id), 0);
+ _last_barpos = 0xff;
+ }
+
_bar_mode = bar_mode;
- _base.tx_midi3 (0xb0, 0x38 + _id, bar_mode);
+ _base.tx_midi3 (0xb0, midi_ctrl_id (BarMode, _id), bar_mode);
}
void
}
void
-FP8Strip::periodic_update_timecode ()
+FP8Strip::periodic_update_timecode (uint32_t m)
{
- if (_id >= 2 && _id < 6) {
- std::string const& tc = _base.timecode();
- //" HH:MM:SS:FF"
+ if (m == 0) {
+ return;
+ }
+ if (m == 3) {
+ bool mc = _id >= 4;
+ std::string const& tc = mc ? _base.musical_time () : _base.timecode();
+ std::string t;
+ if (tc.size () == 12) {
+ t = tc.substr (1 + (_id - (mc ? 4 : 0)) * 3, 2);
+ }
+ set_text_line (2, t);
+ } else if (_id >= 2 && _id < 6) {
+ std::string const& tc = (m == 2) ? _base.musical_time () : _base.timecode();
+ //" HH:MM:SS:FF" or " BR|BT|TI|CK"
std::string t;
if (tc.size () == 12) {
t = tc.substr (1 + (_id - 2) * 3, 2);
}
- set_text_line (0x02, t);
+ set_text_line (2, t);
+ } else {
+ set_text_line (2, "");
}
}
{
periodic_update_fader ();
periodic_update_meter ();
- if (_displaymode != PluginSelect) {
- periodic_update_timecode ();
+ if (_displaymode != PluginSelect && _displaymode != PluginParam) {
+ periodic_update_timecode (_base.clock_mode ());
}
}