remote control ID and "order keys" have been removed.
const string& name_template,
bool strict_io,
PluginInfoPtr instrument,
- Plugin::PresetRecord* pset)
+ Plugin::PresetRecord* pset,
+ ARDOUR::PresentationInfo::order_t order)
{
list<boost::shared_ptr<MidiTrack> > tracks;
}
try {
- tracks = _session->new_midi_track (input, output, instrument, ARDOUR::Normal, route_group, how_many, name_template, pset);
+ tracks = _session->new_midi_track (input, output, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
if (tracks.size() != how_many) {
error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
const string& name_template,
bool strict_io,
PluginInfoPtr instrument,
- Plugin::PresetRecord* pset)
+ Plugin::PresetRecord* pset,
+ ARDOUR::PresentationInfo::order_t order)
{
RouteList routes;
}
try {
- routes = _session->new_midi_route (route_group, how_many, name_template, instrument, pset);
+
+ routes = _session->new_midi_route (route_group, how_many, name_template, instrument, pset, PresentationInfo::MidiBus, order);
if (routes.size() != how_many) {
error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
}
const string& name_template,
bool strict_io,
PluginInfoPtr instrument,
- Plugin::PresetRecord* pset)
+ Plugin::PresetRecord* pset,
+ ARDOUR::PresentationInfo::order_t order)
{
ChanCount one_midi_channel;
one_midi_channel.set (DataType::MIDI, 1);
if (disk) {
- session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset);
+ session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, order, instrument, pset);
} else {
- session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset);
+ session_add_midi_bus (route_group, how_many, name_template, strict_io, order, instrument, pset);
}
}
RouteGroup* route_group,
uint32_t how_many,
string const & name_template,
- bool strict_io
- )
+ bool strict_io,
+ ARDOUR::PresentationInfo::order_t order)
{
list<boost::shared_ptr<AudioTrack> > tracks;
RouteList routes;
try {
if (track) {
- tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
+ tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
if (tracks.size() != how_many) {
error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
} else {
- routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
+ routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
if (routes.size() != how_many) {
error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
}
void
-ARDOUR_UI::toggle_record_enable (uint32_t rid)
+ARDOUR_UI::toggle_record_enable (uint16_t rid)
{
if (!_session) {
return;
boost::shared_ptr<Route> r;
- if ((r = _session->route_by_remote_id (rid)) != 0) {
+ if ((r = _session->get_remote_nth_route (rid)) != 0) {
boost::shared_ptr<Track> t;
}
}
-void
-ARDOUR_UI::setup_order_hint (AddRouteDialog::InsertAt place)
+PresentationInfo::order_t
+ARDOUR_UI::translate_order (AddRouteDialog::InsertAt place)
{
- uint32_t order_hint = UINT32_MAX;
-
if (editor->get_selection().tracks.empty()) {
- return;
+ return PresentationInfo::max_order;
}
+ PresentationInfo::order_t order_hint = PresentationInfo::max_order;
+
/*
we want the new routes to have their order keys set starting from
the highest order key in the selection + 1 (if available).
if (place == AddRouteDialog::AfterSelection) {
RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
if (rtav) {
- order_hint = rtav->route()->order_key();
+ order_hint = rtav->route()->presentation_info().group_order();
order_hint++;
}
} else if (place == AddRouteDialog::BeforeSelection) {
RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
if (rtav) {
- order_hint = rtav->route()->order_key();
+ order_hint = rtav->route()->presentation_info().group_order();
}
} else if (place == AddRouteDialog::First) {
order_hint = 0;
} else {
- /* leave order_hint at UINT32_MAX */
- }
-
- if (order_hint == UINT32_MAX) {
- /** AddRouteDialog::Last or selection with first/last not a RouteTimeAxisView
- * not setting an order hint will place new routes last.
- */
- return;
+ /* leave order_hint at max_order */
}
- _session->set_order_hint (order_hint);
-
- /* create a gap in the existing route order keys to accomodate new routes.*/
- boost::shared_ptr <RouteList> rd = _session->get_routes();
- for (RouteList::iterator ri = rd->begin(); ri != rd->end(); ++ri) {
- boost::shared_ptr<Route> rt (*ri);
-
- if (rt->is_monitor()) {
- continue;
- }
-
- if (rt->order_key () >= order_hint) {
- rt->set_order_key (rt->order_key () + add_route_dialog->count());
- }
- }
+ return order_hint;
}
void
return;
}
- setup_order_hint(add_route_dialog->insert_at());
+ PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
string template_path = add_route_dialog->track_template();
DisplaySuspender ds;
switch (add_route_dialog->type_wanted()) {
case AddRouteDialog::AudioTrack:
- session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io);
+ session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io, order);
break;
case AddRouteDialog::MidiTrack:
- session_add_midi_track (route_group, count, name_template, strict_io, instrument);
+ session_add_midi_track (route_group, count, name_template, strict_io, instrument, 0, order);
break;
case AddRouteDialog::MixedTrack:
- session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0);
+ session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
break;
case AddRouteDialog::AudioBus:
- session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io);
+ session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io, order);
break;
case AddRouteDialog::MidiBus:
- session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0);
+ session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
break;
case AddRouteDialog::VCAMaster:
session_add_vca (name_template, count);
ARDOUR::RouteGroup* route_group,
uint32_t how_many,
std::string const & name_template,
- bool strict_io
+ bool strict_io,
+ ARDOUR::PresentationInfo::order_t order
) {
- session_add_audio_route (true, input_channels, output_channels, mode, route_group, how_many, name_template, strict_io);
+ session_add_audio_route (true, input_channels, output_channels, mode, route_group, how_many, name_template, strict_io, order);
}
void session_add_audio_bus (
ARDOUR::RouteGroup* route_group,
uint32_t how_many,
std::string const & name_template,
- bool strict_io
+ bool strict_io,
+ ARDOUR::PresentationInfo::order_t order
) {
- session_add_audio_route (false, input_channels, output_channels, ARDOUR::Normal, route_group, how_many, name_template, strict_io);
+ session_add_audio_route (false, input_channels, output_channels, ARDOUR::Normal, route_group, how_many, name_template, strict_io, order);
}
void session_add_midi_track (
uint32_t how_many,
std::string const & name_template,
bool strict_io,
+ ARDOUR::PresentationInfo::order_t order,
ARDOUR::PluginInfoPtr instrument,
ARDOUR::Plugin::PresetRecord* preset = NULL) {
- session_add_midi_route (true, route_group, how_many, name_template, strict_io, instrument, preset);
+ session_add_midi_route (true, route_group, how_many, name_template, strict_io, order, instrument, preset);
}
- void session_add_mixed_track (const ARDOUR::ChanCount&, const ARDOUR::ChanCount&, ARDOUR::RouteGroup*, uint32_t, std::string const &, bool, ARDOUR::PluginInfoPtr, ARDOUR::Plugin::PresetRecord*);
- void session_add_midi_bus (ARDOUR::RouteGroup*, uint32_t, std::string const &, bool, ARDOUR::PluginInfoPtr, ARDOUR::Plugin::PresetRecord*);
- void session_add_audio_route (bool, int32_t, int32_t, ARDOUR::TrackMode, ARDOUR::RouteGroup *, uint32_t, std::string const &, bool);
- void session_add_midi_route (bool, ARDOUR::RouteGroup *, uint32_t, std::string const &, bool, ARDOUR::PluginInfoPtr, ARDOUR::Plugin::PresetRecord*);
+ void session_add_mixed_track (const ARDOUR::ChanCount&, const ARDOUR::ChanCount&, ARDOUR::RouteGroup*, uint32_t, std::string const &, bool, ARDOUR::PluginInfoPtr,
+ ARDOUR::PresentationInfo::order_t order);
+ void session_add_midi_bus (ARDOUR::RouteGroup*, uint32_t, std::string const &, bool, ARDOUR::PluginInfoPtr,
+ ARDOUR::PresentationInfo::order_t order);
+ void session_add_audio_route (bool, int32_t, int32_t, ARDOUR::TrackMode, ARDOUR::RouteGroup *, uint32_t, std::string const &, bool,
+ ARDOUR::PresentationInfo::order_t order);
+ void session_add_midi_route (bool, ARDOUR::RouteGroup *, uint32_t, std::string const &, bool, ARDOUR::PresentationInfo::order_t order,
+ ARDOUR::PluginInfoPtr, ARDOUR::Plugin::PresetRecord*);
void display_insufficient_ports_message ();
void button_change_tabbable_visibility (Gtkmm2ext::Tabbable*);
void key_change_tabbable_visibility (Gtkmm2ext::Tabbable*);
void toggle_editor_and_mixer ();
-
+
void tabbable_state_change (Gtkmm2ext::Tabbable&);
void toggle_meterbridge ();
bool save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar);
void save_session_as ();
void rename_session ();
- void setup_order_hint (AddRouteDialog::InsertAt);
+ ARDOUR::PresentationInfo::order_t translate_order (AddRouteDialog::InsertAt);
int create_mixer ();
int create_editor ();
void install_actions ();
- void toggle_record_enable (uint32_t);
+ void toggle_record_enable (uint16_t);
uint32_t rec_enabled_streams;
void count_recenabled_streams (ARDOUR::Route&);
}
void
-Editor::control_select (uint32_t rid, Selection::Operation op)
+Editor::control_select (uint16_t rid, Selection::Operation op)
{
/* handles the (static) signal from the ControlProtocol class that
* requests setting the selected track to a given RID
return;
}
- boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
+ boost::shared_ptr<Route> r = _session->get_remote_nth_route (rid);
if (!r) {
return;
void control_step_tracks_down ();
void control_view (uint32_t);
void control_scroll (float);
- void control_select (uint32_t rid, Selection::Operation);
+ void control_select (uint16_t rid, Selection::Operation);
void control_unselect ();
void access_action (std::string,std::string);
bool deferred_control_scroll (framepos_t);
{
if (!existing_track) {
if (ar) {
- list<boost::shared_ptr<AudioTrack> > at (_session->new_audio_track (in_chans, out_chans, Normal, 0, 1));
+ list<boost::shared_ptr<AudioTrack> > at (_session->new_audio_track (in_chans, out_chans, 0, 1, string(), PresentationInfo::max_order, Normal));
if (at.empty()) {
return -1;
_session->new_midi_track (ChanCount (DataType::MIDI, 1),
ChanCount (DataType::MIDI, 1),
instrument,
- Normal, 0, 1));
+ 0, 1, string(),
+ PresentationInfo::max_order));
if (mt.empty()) {
return -1;
return -1;
}
- list<boost::shared_ptr<AudioTrack> > at (_session->new_audio_track (in_chans, out_chans, Destructive));
+ list<boost::shared_ptr<AudioTrack> > at (_session->new_audio_track (in_chans, out_chans, 0, 1, string(), PresentationInfo::max_order, Destructive));
if (!at.empty()) {
boost::shared_ptr<Playlist> playlist = at.front()->playlist();
boost::shared_ptr<Region> copy (RegionFactory::create (region, true));
output_chan = session()->master_out()->n_inputs().n_audio();
}
list<boost::shared_ptr<AudioTrack> > audio_tracks;
- audio_tracks = session()->new_audio_track (region->n_channels(), output_chan, ARDOUR::Normal, 0, 1, region->name());
+ audio_tracks = session()->new_audio_track (region->n_channels(), output_chan, 0, 1, region->name(), PresentationInfo::max_order, ARDOUR::Normal);
rtav = axis_view_from_route (audio_tracks.front());
} else if (boost::dynamic_pointer_cast<MidiRegion> (region)) {
ChanCount one_midi_port (DataType::MIDI, 1);
list<boost::shared_ptr<MidiTrack> > midi_tracks;
- midi_tracks = session()->new_midi_track (one_midi_port, one_midi_port, boost::shared_ptr<ARDOUR::PluginInfo>(), ARDOUR::Normal, 0, 1, region->name());
+ midi_tracks = session()->new_midi_track (one_midi_port, one_midi_port, boost::shared_ptr<ARDOUR::PluginInfo>(), 0, 1, region->name(), PresentationInfo::max_order, ARDOUR::Normal);
rtav = axis_view_from_route (midi_tracks.front());
} else {
return;
return boost::shared_ptr<Region>();
}
-struct EditorOrderTimeAxisViewSorter {
+struct PresentationInfoTimeAxisViewSorter {
bool operator() (TimeAxisView* a, TimeAxisView* b) {
RouteTimeAxisView* ra = dynamic_cast<RouteTimeAxisView*> (a);
RouteTimeAxisView* rb = dynamic_cast<RouteTimeAxisView*> (b);
assert (ra && rb);
- return ra->route()->order_key () < rb->route()->order_key ();
+ return ra->route()->presentation_info () < rb->route()->presentation_info();
}
};
*/
TrackViewList track_views = _editor->track_views;
- track_views.sort (EditorOrderTimeAxisViewSorter ());
+ track_views.sort (PresentationInfoTimeAxisViewSorter ());
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
_time_axis_views.push_back (*i);
if ((Config->get_output_auto_connect() & AutoConnectMaster) && _editor->session()->master_out()) {
output_chan = _editor->session()->master_out()->n_inputs().n_audio();
}
- audio_tracks = _editor->session()->new_audio_track (region->n_channels(), output_chan, ARDOUR::Normal, 0, 1, region->name());
+ audio_tracks = _editor->session()->new_audio_track (region->n_channels(), output_chan, 0, 1, region->name(), PresentationInfo::max_order, ARDOUR::Normal);
RouteTimeAxisView* rtav = _editor->axis_view_from_route (audio_tracks.front());
if (rtav) {
rtav->set_height (original->current_height());
} else {
ChanCount one_midi_port (DataType::MIDI, 1);
list<boost::shared_ptr<MidiTrack> > midi_tracks;
- midi_tracks = _editor->session()->new_midi_track (one_midi_port, one_midi_port, boost::shared_ptr<ARDOUR::PluginInfo>(), ARDOUR::Normal, 0, 1, region->name());
+ midi_tracks = _editor->session()->new_midi_track (one_midi_port, one_midi_port, boost::shared_ptr<ARDOUR::PluginInfo>(), 0, 1, region->name(), PresentationInfo::max_order, ARDOUR::Normal);
RouteTimeAxisView* rtav = _editor->axis_view_from_route (midi_tracks.front());
if (rtav) {
rtav->set_height (original->current_height());
return rl;
}
-void
-EditorGroupTabs::sync_order_keys ()
-{
- _editor->_routes->sync_order_keys_from_treeview ();
-}
}
void add_menu_items (Gtk::Menu *, ARDOUR::RouteGroup *);
ARDOUR::RouteList selected_routes () const;
- void sync_order_keys ();
};
}
}
-struct EditorOrderRouteSorter {
- bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
- return a->order_key () < b->order_key ();
- }
-};
-
void
Editor::select_next_route()
{
} else {
// Put on a new track
DEBUG_TRACE (DEBUG::FileUtils, string_compose ("\twav(%1) reg(%2) new_tr(%3)\n", a->reg.wave.filename.c_str(), a->reg.index, nth));
- list<boost::shared_ptr<AudioTrack> > at (_session->new_audio_track (1, 2, Normal, 0, 1));
+ list<boost::shared_ptr<AudioTrack> > at (_session->new_audio_track (1, 2, 0, 1, string(), PresentationInfo::max_order, Normal));
if (at.empty()) {
return;
}
#include "pbd/unwind.h"
#include "ardour/debug.h"
+#include "ardour/audio_track.h"
#include "ardour/midi_track.h"
#include "ardour/route.h"
#include "ardour/session.h"
_display.set_enable_search (false);
- Route::SyncOrderKeys.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::sync_treeview_from_order_keys, this), gui_context());
Route::PluginSetup.connect_same_thread (*this, boost::bind (&EditorRoutes::plugin_setup, this, _1, _2, _3));
-
+ Stripable::PresentationInfoChange.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::sync_treeview_from_presentation_info, this), gui_context());
}
bool
* when a route is actually removed. we don't differentiate between
* the two cases.
*
- * note that the sync_orders_keys() step may not actually change any
- * RID's (e.g. the last track may be removed, so all other tracks keep
- * the same RID), which means that no redisplay would happen. so we
- * have to force a redisplay.
+ * note that the sync_presentation_info_from_treeview() step may not
+ * actually change any presentation info (e.g. the last track may be
+ * removed, so all other tracks keep the same presentation info), which
+ * means that no redisplay would happen. so we have to force a
+ * redisplay.
*/
DEBUG_TRACE (DEBUG::OrderKeys, "editor routes treeview row deleted\n");
DisplaySuspender ds;
- sync_order_keys_from_treeview ();
+ sync_presentation_info_from_treeview ();
}
void
EditorRoutes::reordered (TreeModel::Path const &, TreeModel::iterator const &, int* /*what*/)
{
- /* reordering implies that RID's will change, so sync_order_keys() will
- cause a redisplay.
+ /* reordering implies that RID's will change, so
+ sync_presentation_info_from_treeview() will cause a redisplay.
*/
DEBUG_TRACE (DEBUG::OrderKeys, "editor routes treeview reordered\n");
- sync_order_keys_from_treeview ();
+ sync_presentation_info_from_treeview ();
}
void
for (Gtk::TreeModel::Children::iterator it = _model->children().begin(); it != _model->children().end(); ++it) {
boost::shared_ptr<Route> r = (*it)[_columns.route];
- if (r->order_key() == (routes.front()->route()->order_key() + routes.size())) {
+ if (r->presentation_info().group_order() == (routes.front()->route()->presentation_info().group_order() + routes.size())) {
insert_iter = it;
break;
}
/* now update route order keys from the treeview/track display order */
if (!from_scratch) {
- sync_order_keys_from_treeview ();
+ sync_presentation_info_from_treeview ();
}
}
/* force route order keys catch up with visibility changes
*/
- sync_order_keys_from_treeview ();
+ sync_presentation_info_from_treeview ();
}
void
return;
}
- TreeModel::Children rows = _model->children();
-
- if (rows.empty()) {
- return;
- }
-
-
- DEBUG_TRACE (DEBUG::OrderKeys, "editor reset remote control ids\n");
-
- TreeModel::Children::iterator ri;
- bool rid_change = false;
- uint32_t rid = 1;
- uint32_t invisible_key = UINT32_MAX;
-
- for (ri = rows.begin(); ri != rows.end(); ++ri) {
-
- /* skip two special values */
-
- if (rid == Route::MasterBusRemoteControlID) {
- rid++;
- }
-
- if (rid == Route::MonitorBusRemoteControlID) {
- rid++;
- }
-
- boost::shared_ptr<Route> route = (*ri)[_columns.route];
- bool visible = (*ri)[_columns.visible];
-
- if (!route->is_master() && !route->is_monitor()) {
-
- uint32_t new_rid = (visible ? rid : invisible_key--);
-
- if (new_rid != route->remote_control_id()) {
- route->set_remote_control_id_explicit (new_rid);
- rid_change = true;
- }
-
- if (visible) {
- rid++;
- }
-
- }
- }
-
- if (rid_change) {
- /* tell the world that we changed the remote control IDs */
- _session->notify_remote_id_change ();
- }
+ sync_presentation_info_from_treeview ();
}
-
-
void
-EditorRoutes::sync_order_keys_from_treeview ()
+EditorRoutes::sync_presentation_info_from_treeview ()
{
if (_ignore_reorder || !_session || _session->deletion_in_progress()) {
return;
return;
}
-
DEBUG_TRACE (DEBUG::OrderKeys, "editor sync order keys from treeview\n");
TreeModel::Children::iterator ri;
- bool changed = false;
- bool rid_change = false;
- uint32_t order = 0;
- uint32_t rid = 1;
- uint32_t invisible_key = UINT32_MAX;
+ bool change = false;
+ PresentationInfo::order_t order = 0;
+
+ /* hmm, problem ... editor doesn't represent all Stripables... we can't
+ reset the whole presentation order from here.
+ */
for (ri = rows.begin(); ri != rows.end(); ++ri) {
boost::shared_ptr<Route> route = (*ri)[_columns.route];
bool visible = (*ri)[_columns.visible];
- uint32_t old_key = route->order_key ();
-
- if (order != old_key) {
- route->set_order_key (order);
-
- changed = true;
+ if (route->presentation_info().special ()) {
+ continue;
}
- if ((Config->get_remote_model() == MixerOrdered) && !route->is_master() && !route->is_monitor()) {
-
- uint32_t new_rid = (visible ? rid : invisible_key--);
-
- if (new_rid != route->remote_control_id()) {
- route->set_remote_control_id_explicit (new_rid);
- rid_change = true;
- }
-
- if (visible) {
- rid++;
- }
+ if (!visible) {
+ route->presentation_info().set_flag (PresentationInfo::Hidden);
+ } else {
+ route->presentation_info().unset_flag (PresentationInfo::Hidden);
+ }
+ if (order != route->presentation_info().group_order()) {
+ route->set_presentation_group_order_explicit (order);
+ change = true;
}
++order;
}
- if (changed) {
- /* tell the world that we changed the editor sort keys */
- _session->sync_order_keys ();
- }
-
- if (rid_change) {
- /* tell the world that we changed the remote control IDs */
- _session->notify_remote_id_change ();
+ if (change) {
+ Stripable::PresentationInfoChange(); /* EMIT SIGNAL */
}
}
void
-EditorRoutes::sync_treeview_from_order_keys ()
+EditorRoutes::sync_treeview_from_presentation_info ()
{
/* Some route order key(s) have been changed, make sure that
we update out tree/list model and GUI to reflect the change.
return;
}
- DEBUG_TRACE (DEBUG::OrderKeys, "editor sync model from order keys.\n");
+ DEBUG_TRACE (DEBUG::OrderKeys, "editor sync model from presentation info.\n");
/* we could get here after either a change in the Mixer or Editor sort
* order, but either way, the mixer order keys reflect the intended
for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri, ++old_order) {
boost::shared_ptr<Route> route = (*ri)[_columns.route];
- sorted.push_back (OrderKeys (old_order, route->order_key ()));
+ sorted.push_back (OrderKeys (old_order, route->presentation_info().group_order()));
+ DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("build new order: route %3 old = %1 new = %1\n",
+ old_order,
+ route->presentation_info().group_order(),
+ route->name()));
}
SortByNewDisplayOrder cmp;
/* force route order keys catch up with visibility changes
*/
- sync_order_keys_from_treeview ();
+ sync_presentation_info_from_treeview ();
}
void
/* force route order keys catch up with visibility changes
*/
- sync_order_keys_from_treeview ();
+ sync_presentation_info_from_treeview ();
}
void
return true;
}
-struct EditorOrderRouteSorter
+struct PresentationInfoRouteSorter
{
bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
if (a->is_master()) {
/* everything else before master */
return false;
}
- return a->order_key () < b->order_key ();
+ return a->presentation_info().global_order () < b->presentation_info().global_order ();
}
};
RouteList r (*_session->get_routes());
- r.sort (EditorOrderRouteSorter ());
+ r.sort (PresentationInfoRouteSorter ());
_editor->add_routes (r);
}
}
for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) {
- uint32_t order = leading->second->order_key ();
+ uint32_t order = (uint32_t) leading->second->presentation_info().group_order ();
neworder.push_back (order);
}
/* force route order keys catch up with visibility changes
*/
- sync_order_keys_from_treeview ();
+ sync_presentation_info_from_treeview ();
}
int
std::list<TimeAxisView*> views () const;
void hide_all_tracks (bool);
void clear ();
- void sync_order_keys_from_treeview ();
+ void sync_presentation_info_from_treeview ();
void reset_remote_control_ids ();
private:
void on_tv_solo_safe_toggled (std::string const &);
void build_menu ();
void show_menu ();
- void sync_treeview_from_order_keys ();
+ void sync_treeview_from_presentation_info ();
void row_deleted (Gtk::TreeModel::Path const &);
void visible_changed (std::string const &);
void active_changed (std::string const &);
RouteTimeAxisView* closest = 0;
int distance = INT_MAX;
- int key = rtv->route()->order_key ();
+ int key = rtv->route()->presentation_info().global_order ();
for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
if (result.second) {
/* newly added to already_in_selection */
- int d = artv->route()->order_key ();
+ int d = artv->route()->presentation_info().global_order ();
d -= key;
/* now add all tracks between that one and this one */
- int okey = closest->route()->order_key ();
+ int okey = closest->route()->presentation_info().global_order ();
if (okey > key) {
swap (okey, key);
RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(*x);
if (artv && artv != rtv) {
- int k = artv->route()->order_key ();
+ int k = artv->route()->presentation_info().global_order ();
if (k >= okey && k <= key) {
if (_session) {
Region::RegionPropertyChanged.connect (region_property_connection, invalidator (*this), boost::bind (&EditorSummary::set_background_dirty, this), gui_context());
- Route::RemoteControlIDChange.connect (route_ctrl_id_connection, invalidator (*this), boost::bind (&EditorSummary::set_background_dirty, this), gui_context());
+ Stripable::PresentationInfoChange.connect (route_ctrl_id_connection, invalidator (*this), boost::bind (&EditorSummary::set_background_dirty, this), gui_context());
_editor->playhead_cursor->PositionChanged.connect (position_connection, invalidator (*this), boost::bind (&EditorSummary::playhead_position_changed, this, _1), gui_context());
_session->StartTimeChanged.connect (_session_connections, invalidator (*this), boost::bind (&EditorSummary::set_background_dirty, this), gui_context());
_session->EndTimeChanged.connect (_session_connections, invalidator (*this), boost::bind (&EditorSummary::set_background_dirty, this), gui_context());
*/
-#include "export_channel_selector.h"
-
#include <algorithm>
#include "pbd/convert.h"
#include <sstream>
+#include "export_channel_selector.h"
+#include "route_sorter.h"
+
#include "i18n.h"
using namespace std;
using namespace ARDOUR;
using namespace PBD;
-struct EditorOrderRouteSorter {
- bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
- return a->order_key () < b->order_key ();
- }
-};
-
PortExportChannelSelector::PortExportChannelSelector (ARDOUR::Session * session, ProfileManagerPtr manager) :
ExportChannelSelector (session, manager),
channels_label (_("Channels:"), Gtk::ALIGN_LEFT),
channel_view.add_route (master);
}
- routes.sort (EditorOrderRouteSorter ());
+ routes.sort (PresentationInfoSorter ());
for (RouteList::iterator it = routes.begin(); it != routes.end(); ++it) {
if ((*it)->is_master () || (*it)->is_monitor ()) {
row[track_cols.selected] = false;
row[track_cols.label] = route->name();
row[track_cols.route] = route;
- row[track_cols.order_key] = route->order_key();
+ row[track_cols.order_key] = route->presentation_info().global_order();
}
void
struct CollectSorter {
bool operator () (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
- return a->order_key () < b->order_key ();
+ return a->presentation_info () < b->presentation_info();
}
};
struct OrderSorter {
bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
- return a->order_key () < b->order_key ();
+ return a->presentation_info() < b->presentation_info();
}
};
int coll = -1;
while (i != group_routes->end() && j != routes->end()) {
- int const k = (*j)->order_key ();
+ PresentationInfo::order_t const k = (*j)->presentation_info ().group_order();
if (*i == *j) {
--diff;
}
- (*j)->set_order_key (coll);
+ (*j)->set_presentation_group_order_explicit (coll);
++coll;
++i;
} else {
- (*j)->set_order_key (k + diff);
+ (*j)->set_presentation_group_order_explicit (k + diff);
}
++j;
}
- _session->sync_order_keys ();
+ _session->notify_presentation_info_change ();
}
void
virtual void add_menu_items (Gtk::Menu *, ARDOUR::RouteGroup *) {}
virtual ARDOUR::RouteList selected_routes () const = 0;
- virtual void sync_order_keys () = 0;
void new_from_selection ();
void new_from_rec_enabled ();
SESSION(Located, Located, 0)
SESSION(RoutesReconnected, session_routes_reconnected, 0)
SESSION(RouteAdded, RouteAdded, 1)
-SESSION(RouteAddedOrRemoved, RouteAddedOrRemoved, 1)
SESSION(RouteGroupPropertyChanged, RouteGroupPropertyChanged, 1)
SESSION(RouteAddedToRouteGroup, RouteAddedToRouteGroup, 2)
SESSION(RouteRemovedFromRouteGroup, RouteRemovedFromRouteGroup, 2)
SESSION(RouteGroupRemoved, route_group_removed, 0)
SESSION(RouteGroupsReordered, route_groups_reordered, 0)
-// route static globals
-STATIC(SyncOrderKeys, &Route::SyncOrderKeys, 0)
-
// plugin manager instance
STATIC(PluginListChanged, &(PluginManager::instance().PluginListChanged), 0)
STATIC(PluginStatusesChanged, &(PluginManager::instance().PluginStatusesChanged), 0)
}
name_label.set_text(_route->name ());
if (_session && _session->config.get_track_name_number()) {
- const int64_t track_number = _route->track_number ();
+ const uint64_t track_number = _route->track_number();
if (track_number == 0) {
number_label.set_text("-");
number_label.hide();
} else {
- number_label.set_text (PBD::to_string (abs(_route->track_number ()), std::dec));
+ number_label.set_text (PBD::to_string (track_number, std::dec));
number_label.show();
}
const int tnh = 4 + std::max(2u, _session->track_number_decimals()) * 8; // TODO 8 = max_width_of_digit_0_to_9()
#include "ardour/audio_track.h"
#include "ardour/midi_track.h"
-#include "ardour/route_sorters.h"
#include "meterbridge.h"
signal_delete_event().connect (sigc::mem_fun (*this, &Meterbridge::hide_window));
signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
- Route::SyncOrderKeys.connect (*this, invalidator (*this), boost::bind (&Meterbridge::sync_order_keys, this), gui_context());
MeterStrip::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Meterbridge::remove_strip, this, _1), gui_context());
MeterStrip::MetricChanged.connect (*this, invalidator (*this), boost::bind(&Meterbridge::resync_order, this), gui_context());
MeterStrip::ConfigurationChanged.connect (*this, invalidator (*this), boost::bind(&Meterbridge::queue_resize, this), gui_context());
metrics_right.set_metric_mode(mm_right, mt_right);
}
+struct PresentationInfoRouteSorter
+{
+ bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
+ if (a->is_master()) {
+ /* master before everything else */
+ return true;
+ } else if (b->is_master()) {
+ /* everything else before b */
+ return false;
+ }
+ return a->presentation_info() < b->presentation_info();
+ }
+};
+
void
Meterbridge::set_session (Session* s)
{
_show_master = _session->config.get_show_master_on_meterbridge();
_show_midi = _session->config.get_show_midi_on_meterbridge();
- ARDOUR::SignalOrderRouteSorter sorter;
+ PresentationInfoRouteSorter sorter;
boost::shared_ptr<RouteList> routes = _session->get_routes();
RouteList copy(*routes);
/* everything comes before b */
return true;
}
- return a->order_key () < b->order_key ();
+ return a->presentation_info() < b->presentation_info ();
}
};
return rl;
}
-void
-MixerGroupTabs::sync_order_keys ()
-{
- _mixer->sync_order_keys_from_treeview ();
-}
}
ARDOUR::RouteList selected_routes () const;
- void sync_order_keys ();
Mixer_UI* _mixer;
};
#include "ardour/amp.h"
#include "ardour/debug.h"
+#include "ardour/audio_track.h"
#include "ardour/midi_track.h"
#include "ardour/plugin_manager.h"
#include "ardour/route_group.h"
-#include "ardour/route_sorters.h"
#include "ardour/session.h"
#include "ardour/vca.h"
#include "ardour/vca_manager.h"
, _maximised (false)
, _show_mixer_list (true)
{
- Route::SyncOrderKeys.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::sync_treeview_from_order_keys, this), gui_context());
+ Stripable::PresentationInfoChange.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::sync_treeview_from_presentation_info, this), gui_context());
/* bindings was already set in MixerActor constructor */
nroutes++;
- if (r->order_key() == (routes.front()->order_key() + routes.size())) {
+ if (r->presentation_info().group_order() == (routes.front()->presentation_info().group_order() + routes.size())) {
insert_iter = it;
break;
}
no_track_list_redisplay = false;
track_display.set_model (track_model);
- sync_order_keys_from_treeview ();
+ sync_presentation_info_from_treeview ();
redisplay_track_list ();
}
}
void
-Mixer_UI::reset_remote_control_ids ()
+Mixer_UI::sync_presentation_info_from_treeview ()
{
- if (Config->get_remote_model() == UserOrdered || !_session || _session->deletion_in_progress()) {
- return;
- }
-
- TreeModel::Children rows = track_model->children();
-
- if (rows.empty()) {
- return;
- }
-
- DEBUG_TRACE (DEBUG::OrderKeys, "mixer resets remote control ids after remote model change\n");
-
- TreeModel::Children::iterator ri;
- bool rid_change = false;
- uint32_t rid = 1;
- uint32_t invisible_key = UINT32_MAX;
-
- for (ri = rows.begin(); ri != rows.end(); ++ri) {
-
- /* skip two special values */
-
- if (rid == Route::MasterBusRemoteControlID) {
- rid++;
- }
-
- if (rid == Route::MonitorBusRemoteControlID) {
- rid++;
- }
-
- boost::shared_ptr<Route> route = (*ri)[track_columns.route];
- bool visible = (*ri)[track_columns.visible];
-
- if (!route) {
- continue;
- }
-
- if (!route->is_master() && !route->is_monitor()) {
-
- uint32_t new_rid = (visible ? rid : invisible_key--);
-
- if (new_rid != route->remote_control_id()) {
- route->set_remote_control_id_explicit (new_rid);
- rid_change = true;
- }
-
- if (visible) {
- rid++;
- }
- }
- }
-
- if (rid_change) {
- /* tell the world that we changed the remote control IDs */
- _session->notify_remote_id_change ();
- }
-}
-
-void
-Mixer_UI::sync_order_keys_from_treeview ()
-{
- if (ignore_reorder || !_session || _session->deletion_in_progress()) {
+ if (ignore_reorder || !_session || _session->deletion_in_progress() || (Config->get_remote_model() != MixerOrdered)) {
return;
}
DEBUG_TRACE (DEBUG::OrderKeys, "mixer sync order keys from model\n");
TreeModel::Children::iterator ri;
- bool changed = false;
- bool rid_change = false;
+ bool change = false;
uint32_t order = 0;
- uint32_t rid = 1;
- uint32_t invisible_key = UINT32_MAX;
for (ri = rows.begin(); ri != rows.end(); ++ri) {
boost::shared_ptr<Route> route = (*ri)[track_columns.route];
bool visible = (*ri)[track_columns.visible];
+
if (!route) {
continue;
}
- uint32_t old_key = route->order_key ();
-
- if (order != old_key) {
- route->set_order_key (order);
- changed = true;
+ if (route->presentation_info().special()) {
+ continue;
}
- if ((Config->get_remote_model() == MixerOrdered) && !route->is_master() && !route->is_monitor()) {
-
- uint32_t new_rid = (visible ? rid : invisible_key--);
-
- if (new_rid != route->remote_control_id()) {
- route->set_remote_control_id_explicit (new_rid);
- rid_change = true;
- }
+ if (!visible) {
+ route->presentation_info().set_flag (PresentationInfo::Hidden);
+ } else {
+ route->presentation_info().unset_flag (PresentationInfo::Hidden);
+ }
- if (visible) {
- rid++;
- }
+ DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("route %1 old order %2 new order %3\n", route->name(), route->presentation_info().group_order(), order));
+ if (order != route->presentation_info().group_order()) {
+ route->set_presentation_group_order_explicit (order);
+ change = true;
}
++order;
}
- if (changed) {
- /* tell everyone that we changed the mixer sort keys */
- _session->sync_order_keys ();
- }
-
- if (rid_change) {
- /* tell the world that we changed the remote control IDs */
- _session->notify_remote_id_change ();
+ if (change) {
+ DEBUG_TRACE (DEBUG::OrderKeys, "... notify PI change from mixer GUI\n");
+ _session->notify_presentation_info_change ();
}
}
void
-Mixer_UI::sync_treeview_from_order_keys ()
+Mixer_UI::sync_treeview_from_presentation_info ()
{
if (!_session || _session->deletion_in_progress()) {
return;
for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri) {
boost::shared_ptr<Route> route = (*ri)[track_columns.route];
if (route) {
- max_route_order_key = max (route->order_key(), max_route_order_key);
+ max_route_order_key = max (route->presentation_info().group_order(), max_route_order_key);
}
}
*/
sorted.push_back (OrderKeys (old_order, max_route_order_key + ++vca_cnt));
} else {
- sorted.push_back (OrderKeys (old_order, route->order_key ()));
+ sorted.push_back (OrderKeys (old_order, route->presentation_info().group_order()));
}
}
}
}
- /* force route order keys catch up with visibility changes
+ /* force presentation catch up with visibility changes
*/
- sync_order_keys_from_treeview ();
+ sync_presentation_info_from_treeview ();
}
redisplay_track_list ();
Mixer_UI::track_list_reorder (const TreeModel::Path&, const TreeModel::iterator&, int* /*new_order*/)
{
DEBUG_TRACE (DEBUG::OrderKeys, "mixer UI treeview reordered\n");
- sync_order_keys_from_treeview ();
+ sync_presentation_info_from_treeview ();
}
void
*/
DEBUG_TRACE (DEBUG::OrderKeys, "mixer UI treeview row deleted\n");
- sync_order_keys_from_treeview ();
+ sync_presentation_info_from_treeview ();
if (_route_deletion_in_progress) {
redisplay_track_list ();
if (n_masters == 0) {
UIConfiguration::instance().set_mixer_strip_visibility (VisibilityGroup::remove_element (UIConfiguration::instance().get_mixer_strip_visibility(), X_("VCA")));
+ vca_scroller.hide ();
} else {
UIConfiguration::instance().set_mixer_strip_visibility (VisibilityGroup::add_element (UIConfiguration::instance().get_mixer_strip_visibility(), X_("VCA")));
+ vca_scroller.show ();
}
_group_tabs->set_dirty ();
}
+struct PresentationInfoRouteSorter
+{
+ bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
+ return a->presentation_info().global_order () < b->presentation_info().global_order ();
+ }
+};
+
void
Mixer_UI::initial_track_display ()
{
boost::shared_ptr<RouteList> routes = _session->get_routes();
RouteList copy (*routes);
- ARDOUR::SignalOrderRouteSorter sorter;
+ PresentationInfoRouteSorter sorter;
copy.sort (sorter);
add_strips (copy);
}
- _session->sync_order_keys ();
-
redisplay_track_list ();
}
for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
(*i)->set_width_enum (s ? Narrow : Wide, this);
}
- } else if (p == "remote-model") {
- reset_remote_control_ids ();
} else if (p == "use-monitor-bus") {
if (_session && !_session->monitor_out()) {
monitor_section_detached ();
Width _strip_width;
- void sync_order_keys_from_treeview ();
- void sync_treeview_from_order_keys ();
- void reset_remote_control_ids ();
- void reset_order_keys ();
+ void sync_presentation_info_from_treeview ();
+ void sync_treeview_from_presentation_info ();
bool ignore_reorder;
class RouteIOsComparator {
public:
bool operator() (RouteIOs const & a, RouteIOs const & b) {
- return a.route->order_key () < b.route->order_key ();
+ return a.route->presentation_info ().group_order() < b.route->presentation_info().group_order();
}
};
_session->engine().PortRegisteredOrUnregistered.connect (_session_connections, invalidator (*this), boost::bind (&PortMatrix::setup_global_ports, this), gui_context());
/* watch for route order keys changing, which changes the order of things in our global ports list(s) */
- Route::SyncOrderKeys.connect (_session_connections, invalidator (*this), boost::bind (&PortMatrix::setup_global_ports_proxy, this), gui_context());
+ Stripable::PresentationInfoChange.connect (_session_connections, invalidator (*this), boost::bind (&PortMatrix::setup_global_ports_proxy, this), gui_context());
/* Part 3: other stuff */
spin->set_digits (0);
spin->set_increments (1, 10);
spin->set_range (0, limit);
- spin->set_value (_route->remote_control_id());
+ spin->set_value (_route->presentation_info().group_order());
hbox->pack_start (*spin);
dialog.get_vbox()->pack_start (*hbox);
l->set_markup (string_compose (_("The remote control ID of %1 is: %2\n\n\n"
"The remote control ID of %3 cannot be changed."),
Gtkmm2ext::markup_escape_text (_route->name()),
- _route->remote_control_id(),
+ _route->presentation_info().group_order(),
(_route->is_master() ? _("the master bus") : _("the monitor bus"))));
} else {
l->set_markup (string_compose (_("The remote control ID of %5 is: %2\n\n\n"
"Remote Control IDs are currently determined by track/bus ordering in %6.\n\n"
"%3Use the User Interaction tab of the Preferences window if you want to change this%4"),
(is_track() ? _("track") : _("bus")),
- _route->remote_control_id(),
+ _route->presentation_info().group_order(),
"<span size=\"small\" style=\"italic\">",
"</span>",
Gtkmm2ext::markup_escape_text (_route->name()),
int const r = dialog.run ();
if (r == RESPONSE_ACCEPT && spin) {
- _route->set_remote_control_id (spin->get_value_as_int ());
+ _route->set_presentation_group_order_explicit (spin->get_value_as_int ());
}
}
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <gtkmm/stock.h>
+
#include "pbd/convert.h"
#include "ardour/rc_configuration.h"
#include "gtkmm2ext/doi.h"
#include "gtkmm2ext/keyboard.h"
-#include "gui_thread.h"
+#include "ardour_dialog.h"
#include "floating_text_entry.h"
+#include "gui_thread.h"
#include "tooltips.h"
#include "vca_master_strip.h"
, _vca (v)
, gain_meter (s, 250)
, context_menu (0)
+ , delete_dialog (0)
{
gain_meter.set_controls (boost::shared_ptr<Route>(),
boost::shared_ptr<PeakMeter>(),
VCAMasterStrip::~VCAMasterStrip ()
{
+ delete delete_dialog;
+ delete context_menu;
+
CatchDeletion (this); /* EMIT SIGNAL */
}
void
VCAMasterStrip::hide_clicked ()
{
- /* get everything to deassign. This will also delete ourselves (when
- * idle) and that in turn will remove us from the Mixer GUI
- */
- _session->vca_manager().remove_vca (_vca);
+ if (!delete_dialog) {
+ delete_dialog = new MessageDialog (_("Removing a Master will deassign all slaves. Remove it anyway?"),
+ true, MESSAGE_WARNING, BUTTONS_YES_NO, true);
+ delete_dialog->signal_response().connect (sigc::mem_fun (*this, &VCAMasterStrip::hide_confirmation));
+ }
+
+ delete_dialog->set_position (Gtk::WIN_POS_MOUSE);
+ delete_dialog->present ();
+}
+
+void
+VCAMasterStrip::hide_confirmation (int response)
+{
+ delete_dialog->hide ();
+
+ switch (response) {
+ case RESPONSE_OK:
+ /* get everything to deassign. This will also delete ourselves (when
+ * idle) and that in turn will remove us from the Mixer GUI
+ */
+ _session->vca_manager().remove_vca (_vca);
+ break;
+ default:
+ break;
+ }
}
bool
ArdourButton assign_button;
Gtk::Menu* context_menu;
PBD::ScopedConnectionList vca_connections;
+ Gtk::MessageDialog* delete_dialog;
void hide_clicked();
bool width_button_pressed (GdkEventButton *);
void vca_property_changed (PBD::PropertyChange const & what_changed);
void update_vca_name ();
void build_context_menu ();
+ void hide_confirmation (int);
void self_delete ();
};
class LIBARDOUR_API AudioTrack : public Track
{
public:
- AudioTrack (Session&, std::string name, Route::Flag f = Route::Flag (0), TrackMode m = Normal);
+ AudioTrack (Session&, std::string name, TrackMode m = Normal);
~AudioTrack ();
int set_mode (TrackMode m);
class LIBARDOUR_API MidiTrack : public Track
{
public:
- MidiTrack (Session&, std::string name, Route::Flag f = Route::Flag (0), TrackMode m = Normal);
+ MidiTrack (Session&, std::string name, TrackMode m = Normal);
~MidiTrack ();
int init ();
#include "ardour/slavable_automation_control.h"
+#include "ardour/mute_master.h"
#include "ardour/libardour_visibility.h"
namespace ARDOUR {
--- /dev/null
+/*
+ Copyright (C) 2016 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __libardour_presentation_info_h__
+#define __libardour_presentation_info_h__
+
+#include <iostream>
+#include <string>
+
+#include <stdint.h>
+
+#include "ardour/libardour_visibility.h"
+
+class XMLNode;
+
+namespace ARDOUR {
+
+class LIBARDOUR_API PresentationInfo
+{
+ public:
+
+ /* a PresentationInfo object exists to share information between
+ * different user interfaces (e.g. GUI and a Mackie Control surface)
+ * about:
+ *
+ * - ordering
+ * - selection status
+ * - visibility
+ * - object identity
+ *
+ * ORDERING
+ *
+ * One UI takes control of ordering by setting the "order" value for
+ * the PresentationInfo component of every Stripable object. In Ardour,
+ * this is done by the GUI (mostly because it is very hard for the user
+ * to re-order things on a control surface).
+ *
+ * Ordering is a complex beast, however. Different user interfaces may
+ * display things in different ways. For example, the GUI of Ardour
+ * allows the user to mix busses in between tracks. A control surface
+ * may do the same, but may also allow the user to press a button that
+ * makes it show only busses, or only MIDI tracks. At that point, the
+ * ordering on the surface differs from the ordering in the GUI.
+ *
+ * The ordering is given via a combination of an object type and a
+ * simple numeric position within that type. The object types at this
+ * time are:
+ *
+ * Route
+ * - object has inputs and outputs; processes data
+ * Output
+ * - Route used to connect to outside the application (MasterOut, MonitorOut)
+ * Special
+ * - special type of Route (e.g. Auditioner)
+ * VCA
+ * - no data flows through; control only
+ *
+ * Objects with a numeric order of zero are considered unsorted. This
+ * applies (for now) to special objects such as the master out,
+ * auditioner and monitor out. The rationale here is that the GUI
+ * presents these objects in special ways, rather than as part of some
+ * (potentially) re-orderable container. The same is true for hardware
+ * surfaces, where the master fader (for instance) is typically
+ * separate and distinct from anything else.
+ *
+ * There are several pathways for the order being set:
+ *
+ * - object created during session loading from XML
+ * - numeric order will be set during ::set_state(), based on
+ * - type will be set during ctor call
+ *
+ * - object created in response to user request
+ * - numeric order will be set by Session, before adding
+ * to container.
+ * - type set during ctor call
+ *
+ *
+ * OBJECT IDENTITY
+ *
+ * Control surfaces/protocols often need to be able to get a handle on
+ * an object identified only abstractly, such as the "5th audio track"
+ * or "the master out". A PresentationInfo object uniquely identifies
+ * all objects in this way through the combination of its _order member
+ * and part of its _flags member. The _flags member identifies the type
+ * of object, as well as selection/hidden status. The type may never
+ * change after construction (not strictly the constructor itself, but
+ * a more generalized notion of construction, as in "ready to use").
+ *
+ * SELECTION
+ *
+ * When an object is selected, its _flags member will have the Selected
+ * bit set.
+ *
+ * VISIBILITY
+ *
+ * When an object is hidden, its _flags member will have the Hidden
+ * bit set.
+ *
+ *
+ */
+
+
+ enum Flag {
+ /* Type information */
+ AudioTrack = 0x1,
+ MidiTrack = 0x2,
+ AudioBus = 0x4,
+ MidiBus = 0x8,
+ VCA = 0x10,
+
+ /* These need to be at the high end */
+ MasterOut = 0x800,
+ MonitorOut = 0x1000,
+ Auditioner = 0x2000,
+
+ /* These are for sharing Stripable states between the GUI and other
+ * user interfaces/control surfaces
+ */
+ Selected = 0x4000,
+ Hidden = 0x8000,
+
+ /* single bit indicates that the group order is set */
+ GroupOrderSet = 0x100000000,
+
+ /* Masks */
+
+ GroupMask = (AudioTrack|MidiTrack|AudioBus|MidiBus|VCA),
+ SpecialMask = (MasterOut|MonitorOut|Auditioner),
+ StatusMask = (Selected|Hidden),
+ };
+
+ static const Flag Route;
+ static const Flag Track;
+ static const Flag Bus;
+
+ typedef uint32_t order_t;
+ typedef uint64_t global_order_t;
+
+ PresentationInfo (Flag f) : _order (0), _flags (Flag (f & ~GroupOrderSet)) { /* GroupOrderSet is not set */ }
+ PresentationInfo (order_t o, Flag f) : _order (o), _flags (Flag (f | GroupOrderSet)) { /* GroupOrderSet is set */ }
+
+ static const order_t max_order;
+
+ order_t group_order() const { return _order; }
+ global_order_t global_order () const {
+ if (_flags & Route) {
+
+ /* set all bits related to Route so that all Routes
+ sort together, with order() in the range of
+ 64424509440..68719476735
+
+ Consider the following arrangement:
+
+ Track 1
+ Bus 1
+ Track 2
+ ---------
+ VCA 1
+ ---------
+ Master
+ ---------
+ Monitor
+
+ these translate into the following
+
+ _order | _flags | order()
+ --------------------------------------
+ 1 | 0x1 AudioTrack | ((0x1|0x2|0x4|0x8)<<32)|1 = 64424509441
+ 2 | 0x2 AudioBus | ((0x1|0x2|0x4|0x8)<<32)|2 = 64424509442
+ 3 | 0x1 AudioTrack | ((0x1|0x2|0x4|0x8)<<32)|3 = 64424509443
+
+ 1 | 0x10 VCA | ((0x10)<<32)|1 = 68719476737
+
+ 0 | 0x800 Master | (0x800<<32) = 8796093022208
+
+ 0 | 0x1000 Monitor | (0x1000<<32) = 17592186044416
+
+ */
+
+ return (((global_order_t) (_flags | Route)) << sizeof(order_t)) | _order;
+ } else {
+ return (((global_order_t) _flags) << sizeof(order_t)) | _order;
+ }
+ }
+
+ PresentationInfo::Flag flags() const { return _flags; }
+
+ bool order_set() const { return _order != 0; }
+
+ /* these objects have no defined order */
+ bool special () const { return _flags & SpecialMask; }
+
+ /* detect group order set/not set */
+ bool unordered() const { return !(_flags & GroupOrderSet); }
+ bool ordered() const { return _flags & GroupOrderSet; }
+
+ void set_flag (PresentationInfo::Flag f) {
+ _flags = PresentationInfo::Flag (_flags | f);
+ }
+
+ void unset_flag (PresentationInfo::Flag f) {
+ _flags = PresentationInfo::Flag (_flags & ~f);
+ }
+
+ void set_flags (Flag f) {
+ _flags = f;
+ }
+
+ bool flag_match (Flag f) const {
+ /* no flags, match all */
+
+ if (f == Flag (0)) {
+ return true;
+ }
+
+ if (f & StatusMask) {
+ /* status bits set, must match them */
+ if ((_flags & StatusMask) != (f & StatusMask)) {
+ return false;
+ }
+ }
+
+ /* Generic flags in f, match the right stuff */
+
+ if (f == Bus && (_flags & Bus)) {
+ /* some kind of bus */
+ return true;
+ }
+ if (f == Track && (_flags & Track)) {
+ /* some kind of track */
+ return true;
+ }
+ if (f == Route && (_flags & Route)) {
+ /* any kind of route */
+ return true;
+ }
+
+ return f == _flags;
+ }
+
+ std::string to_string () const;
+
+ uint64_t to_integer () const {
+ return ((uint64_t) _flags << sizeof(order_t)) | _order;
+ }
+
+ bool operator< (PresentationInfo const& other) const {
+ return global_order() < other.global_order();
+ }
+
+ PresentationInfo& operator= (std::string const& str) {
+ parse (str);
+ return *this;
+ }
+
+ bool match (PresentationInfo const& other) const {
+ return (_order == other.group_order()) && flag_match (other.flags());
+ }
+
+ bool operator==(PresentationInfo const& other) {
+ return (_order == other.group_order()) && (_flags == other.flags());
+ }
+
+ bool operator!=(PresentationInfo const& other) {
+ return (_order != other.group_order()) || (_flags != other.flags());
+ }
+
+ static Flag get_flags (XMLNode const& node);
+
+ protected:
+ friend class Stripable;
+ void set_group_order (order_t order) { _order = order; _flags = Flag (_flags|GroupOrderSet); }
+
+ private:
+ order_t _order;
+ Flag _flags;
+
+ PresentationInfo (std::string const & str);
+ int parse (std::string const&);
+ int parse (order_t, Flag f);
+};
+
+}
+
+std::ostream& operator<<(std::ostream& o, ARDOUR::PresentationInfo const& rid);
+
+#endif /* __libardour_presentation_info_h__ */
typedef std::list<boost::shared_ptr<Processor> > ProcessorList;
- enum Flag {
- Auditioner = 0x1,
- MasterOut = 0x2,
- MonitorOut = 0x4
- };
-
- Route (Session&, std::string name, Flag flags = Flag(0), DataType default_type = DataType::AUDIO);
+ Route (Session&, std::string name, PresentationInfo::Flag flags = PresentationInfo::Flag(0), DataType default_type = DataType::AUDIO);
virtual ~Route();
virtual int init ();
bool set_name (const std::string& str);
static void set_name_in_state (XMLNode &, const std::string &, bool rename_playlist = true);
- uint32_t order_key () const;
- bool has_order_key () const;
- void set_order_key (uint32_t);
-
- bool is_auditioner() const { return _flags & Auditioner; }
- bool is_master() const { return _flags & MasterOut; }
- bool is_monitor() const { return _flags & MonitorOut; }
-
MonitorState monitoring_state () const;
virtual MeterState metering_state () const;
void protect_automation ();
- enum {
- /* These numbers are taken from MIDI Machine Control,
- which can only control up to 317 tracks without
- doing sysex segmentation.
- */
- MasterBusRemoteControlID = 318,
- MonitorBusRemoteControlID = 319,
- };
-
- void set_remote_control_id (uint32_t id, bool notify_class_listeners = true);
- uint32_t remote_control_id () const;
- void set_remote_control_id_explicit (uint32_t order_key);
-
- /* for things concerned about *this* route's RID */
-
- PBD::Signal0<void> RemoteControlIDChanged;
-
- /* for things concerned about *any* route's RID changes */
-
- static PBD::Signal0<void> RemoteControlIDChange;
- static PBD::Signal0<void> SyncOrderKeys;
-
bool has_external_redirects() const;
/* can only be executed by a route for which is_monitor() is true
gint _pending_process_reorder; // atomic
gint _pending_signals; // atomic
- Flag _flags;
int _pending_declick;
MeterPoint _meter_point;
MeterPoint _pending_meter_point;
boost::shared_ptr<Processor> the_instrument_unlocked() const;
-private:
+ private:
+ int64_t _track_number;
+
int set_state_2X (const XMLNode&, int);
void set_processor_state_2X (XMLNodeList const &, int);
- uint32_t _order_key;
- bool _has_order_key;
- uint32_t _remote_control_id;
-
- int64_t _track_number;
-
void input_change_handler (IOChange, void *src);
void output_change_handler (IOChange, void *src);
void sidechain_change_handler (IOChange, void *src);
void reset_instrument_info ();
- void set_remote_control_id_internal (uint32_t id, bool notify_class_listeners = true);
void solo_control_changed (bool self, PBD::Controllable::GroupControlDisposition);
};
+++ /dev/null
-/*
- Copyright (C) 2000-2014 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#ifndef __libardour_route_sorters_h__
-#define __libardour_route_sorters_h__
-
-#include "ardour/route.h"
-
-namespace ARDOUR {
-
-struct SignalOrderRouteSorter {
- bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
- if (a->is_master() || a->is_monitor()) {
- /* "a" is a special route (master, monitor, etc), and comes
- * last in the mixer ordering
- */
- return false;
- } else if (b->is_master() || b->is_monitor()) {
- /* everything comes before b */
- return true;
- }
- return a->order_key () < b->order_key ();
- }
-};
-
-} // namespace
-
-#endif /* __libardour_route_sorters_h__ */
#include "ardour/luascripting.h"
#include "ardour/location.h"
#include "ardour/monitor_processor.h"
+#include "ardour/presentation_info.h"
#include "ardour/rc_configuration.h"
#include "ardour/session_configuration.h"
#include "ardour/session_event.h"
#include "ardour/interpolation.h"
#include "ardour/plugin.h"
+#include "ardour/presentation_info.h"
#include "ardour/route.h"
#include "ardour/route_graph.h"
PBD::Signal0<void> DirtyChanged;
- PBD::Signal1<void, bool> RouteAddedOrRemoved;
-
const SessionDirectory& session_directory () const { return *(_session_dir.get()); }
static PBD::Signal1<void,std::string> Dialog;
bool operator() (boost::shared_ptr<Route>, boost::shared_ptr<Route> b);
};
- void set_order_hint (int32_t order_hint) {_order_hint = order_hint;};
- void notify_remote_id_change ();
- void sync_order_keys ();
+ void notify_presentation_info_change ();
template<class T> void foreach_route (T *obj, void (T::*func)(Route&), bool sort = true);
template<class T> void foreach_route (T *obj, void (T::*func)(boost::shared_ptr<Route>), bool sort = true);
template<class T, class A> void foreach_route (T *obj, void (T::*func)(Route&, A), A arg, bool sort = true);
static char session_name_is_legal (const std::string&);
- bool io_name_is_legal (const std::string&);
- boost::shared_ptr<Route> route_by_name (std::string);
- boost::shared_ptr<Route> route_by_id (PBD::ID);
- boost::shared_ptr<Route> route_by_remote_id (uint32_t id);
- boost::shared_ptr<Stripable> stripable_by_remote_id (uint32_t id);
- boost::shared_ptr<Route> route_by_selected_count (uint32_t cnt);
- boost::shared_ptr<Track> track_by_diskstream_id (PBD::ID);
+ bool io_name_is_legal (const std::string&) const;
+ boost::shared_ptr<Route> route_by_name (std::string) const;
+ boost::shared_ptr<Route> route_by_id (PBD::ID) const;
+ boost::shared_ptr<Stripable> get_remote_nth_stripable (uint16_t n, PresentationInfo::Flag) const;
+ boost::shared_ptr<Route> get_remote_nth_route (uint16_t n) const;
+ boost::shared_ptr<Route> route_by_selected_count (uint32_t cnt) const;
+ boost::shared_ptr<Track> track_by_diskstream_id (PBD::ID) const;
void routes_using_input_from (const std::string& str, RouteList& rl);
bool route_name_unique (std::string) const;
std::list<boost::shared_ptr<AudioTrack> > new_audio_track (
int input_channels,
int output_channels,
- TrackMode mode = Normal,
- RouteGroup* route_group = 0,
- uint32_t how_many = 1,
- std::string name_template = ""
- );
-
- RouteList new_audio_route (
- int input_channels, int output_channels, RouteGroup* route_group, uint32_t how_many, std::string name_template = ""
+ RouteGroup* route_group,
+ uint32_t how_many,
+ std::string name_template,
+ PresentationInfo::order_t order,
+ TrackMode mode = Normal
);
std::list<boost::shared_ptr<MidiTrack> > new_midi_track (
const ChanCount& input, const ChanCount& output,
- boost::shared_ptr<PluginInfo> instrument = boost::shared_ptr<PluginInfo>(),
- TrackMode mode = Normal,
- RouteGroup* route_group = 0, uint32_t how_many = 1, std::string name_template = "",
- Plugin::PresetRecord* pset = 0
+ boost::shared_ptr<PluginInfo> instrument,
+ Plugin::PresetRecord* pset = 0,
+ RouteGroup* route_group, uint32_t how_many, std::string name_template,
+ PresentationInfo::order_t,
+ TrackMode mode = Normal
);
- RouteList new_midi_route (RouteGroup* route_group,
- uint32_t how_many,
- std::string name_template = "",
- boost::shared_ptr<PluginInfo> instrument = boost::shared_ptr<PluginInfo>(),
- Plugin::PresetRecord* pset = 0);
+ RouteList new_audio_route (int input_channels, int output_channels, RouteGroup* route_group, uint32_t how_many, std::string name_template, PresentationInfo::Flag, PresentationInfo::order_t);
+ RouteList new_midi_route (RouteGroup* route_group, uint32_t how_many, std::string name_template, boost::shared_ptr<PluginInfo> instrument, Plugin::PresetRecord*, PresentationInfo::Flag, PresentationInfo::order_t);
void remove_routes (boost::shared_ptr<RouteList>);
void remove_route (boost::shared_ptr<Route>);
SerializedRCUManager<RouteList> routes;
- void add_routes (RouteList&, bool input_auto_connect, bool output_auto_connect, bool save);
- void add_routes_inner (RouteList&, bool input_auto_connect, bool output_auto_connect);
+ void add_routes (RouteList&, bool input_auto_connect, bool output_auto_connect, bool save, PresentationInfo::order_t);
+ void add_routes_inner (RouteList&, bool input_auto_connect, bool output_auto_connect, PresentationInfo::order_t);
bool _adding_routes_in_progress;
bool _reconnecting_routes_in_progress;
bool _route_deletion_in_progress;
*/
GraphEdges _current_route_graph;
- uint32_t next_control_id () const;
- int32_t _order_hint;
+ void ensure_presentation_info_gap (PresentationInfo::order_t, uint32_t gap_size);
bool ignore_route_processor_changes;
MidiClockTicker* midi_clock;
std::string _template_state_dir;
VCAManager* _vca_manager;
+
+ boost::shared_ptr<Route> get_midi_nth_route_by_id (PresentationInfo::order_t n) const;
};
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
+#include "pbd/signals.h"
+
+#include "ardour/presentation_info.h"
#include "ardour/session_object.h"
+#include "ardour/libardour_visibility.h"
namespace ARDOUR {
* and behaviour of the object.
*/
-class Stripable : public SessionObject {
+class LIBARDOUR_API Stripable : public SessionObject {
public:
- Stripable (Session& session, const std::string& name)
- : SessionObject (session, name) {}
+ Stripable (Session& session, std::string const & name, PresentationInfo const &);
+ virtual ~Stripable () {}
/* XXX
midi on/off
- selected status
- visible/hidden
*/
- virtual uint32_t remote_control_id () const = 0;
+ bool is_auditioner() const { return _presentation_info.flags() & PresentationInfo::Auditioner; }
+ bool is_master() const { return _presentation_info.flags() & PresentationInfo::MasterOut; }
+ bool is_monitor() const { return _presentation_info.flags() & PresentationInfo::MonitorOut; }
+
+ int set_state (XMLNode const&, int);
+
+ bool is_hidden() const { return _presentation_info.flags() & PresentationInfo::Hidden; }
+ bool is_selected() const { return _presentation_info.flags() & PresentationInfo::Selected; }
+
+ PresentationInfo const & presentation_info () const { return _presentation_info; }
+ PresentationInfo& presentation_info () { return _presentation_info; }
+
+ /* set just the order */
+
+ void set_presentation_group_order (PresentationInfo::order_t, bool notify_class_listeners = true);
+ void set_presentation_group_order_explicit (PresentationInfo::order_t);
+
+ /* for things concerned about *this* route's RID */
+
+ PBD::Signal0<void> PresentationInfoChanged;
+
+ /* for things concerned about *any* route's RID changes */
+
+ static PBD::Signal0<void> PresentationInfoChange;
+
+ /***************************************************************
+ * Pure interface begins here
+ ***************************************************************/
+
virtual boost::shared_ptr<PeakMeter> peak_meter() = 0;
virtual boost::shared_ptr<const PeakMeter> peak_meter() const = 0;
virtual boost::shared_ptr<AutomationControl> master_send_enable_controllable () const = 0;
virtual bool muted_by_others_soloing () const = 0;
+
+ protected:
+ PresentationInfo _presentation_info;
+
+ /* set the entire info. This should only be used in cases where the
+ * derived could not supply the correct Flag and/or order information
+ * in its constructor.
+ */
+
+ void set_presentation_info (PresentationInfo id, bool notify_class_listeners = true);
+ void set_presentation_info_explicit (PresentationInfo);
+
+ void add_state (XMLNode&) const;
+
+ private:
+ void set_presentation_info_internal (PresentationInfo id, bool notify_class_listeners = true);
+};
+
+struct PresentationInfoSorter {
+ bool operator() (boost::shared_ptr<Stripable> a, boost::shared_ptr<Stripable> b) {
+ return a->presentation_info() < b->presentation_info();
+ }
};
class LIBARDOUR_API Track : public Route, public Recordable, public PublicDiskstream
{
public:
- Track (Session&, std::string name, Route::Flag f = Route::Flag (0), TrackMode m = Normal, DataType default_type = DataType::AUDIO);
+ Track (Session&, std::string name, PresentationInfo::Flag f = PresentationInfo::Flag (0), TrackMode m = Normal, DataType default_type = DataType::AUDIO);
virtual ~Track ();
int init ();
using namespace ARDOUR;
using namespace PBD;
-AudioTrack::AudioTrack (Session& sess, string name, Route::Flag flag, TrackMode mode)
- : Track (sess, name, flag, mode)
+AudioTrack::AudioTrack (Session& sess, string name, TrackMode mode)
+ : Track (sess, name, PresentationInfo::AudioTrack, mode)
{
}
#include "i18n.h"
Auditioner::Auditioner (Session& s)
- : Track (s, "auditioner", Route::Auditioner)
+ : Track (s, "auditioner", PresentationInfo::Auditioner)
, current_frame (0)
, _auditioning (0)
, length (0)
#include "ardour/location.h"
#include "ardour/midi_model.h"
#include "ardour/mute_master.h"
+#include "ardour/presentation_info.h"
#include "ardour/session.h"
#include "ardour/source.h"
#include "ardour/tempo.h"
AutoConnectOption _AutoConnectOption;
TracksAutoNamingRule _TracksAutoNamingRule;
Session::StateOfTheState _Session_StateOfTheState;
- Route::Flag _Route_Flag;
Source::Flag _Source_Flag;
Diskstream::Flag _Diskstream_Flag;
Location::Flags _Location_Flags;
Evoral::OverlapType _OverlapType;
BufferingPreset _BufferingPreset;
AutoReturnTarget _AutoReturnTarget;
+ PresentationInfo::Flag _PresentationInfo_Flag;
#define REGISTER(e) enum_writer.register_distinct (typeid(e).name(), i, s); i.clear(); s.clear()
#define REGISTER_BITS(e) enum_writer.register_bits (typeid(e).name(), i, s); i.clear(); s.clear()
REGISTER_CLASS_ENUM (Session, pullup_Minus4Minus1);
REGISTER (_Session_PullupFormat);
- REGISTER_CLASS_ENUM (Route, Auditioner);
- REGISTER_CLASS_ENUM (Route, MasterOut);
- REGISTER_CLASS_ENUM (Route, MonitorOut);
- REGISTER_BITS (_Route_Flag);
-
REGISTER_CLASS_ENUM (Source, Writable);
REGISTER_CLASS_ENUM (Source, CanRename);
REGISTER_CLASS_ENUM (Source, Broadcast);
REGISTER_ENUM (Loop);
REGISTER_ENUM (RegionSelectionStart);
REGISTER_BITS (_AutoReturnTarget);
+
+ REGISTER_CLASS_ENUM (PresentationInfo, AudioTrack);
+ REGISTER_CLASS_ENUM (PresentationInfo, MidiTrack);
+ REGISTER_CLASS_ENUM (PresentationInfo, AudioBus);
+ REGISTER_CLASS_ENUM (PresentationInfo, MidiBus);
+ REGISTER_CLASS_ENUM (PresentationInfo, MasterOut);
+ REGISTER_CLASS_ENUM (PresentationInfo, MonitorOut);
+ REGISTER_CLASS_ENUM (PresentationInfo, VCA);
+ REGISTER_CLASS_ENUM (PresentationInfo, Bus);
+ REGISTER_CLASS_ENUM (PresentationInfo, Track);
+ REGISTER_CLASS_ENUM (PresentationInfo, Route);
+ REGISTER_CLASS_ENUM (PresentationInfo, Selected);
+ REGISTER_CLASS_ENUM (PresentationInfo, Hidden);
+ REGISTER (_PresentationInfo_Flag);
}
} /* namespace ARDOUR */
.addFunction ("record_status", &Session::record_status)
.addFunction ("route_by_id", &Session::route_by_id)
.addFunction ("route_by_name", &Session::route_by_name)
- .addFunction ("route_by_remote_id", &Session::route_by_remote_id)
+ // STRIPABLE .addFunction ("route_by_remote_id", &Session::route_by_remote_id)
.addFunction ("track_by_diskstream_id", &Session::track_by_diskstream_id)
.addFunction ("source_by_id", &Session::source_by_id)
.addFunction ("controllable_by_id", &Session::controllable_by_id)
using namespace ARDOUR;
using namespace PBD;
-MidiTrack::MidiTrack (Session& sess, string name, Route::Flag flag, TrackMode mode)
- : Track (sess, name, flag, mode, DataType::MIDI)
+MidiTrack::MidiTrack (Session& sess, string name, TrackMode mode)
+ : Track (sess, name, PresentationInfo::MidiTrack, mode, DataType::MIDI)
, _immediate_events(1024) // FIXME: size?
, _step_edit_ring_buffer(64) // FIXME: size?
, _note_mode(Sustained)
--- /dev/null
+/*
+ Copyright (C) 2016 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <sstream>
+#include <typeinfo>
+
+#include <cassert>
+
+#include "pbd/enumwriter.h"
+#include "pbd/error.h"
+#include "pbd/failed_constructor.h"
+#include "pbd/xml++.h"
+
+#include "ardour/presentation_info.h"
+
+#include "i18n.h"
+
+using namespace ARDOUR;
+using namespace PBD;
+using std::string;
+
+const PresentationInfo::order_t PresentationInfo::max_order = UINT32_MAX;
+const PresentationInfo::Flag PresentationInfo::Bus = PresentationInfo::Flag (PresentationInfo::AudioBus|PresentationInfo::MidiBus);
+const PresentationInfo::Flag PresentationInfo::Track = PresentationInfo::Flag (PresentationInfo::AudioTrack|PresentationInfo::MidiTrack);
+const PresentationInfo::Flag PresentationInfo::Route = PresentationInfo::Flag (PresentationInfo::Bus|PresentationInfo::Track);
+
+PresentationInfo::PresentationInfo (std::string const & str)
+{
+ if (parse (str)) {
+ throw failed_constructor ();
+ }
+}
+
+int
+PresentationInfo::parse (string const& str)
+{
+ std::stringstream s (str);
+
+ /* new school, segmented string "NNN:TYPE" */
+ string f;
+ char c;
+ s >> _order;
+ /* skip colon */
+ s >> c;
+ /* grab flags */
+ s >> f;
+ _flags = Flag (string_2_enum (f, _flags)|GroupOrderSet);
+ std::cerr << "Parsed [" << str << "] as " << _order << " + " << enum_2_string (_flags) << std::endl;
+ return 0;
+}
+
+int
+PresentationInfo::parse (uint32_t n, Flag f)
+{
+ if (n < UINT16_MAX) {
+ assert (f != Flag (0));
+ _order = n;
+ _flags = Flag (f|GroupOrderSet);
+ } else {
+ _order = (n & 0xffff);
+ _flags = Flag ((n >> 16)|GroupOrderSet);
+ }
+
+ return 0;
+}
+
+std::string
+PresentationInfo::to_string() const
+{
+ std::stringstream ss;
+
+ /* Do not save or selected hidden status, or group-order set bit */
+
+ Flag f = Flag (_flags & ~(Hidden|Selected|GroupOrderSet));
+
+ ss << _order << ':' << enum_2_string (f);
+
+ return ss.str();
+}
+
+PresentationInfo::Flag
+PresentationInfo::get_flags (XMLNode const& node)
+{
+ const XMLProperty *prop;
+ XMLNodeList nlist = node.children ();
+ XMLNodeConstIterator niter;
+ XMLNode *child;
+
+ for (niter = nlist.begin(); niter != nlist.end(); ++niter){
+ child = *niter;
+
+ if (child->name() == X_("PresentationInfo")) {
+ if ((prop = child->property (X_("value"))) != 0) {
+ PresentationInfo pi (prop->value());
+ return pi.flags ();
+ }
+ }
+ }
+ return Flag (0);
+}
+
+std::ostream&
+operator<<(std::ostream& o, ARDOUR::PresentationInfo const& rid)
+{
+ return o << rid.to_string ();
+}
using namespace ARDOUR;
using namespace PBD;
-PBD::Signal0<void> Route::SyncOrderKeys;
-PBD::Signal0<void> Route::RemoteControlIDChange;
PBD::Signal3<int,boost::shared_ptr<Route>, boost::shared_ptr<PluginInsert>, Route::PluginSetupOptions > Route::PluginSetup;
/** Base class for all routable/mixable objects (tracks and busses) */
-Route::Route (Session& sess, string name, Flag flg, DataType default_type)
+Route::Route (Session& sess, string name, PresentationInfo::Flag flag, DataType default_type)
: GraphNode (sess._process_graph)
- , Stripable (sess, name)
+ , Stripable (sess, name, PresentationInfo (flag))
, Muteable (sess, name)
, Automatable (sess)
, _active (true)
, _roll_delay (0)
, _pending_process_reorder (0)
, _pending_signals (0)
- , _flags (flg)
, _pending_declick (true)
, _meter_point (MeterPostFader)
, _pending_meter_point (MeterPostFader)
, _declickable (false)
, _have_internal_generator (false)
, _default_type (default_type)
- , _order_key (0)
- , _has_order_key (false)
- , _remote_control_id (0)
- , _track_number (0)
, _in_configure_processors (false)
, _initial_io_setup (false)
, _in_sidechain_setup (false)
/* panning */
- if (!(_flags & Route::MonitorOut)) {
+ if (!(_presentation_info.flags() & PresentationInfo::MonitorOut)) {
_pannable.reset (new Pannable (_session));
}
_processors.clear ();
}
-void
-Route::set_remote_control_id (uint32_t id, bool notify_class_listeners)
-{
- if (Config->get_remote_model() != UserOrdered) {
- return;
- }
-
- set_remote_control_id_internal (id, notify_class_listeners);
-}
-
-void
-Route::set_remote_control_id_internal (uint32_t id, bool notify_class_listeners)
-{
- /* force IDs for master/monitor busses and prevent
- any other route from accidentally getting these IDs
- (i.e. legacy sessions)
- */
-
- if (is_master() && id != MasterBusRemoteControlID) {
- id = MasterBusRemoteControlID;
- }
-
- if (is_monitor() && id != MonitorBusRemoteControlID) {
- id = MonitorBusRemoteControlID;
- }
-
- if (id < 1) {
- return;
- }
-
- /* don't allow it to collide */
-
- if (!is_master () && !is_monitor() &&
- (id == MasterBusRemoteControlID || id == MonitorBusRemoteControlID)) {
- id += MonitorBusRemoteControlID;
- }
-
- if (id != remote_control_id()) {
- _remote_control_id = id;
- RemoteControlIDChanged ();
-
- if (notify_class_listeners) {
- RemoteControlIDChange ();
- }
- }
-}
-
-uint32_t
-Route::remote_control_id() const
-{
- if (is_master()) {
- return MasterBusRemoteControlID;
- }
-
- if (is_monitor()) {
- return MonitorBusRemoteControlID;
- }
-
- return _remote_control_id;
-}
-
-bool
-Route::has_order_key () const
-{
- return _has_order_key;
-}
-
-uint32_t
-Route::order_key () const
-{
- return _order_key;
-}
-
-void
-Route::set_remote_control_id_explicit (uint32_t rid)
-{
- if (is_master() || is_monitor() || is_auditioner()) {
- /* hard-coded remote IDs, or no remote ID */
- return;
- }
-
- if (_remote_control_id != rid) {
- DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("%1: set edit-based RID to %2\n", name(), rid));
- _remote_control_id = rid;
- RemoteControlIDChanged (); /* EMIT SIGNAL (per-route) */
- }
-
- /* don't emit the class-level RID signal RemoteControlIDChange here,
- leave that to the entity that changed the order key, so that we
- don't get lots of emissions for no good reasons (e.g. when changing
- all route order keys).
-
- See Session::sync_remote_id_from_order_keys() for the (primary|only)
- spot where that is emitted.
- */
-}
-
-void
-Route::set_order_key (uint32_t n)
-{
- _has_order_key = true;
-
- if (_order_key == n) {
- return;
- }
-
- _order_key = n;
-
- DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("%1 order key set to %2\n",
- name(), order_key ()));
-
- _session.set_dirty ();
-}
-
string
Route::ensure_track_or_route_name(string name, Session &session)
{
node->add_property("default-type", _default_type.to_string());
node->add_property ("strict-io", _strict_io);
- if (_flags) {
- node->add_property("flags", enum_2_string (_flags));
- }
+ Stripable::add_state (*node);
node->add_property("active", _active?"yes":"no");
string p;
node->add_property("route-group", _route_group->name());
}
- snprintf (buf, sizeof (buf), "%d", _order_key);
- node->add_property ("order-key", buf);
-
node->add_child_nocopy (_solo_control->get_state ());
node->add_child_nocopy (_solo_isolate_control->get_state ());
node->add_child_nocopy (_solo_safe_control->get_state ());
node->add_child_nocopy (Automatable::get_automation_xml_state ());
}
- XMLNode* remote_control_node = new XMLNode (X_("RemoteControl"));
- snprintf (buf, sizeof (buf), "%d", _remote_control_id);
- remote_control_node->add_property (X_("id"), buf);
- node->add_child_nocopy (*remote_control_node);
-
if (_comment.length()) {
XMLNode *cmt = node->add_child ("Comment");
cmt->add_content (_comment);
set_id (node);
_initial_io_setup = true;
- if ((prop = node.property (X_("flags"))) != 0) {
- _flags = Flag (string_2_enum (prop->value(), _flags));
- } else {
- _flags = Flag (0);
- }
+ Stripable::set_state (node, version);
if ((prop = node.property (X_("strict-io"))) != 0) {
_strict_io = string_is_affirmative (prop->value());
set_active (yn, this);
}
- if ((prop = node.property (X_("order-key"))) != 0) { // New order key (no separate mixer/editor ordering)
- set_order_key (atoi(prop->value()));
- }
-
- if ((prop = node.property (X_("order-keys"))) != 0) { // Deprecated order keys
-
- int32_t n;
-
- string::size_type colon, equal;
- string remaining = prop->value();
-
- while (remaining.length()) {
-
- if ((equal = remaining.find_first_of ('=')) == string::npos || equal == remaining.length()) {
- error << string_compose (_("badly formed order key string in state file! [%1] ... ignored."), remaining)
- << endmsg;
- } else {
- if (sscanf (remaining.substr (equal+1).c_str(), "%d", &n) != 1) {
- error << string_compose (_("badly formed order key string in state file! [%1] ... ignored."), remaining)
- << endmsg;
- } else {
- string keyname = remaining.substr (0, equal);
-
- if ((keyname == "EditorSort") || (keyname == "editor")) {
- cerr << "Setting " << name() << " order key to " << n << " using saved Editor order." << endl;
- set_order_key (n);
- }
- }
- }
-
- colon = remaining.find_first_of (':');
-
- if (colon != string::npos) {
- remaining = remaining.substr (colon+1);
- } else {
- break;
- }
- }
- }
-
if ((prop = node.property (X_("processor-after-last-custom-meter"))) != 0) {
PBD::ID id (prop->value ());
Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
_mute_control->set_state (*child, version);
}
- } else if (child->name() == X_("RemoteControl")) {
- if ((prop = child->property (X_("id"))) != 0) {
- int32_t x;
- sscanf (prop->value().c_str(), "%d", &x);
- set_remote_control_id_internal (x);
- }
-
} else if (child->name() == MuteMaster::xml_node_name) {
_mute_master->set_state (*child, version);
return -1;
}
- if ((prop = node.property (X_("flags"))) != 0) {
- string f = prop->value ();
- boost::replace_all (f, "ControlOut", "MonitorOut");
- _flags = Flag (string_2_enum (f, _flags));
- } else {
- _flags = Flag (0);
- }
+ Stripable::set_state (node, version);
if (is_master() || is_monitor() || is_auditioner()) {
_mute_master->set_solo_ignore (true);
_meter_point = MeterPoint (string_2_enum (prop->value (), _meter_point));
}
- /* do not carry over edit/mix groups from 2.X because (a) its hard (b) they
- don't mean the same thing.
- */
-
- if ((prop = node.property (X_("order-keys"))) != 0) {
-
- int32_t n;
-
- string::size_type colon, equal;
- string remaining = prop->value();
-
- while (remaining.length()) {
-
- if ((equal = remaining.find_first_of ('=')) == string::npos || equal == remaining.length()) {
- error << string_compose (_("badly formed order key string in state file! [%1] ... ignored."), remaining)
- << endmsg;
- } else {
- if (sscanf (remaining.substr (equal+1).c_str(), "%d", &n) != 1) {
- error << string_compose (_("badly formed order key string in state file! [%1] ... ignored."), remaining)
- << endmsg;
- } else {
- string keyname = remaining.substr (0, equal);
-
- if (keyname == "EditorSort" || keyname == "editor") {
- info << string_compose(_("Converting deprecated order key for %1 using Editor order %2"), name (), n) << endmsg;
- set_order_key (n);
- }
- }
- }
-
- colon = remaining.find_first_of (':');
-
- if (colon != string::npos) {
- remaining = remaining.substr (colon+1);
- } else {
- break;
- }
- }
- }
-
/* IOs */
nlist = node.children ();
_mute_control->set_state (*child, version);
}
- } else if (child->name() == X_("RemoteControl")) {
- if ((prop = child->property (X_("id"))) != 0) {
- int32_t x;
- sscanf (prop->value().c_str(), "%d", &x);
- set_remote_control_id_internal (x);
- }
-
}
}
{
boost::shared_ptr<Track> t1 (boost::dynamic_pointer_cast<Track>(r1));
boost::shared_ptr<Track> t2 (boost::dynamic_pointer_cast<Track>(r2));
+ PresentationInfo::global_order_t r1o = r1->presentation_info().global_order();
+ PresentationInfo::global_order_t r2o = r2->presentation_info().global_order();
if (!t1) {
if (!t2) {
- /* makes no difference which is first, use signal order */
- return r1->order_key () < r2->order_key ();
+ /* makes no difference which is first, use presentation order */
+ return r1o < r2o;
} else {
/* r1 is not a track, r2 is, run it early */
return false;
}
if (!t2) {
- /* we already tested !t1, so just use signal order */
- return r1->order_key () < r2->order_key ();
+ /* we already tested !t1, so just use presentation order */
+ return r1o < r2o;
}
if (t1->rec_enable_control()->get_value()) {
if (t2->rec_enable_control()->get_value()) {
/* both rec-enabled, just use signal order */
- return t1->order_key () < t2->order_key ();
+ return r1o < r2o;
} else {
/* t1 rec-enabled, t2 not rec-enabled, run t2 early */
return false;
/* t2 rec-enabled, t1 not rec-enabled, run t1 early */
return true;
} else {
- /* neither rec-enabled, use signal order */
- return t1->order_key () < t2->order_key ();
+ /* neither rec-enabled, use presentation order */
+ return r1o < r2o;
}
}
}
* (since tracks can't have fewer outs than ins,
* "nin" currently defines the number of outpus if nin > 2)
*/
- rl = _session.new_audio_route (nin, 2 /*XXX*/, 0, 1);
+ rl = _session.new_audio_route (nin, 2, 0, 1, string(), PresentationInfo::AudioBus, PresentationInfo::max_order);
} catch (...) {
return;
}
#include "ardour/region_factory.h"
#include "ardour/route_graph.h"
#include "ardour/route_group.h"
-#include "ardour/route_sorters.h"
#include "ardour/send.h"
#include "ardour/session.h"
#include "ardour/session_directory.h"
, _step_editors (0)
, _suspend_timecode_transmission (0)
, _speakers (new Speakers)
- , _order_hint (-1)
, ignore_route_processor_changes (false)
, midi_clock (0)
, _scene_changer (0)
return;
}
- boost::shared_ptr<Route> r (new Route (*this, _("Monitor"), Route::MonitorOut, DataType::AUDIO));
+ boost::shared_ptr<Route> r (new Route (*this, _("Monitor"), PresentationInfo::MonitorOut, DataType::AUDIO));
if (r->init ()) {
return;
}
rl.push_back (r);
- add_routes (rl, false, false, false);
+ add_routes (rl, false, false, false, 0);
assert (_monitor_out);
#ifndef NDEBUG
DEBUG_TRACE (DEBUG::Graph, "Routes resorted, order follows:\n");
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
- DEBUG_TRACE (DEBUG::Graph, string_compose ("\t%1 signal order %2\n",
- (*i)->name(), (*i)->order_key ()));
+ DEBUG_TRACE (DEBUG::Graph, string_compose ("\t%1 presentation order %2\n", (*i)->name(), (*i)->presentation_info().global_order()));
}
#endif
* @param instrument plugin info for the instrument to insert pre-fader, if any
*/
list<boost::shared_ptr<MidiTrack> >
-Session::new_midi_track (const ChanCount& input, const ChanCount& output, boost::shared_ptr<PluginInfo> instrument,
- TrackMode mode, RouteGroup* route_group, uint32_t how_many, string name_template, Plugin::PresetRecord* pset)
+Session::new_midi_track (boost::shared_ptr<PluginInfo> instrument, Plugin::PresetRecord* pset,
+ RouteGroup* route_group, uint32_t how_many, string name_template, PresentationInfo::order_t order,
+ TrackMode mode)
{
string track_name;
uint32_t track_id = 0;
boost::shared_ptr<MidiTrack> track;
try {
- track.reset (new MidiTrack (*this, track_name, Route::Flag (0), mode));
+ track.reset (new MidiTrack (*this, track_name, mode));
if (track->init ()) {
goto failed;
track->DiskstreamChanged.connect_same_thread (*this, boost::bind (&Session::resort_routes, this));
- if (Config->get_remote_model() == UserOrdered) {
- track->set_remote_control_id (next_control_id());
- }
-
new_routes.push_back (track);
ret.push_back (track);
-
- RouteAddedOrRemoved (true); /* EMIT SIGNAL */
}
catch (failed_constructor &err) {
if (!new_routes.empty()) {
StateProtector sp (this);
if (Profile->get_trx()) {
- add_routes (new_routes, false, false, false);
+ add_routes (new_routes, false, false, false, order);
} else {
- add_routes (new_routes, true, true, false);
+ add_routes (new_routes, true, true, false, order);
}
if (instrument) {
}
RouteList
-Session::new_midi_route (RouteGroup* route_group, uint32_t how_many, string name_template, boost::shared_ptr<PluginInfo> instrument, Plugin::PresetRecord* pset)
+Session::new_midi_route (RouteGroup* route_group, uint32_t how_many, string name_template, boost::shared_ptr<PluginInfo> instrument, Plugin::PresetRecord* pset,
+ PresentationInfo::Flag flag, PresentationInfo::order_t order)
{
string bus_name;
uint32_t bus_id = 0;
error << "cannot find name for new midi bus" << endmsg;
goto failure;
}
-
+
try {
- boost::shared_ptr<Route> bus (new Route (*this, bus_name, Route::Flag(0), DataType::AUDIO)); // XXX Editor::add_routes is not ready for ARDOUR::DataType::MIDI
+ boost::shared_ptr<Route> bus (new Route (*this, bus_name, flag, DataType::AUDIO)); // XXX Editor::add_routes is not ready for ARDOUR::DataType::MIDI
if (bus->init ()) {
goto failure;
if (route_group) {
route_group->add (bus);
}
- if (Config->get_remote_model() == UserOrdered) {
- bus->set_remote_control_id (next_control_id());
- }
ret.push_back (bus);
- RouteAddedOrRemoved (true); /* EMIT SIGNAL */
- ARDOUR::GUIIdle ();
}
catch (failed_constructor &err) {
failure:
if (!ret.empty()) {
StateProtector sp (this);
- add_routes (ret, false, false, false);
+ add_routes (ret, false, false, false, order);
if (instrument) {
for (RouteList::iterator r = ret.begin(); r != ret.end(); ++r) {
#endif
+void
+Session::ensure_presentation_info_gap (PresentationInfo::order_t first_new_order, uint32_t how_many)
+{
+ if (first_new_order == PresentationInfo::max_order) {
+ /* adding at end, no worries */
+ return;
+ }
+
+ /* create a gap in the existing route order keys to accomodate new routes.*/
+ boost::shared_ptr <RouteList> rd = routes.reader();
+ for (RouteList::iterator ri = rd->begin(); ri != rd->end(); ++ri) {
+ boost::shared_ptr<Route> rt (*ri);
+
+ if (rt->presentation_info().special()) {
+ continue;
+ }
+
+ if (rt->presentation_info().group_order () >= first_new_order) {
+ rt->set_presentation_group_order (rt->presentation_info().group_order () + how_many);
+ }
+ }
+}
+
/** Caller must not hold process lock
* @param name_template string to use for the start of the name, or "" to use "Audio".
*/
list< boost::shared_ptr<AudioTrack> >
-Session::new_audio_track (int input_channels, int output_channels, TrackMode mode, RouteGroup* route_group,
- uint32_t how_many, string name_template)
+Session::new_audio_track (int input_channels, int output_channels, RouteGroup* route_group,
+ uint32_t how_many, string name_template, PresentationInfo::order_t order,
+ TrackMode mode)
{
string track_name;
uint32_t track_id = 0;
boost::shared_ptr<AudioTrack> track;
try {
- track.reset (new AudioTrack (*this, track_name, Route::Flag (0), mode));
+ track.reset (new AudioTrack (*this, track_name, mode));
if (track->init ()) {
goto failed;
track->set_strict_io (true);
}
-
if (ARDOUR::Profile->get_trx ()) {
// TRACKS considers it's not a USE CASE, it's
// a piece of behavior of the session model:
track->non_realtime_input_change();
track->DiskstreamChanged.connect_same_thread (*this, boost::bind (&Session::resort_routes, this));
- if (Config->get_remote_model() == UserOrdered) {
- track->set_remote_control_id (next_control_id());
- }
new_routes.push_back (track);
ret.push_back (track);
-
- RouteAddedOrRemoved (true); /* EMIT SIGNAL */
}
catch (failed_constructor &err) {
if (!new_routes.empty()) {
StateProtector sp (this);
if (Profile->get_trx()) {
- add_routes (new_routes, false, false, false);
+ add_routes (new_routes, false, false, false, order);
} else {
- add_routes (new_routes, true, true, false);
+ add_routes (new_routes, true, true, false, order);
}
}
* @param name_template string to use for the start of the name, or "" to use "Bus".
*/
RouteList
-Session::new_audio_route (int input_channels, int output_channels, RouteGroup* route_group, uint32_t how_many, string name_template)
+Session::new_audio_route (int input_channels, int output_channels, RouteGroup* route_group, uint32_t how_many, string name_template,
+ PresentationInfo::Flag flags, PresentationInfo::order_t order)
{
string bus_name;
uint32_t bus_id = 0;
bool const use_number = (how_many != 1) || name_template.empty () || name_template == _("Bus");
+ ensure_presentation_info_gap (order, how_many);
+
while (how_many) {
if (!find_route_name (name_template.empty () ? _("Bus") : name_template, ++bus_id, bus_name, use_number)) {
error << "cannot find name for new audio bus" << endmsg;
}
try {
- boost::shared_ptr<Route> bus (new Route (*this, bus_name, Route::Flag(0), DataType::AUDIO));
+ boost::shared_ptr<Route> bus (new Route (*this, bus_name, flags, DataType::AUDIO));
if (bus->init ()) {
goto failure;
if (route_group) {
route_group->add (bus);
}
- if (Config->get_remote_model() == UserOrdered) {
- bus->set_remote_control_id (next_control_id());
- }
bus->add_internal_return ();
-
ret.push_back (bus);
-
- RouteAddedOrRemoved (true); /* EMIT SIGNAL */
-
- ARDOUR::GUIIdle ();
}
-
catch (failed_constructor &err) {
error << _("Session: could not create new audio route.") << endmsg;
goto failure;
if (!ret.empty()) {
StateProtector sp (this);
if (Profile->get_trx()) {
- add_routes (ret, false, false, false);
+ add_routes (ret, false, false, false, order);
} else {
- add_routes (ret, false, true, true); // autoconnect // outputs only
+ add_routes (ret, false, true, true, order); // autoconnect // outputs only
}
}
Session::new_route_from_template (uint32_t how_many, XMLNode& node, const std::string& name_base, PlaylistDisposition pd)
{
RouteList ret;
- uint32_t control_id;
uint32_t number = 0;
const uint32_t being_added = how_many;
/* This will prevent the use of any existing XML-provided PBD::ID
Stateful::ForceIDRegeneration force_ids;
IO::disable_connecting ();
- control_id = next_control_id ();
-
while (how_many) {
/* We're going to modify the node contents a bit so take a
route->output()->changed (change, this);
}
- route->set_remote_control_id (control_id);
- ++control_id;
-
boost::shared_ptr<Track> track;
if ((track = boost::dynamic_pointer_cast<Track> (route))) {
};
ret.push_back (route);
-
- RouteAddedOrRemoved (true); /* EMIT SIGNAL */
}
catch (failed_constructor &err) {
if (!ret.empty()) {
StateProtector sp (this);
if (Profile->get_trx()) {
- add_routes (ret, false, false, false);
+ add_routes (ret, false, false, false, PresentationInfo::max_order);
} else {
- add_routes (ret, true, true, false);
+ add_routes (ret, true, true, false, PresentationInfo::max_order);
}
IO::enable_connecting ();
}
}
void
-Session::add_routes (RouteList& new_routes, bool input_auto_connect, bool output_auto_connect, bool save)
+Session::add_routes (RouteList& new_routes, bool input_auto_connect, bool output_auto_connect, bool save, PresentationInfo::order_t order)
{
try {
PBD::Unwinder<bool> aip (_adding_routes_in_progress, true);
- add_routes_inner (new_routes, input_auto_connect, output_auto_connect);
+ add_routes_inner (new_routes, input_auto_connect, output_auto_connect, order);
} catch (...) {
error << _("Adding new tracks/busses failed") << endmsg;
save_state (_current_snapshot_name);
}
- reassign_track_numbers();
-
update_route_record_state ();
RouteAdded (new_routes); /* EMIT SIGNAL */
}
void
-Session::add_routes_inner (RouteList& new_routes, bool input_auto_connect, bool output_auto_connect)
+Session::add_routes_inner (RouteList& new_routes, bool input_auto_connect, bool output_auto_connect, PresentationInfo::order_t order)
{
ChanCount existing_inputs;
ChanCount existing_outputs;
- uint32_t order = next_control_id();
-
-
- if (_order_hint > -1) {
- order = _order_hint;
- _order_hint = -1;
- }
+ uint32_t n_routes;
+ uint32_t added = 0;
count_existing_track_channels (existing_inputs, existing_outputs);
RCUWriter<RouteList> writer (routes);
boost::shared_ptr<RouteList> r = writer.get_copy ();
r->insert (r->end(), new_routes.begin(), new_routes.end());
+ n_routes = r->size();
/* if there is no control out and we're not in the middle of loading,
* resort the graph here. if there is a control out, we will resort
}
}
- for (RouteList::iterator x = new_routes.begin(); x != new_routes.end(); ++x) {
+ DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("ensure order gap starting at %1 for %2\n", order, new_routes.size()));
+ ensure_presentation_info_gap (order, new_routes.size());
+
+ for (RouteList::iterator x = new_routes.begin(); x != new_routes.end(); ++x, ++added) {
boost::weak_ptr<Route> wpr (*x);
boost::shared_ptr<Route> r (*x);
}
}
- if (input_auto_connect || output_auto_connect) {
- auto_connect_route (r, input_auto_connect, ChanCount (), ChanCount (), existing_inputs, existing_outputs);
- existing_inputs += r->n_inputs();
- existing_outputs += r->n_outputs();
- }
+ if (!r->presentation_info().special()) {
- /* order keys are a GUI responsibility but we need to set up
- reasonable defaults because they also affect the remote control
- ID in most situations.
- */
+ DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("checking PI state for %1\n", r->name()));
+
+ /* presentation info order may already have been set from XML */
+
+ if (r->presentation_info().unordered()) {
- if (!r->has_order_key ()) {
- if (r->is_auditioner()) {
- /* use an arbitrarily high value */
- r->set_order_key (UINT_MAX);
+ if (order == PresentationInfo::max_order) {
+ /* just add to the end */
+ r->set_presentation_group_order_explicit (n_routes + added);
+ DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("group order not set, set to NR %1 + %2 = %3\n", n_routes, added, n_routes + added));
+ } else {
+ r->set_presentation_group_order_explicit (order + added);
+ DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("group order not set, set to %1 + %2 = %3\n", order, added, order + added));
+ }
} else {
- DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("while adding, set %1 to order key %2\n", r->name(), order));
- r->set_order_key (order);
- order++;
+ DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("group order already set to %1\n", r->presentation_info().group_order()));
}
}
+ DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("added route %1, group order %2 global order %3 type %4 (summary: %5)\n",
+ r->name(),
+ r->presentation_info().group_order(),
+ r->presentation_info().global_order(),
+ enum_2_string (r->presentation_info().flags()),
+ r->presentation_info().to_string()));
+
+
+ if (input_auto_connect || output_auto_connect) {
+ auto_connect_route (r, input_auto_connect, ChanCount (), ChanCount (), existing_inputs, existing_outputs);
+ existing_inputs += r->n_inputs();
+ existing_outputs += r->n_outputs();
+ }
+
ARDOUR::GUIIdle ();
}
} // end of RCU Writer scope
update_route_solo_state ();
- RouteAddedOrRemoved (false); /* EMIT SIGNAL */
update_latency_compensation ();
set_dirty();
return;
}
- Route::RemoteControlIDChange(); /* EMIT SIGNAL */
+ Stripable::PresentationInfoChange(); /* EMIT SIGNAL */
/* save the new state of the world */
save_history (_current_snapshot_name);
}
- reassign_track_numbers();
update_route_record_state ();
}
}
bool
-Session::io_name_is_legal (const std::string& name)
+Session::io_name_is_legal (const std::string& name) const
{
boost::shared_ptr<RouteList> r = routes.reader ();
}
boost::shared_ptr<Route>
-Session::route_by_name (string name)
+Session::route_by_name (string name) const
{
boost::shared_ptr<RouteList> r = routes.reader ();
}
boost::shared_ptr<Route>
-Session::route_by_id (PBD::ID id)
+Session::route_by_id (PBD::ID id) const
{
boost::shared_ptr<RouteList> r = routes.reader ();
}
boost::shared_ptr<Track>
-Session::track_by_diskstream_id (PBD::ID id)
+Session::track_by_diskstream_id (PBD::ID id) const
{
boost::shared_ptr<RouteList> r = routes.reader ();
}
boost::shared_ptr<Route>
-Session::route_by_remote_id (uint32_t id)
+Session::get_remote_nth_route (uint16_t n) const
{
- boost::shared_ptr<RouteList> r = routes.reader ();
-
- for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
- if ((*i)->remote_control_id() == id) {
- return *i;
- }
- }
-
- return boost::shared_ptr<Route> ((Route*) 0);
+ return boost::dynamic_pointer_cast<Route> (get_remote_nth_stripable (n, PresentationInfo::Route));
}
-
boost::shared_ptr<Stripable>
-Session::stripable_by_remote_id (uint32_t id)
+Session::get_remote_nth_stripable (uint16_t n, PresentationInfo::Flag flags) const
{
boost::shared_ptr<RouteList> r = routes.reader ();
+ vector<boost::shared_ptr<Route> > v;
+
+ if (n > r->size()) {
+ return boost::shared_ptr<Route> ();
+ }
+
+ v.assign (r->size(), boost::shared_ptr<Route>());
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
- if ((*i)->remote_control_id() == id) {
- return *i;
+ if ((*i)->presentation_info().flag_match (flags)) {
+ v[(*i)->presentation_info().group_order()] = (*i);
}
}
- return boost::shared_ptr<Route> ((Route*) 0);
+ return v[n];
}
-
boost::shared_ptr<Route>
-Session::route_by_selected_count (uint32_t id)
+Session::route_by_selected_count (uint32_t id) const
{
boost::shared_ptr<RouteList> r = routes.reader ();
return boost::shared_ptr<Route> ((Route*) 0);
}
+struct PresentationOrderSorter {
+ bool operator() (boost::shared_ptr<Stripable> a, boost::shared_ptr<Stripable> b) {
+ if (a->presentation_info().special() && !b->presentation_info().special()) {
+ /* a is not ordered, b is; b comes before a */
+ return false;
+ } else if (b->presentation_info().unordered() && !a->presentation_info().unordered()) {
+ /* b is not ordered, a is; a comes before b */
+ return true;
+ } else {
+ return a->presentation_info().global_order() < b->presentation_info().global_order();
+ }
+ }
+};
void
Session::reassign_track_numbers ()
int64_t tn = 0;
int64_t bn = 0;
RouteList r (*(routes.reader ()));
- SignalOrderRouteSorter sorter;
+ PresentationOrderSorter sorter;
r.sort (sorter);
StateProtector sp (this);
if (b->is_monitor()) {
return false;
}
- return a->order_key () < b->order_key ();
+ return a->presentation_info() < b->presentation_info();
}
bool
return 0;
}
-uint32_t
-Session::next_control_id () const
-{
- int subtract = 0;
-
- /* the monitor bus remote ID is in a different
- * "namespace" than regular routes. its existence doesn't
- * affect normal (low) numbered routes.
- */
-
- if (_monitor_out) {
- subtract++;
- }
-
- /* the same about masterbus in Waves Tracks */
-
- if (Profile->get_trx() && _master_out) {
- subtract++;
- }
-
- return nroutes() - subtract;
-}
-
void
-Session::notify_remote_id_change ()
+Session::notify_presentation_info_change ()
{
if (deletion_in_progress()) {
return;
switch (Config->get_remote_model()) {
case MixerOrdered:
- Route::RemoteControlIDChange (); /* EMIT SIGNAL */
+ Stripable::PresentationInfoChange (); /* EMIT SIGNAL */
break;
default:
break;
}
-#ifdef USE_TRACKS_CODE_FEATURES
- /* Waves Tracks: for Waves Tracks session it's required to reconnect their IOs
- * if track order has been changed by user
- */
- reconnect_existing_routes(true, true);
-#endif
-
-}
-
-void
-Session::sync_order_keys ()
-{
- if (deletion_in_progress()) {
- return;
- }
-
- /* tell everyone that something has happened to the sort keys
- and let them sync up with the change(s)
- this will give objects that manage the sort order keys the
- opportunity to keep them in sync if they wish to.
- */
-
- DEBUG_TRACE (DEBUG::OrderKeys, "Sync Order Keys.\n");
-
reassign_track_numbers();
- Route::SyncOrderKeys (); /* EMIT SIGNAL */
+#ifdef USE_TRACKS_CODE_FEATURES
+ /* Waves Tracks: for Waves Tracks session it's required to reconnect their IOs
+ * if track order has been changed by user
+ */
+ reconnect_existing_routes(true, true);
+#endif
- DEBUG_TRACE (DEBUG::OrderKeys, "\tsync done\n");
}
bool
}
}
+boost::shared_ptr<Route>
+Session::get_midi_nth_route_by_id (PresentationInfo::order_t n) const
+{
+ PresentationInfo id (PresentationInfo::Flag (0));
+
+ if (n == 318) {
+ id.set_flags (PresentationInfo::MasterOut);
+ } else if (n == 319) {
+ id.set_flags (PresentationInfo::MonitorOut);
+ } else {
+ id = PresentationInfo (n, PresentationInfo::Route);
+ }
+
+ boost::shared_ptr<RouteList> r = routes.reader ();
+
+ for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+ if ((*i)->presentation_info().match (id)) {
+ return *i;
+ }
+ }
+
+ return boost::shared_ptr<Route>();
+}
+
void
Session::mmc_record_enable (MIDI::MachineControl &mmc, size_t trk, bool enabled)
{
return;
}
- RouteList::iterator i;
- boost::shared_ptr<RouteList> r = routes.reader();
+ boost::shared_ptr<Route> r = get_midi_nth_route_by_id (trk);
- for (i = r->begin(); i != r->end(); ++i) {
- AudioTrack *at;
+ if (r) {
+ boost::shared_ptr<AudioTrack> at;
- if ((at = dynamic_cast<AudioTrack*>((*i).get())) != 0) {
- if (trk == at->remote_control_id()) {
- at->rec_enable_control()->set_value (enabled, Controllable::UseGroup);
- break;
- }
+ if ((at = boost::dynamic_pointer_cast<AudioTrack> (r))) {
+ at->rec_enable_control()->set_value (enabled, Controllable::UseGroup);
}
}
}
{
return _midi_ports->mtc_input_port ();
}
-
_state_of_the_state = Clean;
- /* set up Master Out and Control Out if necessary */
+ /* set up Master Out and Monitor Out if necessary */
if (bus_profile) {
// Waves Tracks: always create master bus for Tracks
if (ARDOUR::Profile->get_trx() || bus_profile->master_out_channels) {
- boost::shared_ptr<Route> r (new Route (*this, _("Master"), Route::MasterOut, DataType::AUDIO));
+ boost::shared_ptr<Route> r (new Route (*this, _("Master"), PresentationInfo::MasterOut, DataType::AUDIO));
if (r->init ()) {
return -1;
}
}
if (!rl.empty()) {
- add_routes (rl, false, false, false);
+ add_routes (rl, false, false, false, PresentationInfo::max_order);
}
// Waves Tracks: Skip this. Always use autoconnection for Tracks
BootMessage (_("Tracks/busses loaded; Adding to Session"));
- add_routes (new_routes, false, false, false);
+ add_routes (new_routes, false, false, false, PresentationInfo::max_order);
BootMessage (_("Finished adding tracks/busses"));
ret = track;
} else {
- enum Route::Flag flags = Route::Flag(0);
- XMLProperty const * prop = node.property("flags");
- if (prop) {
- flags = Route::Flag (string_2_enum (prop->value(), flags));
- }
-
+ PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
if (r->init () == 0 && r->set_state (node, version) == 0) {
ret = track;
} else {
- enum Route::Flag flags = Route::Flag(0);
- XMLProperty const * prop = node.property("flags");
- if (prop) {
- flags = Route::Flag (string_2_enum (prop->value(), flags));
- }
-
+ PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
if (r->init () == 0 && r->set_state (node, version) == 0) {
}
case ControllableDescriptor::RemoteControlID:
- r = route_by_remote_id (desc.rid());
+ r = get_remote_nth_route (desc.rid());
break;
case ControllableDescriptor::SelectionCount:
--- /dev/null
+/*
+ Copyright (C) 2016 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <boost/algorithm/string.hpp>
+
+#include "pbd/compose.h"
+#include "pbd/convert.h"
+
+#include "ardour/debug.h"
+#include "ardour/rc_configuration.h"
+#include "ardour/stripable.h"
+
+#include "i18n.h"
+
+using namespace ARDOUR;
+using namespace PBD;
+using std::string;
+
+PBD::Signal0<void> Stripable::PresentationInfoChange;
+
+Stripable::Stripable (Session& s, string const & name, PresentationInfo const & pi)
+ : SessionObject (s, name)
+ , _presentation_info (pi)
+{
+}
+
+void
+Stripable::set_presentation_group_order (PresentationInfo::order_t order, bool notify_class_listeners)
+{
+ set_presentation_info_internal (PresentationInfo (order, _presentation_info.flags()), notify_class_listeners);
+}
+
+void
+Stripable::set_presentation_group_order_explicit (PresentationInfo::order_t order)
+{
+ set_presentation_group_order (order, false);
+}
+
+void
+Stripable::set_presentation_info (PresentationInfo pi, bool notify_class_listeners)
+{
+ if (Config->get_remote_model() != UserOrdered) {
+ return;
+ }
+
+ set_presentation_info_internal (pi, notify_class_listeners);
+}
+
+void
+Stripable::set_presentation_info_internal (PresentationInfo pi, bool notify_class_listeners)
+{
+ if (pi != presentation_info()) {
+
+ DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("%1: set edit-based RID to %2\n", name(), pi));
+
+ if (is_master()) {
+ _presentation_info = PresentationInfo (0, PresentationInfo::MasterOut);
+ } else if (is_monitor()) {
+ _presentation_info = PresentationInfo (0, PresentationInfo::MonitorOut);
+ } else {
+ _presentation_info = pi;
+ }
+
+ PresentationInfoChanged ();
+
+ if (notify_class_listeners) {
+ PresentationInfoChange ();
+ }
+ }
+}
+
+void
+Stripable::set_presentation_info_explicit (PresentationInfo pi)
+{
+ set_presentation_info_internal (pi, false);
+}
+
+int
+Stripable::set_state (XMLNode const& node, int version)
+{
+ const XMLProperty *prop;
+ XMLNodeList const & nlist (node.children());
+ XMLNodeConstIterator niter;
+ XMLNode *child;
+
+ if (version > 3000) {
+
+ std::cerr << "Looking for PI\n";
+
+ for (niter = nlist.begin(); niter != nlist.end(); ++niter){
+ child = *niter;
+
+ if (child->name() == X_("PresentationInfo")) {
+ std::cerr << "Found it\n";
+ if ((prop = child->property (X_("value"))) != 0) {
+ _presentation_info = prop->value ();
+ std::cerr << "Set pinfo to " << _presentation_info << " from " << prop->value() << std::endl;
+ }
+ }
+ }
+
+ } else {
+ std::cerr << "Old\n";
+
+ /* Older versions of Ardour stored "_flags" as a property of the Route
+ * node, only for 3 special Routes (MasterOut, MonitorOut, Auditioner.
+ *
+ * Their presentation order was stored in a node called "RemoteControl"
+ *
+ * This information is now part of the PresentationInfo of every Stripable.
+ */
+
+ if ((prop = node.property (X_("flags"))) != 0) {
+
+ /* 4.x and earlier - didn't have Stripable but the
+ * relevant enums have the same names (MasterOut,
+ * MonitorOut, Auditioner), so we can use string_2_enum
+ */
+
+ PresentationInfo::Flag flags;
+
+ if (version < 3000) {
+ string f (prop->value());
+ boost::replace_all (f, "ControlOut", "MonitorOut");
+ flags = PresentationInfo::Flag (string_2_enum (f, flags));
+ } else {
+ flags = PresentationInfo::Flag (string_2_enum (prop->value(), flags));
+ }
+
+ _presentation_info.set_flags (flags);
+
+ }
+ }
+
+ return 0;
+}
+
+void
+Stripable::add_state (XMLNode& node) const
+{
+ XMLNode* remote_control_node = new XMLNode (X_("PresentationInfo"));
+ remote_control_node->add_property (X_("value"), _presentation_info.to_string());
+ node.add_child_nocopy (*remote_control_node);
+}
using namespace ARDOUR;
using namespace PBD;
-Track::Track (Session& sess, string name, Route::Flag flag, TrackMode mode, DataType default_type)
+Track::Track (Session& sess, string name, PresentationInfo::Flag flag, TrackMode mode, DataType default_type)
: Route (sess, name, flag, default_type)
, _saved_meter_point (_meter_point)
, _mode (mode)
_monitoring_control.reset (new MonitorControl (_session, X_("monitoring"), *this));
add_control (_monitoring_control);
- track_number_changed.connect_same_thread (*this, boost::bind (&Track::resync_track_name, this));
_session.config.ParameterChanged.connect_same_thread (*this, boost::bind (&Track::parameter_changed, this, _1));
_monitoring_control->Changed.connect_same_thread (*this, boost::bind (&Track::monitoring_changed, this, _1, _2));
}
VCA::VCA (Session& s, uint32_t num, const string& name)
- : Stripable (s, name)
+ : Stripable (s, name, PresentationInfo (num, PresentationInfo::VCA))
, Muteable (s, name)
, Automatable (s)
, _number (num)
node->add_property (X_("name"), _name);
node->add_property (X_("number"), _number);
+ Stripable::add_state (*node);
+
node->add_child_nocopy (_gain_control->get_state());
node->add_child_nocopy (_solo_control->get_state());
node->add_child_nocopy (_mute_control->get_state());
{
XMLProperty const* prop;
+ Stripable::set_state (node, version);
+
if ((prop = node.property ("name")) != 0) {
set_name (prop->value());
}
'port_insert.cc',
'port_manager.cc',
'port_set.cc',
+ 'presentation_info.cc',
'process_thread.cc',
'processor.cc',
'progress.cc',
'source_factory.cc',
'speakers.cc',
'srcfilesource.cc',
+ 'stripable.cc',
'strip_silence.cc',
'system_exec.cc',
'revision.cc',
PBD::Signal0<void> ControlProtocol::VerticalZoomInSelected;
PBD::Signal0<void> ControlProtocol::VerticalZoomOutSelected;
PBD::Signal1<void,RouteNotificationListPtr> ControlProtocol::TrackSelectionChanged;
-PBD::Signal1<void,uint32_t> ControlProtocol::AddRouteToSelection;
-PBD::Signal1<void,uint32_t> ControlProtocol::SetRouteSelection;
-PBD::Signal1<void,uint32_t> ControlProtocol::ToggleRouteSelection;
-PBD::Signal1<void,uint32_t> ControlProtocol::RemoveRouteFromSelection;
+PBD::Signal1<void,uint64_t> ControlProtocol::AddRouteToSelection;
+PBD::Signal1<void,uint64_t> ControlProtocol::SetRouteSelection;
+PBD::Signal1<void,uint64_t> ControlProtocol::ToggleRouteSelection;
+PBD::Signal1<void,uint64_t> ControlProtocol::RemoveRouteFromSelection;
PBD::Signal0<void> ControlProtocol::ClearRouteSelection;
PBD::Signal0<void> ControlProtocol::StepTracksDown;
PBD::Signal0<void> ControlProtocol::StepTracksUp;
void
ControlProtocol::next_track (uint32_t initial_id)
{
- uint32_t limit = session->nroutes();
- boost::shared_ptr<Route> cr = route_table[0];
- uint32_t id;
-
- if (cr) {
- id = cr->remote_control_id ();
- } else {
- id = 0;
- }
-
- if (id == limit) {
- id = 0;
- } else {
- id++;
- }
-
- while (id <= limit) {
- if ((cr = session->route_by_remote_id (id)) != 0) {
- break;
- }
- id++;
- }
-
- if (id >= limit) {
- id = 0;
- while (id != initial_id) {
- if ((cr = session->route_by_remote_id (id)) != 0) {
- break;
- }
- id++;
- }
- }
-
- route_table[0] = cr;
+ // STRIPABLE route_table[0] = _session->get_nth_stripable (++initial_id, RemoteControlID::Route);
}
void
ControlProtocol::prev_track (uint32_t initial_id)
{
- uint32_t limit = session->nroutes();
- boost::shared_ptr<Route> cr = route_table[0];
- int32_t id;
-
- if (cr) {
- id = cr->remote_control_id ();
- } else {
- id = 0;
- }
-
- if (id == 0) {
- id = limit;
- } else {
- id--;
- }
-
- while (id >= 0) {
- if ((cr = session->route_by_remote_id (id)) != 0) {
- break;
- }
- id--;
- }
-
- if (id < 0) {
- uint32_t i = limit;
- while (i > initial_id) {
- if ((cr = session->route_by_remote_id (i)) != 0) {
- break;
- }
- i--;
- }
+ if (!initial_id) {
+ return;
}
-
- route_table[0] = cr;
+ // STRIPABLE route_table[0] = _session->get_nth_stripable (--initial_id, RemoteControlID::Route);
}
-
void
ControlProtocol::set_route_table_size (uint32_t size)
{
bool
ControlProtocol::set_route_table (uint32_t table_index, uint32_t remote_control_id)
{
+#if 0 // STRIPABLE
boost::shared_ptr<Route> r = session->route_by_remote_id (remote_control_id);
if (!r) {
}
set_route_table (table_index, r);
-
+#endif
return true;
}
static PBD::Signal0<void> StepTracksDown;
static PBD::Signal0<void> StepTracksUp;
- static PBD::Signal1<void,uint32_t> AddRouteToSelection;
- static PBD::Signal1<void,uint32_t> SetRouteSelection;
- static PBD::Signal1<void,uint32_t> ToggleRouteSelection;
- static PBD::Signal1<void,uint32_t> RemoveRouteFromSelection;
+ static PBD::Signal1<void,uint64_t> AddRouteToSelection;
+ static PBD::Signal1<void,uint64_t> SetRouteSelection;
+ static PBD::Signal1<void,uint64_t> ToggleRouteSelection;
+ static PBD::Signal1<void,uint64_t> RemoveRouteFromSelection;
static PBD::Signal0<void> ClearRouteSelection;
/* signals that one UI (e.g. the GUI) can emit to get all other UI's to
/* this one is cross-thread */
- Route::RemoteControlIDChange.connect (*this, MISSING_INVALIDATOR, boost::bind (&GenericMidiControlProtocol::reset_controllables, this), midi_ui_context());
+ Stripable::PresentationInfoChange.connect (*this, MISSING_INVALIDATOR, boost::bind (&GenericMidiControlProtocol::reset_controllables, this), midi_ui_context());
/* Catch port connections and disconnections (cross-thread) */
ARDOUR::AudioEngine::instance()->PortConnectedOrDisconnected.connect (port_connection, MISSING_INVALIDATOR,
}
// predicate for sort call in get_sorted_routes
-struct RouteByRemoteId
+struct RouteByPresentationOrder
{
bool operator () (const boost::shared_ptr<Route> & a, const boost::shared_ptr<Route> & b) const
{
- return a->remote_control_id() < b->remote_control_id();
+ return a->presentation_info() < b->presentation_info();
}
bool operator () (const Route & a, const Route & b) const
{
- return a.remote_control_id() < b.remote_control_id();
+ return a.presentation_info() < b.presentation_info();
}
bool operator () (const Route * a, const Route * b) const
{
- return a->remote_control_id() < b->remote_control_id();
+ return a->presentation_info() < b->presentation_info();
}
};
// fetch all routes
boost::shared_ptr<RouteList> routes = session->get_routes();
- set<uint32_t> remote_ids;
+ set<PresentationInfo> remote_ids;
- // routes with remote_id 0 should never be added
- // TODO verify this with ardour devs
- // remote_ids.insert (0);
-
- // sort in remote_id order, and exclude master, control and hidden routes
+ // sort in presentation order, and exclude master, control and hidden routes
// and any routes that are already set.
for (RouteList::iterator it = routes->begin(); it != routes->end(); ++it) {
boost::shared_ptr<Route> route = *it;
- if (remote_ids.find (route->remote_control_id()) != remote_ids.end()) {
- continue;
- }
-
if (route->is_auditioner() || route->is_master() || route->is_monitor()) {
continue;
}
/* don't include locked routes */
- if (route_is_locked_to_strip(route)) {
+ if (route_is_locked_to_strip (route)) {
continue;
}
case Mixer:
if (! is_hidden(route)) {
sorted.push_back (route);
- remote_ids.insert (route->remote_control_id());
+ remote_ids.insert (route->presentation_info());
}
break;
case AudioTracks:
if (is_audio_track(route) && !is_hidden(route)) {
sorted.push_back (route);
- remote_ids.insert (route->remote_control_id());
+ remote_ids.insert (route->presentation_info());
}
break;
case Busses:
#ifdef MIXBUS
if (route->mixbus()) {
sorted.push_back (route);
- remote_ids.insert (route->remote_control_id());
+ remote_ids.insert (route->presentation_info());
}
#endif
} else {
if (!is_track(route) && !is_hidden(route)) {
sorted.push_back (route);
- remote_ids.insert (route->remote_control_id());
+ remote_ids.insert (route->presentation_info());
}
}
break;
case MidiTracks:
if (is_midi_track(route) && !is_hidden(route)) {
sorted.push_back (route);
- remote_ids.insert (route->remote_control_id());
+ remote_ids.insert (route->presentation_info());
}
break;
case Plugins:
#endif
{
sorted.push_back (route);
- remote_ids.insert (route->remote_control_id());
+ remote_ids.insert (route->presentation_info());
}
break;
case Hidden: // Show all the tracks we have hidden
if (is_hidden(route)) {
// maybe separate groups
sorted.push_back (route);
- remote_ids.insert (route->remote_control_id());
+ remote_ids.insert (route->presentation_info());
}
break;
case Selected: // For example: a group (this is USER)
if (selected(route) && !is_hidden(route)) {
sorted.push_back (route);
- remote_ids.insert (route->remote_control_id());
+ remote_ids.insert (route->presentation_info());
}
break;
}
}
- sort (sorted.begin(), sorted.end(), RouteByRemoteId());
+ sort (sorted.begin(), sorted.end(), RouteByPresentationOrder());
return sorted;
}
{
// receive routes added
session->RouteAdded.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&MackieControlProtocol::notify_route_added, this, _1), this);
- session->RouteAddedOrRemoved.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&MackieControlProtocol::notify_route_added_or_removed, this), this);
// receive record state toggled
session->RecordStateChanged.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&MackieControlProtocol::notify_record_state_changed, this), this);
// receive transport state changed
Sorted sorted = get_sorted_routes();
for (Sorted::iterator it = sorted.begin(); it != sorted.end(); ++it) {
- (*it)->RemoteControlIDChanged.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&MackieControlProtocol::notify_remote_id_changed, this), this);
+ (*it)->PresentationInfoChanged.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&MackieControlProtocol::notify_presentation_info_changed, this), this);
}
}
}
void
-MackieControlProtocol::notify_route_added_or_removed ()
+MackieControlProtocol::notify_route_removed ()
{
Glib::Threads::Mutex::Lock lm (surfaces_lock);
for (Surfaces::iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
typedef ARDOUR::RouteList ARS;
for (ARS::iterator it = rl.begin(); it != rl.end(); ++it) {
- (*it)->RemoteControlIDChanged.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&MackieControlProtocol::notify_remote_id_changed, this), this);
+ (*it)->PresentationInfoChanged.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&MackieControlProtocol::notify_presentation_info_changed, this), this);
}
}
}
void
-MackieControlProtocol::notify_remote_id_changed()
+MackieControlProtocol::notify_presentation_info_changed()
{
{
Glib::Threads::Mutex::Lock lm (surfaces_lock);
for (RouteList::iterator r = routes.begin(); r != routes.end(); ++r) {
if (main_modifier_state() == MODIFIER_SHIFT) {
- ToggleRouteSelection ((*r)->remote_control_id ());
+ /* XXX can only use numeric part of ID at present */
+ ToggleRouteSelection ((*r)->presentation_info ().global_order());
} else {
if (r == routes.begin()) {
- SetRouteSelection ((*r)->remote_control_id());
+ /* XXX can only use numeric part of ID at present */
+ SetRouteSelection ((*r)->presentation_info().global_order());
} else {
- AddRouteToSelection ((*r)->remote_control_id());
+ /* XXX can only use numeric part of ID at present */
+ AddRouteToSelection ((*r)->presentation_info().global_order());
}
}
}
if (!r) {
return false;
}
- return (((r->remote_control_id()) >>31) != 0);
+ return (r->presentation_info().flags() & PresentationInfo::Hidden);
}
bool
void handle_button_event (Mackie::Surface&, Mackie::Button& button, Mackie::ButtonState);
void notify_subview_route_deleted ();
- void notify_route_added_or_removed ();
+ void notify_route_removed ();
void notify_route_added (ARDOUR::RouteList &);
- void notify_remote_id_changed();
+ void notify_presentation_info_changed();
void recalibrate_faders ();
void toggle_backlight ();
void
Strip::notify_route_deleted ()
{
+ _surface->mcp().notify_route_removed ();
_surface->mcp().refresh_current_bank();
}
lo_message_add_string (reply, "bad syntax");
} else {
id = argv[0]->i;
- r = session->route_by_remote_id (id);
+ r = session->get_remote_nth_route (id);
if (!r) {
lo_message_add_string (reply, "not found");
} else {
for (int n = 0; n < argc; ++n) {
- boost::shared_ptr<Route> r = session->route_by_remote_id (argv[n]->i);
+ boost::shared_ptr<Route> r = session->get_remote_nth_route (argv[n]->i);
if (!r) {
lo_message_add_string (reply, "not found");
for (int n = 0; n < argc; ++n) {
- boost::shared_ptr<Route> r = session->route_by_remote_id (argv[n]->i);
+ boost::shared_ptr<Route> r = session->get_remote_nth_route (argv[n]->i);
if (r) {
end_listen (r, lo_message_get_source (msg));
}
for (int n = 0; n < (int) session->nroutes(); ++n) {
- boost::shared_ptr<Route> r = session->route_by_remote_id (n);
+ boost::shared_ptr<Route> r = session->get_remote_nth_route (n);
if (r) {
lo_message_add_int32 (reply, r->n_outputs().n_audio());
lo_message_add_int32 (reply, r->muted());
lo_message_add_int32 (reply, r->soloed());
- lo_message_add_int32 (reply, r->remote_control_id());
+ /* XXX Can only use group ID at this point */
+ lo_message_add_int32 (reply, r->presentation_info().group_order());
if (boost::dynamic_pointer_cast<AudioTrack>(r)
|| boost::dynamic_pointer_cast<MidiTrack>(r)) {
{
if (!session) return -1;
- boost::shared_ptr<Route> r = session->route_by_remote_id (rid);
+ boost::shared_ptr<Route> r = session->get_remote_nth_route (rid);
if (r) {
r->mute_control()->set_value (yn ? 1.0 : 0.0, PBD::Controllable::NoGroup);
{
if (!session) return -1;
- boost::shared_ptr<Route> r = session->route_by_remote_id (rid);
+ boost::shared_ptr<Route> r = session->get_remote_nth_route (rid);
if (r) {
r->solo_control()->set_value (yn ? 1.0 : 0.0, PBD::Controllable::NoGroup);
{
if (!session) return -1;
- boost::shared_ptr<Route> r = session->route_by_remote_id (rid);
+ boost::shared_ptr<Route> r = session->get_remote_nth_route (rid);
if (r) {
boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (r);
{
if (!session) return -1;
- boost::shared_ptr<Route> r = session->route_by_remote_id (rid);
+ boost::shared_ptr<Route> r = session->get_remote_nth_route (rid);
if (r) {
r->gain_control()->set_value (level, PBD::Controllable::NoGroup);
{
if (!session) return -1;
- boost::shared_ptr<Route> r = session->route_by_remote_id (rid);
+ boost::shared_ptr<Route> r = session->get_remote_nth_route (rid);
if (r) {
r->set_trim (level, PBD::Controllable::NoGroup);
{
if (!session) return -1;
- boost::shared_ptr<Route> r = session->route_by_remote_id (rid);
+ boost::shared_ptr<Route> r = session->get_remote_nth_route (rid);
if (r) {
boost::shared_ptr<Panner> panner = r->panner();
{
if (!session) return -1;
- boost::shared_ptr<Route> r = session->route_by_remote_id (rid);
+ boost::shared_ptr<Route> r = session->get_remote_nth_route (rid);
if (r) {
boost::shared_ptr<Panner> panner = r->panner();
return -1;
}
- boost::shared_ptr<Route> r = session->route_by_remote_id (rid);
+ boost::shared_ptr<Route> r = session->get_remote_nth_route (rid);
if (!r) {
return -1;
return -1;
}
- boost::shared_ptr<Route> r = session->route_by_remote_id (rid);
+ boost::shared_ptr<Route> r = session->get_remote_nth_route (rid);
if (!r) {
return -1;
if (!session)
return -1;
- boost::shared_ptr<Route> r = session->route_by_remote_id (rid);
+ boost::shared_ptr<Route> r = session->get_remote_nth_route (rid);
if (!r) {
PBD::error << "OSC: Invalid Remote Control ID '" << rid << "'" << endmsg;
return -1;
}
- boost::shared_ptr<Route> r = session->route_by_remote_id (rid);
+ boost::shared_ptr<Route> r = session->get_remote_nth_route (rid);
if (!r) {
return -1;
{
lo_message msg = lo_message_new ();
- lo_message_add_int32 (msg, _route->remote_control_id());
+ /* Can only send ID part of RID at present */
+
+ lo_message_add_int32 (msg, _route->presentation_info().group_order());
lo_message_add_float (msg, (float) controllable->get_value());
/* XXX thread issues */
lo_message msg = lo_message_new ();
- lo_message_add_int32 (msg, _route->remote_control_id());
+ /* XXX can only use group part of ID at present */
+ lo_message_add_int32 (msg, _route->presentation_info().group_order());
lo_message_add_string (msg, _route->name().c_str());
lo_send_message (addr, "/route/name", msg);
{
lo_message msg = lo_message_new ();
- lo_message_add_int32 (msg, _route->remote_control_id());
+ /* XXX can only use group part of ID at present */
+ lo_message_add_int32 (msg, _route->presentation_info().group_order());
lo_message_add_float (msg, (float) controllable->get_value());
/* XXX thread issues */