{
assert (_route && _session);
if (route()->trim() && route()->trim()->active() && route()->n_inputs().n_audio() > 0) {
- route()->trim()->gain_control ()->start_touch (_session->transport_frame());
+ route()->trim()->gain_control ()->start_touch (_session->transport_sample());
}
}
{
assert (_route && _session);
if (route()->trim() && route()->trim()->active() && route()->n_inputs().n_audio() > 0) {
- route()->trim()->gain_control ()->stop_touch (_session->transport_frame());
+ route()->trim()->gain_control ()->stop_touch (_session->transport_sample());
}
}
_route->panner_shell()->Changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::connect_to_pan, this), gui_context());
}
- if (is_audio_track()) {
- audio_track()->DiskstreamChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::diskstream_changed, this), gui_context());
- }
-
_route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::setup_comment_button, this), gui_context());
set_stuff_from_route ();
MixerStrip::output_press (GdkEventButton *ev)
{
using namespace Menu_Helpers;
- if (!_session->engine().connected()) {
- MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
- msg.run ();
+ if (!ARDOUR_UI_UTILS::engine_is_running ()) {
return true;
}
boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
- /* give user bundles first chance at being in the menu */
+ /* guess the user-intended main type of the route output */
+ DataType intended_type = guess_main_type(false);
+ /* try adding the master bus first */
+ boost::shared_ptr<Route> master = _session->master_out();
+ if (master) {
+ maybe_add_bundle_to_output_menu (master->input()->bundle(), current, intended_type);
+ }
+
+ /* then other routes inputs */
+ RouteList copy = _session->get_routelist ();
+ copy.sort (RouteCompareByName ());
+ for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
+ maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current, intended_type);
+ }
+
+ /* then try adding user bundles, often labeled/grouped physical inputs */
for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
- maybe_add_bundle_to_output_menu (*i, current);
+ maybe_add_bundle_to_output_menu (*i, current, intended_type);
}
}
+ /* then all other bundles, including physical outs or other sofware */
for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
- maybe_add_bundle_to_output_menu (*i, current);
+ maybe_add_bundle_to_output_menu (*i, current, intended_type);
}
}
- boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
- RouteList copy = *routes;
- copy.sort (RouteCompareByName ());
- for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
- maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current);
- }
-
if (citems.size() == n_with_separator) {
/* no routes added; remove the separator */
citems.pop_back ();
input_menu.set_name ("ArdourContextMenu");
citems.clear();
- if (!_session->engine().connected()) {
- MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
- msg.run ();
+ if (!ARDOUR_UI_UTILS::engine_is_running ()) {
return true;
}
return;
}
- ARDOUR::BundleList current = _route->input()->bundles_connected ();
-
- if (std::find (current.begin(), current.end(), c) == current.end()) {
- _route->input()->connect_ports_to_bundle (c, true, this);
- } else {
- _route->input()->disconnect_ports_from_bundle (c, this);
- }
+ _route->input()->connect_ports_to_bundle (c, true, this);
}
void
return;
}
- ARDOUR::BundleList current = _route->output()->bundles_connected ();
-
- if (std::find (current.begin(), current.end(), c) == current.end()) {
- _route->output()->connect_ports_to_bundle (c, true, this);
- } else {
- _route->output()->disconnect_ports_from_bundle (c, this);
- }
+ _route->output()->connect_ports_to_bundle (c, true, true, this);
}
void
}
void
-MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
+MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/,
+ DataType type)
{
using namespace Menu_Helpers;
- if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
+ /* The bundle should be an input one, but not ours */
+ if (b->ports_are_inputs() == false || *b == *_route->input()->bundle()) {
+ return;
+ }
+
+ /* Don't add the monitor input unless we are Master */
+ boost::shared_ptr<Route> monitor = _session->monitor_out();
+ if ((!_route->is_master()) && monitor && b->has_same_ports (monitor->input()->bundle()))
return;
+
+ /* It should either match exactly our outputs (if |type| is DataType::NIL)
+ * or have the same number of |type| channels than our outputs. */
+ if (type == DataType::NIL) {
+ if(b->nchannels() != _route->n_outputs())
+ return;
+ } else {
+ if (b->nchannels().n(type) != _route->n_outputs().n(type))
+ return;
}
+ /* Avoid adding duplicates */
list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
++i;
}
-
if (i != output_menu_bundles.end()) {
return;
}
+ /* Now add the bundle to the menu */
output_menu_bundles.push_back (b);
MenuList& citems = output_menu.items();
/*
* Output port labelling
- * =====================
*
* Case 1: Each output has one connection, all connections are to system:playback_%i
* out 1 -> system:playback_1
* Default case (unusual routing):
* Display as: *number of connections*
*
+ *
* Tooltips
- * ========
+ *
* .-----------------------------------------------.
* | Mixdown |
* | out 1 -> ardour:master/in 1, jamin:input/in 1 |
void
MixerStrip::update_io_button (bool for_input)
{
- uint32_t io_count;
- uint32_t io_index;
- boost::shared_ptr<IO> io;
- boost::shared_ptr<Port> port;
- vector<string> port_connections;
-
- uint32_t total_connection_count = 0;
- uint32_t io_connection_count = 0;
- uint32_t ardour_connection_count = 0;
- uint32_t system_connection_count = 0;
- uint32_t other_connection_count = 0;
- uint32_t typed_connection_count = 0;
-
+ ostringstream tooltip;
ostringstream label;
-
bool have_label = false;
- bool each_io_has_one_connection = true;
-
- string connection_name;
- string ardour_track_name;
- string other_connection_type;
- string system_ports;
- string system_port;
- ostringstream tooltip;
- char * tooltip_cstr;
+ uint32_t total_connection_count = 0;
+ uint32_t typed_connection_count = 0;
+ bool each_typed_port_has_one_connection = true;
DataType dt = guess_main_type(for_input);
+ boost::shared_ptr<IO> io = for_input ? _route->input() : _route->output();
+ /* Fill in the tooltip. Also count:
+ * - The total number of connections.
+ * - The number of main-typed connections.
+ * - Whether each main-typed port has exactly one connection. */
if (for_input) {
- io = _route->input();
- } else {
- io = _route->output();
- }
-
- io_count = io->n_ports().n_total();
-
- if ( dt == DataType::MIDI ) {
- tooltip << _("MIDI ");
- }
-
- if (for_input) {
- tooltip << string_compose (_("<b>INPUT</b> to %1"), Gtkmm2ext::markup_escape_text (_route->name()));
+ tooltip << string_compose (_("<b>INPUT</b> to %1"),
+ Gtkmm2ext::markup_escape_text (_route->name()));
} else {
- tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
+ tooltip << string_compose (_("<b>OUTPUT</b> from %1"),
+ Gtkmm2ext::markup_escape_text (_route->name()));
}
- for (io_index = 0; io_index < io_count; ++io_index) {
- port = io->nth (io_index);
-
- port_connections.clear ();
+ string arrow = Gtkmm2ext::markup_escape_text(for_input ? " <- " : " -> ");
+ vector<string> port_connections;
+ for (PortSet::iterator port = io->ports().begin();
+ port != io->ports().end();
+ ++port) {
+ port_connections.clear();
port->get_connections(port_connections);
- //ignore any port connections that don't match our DataType
- if (port->type() != dt) {
- if (!port_connections.empty()) {
- ++typed_connection_count;
- }
- continue;
- }
-
- io_connection_count = 0;
-
- if (!port_connections.empty()) {
- for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
- string pn = "";
- string& connection_name (*i);
-
- if (connection_name.find("system:") == 0) {
- pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
- }
-
- if (io_connection_count == 0) {
- tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
- << " -> "
- << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
- } else {
- tooltip << ", "
- << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
- }
-
- if (connection_name.find(RouteUI::program_port_prefix) == 0) {
- if (ardour_track_name.empty()) {
- // "ardour:Master/in 1" -> "ardour:Master/"
- string::size_type slash = connection_name.find("/");
- if (slash != string::npos) {
- ardour_track_name = connection_name.substr(0, slash + 1);
- }
- }
+ uint32_t port_connection_count = 0;
- if (connection_name.find(ardour_track_name) == 0) {
- ++ardour_connection_count;
- }
- } else if (!pn.empty()) {
- if (system_ports.empty()) {
- system_ports += pn;
- } else {
- system_ports += "/" + pn;
- }
- if (connection_name.find("system:") == 0) {
- ++system_connection_count;
- }
- } else if (connection_name.find("system:midi_") == 0) {
- if (for_input) {
- // "system:midi_capture_123" -> "123"
- system_port = "M " + connection_name.substr(20);
- } else {
- // "system:midi_playback_123" -> "123"
- system_port = "M " + connection_name.substr(21);
- }
+ for (vector<string>::iterator i = port_connections.begin();
+ i != port_connections.end();
+ ++i) {
+ ++port_connection_count;
- if (system_ports.empty()) {
- system_ports += system_port;
- } else {
- system_ports += "/" + system_port;
- }
-
- ++system_connection_count;
-
- } else if (connection_name.find("system:") == 0) {
- if (for_input) {
- // "system:capture_123" -> "123"
- system_port = connection_name.substr(15);
- } else {
- // "system:playback_123" -> "123"
- system_port = connection_name.substr(16);
- }
-
- if (system_ports.empty()) {
- system_ports += system_port;
- } else {
- system_ports += "/" + system_port;
- }
-
- ++system_connection_count;
- } else {
- if (other_connection_type.empty()) {
- // "jamin:in 1" -> "jamin:"
- other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
- }
-
- if (connection_name.find(other_connection_type) == 0) {
- ++other_connection_count;
- }
- }
-
- ++total_connection_count;
- ++io_connection_count;
+ if (port_connection_count == 1) {
+ tooltip << endl << Gtkmm2ext::markup_escape_text (
+ port->name().substr(port->name().find("/") + 1));
+ tooltip << arrow;
+ } else {
+ tooltip << ", ";
}
+
+ tooltip << Gtkmm2ext::markup_escape_text(*i);
}
- if (io_connection_count != 1) {
- each_io_has_one_connection = false;
+ total_connection_count += port_connection_count;
+ if (port->type() == dt) {
+ typed_connection_count += port_connection_count;
+ each_typed_port_has_one_connection &= (port_connection_count == 1);
}
+
}
if (total_connection_count == 0) {
tooltip << endl << _("Disconnected");
}
- tooltip_cstr = new char[tooltip.str().size() + 1];
- strcpy(tooltip_cstr, tooltip.str().c_str());
-
- if (for_input) {
- set_tooltip (&input_button, tooltip_cstr);
- } else {
- set_tooltip (&output_button, tooltip_cstr);
+ if (typed_connection_count == 0) {
+ label << "-";
+ have_label = true;
}
- delete [] tooltip_cstr;
+ /* Are all main-typed channels connected to the same route ? */
+ if (!have_label) {
+ boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
+ for (ARDOUR::RouteList::const_iterator route = routes->begin();
+ route != routes->end();
+ ++route) {
+ boost::shared_ptr<IO> dest_io =
+ for_input ? (*route)->output() : (*route)->input();
+ if (io->bundle()->connected_to(dest_io->bundle(),
+ _session->engine(),
+ dt, true)) {
+ label << Gtkmm2ext::markup_escape_text ((*route)->name());
+ have_label = true;
+ break;
+ }
+ }
+ }
- if (each_io_has_one_connection) {
- if (total_connection_count == ardour_connection_count) {
- // all connections are to the same track in ardour
- // "ardour:Master/" -> "Master"
- string::size_type slash = ardour_track_name.find("/");
- if (slash != string::npos) {
- const size_t ppps = RouteUI::program_port_prefix.size (); // "ardour:"
- label << ardour_track_name.substr (ppps, slash - ppps);
+ /* Are all main-typed channels connected to the same (user) bundle ? */
+ if (!have_label) {
+ boost::shared_ptr<ARDOUR::BundleList> bundles = _session->bundles ();
+ for (ARDOUR::BundleList::iterator bundle = bundles->begin();
+ bundle != bundles->end();
+ ++bundle) {
+ if (boost::dynamic_pointer_cast<UserBundle> (*bundle) == 0)
+ continue;
+ if (io->bundle()->connected_to(*bundle, _session->engine(),
+ dt, true)) {
+ label << Gtkmm2ext::markup_escape_text ((*bundle)->name());
have_label = true;
+ break;
}
}
- else if (total_connection_count == system_connection_count) {
- // all connections are to system ports
- label << system_ports;
- have_label = true;
+ }
+
+ /* Is each main-typed channel only connected to a physical output ? */
+ if (!have_label && each_typed_port_has_one_connection) {
+ ostringstream temp_label;
+ vector<string> phys;
+ string playorcapture;
+ if (for_input) {
+ _session->engine().get_physical_inputs(dt, phys);
+ playorcapture = "capture_";
+ } else {
+ _session->engine().get_physical_outputs(dt, phys);
+ playorcapture = "playback_";
}
- else if (total_connection_count == other_connection_count) {
- // all connections are to the same external program eg jamin
- // "jamin:" -> "jamin"
- label << other_connection_type.substr(0, other_connection_type.size() - 1);
+ for (PortSet::iterator port = io->ports().begin(dt);
+ port != io->ports().end(dt);
+ ++port) {
+ string pn = "";
+ for (vector<string>::iterator s = phys.begin();
+ s != phys.end();
+ ++s) {
+ if (!port->connected_to(*s))
+ continue;
+ pn = AudioEngine::instance()->get_pretty_name_by_name(*s);
+ if (pn.empty()) {
+ string::size_type start = (*s).find(playorcapture);
+ if (start != string::npos) {
+ pn = (*s).substr(start + playorcapture.size());
+ }
+ }
+ break;
+ }
+ if (pn.empty()) {
+ temp_label.str(""); /* erase the failed attempt */
+ break;
+ }
+ if (port != io->ports().begin(dt))
+ temp_label << "/";
+ temp_label << pn;
+ }
+
+ if (!temp_label.str().empty()) {
+ label << temp_label.str();
have_label = true;
}
}
- if (!have_label) {
- if (total_connection_count == 0) {
- // Disconnected
- label << "-";
- } else {
- // Odd configuration
- label << "*" << total_connection_count << "*";
+ /* Is each main-typed channel connected to a single and different port with
+ * the same client name (e.g. another JACK client) ? */
+ if (!have_label && each_typed_port_has_one_connection) {
+ string maybe_client = "";
+ vector<string> connections;
+ for (PortSet::iterator port = io->ports().begin(dt);
+ port != io->ports().end(dt);
+ ++port) {
+ port_connections.clear();
+ port->get_connections(port_connections);
+ string connection = port_connections.front();
+
+ vector<string>::iterator i = connections.begin();
+ while (i != connections.end() && *i != connection) {
+ ++i;
+ }
+ if (i != connections.end())
+ break; /* duplicate connection */
+ connections.push_back(connection);
+
+ connection = connection.substr(0, connection.find(":"));
+ if (maybe_client.empty())
+ maybe_client = connection;
+ if (maybe_client != connection)
+ break;
}
- if (typed_connection_count > 0) {
- label << "\u2295"; // circled plus
+ if (connections.size() == io->n_ports().n(dt)) {
+ label << maybe_client;
+ have_label = true;
}
}
+ /* Odd configuration */
+ if (!have_label) {
+ label << "*" << total_connection_count << "*";
+ }
+
+ if (total_connection_count > typed_connection_count) {
+ label << "\u2295"; /* circled plus */
+ }
+
+ /* Actually set the properties of the button */
+ char * cstr = new char[tooltip.str().size() + 1];
+ strcpy(cstr, tooltip.str().c_str());
+
if (for_input) {
input_button.set_text (label.str());
+ set_tooltip (&input_button, cstr);
} else {
output_button.set_text (label.str());
+ set_tooltip (&output_button, cstr);
}
+
+ delete [] cstr;
}
void
i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
}
+ if (is_track()) {
+ items.push_back (SeparatorElem());
+
+ Gtk::Menu* dio_menu = new Menu;
+ MenuList& dio_items = dio_menu->items();
+ dio_items.push_back (MenuElem (_("Record Pre-Fader"), sigc::bind (sigc::mem_fun (*this, &RouteUI::set_disk_io_point), DiskIOPreFader)));
+ dio_items.push_back (MenuElem (_("Record Post-Fader"), sigc::bind (sigc::mem_fun (*this, &RouteUI::set_disk_io_point), DiskIOPostFader)));
+ dio_items.push_back (MenuElem (_("Custom Record+Playback Positions"), sigc::bind (sigc::mem_fun (*this, &RouteUI::set_disk_io_point), DiskIOCustom)));
+
+ items.push_back (MenuElem (_("Disk I/O..."), *dio_menu));
+ }
+
_plugin_insert_cnt = 0;
_route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::help_count_plugins));
if (_plugin_insert_cnt > 0) {
items.push_back (MenuElem (_("Pin Connections..."), sigc::mem_fun (*this, &RouteUI::manage_pins)));
}
+ if (boost::dynamic_pointer_cast<MidiTrack>(_route) || _route->the_instrument ()) {
+ items.push_back (MenuElem (_("Patch Selector..."),
+ sigc::mem_fun(*this, &RouteUI::select_midi_patch)));
+ }
+
if (_route->the_instrument () && _route->the_instrument ()->output_streams().n_audio() > 2) {
// TODO ..->n_audio() > 1 && separate_output_groups) hard to check here every time.
items.push_back (MenuElem (_("Fan out to Busses"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), true, true)));
break;
}
- set_tooltip (name_button, _route->name());
+ set_tooltip (name_button, Gtkmm2ext::markup_escape_text(_route->name()));
if (_session->config.get_track_name_number()) {
const int64_t track_number = _route->track_number ();
monitor_input_button->set_sensitive (true);
monitor_disk_button->set_sensitive (true);
_comment_button.set_sensitive (true);
+ trim_control.set_sensitive (true);
+ if (midi_input_enable_button) {
+ midi_input_enable_button->set_sensitive (true);
+ }
+ control_slave_ui.set_sensitive (true);
RouteUI::check_rec_enable_sensitivity ();
set_button_names (); // update solo button visual state
}
monitor_input_button->set_sensitive (false);
monitor_disk_button->set_sensitive (false);
_comment_button.set_sensitive (false);
+ trim_control.set_sensitive (false);
+ if (midi_input_enable_button) {
+ midi_input_enable_button->set_sensitive (false);
+ }
+ control_slave_ui.set_sensitive (false);
if (boost::dynamic_pointer_cast<InternalSend>(send)) {
output_button.set_sensitive (false);
_visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
} else if (p == "track-name-number") {
name_changed ();
+ update_track_number_visibility();
} else if (p == "use-monitor-bus") {
if (monitor_section_button) {
if (mute_button->get_parent()) {
mute_button->show();
}
}
- } else if (p == "track-name-number") {
- update_track_number_visibility();
}
}