, _exporting (false)
, _export_rolling (false)
, _realtime_export (false)
+ , _region_export (false)
, _export_preroll (0)
, _export_latency (0)
, _pre_export_mmc_enabled (false)
, _step_editors (0)
, _suspend_timecode_transmission (0)
, _speakers (new Speakers)
- , ignore_route_processor_changes (false)
+ , _ignore_route_processor_changes (0)
, midi_clock (0)
, _scene_changer (0)
, _midi_ports (0)
, _mmc (0)
, _vca_manager (new VCAManager (*this))
- , _midi_regions_use_bbt_beats (false)
{
uint32_t sr = 0;
}
}
#endif
- _midi_regions_use_bbt_beats = false;
_is_new = false;
session_loaded ();
+
BootMessage (_("Session loading complete"));
}
}
}
+void
+Session::get_physical_ports (vector<string>& inputs, vector<string>& outputs, DataType type,
+ MidiPortFlags include, MidiPortFlags exclude)
+{
+ _engine.get_physical_inputs (type, inputs, include, exclude);
+ _engine.get_physical_outputs (type, outputs, include, exclude);
+}
+
void
Session::setup_bundles ()
{
vector<string> inputs[DataType::num_types];
vector<string> outputs[DataType::num_types];
+
for (uint32_t i = 0; i < DataType::num_types; ++i) {
- _engine.get_physical_inputs (DataType (DataType::Symbol (i)), inputs[i]);
- _engine.get_physical_outputs (DataType (DataType::Symbol (i)), outputs[i]);
+ get_physical_ports (inputs[i], outputs[i], DataType (DataType::Symbol (i)),
+ MidiPortFlags (0), /* no specific inclusions */
+ MidiPortFlags (MidiPortControl|MidiPortVirtual) /* exclude control & virtual ports */
+ );
}
/* Create a set of Bundle objects that map
for (uint32_t np = 0; np < inputs[DataType::MIDI].size(); ++np) {
string n = inputs[DataType::MIDI][np];
+
std::string pn = _engine.get_pretty_name_by_name (n);
if (!pn.empty()) {
n = pn;
boost::shared_ptr<RouteList> r = routes.reader ();
- PBD::Unwinder<bool> uw (ignore_route_processor_changes, true);
+ ProcessorChangeBlocker pcb (this, false);
for (RouteList::iterator x = r->begin(); x != r->end(); ++x) {
boost::shared_ptr<RouteList> rls = routes.reader ();
- PBD::Unwinder<bool> uw (ignore_route_processor_changes, true);
+ ProcessorChangeBlocker pcb (this, false /* XXX */);
for (RouteList::iterator x = rls->begin(); x != rls->end(); ++x) {
boost::shared_ptr<RouteList> rls = routes.reader ();
- PBD::Unwinder<bool> uw (ignore_route_processor_changes, true);
+ ProcessorChangeBlocker pcb (this, false);
for (RouteList::iterator x = rls->begin(); x != rls->end(); ++x) {
}
}
- if (!definitely_add_number && route_by_name (base) == 0) {
- /* juse use the base */
+ /* if we have "base 1" already, it doesn't make sense to add "base"
+ * if "base 1" has been deleted, adding "base" is no worse than "base 1"
+ */
+ if (!definitely_add_number && route_by_name (base) == 0 && (route_by_name (string_compose("%1 1", base)) == 0)) {
+ /* just use the base */
name = base;
return true;
}
if (instrument) {
for (RouteList::iterator r = new_routes.begin(); r != new_routes.end(); ++r) {
PluginPtr plugin = instrument->load (*this);
+ if (!plugin) {
+ warning << "Failed to add Synth Plugin to newly created track." << endmsg;
+ continue;
+ }
if (pset) {
plugin->load_preset (*pset);
}
boost::shared_ptr<Processor> p (new PluginInsert (*this, plugin));
(*r)->add_processor (p, PreFader);
-
}
}
}
if (instrument) {
for (RouteList::iterator r = ret.begin(); r != ret.end(); ++r) {
PluginPtr plugin = instrument->load (*this);
+ if (!plugin) {
+ warning << "Failed to add Synth Plugin to newly created track." << endmsg;
+ continue;
+ }
if (pset) {
plugin->load_preset (*pset);
}
bool rename_playlist;
switch (pd) {
case NewPlaylist:
+ case CopyPlaylist:
rename_playlist = true;
break;
default:
- case CopyPlaylist:
case SharePlaylist:
rename_playlist = false;
}
if ((track = boost::dynamic_pointer_cast<Track> (route))) {
switch (pd) {
case NewPlaylist:
- track->use_new_playlist ();
break;
case CopyPlaylist:
track->use_copy_playlist ();
if (mt) {
mt->StepEditStatusChange.connect_same_thread (*this, boost::bind (&Session::step_edit_status_change, this, _1));
mt->output()->changed.connect_same_thread (*this, boost::bind (&Session::midi_output_change_handler, this, _1, _2, boost::weak_ptr<Route>(mt)));
+ mt->presentation_info().PropertyChanged.connect_same_thread (*this, boost::bind (&Session::midi_track_presentation_info_changed, this, _1, boost::weak_ptr<MidiTrack>(mt)));
}
}
/* 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);
+ ProcessorChangeBlocker pcb (this, false);
(*iter)->remove_aux_or_listen (_monitor_out);
}
*/
for (RouteList::iterator iter = routes_to_remove->begin(); iter != routes_to_remove->end(); ++iter) {
+ cerr << "Drop references to " << (*iter)->name() << endl;
(*iter)->drop_references ();
}
_listen_cnt--;
}
-
- update_route_solo_state ();
}
void
void
Session::route_solo_changed (bool self_solo_changed, Controllable::GroupControlDisposition group_override, boost::weak_ptr<Route> wpr)
{
- DEBUG_TRACE (DEBUG::Solo, string_compose ("route solo change, self = %1\n", self_solo_changed));
+ DEBUG_TRACE (DEBUG::Solo, string_compose ("route solo change, self = %1, update\n", self_solo_changed));
boost::shared_ptr<Route> route (wpr.lock());
DEBUG_TRACE (DEBUG::Solo, string_compose ("%1: self %2 masters %3 transition %4\n", route->name(), route->self_soloed(), route->solo_control()->get_masters_value(), route->solo_control()->transitioned_into_solo()));
if (route->solo_control()->transitioned_into_solo() == 0) {
- /* route solo changed by upstream/downstream; not interesting
+ /* route solo changed by upstream/downstream or clear all solo state; not interesting
to Session.
*/
DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 not self-soloed nor soloed by master (%2), ignoring\n", route->name(), route->solo_control()->get_masters_value()));
return;
}
- if (route->solo_control()->transitioned_into_solo() == 0) {
- /* reason for being soloed changed (e.g. master went away, we
- * took over the master state), but actual status did
- * not. nothing to do.
- */
- DEBUG_TRACE (DEBUG::Solo, string_compose ("%1: solo change was change in reason, not status\n", route->name()));
- }
-
boost::shared_ptr<RouteList> r = routes.reader ();
int32_t delta = route->solo_control()->transitioned_into_solo ();
RouteGroup* rg = route->route_group ();
const bool group_already_accounted_for = (group_override == Controllable::ForGroup);
+ DEBUG_TRACE (DEBUG::Solo, string_compose ("propagate to session, group accounted for ? %1\n", group_already_accounted_for));
+
if (delta == 1 && Config->get_exclusive_solo()) {
/* new solo: disable all other solos, but not the group if its solo-enabled */
DEBUG_TRACE (DEBUG::Solo, "propagation complete\n");
- update_route_solo_state (r);
-
/* now notify that the mute state of the routes not involved in the signal
pathway of the just-solo-changed route may have altered.
*/
for (RouteList::iterator i = uninvolved.begin(); i != uninvolved.end(); ++i) {
DEBUG_TRACE (DEBUG::Solo, string_compose ("mute change for %1, which neither feeds or is fed by %2\n", (*i)->name(), route->name()));
(*i)->act_on_mute ();
- (*i)->mute_control()->Changed (false, Controllable::NoGroup);
+ /* Session will emit SoloChanged() after all solo changes are
+ * complete, which should be used by UIs to update mute status
+ */
}
-
- SoloChanged (); /* EMIT SIGNAL */
- set_dirty();
}
void
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
if ((*i)->can_solo()) {
if (Config->get_solo_control_is_listen_control()) {
- if ((*i)->self_soloed() || (*i)->solo_control()->get_masters_value()) {
+ if ((*i)->solo_control()->soloed_by_self_or_masters()) {
listeners++;
something_listening = true;
}
} else {
(*i)->set_listen (false);
- if ((*i)->can_solo() && ((*i)->self_soloed() || (*i)->solo_control()->get_masters_value())) {
+ if ((*i)->can_solo() && (*i)->solo_control()->soloed_by_self_or_masters()) {
something_soloed = true;
}
}
DEBUG_TRACE (DEBUG::Solo, string_compose ("solo state updated by session, soloed? %1 listeners %2 isolated %3\n",
something_soloed, listeners, isolated));
+
+
+ SoloChanged (); /* EMIT SIGNAL */
+ set_dirty();
}
void
void
Session::listen_position_changed ()
{
+ ProcessorChangeBlocker pcb (this);
boost::shared_ptr<RouteList> r = routes.reader ();
-
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
(*i)->listen_position_changed ();
}
Session::solo_control_mode_changed ()
{
if (soloing() || listening()) {
- /* We can't use ::clear_all_solo_state() here because during
- session loading at program startup, that will queue a call
- to rt_clear_all_solo_state() that will not execute until
- AFTER solo states have been established (thus throwing away
- the session's saved solo state). So just explicitly turn
- them all off.
- */
- set_controls (route_list_to_control_list (get_routes(), &Stripable::solo_control), 0.0, Controllable::NoGroup);
+ if (loading()) {
+ /* We can't use ::clear_all_solo_state() here because during
+ session loading at program startup, that will queue a call
+ to rt_clear_all_solo_state() that will not execute until
+ AFTER solo states have been established (thus throwing away
+ the session's saved solo state). So just explicitly turn
+ them all off.
+ */
+ set_controls (route_list_to_control_list (get_routes(), &Stripable::solo_control), 0.0, Controllable::NoGroup);
+ } else {
+ clear_all_solo_state (get_routes());
+ }
}
}
{
update_route_record_state ();
RouteRemovedFromRouteGroup (rg, r); /* EMIT SIGNAL */
+
+ if (!rg->has_control_master () && !rg->has_subgroup () && rg->empty()) {
+ remove_route_group (*rg);
+ }
}
boost::shared_ptr<RouteList>
}
void
-Session::goto_start ()
+Session::goto_start (bool and_roll)
{
if (_session_range_location) {
- request_locate (_session_range_location->start(), false);
+ request_locate (_session_range_location->start(), and_roll);
} else {
- request_locate (0, false);
+ request_locate (0, and_roll);
}
}
input_start, output_start,
input_offset, output_offset));
+ auto_connect_thread_wakeup ();
+}
+
+void
+Session::auto_connect_thread_wakeup ()
+{
if (pthread_mutex_trylock (&_auto_connect_mutex) == 0) {
pthread_cond_signal (&_auto_connect_cond);
pthread_mutex_unlock (&_auto_connect_mutex);
Session::queue_latency_recompute ()
{
g_atomic_int_inc (&_latency_recompute_pending);
- if (pthread_mutex_trylock (&_auto_connect_mutex) == 0) {
- pthread_cond_signal (&_auto_connect_cond);
- pthread_mutex_unlock (&_auto_connect_mutex);
- }
+ auto_connect_thread_wakeup ();
}
void
vector<string> physinputs;
vector<string> physoutputs;
- _engine.get_physical_outputs (*t, physoutputs);
- _engine.get_physical_inputs (*t, physinputs);
+
+ /* for connecting track inputs we only want MIDI ports marked
+ * for "music".
+ */
+
+ get_physical_ports (physinputs, physoutputs, *t, MidiPortMusic);
if (!physinputs.empty() && ar.connect_inputs) {
uint32_t nphysical_in = physinputs.size();
}
}
- if (pthread_mutex_lock (&_auto_connect_mutex) == 0) {
- pthread_cond_signal (&_auto_connect_cond);
- pthread_mutex_unlock (&_auto_connect_mutex);
- }
+ auto_connect_thread_wakeup ();
void *status;
pthread_join (_auto_connect_thread, &status);
}
}
+ AudioEngine::instance()->clear_pending_port_deletions ();
+
pthread_cond_wait (&_auto_connect_cond, &_auto_connect_mutex);
}
pthread_mutex_unlock (&_auto_connect_mutex);