#include "ardour/plugin.h"
#include "ardour/plugin_insert.h"
#include "ardour/process_thread.h"
+#include "ardour/profile.h"
#include "ardour/rc_configuration.h"
#include "ardour/recent_sessions.h"
#include "ardour/region.h"
, _all_route_group (new RouteGroup (*this, "all"))
, routes (new RouteList)
, _adding_routes_in_progress (false)
+ , _route_deletion_in_progress (false)
, destructive_index (0)
, _track_number_decimals(1)
, solo_update_disabled (false)
, first_file_header_format_reset (true)
, have_looped (false)
, _have_rec_enabled_track (false)
+ , _have_rec_disabled_track (true)
, _step_editors (0)
, _suspend_timecode_transmission (0)
, _speakers (new Speakers)
* of a template.
*/
- if (!mix_template.empty() && load_state (_current_snapshot_name)) {
- throw failed_constructor ();
+ if (!mix_template.empty()) {
+ if (load_state (_current_snapshot_name)) {
+ throw failed_constructor ();
+ }
+ store_recent_templates (mix_template);
}
/* load default session properties - if any */
framepos_t dcp;
framecnt_t dcl;
auto_loop_declick_range (location, dcp, dcl);
- replace_event (SessionEvent::AutoLoopDeclick, dcp, dcl);
if (transport_rolling() && play_loop) {
+ replace_event (SessionEvent::AutoLoopDeclick, dcp, dcl);
// if (_transport_frame > location->end()) {
}
}
+ } else {
+ clear_events (SessionEvent::AutoLoopDeclick);
+ clear_events (SessionEvent::AutoLoop);
}
last_loopend = location->end();
_session_range_location = location;
}
+ if (location->is_mark()) {
+ /* listen for per-location signals that require us to do any * global updates for marks */
+
+ location->StartChanged.connect_same_thread (skip_update_connections, boost::bind (&Session::update_marks, this, location));
+ location->EndChanged.connect_same_thread (skip_update_connections, boost::bind (&Session::update_marks, this, location));
+ location->Changed.connect_same_thread (skip_update_connections, boost::bind (&Session::update_marks, this, location));
+ location->FlagsChanged.connect_same_thread (skip_update_connections, boost::bind (&Session::update_marks, this, location));
+ }
+
if (location->is_skip()) {
/* listen for per-location signals that require us to update skip-locate events */
update_skips (location, true);
}
-
+
set_dirty ();
}
failed:
if (!new_routes.empty()) {
StateProtector sp (this);
- add_routes (new_routes, true, true, true);
+ if (Profile->get_trx()) {
+ add_routes (new_routes, false, false, false);
+ } else {
+ add_routes (new_routes, true, true, false);
+ }
if (instrument) {
for (RouteList::iterator r = new_routes.begin(); r != new_routes.end(); ++r) {
*/
}
+#ifdef USE_TRACKS_CODE_FEATURES
+
+void
+Session::reconnect_midi_scene_ports(bool inputs)
+{
+ if (inputs) {
+ scene_in()->disconnect_all ();
+
+ std::vector<EngineStateController::MidiPortState> midi_port_states;
+ EngineStateController::instance()->get_physical_midi_input_states (midi_port_states);
+
+ std::vector<EngineStateController::MidiPortState>::iterator state_iter = midi_port_states.begin();
+
+ for (; state_iter != midi_port_states.end(); ++state_iter) {
+ if (state_iter->active && state_iter->available && state_iter->connected) {
+ scene_in()->connect (state_iter->name);
+ }
+ }
+
+ } else {
+ scene_out()->disconnect_all ();
+
+ std::vector<EngineStateController::MidiPortState> midi_port_states;
+ EngineStateController::instance()->get_physical_midi_output_states (midi_port_states);
+
+ std::vector<EngineStateController::MidiPortState>::iterator state_iter = midi_port_states.begin();
+
+ for (; state_iter != midi_port_states.end(); ++state_iter) {
+ if (state_iter->active && state_iter->available && state_iter->connected) {
+ scene_out()->connect (state_iter->name);
+ }
+ }
+
+ }
+}
+
+#endif
/** Caller must not hold process lock
* @param name_template string to use for the start of the name, or "" to use "Audio".
RouteList new_routes;
list<boost::shared_ptr<AudioTrack> > ret;
- bool const use_number = (how_many != 1) || name_template.empty () || name_template == _("Audio");
+ string name_pattern;
+ if (Profile->get_trx() ) {
+ name_pattern = "Track ";
+ } else {
+ name_pattern = "Audio ";
+ }
+
+ bool const use_number = (how_many != 1) || name_template.empty () || name_template == _(name_pattern.c_str() );
+
while (how_many) {
- if (!find_route_name (name_template.empty() ? _("Audio") : name_template, ++track_id, track_name, sizeof(track_name), use_number)) {
+
+ if (!find_route_name (name_template.empty() ? _(name_pattern.c_str()) : name_template, ++track_id, track_name, sizeof(track_name), use_number)) {
error << "cannot find name for new audio track" << endmsg;
goto failed;
}
failed:
if (!new_routes.empty()) {
StateProtector sp (this);
- add_routes (new_routes, true, true, true);
+ if (Profile->get_trx()) {
+ add_routes (new_routes, false, false, false);
+ } else {
+ add_routes (new_routes, true, true, false);
+ }
}
return ret;
failure:
if (!ret.empty()) {
StateProtector sp (this);
- add_routes (ret, false, true, true); // autoconnect outputs only
+ if (Profile->get_trx()) {
+ add_routes (ret, false, false, false);
+ } else {
+ add_routes (ret, false, true, true); // autoconnect // outputs only
+ }
}
return ret;
out:
if (!ret.empty()) {
StateProtector sp (this);
- add_routes (ret, true, true, true);
+ if (Profile->get_trx()) {
+ add_routes (ret, false, false, false);
+ } else {
+ add_routes (ret, true, true, false);
+ }
IO::enable_connecting ();
}
reassign_track_numbers();
+ update_route_record_state ();
+
RouteAdded (new_routes); /* EMIT SIGNAL */
}
if (tr) {
tr->PlaylistChanged.connect_same_thread (*this, boost::bind (&Session::track_playlist_changed, this, boost::weak_ptr<Track> (tr)));
track_playlist_changed (boost::weak_ptr<Track> (tr));
- tr->RecordEnableChanged.connect_same_thread (*this, boost::bind (&Session::update_have_rec_enabled_track, this));
+ tr->RecordEnableChanged.connect_same_thread (*this, boost::bind (&Session::update_route_record_state, this));
boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (tr);
if (mt) {
graph_reordered ();
}
+
void
-Session::remove_route (boost::shared_ptr<Route> route)
+Session::remove_routes (boost::shared_ptr<RouteList> routes_to_remove)
{
- if (route == _master_out) {
- return;
- }
-
- route->set_solo (false, this);
-
- {
+ { // RCU Writer scope
RCUWriter<RouteList> writer (routes);
boost::shared_ptr<RouteList> rs = writer.get_copy ();
-
- rs->remove (route);
-
- /* deleting the master out seems like a dumb
- idea, but its more of a UI policy issue
- than our concern.
- */
-
- if (route == _master_out) {
- _master_out = boost::shared_ptr<Route> ();
- }
-
- if (route == _monitor_out) {
- _monitor_out.reset ();
- }
-
- /* writer goes out of scope, forces route list update */
- }
-
- update_route_solo_state ();
-
- // We need to disconnect the route's inputs and outputs
-
- route->input()->disconnect (0);
- route->output()->disconnect (0);
-
- /* if the route had internal sends sending to it, remove them */
- if (route->internal_return()) {
-
- boost::shared_ptr<RouteList> r = routes.reader ();
- for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
- boost::shared_ptr<Send> s = (*i)->internal_send_for (route);
- if (s) {
- (*i)->remove_processor (s);
+
+
+ for (RouteList::iterator iter = routes_to_remove->begin(); iter != routes_to_remove->end(); ++iter) {
+
+ if (*iter == _master_out) {
+ continue;
+ }
+
+ (*iter)->set_solo (false, this);
+
+ rs->remove (*iter);
+
+ /* deleting the master out seems like a dumb
+ idea, but its more of a UI policy issue
+ than our concern.
+ */
+
+ if (*iter == _master_out) {
+ _master_out = boost::shared_ptr<Route> ();
+ }
+
+ if (*iter == _monitor_out) {
+ _monitor_out.reset ();
}
- }
- }
- /* if the monitoring section had a pointer to this route, remove it */
- if (_monitor_out && !route->is_master() && !route->is_monitor()) {
- Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
- PBD::Unwinder<bool> uw (ignore_route_processor_changes, true);
- route->remove_aux_or_listen (_monitor_out);
- }
+ update_route_solo_state ();
+
+ // We need to disconnect the route's inputs and outputs
+
+ (*iter)->input()->disconnect (0);
+ (*iter)->output()->disconnect (0);
+
+ /* if the route had internal sends sending to it, remove them */
+ if ((*iter)->internal_return()) {
+
+ boost::shared_ptr<RouteList> r = routes.reader ();
+ for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+ boost::shared_ptr<Send> s = (*i)->internal_send_for (*iter);
+ if (s) {
+ (*i)->remove_processor (s);
+ }
+ }
+ }
+
+ /* if the monitoring section had a pointer to this route, remove it */
+ if (_monitor_out && !(*iter)->is_master() && !(*iter)->is_monitor()) {
+ Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+ PBD::Unwinder<bool> uw (ignore_route_processor_changes, true);
+ (*iter)->remove_aux_or_listen (_monitor_out);
+ }
+
+ boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (*iter);
+ if (mt && mt->step_editing()) {
+ if (_step_editors > 0) {
+ _step_editors--;
+ }
+ }
- boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (route);
- if (mt && mt->step_editing()) {
- if (_step_editors > 0) {
- _step_editors--;
+ RouteAddedOrRemoved (false); /* EMIT SIGNAL */
}
- }
+
+ /* writer goes out of scope, forces route list update */
+ } // end of RCU Writer scope
+
update_latency_compensation ();
set_dirty();
-
+
/* Re-sort routes to remove the graph's current references to the one that is
* going away, then flush old references out of the graph.
+ * Wave Tracks: reconnect routes
*/
- resort_routes ();
+ if (ARDOUR::Profile->get_trx () ) {
+ reconnect_existing_routes(true, false);
+ } else {
+ resort_routes ();
+ }
+
if (_process_graph) {
_process_graph->clear_other_chain ();
}
-
+
/* get rid of it from the dead wood collection in the route list manager */
-
/* XXX i think this is unsafe as it currently stands, but i am not sure. (pd, october 2nd, 2006) */
-
+
routes.flush ();
+
+ /* try to cause everyone to drop their references
+ * and unregister ports from the backend
+ */
+ PBD::Unwinder<bool> uw_flag (_route_deletion_in_progress, true);
- /* try to cause everyone to drop their references */
-
- route->drop_references ();
-
+ for (RouteList::iterator iter = routes_to_remove->begin(); iter != routes_to_remove->end(); ++iter) {
+ (*iter)->drop_references ();
+ }
+
Route::RemoteControlIDChange(); /* EMIT SIGNAL */
-
+
/* save the new state of the world */
-
+
if (save_state (_current_snapshot_name)) {
save_history (_current_snapshot_name);
}
+
reassign_track_numbers();
+ update_route_record_state ();
+}
+
+void
+Session::remove_route (boost::shared_ptr<Route> route)
+{
+ boost::shared_ptr<RouteList> rl (new RouteList);
+ rl->push_back (route);
+ remove_routes (rl);
}
void
return g_atomic_int_get (const_cast<gint*>(&_have_rec_enabled_track)) == 1;
}
+bool
+Session::have_rec_disabled_track () const
+{
+ return g_atomic_int_get (const_cast<gint*>(&_have_rec_disabled_track)) == 1;
+}
+
/** Update the state of our rec-enabled tracks flag */
void
-Session::update_have_rec_enabled_track ()
+Session::update_route_record_state ()
{
boost::shared_ptr<RouteList> rl = routes.reader ();
RouteList::iterator i = rl->begin();
if (g_atomic_int_get (&_have_rec_enabled_track) != old) {
RecordStateChanged (); /* EMIT SIGNAL */
}
+
+
+ i = rl->begin();
+ while (i != rl->end ()) {
+
+ boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
+ if (tr && !tr->record_enabled ()) {
+ break;
+ }
+
+ ++i;
+ }
+
+ g_atomic_int_set (&_have_rec_disabled_track, i != rl->end () ? 1 : 0);
}
void
void
Session::route_removed_from_route_group (RouteGroup* rg, boost::weak_ptr<Route> r)
{
- RouteRemovedFromRouteGroup (rg, r);
+ update_route_record_state ();
+ RouteRemovedFromRouteGroup (rg, r); /* EMIT SIGNAL */
}
boost::shared_ptr<RouteList>