X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fsession.cc;h=c335e021aa616e7294ac25542db15af52c68aa2c;hb=7b818e9a7f3d999eb6bcc90c961d2b42531c3917;hp=624e5df13d62645b8f53fc536b9985d965d539dd;hpb=bf96210e34f9ae1d080b19c38494f02e0586d340;p=ardour.git diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 624e5df13d..c335e021aa 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -30,7 +30,7 @@ #include #include -#include +#include #include #include @@ -45,7 +45,6 @@ #include "pbd/file_utils.h" #include "pbd/convert.h" #include "pbd/strsplit.h" -#include "pbd/strsplit.h" #include "pbd/unwind.h" #include "ardour/amp.h" @@ -56,63 +55,51 @@ #include "ardour/audio_track.h" #include "ardour/audioengine.h" #include "ardour/audiofilesource.h" -#include "ardour/audioplaylist.h" -#include "ardour/audioregion.h" #include "ardour/auditioner.h" #include "ardour/buffer_manager.h" #include "ardour/buffer_set.h" #include "ardour/bundle.h" #include "ardour/butler.h" #include "ardour/click.h" -#include "ardour/configuration.h" #include "ardour/control_protocol_manager.h" -#include "ardour/crossfade.h" -#include "ardour/cycle_timer.h" #include "ardour/data_type.h" #include "ardour/debug.h" #include "ardour/filename_extensions.h" -#include "ardour/internal_send.h" -#include "ardour/io_processor.h" -#include "ardour/midi_diskstream.h" -#include "ardour/midi_playlist.h" -#include "ardour/midi_region.h" +#include "ardour/graph.h" #include "ardour/midi_track.h" #include "ardour/midi_ui.h" -#include "ardour/named_selection.h" -#include "ardour/process_thread.h" +#include "ardour/operations.h" #include "ardour/playlist.h" #include "ardour/plugin.h" #include "ardour/plugin_insert.h" -#include "ardour/port_insert.h" -#include "ardour/processor.h" +#include "ardour/process_thread.h" #include "ardour/rc_configuration.h" #include "ardour/recent_sessions.h" +#include "ardour/region.h" #include "ardour/region_factory.h" -#include "ardour/return.h" #include "ardour/route_graph.h" #include "ardour/route_group.h" #include "ardour/send.h" #include "ardour/session.h" #include "ardour/session_directory.h" -#include "ardour/session_directory.h" -#include "ardour/session_metadata.h" #include "ardour/session_playlists.h" -#include "ardour/slave.h" #include "ardour/smf_source.h" #include "ardour/source_factory.h" -#include "ardour/tape_file_matcher.h" -#include "ardour/tempo.h" #include "ardour/utils.h" -#include "ardour/graph.h" -#include "ardour/speakers.h" -#include "ardour/operations.h" #include "midi++/port.h" +#include "midi++/jack_midi_port.h" #include "midi++/mmc.h" #include "midi++/manager.h" #include "i18n.h" +namespace ARDOUR { +class MidiSource; +class Processor; +class Speakers; +} + using namespace std; using namespace ARDOUR; using namespace PBD; @@ -127,8 +114,6 @@ PBD::Signal3 Session::MissingFile; PBD::Signal1 Session::StartTimeChanged; PBD::Signal1 Session::EndTimeChanged; -PBD::Signal0 Session::AutoBindingOn; -PBD::Signal0 Session::AutoBindingOff; PBD::Signal2 Session::Exported; PBD::Signal1 > Session::AskAboutPlaylistDeletion; PBD::Signal0 Session::Quit; @@ -138,7 +123,7 @@ PBD::Signal0 Session::SuccessfulGraphSort; static void clean_up_session_event (SessionEvent* ev) { delete ev; } const SessionEvent::RTeventCallback Session::rt_cleanup (clean_up_session_event); -/** @param snapshot_name Snapshot name, without .ardour prefix */ +/** @param snapshot_name Snapshot name, without .ardour suffix */ Session::Session (AudioEngine &eng, const string& fullpath, const string& snapshot_name, @@ -156,18 +141,20 @@ Session::Session (AudioEngine &eng, , _all_route_group (new RouteGroup (*this, "all")) , routes (new RouteList) , _total_free_4k_blocks (0) + , _total_free_4k_blocks_uncertain (false) , _bundles (new BundleList) , _bundle_xml_node (0) , _current_trans (0) - , _click_io ((IO*) 0) , click_data (0) , click_emphasis_data (0) , main_outs (0) - , _metadata (new SessionMetadata()) , _have_rec_enabled_track (false) , _suspend_timecode_transmission (0) { _locations = new Locations (*this); +#ifdef HAVE_LTC + ltc_encoder = NULL; +#endif if (how_many_dsp_threads () > 1) { /* For now, only create the graph if we are using >1 DSP threads, as @@ -247,6 +234,16 @@ Session::destroy () _engine.remove_session (); + /* deregister all ports - there will be no process or any other + * callbacks from the engine any more. + */ + + Port::PortDrop (); /* EMIT SIGNAL */ + +#ifdef HAVE_LTC + ltc_tx_cleanup(); +#endif + /* clear history so that no references to objects are held any more */ _history.clear (); @@ -261,6 +258,8 @@ Session::destroy () _butler->drop_references (); delete _butler; + _butler = 0; + delete midi_control_ui; delete _all_route_group; @@ -286,9 +285,6 @@ Session::destroy () /* tell everyone to drop references and delete objects as we go */ - DEBUG_TRACE (DEBUG::Destruction, "delete named selections\n"); - named_selections.clear (); - DEBUG_TRACE (DEBUG::Destruction, "delete regions\n"); RegionFactory::delete_all_regions (); @@ -328,8 +324,6 @@ Session::destroy () delete *i; } - Crossfade::set_buffer_size (0); - /* not strictly necessary, but doing it here allows the shared_ptr debugging to work */ playlists.reset (); @@ -376,7 +370,30 @@ Session::when_engine_running () try { XMLNode* child = 0; + + _ltc_input.reset (new IO (*this, _("LTC In"), IO::Input)); + _ltc_output.reset (new IO (*this, _("LTC Out"), IO::Output)); + + if (state_tree && (child = find_named_node (*state_tree->root(), "LTC-In")) != 0) { + _ltc_input->set_state (*(child->children().front()), Stateful::loading_state_version); + } else { + { + Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); + _ltc_input->ensure_io (ChanCount (DataType::AUDIO, 1), true, this); + } + reconnect_ltc_input (); + } + if (state_tree && (child = find_named_node (*state_tree->root(), "LTC-Out")) != 0) { + _ltc_output->set_state (*(child->children().front()), Stateful::loading_state_version); + } else { + { + Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); + _ltc_output->ensure_io (ChanCount (DataType::AUDIO, 1), true, this); + } + reconnect_ltc_output (); + } + _click_io.reset (new ClickIO (*this, "click")); _click_gain.reset (new Amp (*this)); _click_gain->activate (); @@ -542,11 +559,21 @@ Session::when_engine_running () BootMessage (_("Setup signal flow and plugins")); + /* Reset all panners */ + + Delivery::reset_panners (); + + /* this will cause the CPM to instantiate any protocols that are in use + * (or mandatory), which will pass it this Session, and then call + * set_state() on each instantiated protocol to match stored state. + */ + ControlProtocolManager::instance().set_session (this); /* This must be done after the ControlProtocolManager set_session above, as it will set states for ports which the ControlProtocolManager creates. */ + MIDI::Manager::instance()->set_port_states (Config->midi_port_states ()); /* And this must be done after the MIDI::Manager::set_port_states as @@ -555,8 +582,14 @@ Session::when_engine_running () hookup_io (); + /* Let control protocols know that we are now all connected, so they + * could start talking to surfaces if they want to. + */ + + ControlProtocolManager::instance().midi_connectivity_established (); + if (_is_new && !no_auto_connect()) { - Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock()); + Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock()); auto_connect_master_bus (); } @@ -570,6 +603,7 @@ Session::when_engine_running () BootMessage (_("Connect to engine")); _engine.set_session (this); + _engine.reset_timebase (); } void @@ -621,7 +655,7 @@ Session::remove_monitor_section () * pieces of audio as we work on each route. */ - Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); + Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); /* Connect tracks to monitor section. Note that in an existing session, the internal sends will already exist, but we want the @@ -667,7 +701,7 @@ Session::add_monitor_section () // boost_debug_shared_ptr_mark_interesting (r.get(), "Route"); #endif { - Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); + Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); r->input()->ensure_io (_master_out->output()->n_ports(), false, this); r->output()->ensure_io (_master_out->output()->n_ports(), false, this); } @@ -720,7 +754,7 @@ Session::add_monitor_section () boost::shared_ptr b = bundle_by_name (Config->get_monitor_bus_preferred_bundle()); if (b) { - _monitor_out->output()->connect_ports_to_bundle (b, this); + _monitor_out->output()->connect_ports_to_bundle (b, true, this); } else { warning << string_compose (_("The preferred I/O for the monitor bus (%1) cannot be found"), Config->get_monitor_bus_preferred_bundle()) @@ -768,7 +802,7 @@ Session::add_monitor_section () * pieces of audio as we work on each route. */ - Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); + Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); /* Connect tracks to monitor section. Note that in an existing session, the internal sends will already exist, but we want the @@ -830,11 +864,7 @@ Session::hookup_io () /* Tell all IO objects to connect themselves together */ IO::enable_connecting (); - MIDI::Port::MakeConnections (); - - /* Now reset all panners */ - - Delivery::reset_panners (); + MIDI::JackMIDIPort::MakeConnections (); /* Anyone who cares about input state, wake up and do something */ @@ -930,10 +960,25 @@ Session::auto_punch_changed (Location* location) replace_event (SessionEvent::PunchOut, when_to_stop); } +/** @param loc A loop location. + * @param pos Filled in with the start time of the required fade-out (in session frames). + * @param length Filled in with the length of the required fade-out. + */ +void +Session::auto_loop_declick_range (Location* loc, framepos_t & pos, framepos_t & length) +{ + pos = max (loc->start(), loc->end() - 64); + length = loc->end() - pos; +} + void Session::auto_loop_changed (Location* location) { replace_event (SessionEvent::AutoLoop, location->end(), location->start()); + framepos_t dcp; + framecnt_t dcl; + auto_loop_declick_range (location, dcp, dcl); + replace_event (SessionEvent::AutoLoopDeclick, dcp, dcl); if (transport_rolling() && play_loop) { @@ -1011,6 +1056,10 @@ Session::set_auto_loop_location (Location* location) loop_connections.drop_connections (); existing->set_auto_loop (false, this); remove_event (existing->end(), SessionEvent::AutoLoop); + framepos_t dcp; + framecnt_t dcl; + auto_loop_declick_range (existing, dcp, dcl); + remove_event (dcp, SessionEvent::AutoLoopDeclick); auto_loop_location_changed (0); } @@ -1240,7 +1289,7 @@ Session::audible_frame () const of audible frames, we have not moved yet. `Start position' in this context means the time we last - either started or changed transport direction. + either started, located, or changed transport direction. */ if (_transport_speed > 0.0f) { @@ -1486,13 +1535,13 @@ Session::resort_routes_using (boost::shared_ptr r) trace_terminal (*i, *i); } - r = sorted_routes; + *r = *sorted_routes; #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 ("signal"))); + (*i)->name(), (*i)->order_key (MixerSort))); } #endif @@ -1571,16 +1620,16 @@ Session::count_existing_track_channels (ChanCount& in, ChanCount& out) * @param instrument plugin info for the instrument to insert pre-fader, if any */ list > -Session::new_midi_track (boost::shared_ptr instrument, TrackMode mode, RouteGroup* route_group, uint32_t how_many, string name_template) +Session::new_midi_track (const ChanCount& input, const ChanCount& output, boost::shared_ptr instrument, + TrackMode mode, RouteGroup* route_group, uint32_t how_many, string name_template) { char track_name[32]; uint32_t track_id = 0; string port; RouteList new_routes; list > ret; - uint32_t control_id; - control_id = next_control_id (); + cerr << "Adding MIDI track with in = " << input << " out = " << output << endl; bool const use_number = (how_many != 1) || name_template.empty () || name_template == _("MIDI"); @@ -1605,14 +1654,14 @@ Session::new_midi_track (boost::shared_ptr instrument, TrackMode mod // boost_debug_shared_ptr_mark_interesting (track.get(), "Track"); #endif { - Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); - if (track->input()->ensure_io (ChanCount(DataType::MIDI, 1), false, this)) { - error << "cannot configure 1 in/1 out configuration for new midi track" << endmsg; + Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); + if (track->input()->ensure_io (input, false, this)) { + error << "cannot configure " << input << " out configuration for new midi track" << endmsg; goto failed; } - if (track->output()->ensure_io (ChanCount(DataType::MIDI, 1), false, this)) { - error << "cannot configure 1 in/1 out configuration for new midi track" << endmsg; + if (track->output()->ensure_io (output, false, this)) { + error << "cannot configure " << output << " out configuration for new midi track" << endmsg; goto failed; } } @@ -1624,7 +1673,10 @@ Session::new_midi_track (boost::shared_ptr instrument, TrackMode mod } track->DiskstreamChanged.connect_same_thread (*this, boost::bind (&Session::resort_routes, this)); - track->set_remote_control_id (control_id); + + if (Config->get_remote_model() == UserOrdered) { + track->set_remote_control_id (next_control_id()); + } new_routes.push_back (track); ret.push_back (track); @@ -1702,7 +1754,7 @@ Session::auto_connect_route (boost::shared_ptr route, ChanCount& existing return; } - Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock (), Glib::NOT_LOCK); + Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock (), Glib::Threads::NOT_LOCK); if (with_lock) { lm.acquire (); @@ -1813,9 +1865,6 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod string port; RouteList new_routes; list > ret; - uint32_t control_id; - - control_id = next_control_id (); bool const use_number = (how_many != 1) || name_template.empty () || name_template == _("Audio"); @@ -1840,7 +1889,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod // boost_debug_shared_ptr_mark_interesting (track.get(), "Track"); #endif { - Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); + Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); if (track->input()->ensure_io (ChanCount(DataType::AUDIO, input_channels), false, this)) { error << string_compose ( @@ -1866,8 +1915,9 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod track->non_realtime_input_change(); track->DiskstreamChanged.connect_same_thread (*this, boost::bind (&Session::resort_routes, this)); - track->set_remote_control_id (control_id); - ++control_id; + if (Config->get_remote_model() == UserOrdered) { + track->set_remote_control_id (next_control_id()); + } new_routes.push_back (track); ret.push_back (track); @@ -1895,33 +1945,6 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod return ret; } -void -Session::set_remote_control_ids () -{ - RemoteModel m = Config->get_remote_model(); - bool emit_signal = false; - - boost::shared_ptr r = routes.reader (); - - for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { - if (MixerOrdered == m) { - int32_t order = (*i)->order_key(N_("signal")); - (*i)->set_remote_control_id (order+1, false); - emit_signal = true; - } else if (EditorOrdered == m) { - int32_t order = (*i)->order_key(N_("editor")); - (*i)->set_remote_control_id (order+1, false); - emit_signal = true; - } else if (UserOrdered == m) { - //do nothing ... only changes to remote id's are initiated by user - } - } - - if (emit_signal) { - Route::RemoteControlIDChange(); - } -} - /** Caller must not hold process lock. * @param name_template string to use for the start of the name, or "" to use "Bus". */ @@ -1932,9 +1955,6 @@ Session::new_audio_route (int input_channels, int output_channels, RouteGroup* r uint32_t bus_id = 0; string port; RouteList ret; - uint32_t control_id; - - control_id = next_control_id (); bool const use_number = (how_many != 1) || name_template.empty () || name_template == _("Bus"); @@ -1955,7 +1975,7 @@ Session::new_audio_route (int input_channels, int output_channels, RouteGroup* r // boost_debug_shared_ptr_mark_interesting (bus.get(), "Route"); #endif { - Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); + Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); if (bus->input()->ensure_io (ChanCount(DataType::AUDIO, input_channels), false, this)) { error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"), @@ -1976,8 +1996,9 @@ Session::new_audio_route (int input_channels, int output_channels, RouteGroup* r if (route_group) { route_group->add (bus); } - bus->set_remote_control_id (control_id); - ++control_id; + if (Config->get_remote_model() == UserOrdered) { + bus->set_remote_control_id (next_control_id()); + } bus->add_internal_return (); @@ -2070,7 +2091,7 @@ Session::new_route_from_template (uint32_t how_many, const std::string& template loading this normally happens in a different way. */ - Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); + Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); IOChange change (IOChange::Type (IOChange::ConfigurationChanged | IOChange::ConnectionsChanged)); change.after = route->input()->n_ports(); @@ -2112,6 +2133,7 @@ Session::add_routes (RouteList& new_routes, bool input_auto_connect, bool output { ChanCount existing_inputs; ChanCount existing_outputs; + uint32_t order = next_control_id(); count_existing_track_channels (existing_inputs, existing_outputs); @@ -2142,7 +2164,6 @@ Session::add_routes (RouteList& new_routes, bool input_auto_connect, bool output r->mute_changed.connect_same_thread (*this, boost::bind (&Session::route_mute_changed, this, _1)); r->output()->changed.connect_same_thread (*this, boost::bind (&Session::set_worst_io_latencies_x, this, _1, _2)); r->processors_changed.connect_same_thread (*this, boost::bind (&Session::route_processors_changed, this, _1)); - r->order_key_changed.connect_same_thread (*this, boost::bind (&Session::route_order_key_changed, this)); if (r->is_master()) { _master_out = r; @@ -2168,12 +2189,30 @@ Session::add_routes (RouteList& new_routes, bool input_auto_connect, bool output if (input_auto_connect || output_auto_connect) { auto_connect_route (r, existing_inputs, existing_outputs, true, input_auto_connect); } + + /* 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. + */ + + if (!r->has_order_key (EditorSort)) { + if (r->is_hidden()) { + /* use an arbitrarily high value */ + r->set_order_key (EditorSort, UINT_MAX); + r->set_order_key (MixerSort, UINT_MAX); + } else { + DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("while adding, set %1 to order key %2\n", r->name(), order)); + r->set_order_key (EditorSort, order); + r->set_order_key (MixerSort, order); + order++; + } + } } if (_monitor_out && IO::connecting_legal) { { - Glib::Mutex::Lock lm (_engine.process_lock()); + Glib::Threads::Mutex::Lock lm (_engine.process_lock()); for (RouteList::iterator x = new_routes.begin(); x != new_routes.end(); ++x) { if ((*x)->is_monitor()) { @@ -2196,7 +2235,6 @@ Session::add_routes (RouteList& new_routes, bool input_auto_connect, bool output } RouteAdded (new_routes); /* EMIT SIGNAL */ - Route::RemoteControlIDChange (); /* EMIT SIGNAL */ } void @@ -2364,8 +2402,6 @@ Session::remove_route (boost::shared_ptr route) route->drop_references (); - sync_order_keys (N_("session")); - Route::RemoteControlIDChange(); /* EMIT SIGNAL */ /* save the new state of the world */ @@ -2847,7 +2883,7 @@ Session::find_whole_file_parent (boost::shared_ptr child) const RegionFactory::RegionMap::const_iterator i; boost::shared_ptr region; - Glib::Mutex::Lock lm (region_lock); + Glib::Threads::Mutex::Lock lm (region_lock); for (i = regions.begin(); i != regions.end(); ++i) { @@ -2893,7 +2929,7 @@ Session::destroy_sources (list > srcs) for (list >::iterator s = srcs.begin(); s != srcs.end(); ) { { - Glib::Mutex::Lock ls (source_lock); + Glib::Threads::Mutex::Lock ls (source_lock); /* remove from the main source list */ sources.erase ((*s)->id()); } @@ -2946,7 +2982,7 @@ Session::add_source (boost::shared_ptr source) entry.second = source; { - Glib::Mutex::Lock lm (source_lock); + Glib::Threads::Mutex::Lock lm (source_lock); result = sources.insert (entry); } @@ -2954,6 +2990,14 @@ Session::add_source (boost::shared_ptr source) /* yay, new source */ + boost::shared_ptr fs = boost::dynamic_pointer_cast (source); + + if (fs) { + if (!fs->within_session()) { + ensure_search_path_includes (Glib::path_get_dirname (fs->path()), fs->type()); + } + } + set_dirty(); boost::shared_ptr afs; @@ -2983,7 +3027,7 @@ Session::remove_source (boost::weak_ptr src) } { - Glib::Mutex::Lock lm (source_lock); + Glib::Threads::Mutex::Lock lm (source_lock); if ((i = sources.find (source->id())) != sources.end()) { sources.erase (i); @@ -3003,7 +3047,7 @@ Session::remove_source (boost::weak_ptr src) boost::shared_ptr Session::source_by_id (const PBD::ID& id) { - Glib::Mutex::Lock lm (source_lock); + Glib::Threads::Mutex::Lock lm (source_lock); SourceMap::iterator i; boost::shared_ptr source; @@ -3017,7 +3061,7 @@ Session::source_by_id (const PBD::ID& id) boost::shared_ptr Session::source_by_path_and_channel (const string& path, uint16_t chn) { - Glib::Mutex::Lock lm (source_lock); + Glib::Threads::Mutex::Lock lm (source_lock); for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) { boost::shared_ptr afs @@ -3034,7 +3078,7 @@ uint32_t Session::count_sources_by_origin (const string& path) { uint32_t cnt = 0; - Glib::Mutex::Lock lm (source_lock); + Glib::Threads::Mutex::Lock lm (source_lock); for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) { boost::shared_ptr fs @@ -3164,7 +3208,7 @@ Session::new_source_path_from_name (DataType type, const string& name) SessionDirectory sdir(get_best_session_directory_for_new_source()); - sys::path p; + std::string p; if (type == DataType::AUDIO) { p = sdir.sound_path(); } else if (type == DataType::MIDI) { @@ -3174,16 +3218,13 @@ Session::new_source_path_from_name (DataType type, const string& name) return ""; } - p /= name; - return p.to_string(); + return Glib::build_filename (p, name); } string Session::peak_path (string base) const { - sys::path peakfile_path(_session_dir->peak_path()); - peakfile_path /= base + peakfile_suffix; - return peakfile_path.to_string(); + return Glib::build_filename (_session_dir->peak_path(), base + peakfile_suffix); } /** Return a unique name based on \a base for a new internal audio source */ @@ -3247,7 +3288,7 @@ Session::new_audio_source_name (const string& base, uint32_t nchan, uint32_t cha SessionDirectory sdir((*i).path); - string spath = sdir.sound_path().to_string(); + string spath = sdir.sound_path(); /* note that we search *without* the extension so that we don't end up both "Audio 1-1.wav" and "Audio 1-1.caf" @@ -3310,12 +3351,11 @@ Session::new_midi_source_name (const string& base) SessionDirectory sdir((*i).path); - sys::path p = sdir.midi_path(); - p /= legalized; + std::string p = Glib::build_filename (sdir.midi_path(), legalized); - snprintf (buf, sizeof(buf), "%s-%u.mid", p.to_string().c_str(), cnt); + snprintf (buf, sizeof(buf), "%s-%u.mid", p.c_str(), cnt); - if (sys::exists (buf)) { + if (Glib::file_test (buf, Glib::FILE_TEST_EXISTS)) { existing++; } } @@ -3419,12 +3459,9 @@ Session::audition_playlist () void Session::non_realtime_set_audition () { - if (!pending_audition_region) { - auditioner->audition_current_playlist (); - } else { - auditioner->audition_region (pending_audition_region); - pending_audition_region.reset (); - } + assert (pending_audition_region); + auditioner->audition_region (pending_audition_region); + pending_audition_region.reset (); AuditionActive (true); /* EMIT SIGNAL */ } @@ -3454,7 +3491,7 @@ Session::RoutePublicOrderSorter::operator() (boost::shared_ptr a, boost:: if (b->is_monitor()) { return false; } - return a->order_key(N_("signal")) < b->order_key(N_("signal")); + return a->order_key (MixerSort) < b->order_key (MixerSort); } bool @@ -3500,9 +3537,18 @@ Session::graph_reordered () } } -framecnt_t +/** @return Number of frames that there is disk space available to write, + * if known. + */ +boost::optional Session::available_capture_duration () { + Glib::Threads::Mutex::Lock lm (space_lock); + + if (_total_free_4k_blocks_uncertain) { + return boost::optional (); + } + float sample_bytes_on_disk = 4.0; // keep gcc happy switch (config.get_native_file_data_format()) { @@ -3783,56 +3829,6 @@ Session::unmark_insert_id (uint32_t id) } } - -/* Named Selection management */ - -boost::shared_ptr -Session::named_selection_by_name (string name) -{ - Glib::Mutex::Lock lm (named_selection_lock); - for (NamedSelectionList::iterator i = named_selections.begin(); i != named_selections.end(); ++i) { - if ((*i)->name == name) { - return *i; - } - } - return boost::shared_ptr(); -} - -void -Session::add_named_selection (boost::shared_ptr named_selection) -{ - { - Glib::Mutex::Lock lm (named_selection_lock); - named_selections.insert (named_selections.begin(), named_selection); - } - - set_dirty(); - - NamedSelectionAdded (); /* EMIT SIGNAL */ -} - -void -Session::remove_named_selection (boost::shared_ptr named_selection) -{ - bool removed = false; - - { - Glib::Mutex::Lock lm (named_selection_lock); - - NamedSelectionList::iterator i = find (named_selections.begin(), named_selections.end(), named_selection); - - if (i != named_selections.end()) { - named_selections.erase (i); - set_dirty(); - removed = true; - } - } - - if (removed) { - NamedSelectionRemoved (); /* EMIT SIGNAL */ - } -} - void Session::reset_native_file_format () { @@ -3916,7 +3912,7 @@ Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end, framepos_t to_do; BufferSet buffers; SessionDirectory sdir(get_best_session_directory_for_new_source ()); - const string sound_dir = sdir.sound_path().to_string(); + const string sound_dir = sdir.sound_path(); framepos_t len = end - start; bool need_block_size_reset = false; string ext; @@ -4081,6 +4077,12 @@ Session::gain_automation_buffer() const return ProcessThread::gain_automation_buffer (); } +gain_t* +Session::send_gain_automation_buffer() const +{ + return ProcessThread::send_gain_automation_buffer (); +} + pan_t** Session::pan_automation_buffer() const { @@ -4141,31 +4143,6 @@ Session::add_automation_list(AutomationList *al) automation_lists[al->id()] = al; } -void -Session::sync_order_keys (std::string const & base) -{ - if (deletion_in_progress()) { - return; - } - - if (!Config->get_sync_all_route_ordering()) { - /* leave order keys as they are */ - return; - } - - boost::shared_ptr r = routes.reader (); - - for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { - (*i)->sync_order_keys (base); - } - - Route::SyncOrderKeys (base); // EMIT SIGNAL - - /* this might not do anything */ - - set_remote_control_ids (); -} - /** @return true if there is at least one record-enabled track, otherwise false */ bool Session::have_rec_enabled_track () const @@ -4241,18 +4218,6 @@ Session::route_removed_from_route_group (RouteGroup* rg, boost::weak_ptr RouteRemovedFromRouteGroup (rg, r); } -vector -Session::get_available_sync_options () const -{ - vector ret; - - ret.push_back (JACK); - ret.push_back (MTC); - ret.push_back (MIDIClock); - - return ret; -} - boost::shared_ptr Session::get_routes_with_regions_at (framepos_t const p) const { @@ -4317,13 +4282,6 @@ Session::add_session_range_location (framepos_t start, framepos_t end) _locations->add (_session_range_location); } -/** Called when one of our routes' order keys has changed */ -void -Session::route_order_key_changed () -{ - RouteOrderKeyChanged (); /* EMIT SIGNAL */ -} - void Session::step_edit_status_change (bool yn) { @@ -4364,7 +4322,7 @@ Session::start_time_changed (framepos_t old) Location* l = _locations->auto_loop_location (); - if (l->start() == old) { + if (l && l->start() == old) { l->set_start (s->start(), true); } } @@ -4396,10 +4354,10 @@ Session::source_search_path (DataType type) const if (session_dirs.size() == 1) { switch (type) { case DataType::AUDIO: - s.push_back ( _session_dir->sound_path().to_string()); + s.push_back ( _session_dir->sound_path()); break; case DataType::MIDI: - s.push_back (_session_dir->midi_path().to_string()); + s.push_back (_session_dir->midi_path()); break; } } else { @@ -4407,15 +4365,22 @@ Session::source_search_path (DataType type) const SessionDirectory sdir (i->path); switch (type) { case DataType::AUDIO: - s.push_back (sdir.sound_path().to_string()); + s.push_back (sdir.sound_path()); break; case DataType::MIDI: - s.push_back (sdir.midi_path().to_string()); + s.push_back (sdir.midi_path()); break; } } } + if (type == DataType::AUDIO) { + const string sound_path_2X = _session_dir->sound_path_2X(); + if (Glib::file_test (sound_path_2X, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) { + s.push_back (sound_path_2X); + } + } + /* now check the explicit (possibly user-specified) search path */ @@ -4475,7 +4440,7 @@ Session::ensure_search_path_includes (const string& path, DataType type) search_path = config.get_midi_search_path (); break; } - + split (search_path, dirs, ':'); for (vector::iterator i = dirs.begin(); i != dirs.end(); ++i) { @@ -4485,7 +4450,7 @@ Session::ensure_search_path_includes (const string& path, DataType type) On Windows, I think we could just do if (*i == path) here. */ - if (inodes_same (*i, path)) { + if (PBD::equivalent_paths (*i, path)) { return; } } @@ -4621,7 +4586,7 @@ void Session::initialize_latencies () { { - Glib::Mutex::Lock lm (_engine.process_lock()); + Glib::Threads::Mutex::Lock lm (_engine.process_lock()); update_latency (false); update_latency (true); } @@ -4741,5 +4706,103 @@ Session::session_name_is_legal (const string& path) uint32_t Session::next_control_id () const { - return ntracks() + nbusses() + 1; + 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++; + } + + return nroutes() - subtract; +} + +void +Session::notify_remote_id_change () +{ + if (deletion_in_progress()) { + return; + } + + switch (Config->get_remote_model()) { + case MixerSort: + case EditorSort: + Route::RemoteControlIDChange (); /* EMIT SIGNAL */ + break; + default: + break; + } +} + +void +Session::sync_order_keys (RouteSortOrderKey sort_key_changed) +{ + 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, string_compose ("Sync Order Keys, based on %1\n", enum_2_string (sort_key_changed))); + + Route::SyncOrderKeys (sort_key_changed); /* EMIT SIGNAL */ + + DEBUG_TRACE (DEBUG::OrderKeys, "\tsync done\n"); +} + +bool +Session::operation_in_progress (GQuark op) const +{ + return (find (_current_trans_quarks.begin(), _current_trans_quarks.end(), op) != _current_trans_quarks.end()); +} + +boost::shared_ptr +Session::ltc_input_port () const +{ + return _ltc_input->nth (0); +} + +boost::shared_ptr +Session::ltc_output_port () const +{ + return _ltc_output->nth (0); +} + +void +Session::reconnect_ltc_input () +{ + if (_ltc_input) { + + string src = Config->get_ltc_source_port(); + + _ltc_input->disconnect (this); + + if (src != _("None") && !src.empty()) { + _ltc_input->nth (0)->connect (src); + } + } +} + +void +Session::reconnect_ltc_output () +{ + if (_ltc_output) { + +#if 0 + string src = Config->get_ltc_sink_port(); + + _ltc_output->disconnect (this); + + if (src != _("None") && !src.empty()) { + _ltc_output->nth (0)->connect (src); + } +#endif + } }