, _connection_state (ConnectionState (0))
, _device_active (false)
, _ctrls (*this)
- , _channel_off (0)
, _plugin_off (0)
, _parameter_off (0)
, _show_presets (false)
, _shift_lock (false)
, _shift_pressed (0)
, gui (0)
+ , _link_enabled (false)
+ , _link_locked (false)
, _clock_mode (1)
, _scribble_mode (2)
, _two_line_text (false)
setup_actions ();
_ctrls.FaderModeChanged.connect_same_thread (modechange_connections, boost::bind (&FaderPort8::notify_fader_mode_changed, this));
- _ctrls.MixModeChanged.connect_same_thread (modechange_connections, boost::bind (&FaderPort8::assign_strips, this, true));
+ _ctrls.MixModeChanged.connect_same_thread (modechange_connections, boost::bind (&FaderPort8::assign_strips, this));
}
FaderPort8::~FaderPort8 ()
{
- cerr << "~FP8\n";
- disconnected ();
- close ();
+ /* this will be called from the main UI thread. during Session::destroy().
+ * There can be concurrent activity from BaseUI::main_thread -> AsyncMIDIPort
+ * -> MIDI::Parser::signal -> ... to any of the midi_connections
+ *
+ * stop event loop early and join thread */
+ stop ();
if (_input_port) {
DEBUG_TRACE (DEBUG::FaderPort8, string_compose ("unregistering input port %1\n", boost::shared_ptr<ARDOUR::Port>(_input_port)->name()));
- _input_port->disconnect_all ();
- _input_port->drain (5000, 50000);
- _input_port->clear ();
+ Glib::Threads::Mutex::Lock em (AudioEngine::instance()->process_lock());
AudioEngine::instance()->unregister_port (_input_port);
_input_port.reset ();
}
+ disconnected (); // zero faders, turn lights off, clear strips
+
if (_output_port) {
_output_port->drain (10000, 250000); /* check every 10 msecs, wait up to 1/4 second for the port to drain */
DEBUG_TRACE (DEBUG::FaderPort8, string_compose ("unregistering output port %1\n", boost::shared_ptr<ARDOUR::Port>(_output_port)->name()));
+ Glib::Threads::Mutex::Lock em (AudioEngine::instance()->process_lock());
AudioEngine::instance()->unregister_port (_output_port);
_output_port.reset ();
}
tear_down_gui ();
-
- /* stop event loop */
- DEBUG_TRACE (DEBUG::FaderPort8, "BaseUI::quit ()\n");
- BaseUI::quit ();
}
/* ****************************************************************************
call_slot (MISSING_INVALIDATOR, req->the_slot);
} else if (req->type == Quit) {
stop ();
+ disconnected ();
}
}
-int
+void
FaderPort8::stop ()
{
+ DEBUG_TRACE (DEBUG::FaderPort8, "BaseUI::quit ()\n");
BaseUI::quit ();
- return 0;
+ close (); // drop references, disconnect from session signals
}
void
FaderPort8::thread_init ()
{
- struct sched_param rtparam;
-
pthread_set_name (event_loop_name().c_str());
PBD::notify_event_loops_about_thread_creation (pthread_self(), event_loop_name(), 2048);
ARDOUR::SessionEvent::create_per_thread_pool (event_loop_name(), 128);
- memset (&rtparam, 0, sizeof (rtparam));
- rtparam.sched_priority = 9; /* XXX should be relative to audio (JACK) thread */
-
- if (pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam) != 0) {
- // do we care? not particularly.
- }
+ set_thread_priority ();
}
bool
_timecode = Timecode::timecode_format_time(TC);
char buf[16];
- Timecode::BBT_Time BBT = session->tempo_map ().bbt_at_frame (session->transport_frame ());
+ Timecode::BBT_Time BBT = session->tempo_map ().bbt_at_sample (session->transport_sample ());
snprintf (buf, sizeof (buf),
" %02" PRIu32 "|%02" PRIu32 "|%02" PRIu32 "|%02" PRIu32,
BBT.bars % 100, BBT.beats %100,
BaseUI::run ();
connect_session_signals ();
} else {
- BaseUI::quit ();
- close ();
+ stop ();
}
ControlProtocol::set_active (yn);
// ideally check firmware version >= 1.01 (USB bcdDevice 0x0101) (vendor 0x194f prod 0x0202)
// but we don't have a handle to the underlying USB device here.
- _channel_off = _plugin_off = _parameter_off = 0;
+ memset (_channel_off, 0, sizeof (_channel_off));
+ _plugin_off = _parameter_off = 0;
_blink_onoff = false;
_shift_lock = false;
_shift_pressed = 0;
tx_midi3 (0x90, 0x46, 0x00);
send_session_state ();
- assign_strips (true);
+ assign_strips ();
Glib::RefPtr<Glib::TimeoutSource> blink_timer =
Glib::TimeoutSource::create (200);
#ifdef VERBOSE_DEBUG
DEBUG_TRACE (DEBUG::FaderPort8, string_compose ("data available on %1\n", boost::shared_ptr<MIDI::Port>(port)->name()));
#endif
- framepos_t now = session->engine().sample_time();
+ samplepos_t now = session->engine().sample_time();
port->parse (now);
}
node.set_property (X_("clock-mode"), _clock_mode);
node.set_property (X_("scribble-mode"), _scribble_mode);
+ node.set_property (X_("two-line-text"), _two_line_text);
for (UserActionMap::const_iterator i = _user_action_map.begin (); i != _user_action_map.end (); ++i) {
if (i->second.empty()) {
node.get_property (X_("clock-mode"), _clock_mode);
node.get_property (X_("scribble-mode"), _scribble_mode);
+ node.get_property (X_("two-line-text"), _two_line_text);
_user_action_map.clear ();
// TODO: When re-loading state w/o surface re-init becomes possible,
}
int n_strips = strips.size();
- _channel_off = std::min (_channel_off, n_strips - 8);
- _channel_off = std::max (0, _channel_off);
+ int channel_off = get_channel_off (_ctrls.mix_mode ());
+ channel_off = std::min (channel_off, n_strips - 8);
+ channel_off = std::max (0, channel_off);
+ set_channel_off (_ctrls.mix_mode (), channel_off);
uint8_t id = 0;
- int skip = _channel_off;
+ int skip = channel_off;
for (StripableList::const_iterator s = strips.begin(); s != strips.end(); ++s) {
if (skip > 0) {
--skip;
}
}
+/* ****************************************************************************
+ * Control Link/Lock
+ */
+
+void
+FaderPort8::unlock_link (bool drop)
+{
+ link_locked_connection.disconnect ();
+
+ if (drop) {
+ stop_link (); // calls back here with drop = false
+ return;
+ }
+
+ _link_locked = false;
+
+ if (_link_enabled) {
+ assert (_ctrls.button (FP8Controls::BtnLink).is_active ());
+ _link_control.reset ();
+ start_link (); // re-connect & update LED colors
+ } else {
+ _ctrls.button (FP8Controls::BtnLink).set_active (false);
+ _ctrls.button (FP8Controls::BtnLink).set_color (0x888888ff);
+ _ctrls.button (FP8Controls::BtnLock).set_active (false);
+ _ctrls.button (FP8Controls::BtnLock).set_color (0x888888ff);
+ }
+}
+
+void
+FaderPort8::lock_link ()
+{
+ boost::shared_ptr<AutomationControl> ac = boost::dynamic_pointer_cast<AutomationControl> (_link_control.lock ());
+ if (!ac) {
+ return;
+ }
+ ac->DropReferences.connect (link_locked_connection, MISSING_INVALIDATOR, boost::bind (&FaderPort8::unlock_link, this, true), this);
+
+ // stop watching for focus events
+ link_connection.disconnect ();
+
+ _link_locked = true;
+
+ _ctrls.button (FP8Controls::BtnLock).set_color (0x00ff00ff);
+ _ctrls.button (FP8Controls::BtnLink).set_color (0x00ff00ff);
+}
+
+void
+FaderPort8::stop_link ()
+{
+ if (!_link_enabled) {
+ return;
+ }
+ link_connection.disconnect ();
+ _link_control.reset ();
+ _link_enabled = false;
+ unlock_link (); // also updates button colors
+}
+
+void
+FaderPort8::start_link ()
+{
+ assert (!_link_locked);
+
+ _link_enabled = true;
+ _ctrls.button (FP8Controls::BtnLink).set_active (true);
+ _ctrls.button (FP8Controls::BtnLock).set_active (true);
+ nofity_focus_control (_link_control); // update BtnLink, BtnLock colors
+
+ PBD::Controllable::GUIFocusChanged.connect (link_connection, MISSING_INVALIDATOR, boost::bind (&FaderPort8::nofity_focus_control, this, _1), this);
+}
+
+
/* ****************************************************************************
* Plugin selection and parameters
*/
*/
void
-FaderPort8::assign_strips (bool reset_bank)
+FaderPort8::assign_strips ()
{
- if (reset_bank) {
- _channel_off = 0;
- }
-
assigned_stripable_connections.drop_connections ();
_assigned_strips.clear ();
return;
}
#if 1 /* single exclusive selection by default, toggle via shift */
+
+# if 1 /* selecting a selected strip -> move fader to unity */
+ if (s == first_selected_stripable () && !shift_mod ()) {
+ if (_ctrls.fader_mode () == ModeTrack) {
+ boost::shared_ptr<AutomationControl> ac = s->gain_control ();
+ ac->start_touch (ac->session().transport_sample());
+ ac->set_value (ac->normal (), PBD::Controllable::UseGroup);
+ }
+ return;
+ }
+# endif
+
if (shift_mod ()) {
ToggleStripableSelection (s);
} else {
case ModeSend:
_plugin_off = 0;
_parameter_off = 0;
+ stop_link ();
// force unset rec-arm button, see also FaderPort8::button_arm
_ctrls.button (FP8Controls::BtnArm).set_active (false);
ARMButtonChange (false);
break;
}
- assign_strips (false);
+ assign_strips ();
notify_automation_mode_changed ();
}
* - Properties::hidden
* - Properties::order
*/
- assign_strips (false);
+ assign_strips ();
}
/* called from static PresentationInfo::Change */
}
int off = std::distance (strips.begin(), it);
- if (_channel_off <= off && off < _channel_off + 8) {
+ int channel_off = get_channel_off (_ctrls.mix_mode ());
+ if (channel_off <= off && off < channel_off + 8) {
return;
}
- if (_channel_off > off) {
- _channel_off = off;
+ if (channel_off > off) {
+ channel_off = off;
} else {
- _channel_off = off - 7;
+ channel_off = off - 7;
}
- assign_strips (false);
+ set_channel_off (_ctrls.mix_mode (), channel_off);
+ assign_strips ();
}
void
if (down) {
dt *= -1;
}
- _channel_off += dt;
- assign_strips (false);
+ set_channel_off (_ctrls.mix_mode (), get_channel_off (_ctrls.mix_mode ()) + dt);
+ assign_strips ();
}
void