X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fsession.cc;h=fbde7edf607dbf71074ce09d750eaf132fe5ea3e;hb=70308f51747b5beeff99dec9f10490080f00b0c2;hp=4be52a7584fd7628cdd76e5d8dfc1417d4aa0f90;hpb=960a47330a5d3e534e6275f42efc07585a2075e1;p=ardour.git diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 4be52a7584..fbde7edf60 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -44,8 +44,8 @@ #include "pbd/stacktrace.h" #include "pbd/file_utils.h" #include "pbd/convert.h" -#include "pbd/strsplit.h" #include "pbd/unwind.h" +#include "pbd/search_path.h" #include "ardour/amp.h" #include "ardour/analyser.h" @@ -68,6 +68,7 @@ #include "ardour/filename_extensions.h" #include "ardour/graph.h" #include "ardour/midiport_manager.h" +#include "ardour/scene_changer.h" #include "ardour/midi_track.h" #include "ardour/midi_ui.h" #include "ardour/operations.h" @@ -88,6 +89,7 @@ #include "ardour/smf_source.h" #include "ardour/source_factory.h" #include "ardour/speakers.h" +#include "ardour/track.h" #include "ardour/utils.h" #include "midi++/port.h" @@ -123,6 +125,7 @@ PBD::Signal0 Session::FeedbackDetected; PBD::Signal0 Session::SuccessfulGraphSort; PBD::Signal2 Session::VersionMismatch; +const framecnt_t Session::bounce_chunk_size = 65536; static void clean_up_session_event (SessionEvent* ev) { delete ev; } const SessionEvent::RTeventCallback Session::rt_cleanup (clean_up_session_event); @@ -135,6 +138,7 @@ Session::Session (AudioEngine &eng, : playlists (new SessionPlaylists) , _engine (eng) , process_function (&Session::process_with_events) + , _bounce_processing_active (false) , waiting_for_sync_offset (false) , _base_frame_rate (0) , _current_frame_rate (0) @@ -257,7 +261,9 @@ Session::Session (AudioEngine &eng, , _step_editors (0) , _suspend_timecode_transmission (0) , _speakers (new Speakers) + , _order_hint (0) , ignore_route_processor_changes (false) + , _scene_changer (0) , _midi_ports (0) , _mmc (0) { @@ -276,6 +282,21 @@ Session::Session (AudioEngine &eng, throw failed_constructor (); } + /* if a mix template was provided, then ::create() will + * have copied it into the session and we need to load it + * so that we have the state ready for ::set_state() + * after the engine is started. + * + * Note that we do NOT try to get the sample rate from + * the template at this time, though doing so would + * be easy if we decided this was an appropriate part + * of a template. + */ + + if (!mix_template.empty() && load_state (_current_snapshot_name)) { + throw failed_constructor (); + } + } else { if (load_state (_current_snapshot_name)) { @@ -510,13 +531,16 @@ Session::destroy () } routes.flush (); - DEBUG_TRACE (DEBUG::Destruction, "delete sources\n"); - for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) { - DEBUG_TRACE(DEBUG::Destruction, string_compose ("Dropping for source %1 ; pre-ref = %2\n", i->second->name(), i->second.use_count())); - i->second->drop_references (); - } + { + DEBUG_TRACE (DEBUG::Destruction, "delete sources\n"); + Glib::Threads::Mutex::Lock lm (source_lock); + for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) { + DEBUG_TRACE(DEBUG::Destruction, string_compose ("Dropping for source %1 ; pre-ref = %2\n", i->second->name(), i->second.use_count())); + i->second->drop_references (); + } - sources.clear (); + sources.clear (); + } DEBUG_TRACE (DEBUG::Destruction, "delete route groups\n"); for (list::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) { @@ -527,6 +551,8 @@ Session::destroy () /* not strictly necessary, but doing it here allows the shared_ptr debugging to work */ playlists.reset (); + delete _scene_changer; _scene_changer = 0; + delete _mmc; _mmc = 0; delete _midi_ports; _midi_ports = 0; delete _locations; _locations = 0; @@ -543,10 +569,10 @@ Session::setup_ltc () { XMLNode* child = 0; - _ltc_input.reset (new IO (*this, _("LTC In"), IO::Input)); - _ltc_output.reset (new IO (*this, _("LTC Out"), IO::Output)); + _ltc_input.reset (new IO (*this, X_("LTC In"), IO::Input)); + _ltc_output.reset (new IO (*this, X_("LTC Out"), IO::Output)); - if (state_tree && (child = find_named_node (*state_tree->root(), "LTC-In")) != 0) { + if (state_tree && (child = find_named_node (*state_tree->root(), X_("LTC In"))) != 0) { _ltc_input->set_state (*(child->children().front()), Stateful::loading_state_version); } else { { @@ -556,7 +582,7 @@ Session::setup_ltc () reconnect_ltc_input (); } - if (state_tree && (child = find_named_node (*state_tree->root(), "LTC-Out")) != 0) { + if (state_tree && (child = find_named_node (*state_tree->root(), X_("LTC Out"))) != 0) { _ltc_output->set_state (*(child->children().front()), Stateful::loading_state_version); } else { { @@ -570,21 +596,30 @@ Session::setup_ltc () * IO style of NAME/TYPE-{in,out}N */ - _ltc_input->nth (0)->set_name (_("LTC-in")); - _ltc_output->nth (0)->set_name (_("LTC-out")); + _ltc_input->nth (0)->set_name (X_("LTC-in")); + _ltc_output->nth (0)->set_name (X_("LTC-out")); } void Session::setup_click () { - XMLNode* child = 0; - _clicking = false; - _click_io.reset (new ClickIO (*this, "click")); + _click_io.reset (new ClickIO (*this, X_("Click"))); _click_gain.reset (new Amp (*this)); _click_gain->activate (); + if (state_tree) { + setup_click_state (state_tree->root()); + } else { + setup_click_state (0); + } +} + +void +Session::setup_click_state (const XMLNode* node) +{ + const XMLNode* child = 0; - if (state_tree && (child = find_named_node (*state_tree->root(), "Click")) != 0) { + if (node && (child = find_named_node (*node, "Click")) != 0) { /* existing state for Click */ int c = 0; @@ -780,6 +815,12 @@ Session::remove_monitor_section () /* force reversion to Solo-In-Place */ Config->set_solo_control_is_listen_control (false); + /* if we are auditioning, cancel it ... this is a workaround + to a problem (auditioning does not execute the process graph, + which is needed to remove routes when using >1 core for processing) + */ + cancel_audition (); + { /* Hold process lock while doing this so that we don't hear bits and * pieces of audio as we work on each route. @@ -810,6 +851,10 @@ Session::remove_monitor_section () remove_route (_monitor_out); auto_connect_master_bus (); + + if (auditioner) { + auditioner->connect (); + } } void @@ -954,6 +999,10 @@ Session::add_monitor_section () (*x)->enable_monitor_send (); } } + + if (auditioner) { + auditioner->connect (); + } } void @@ -1675,7 +1724,7 @@ Session::resort_routes_using (boost::shared_ptr r) 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 (MixerSort))); + (*i)->name(), (*i)->order_key ())); } #endif @@ -1960,9 +2009,9 @@ Session::auto_connect_route (boost::shared_ptr route, ChanCount& existing for (uint32_t i = output_start.get(*t); i < route->n_outputs().get(*t); ++i) { string port; - if ((*t) == DataType::MIDI || Config->get_output_auto_connect() & AutoConnectPhysical) { + if ((*t) == DataType::MIDI && (Config->get_output_auto_connect() & AutoConnectPhysical)) { port = physoutputs[(out_offset.get(*t) + i) % nphysical_out]; - } else if ((*t) == DataType::AUDIO && Config->get_output_auto_connect() & AutoConnectMaster) { + } else if ((*t) == DataType::AUDIO && (Config->get_output_auto_connect() & AutoConnectMaster)) { /* master bus is audio only */ if (_master_out && _master_out->n_inputs().get(*t) > 0) { port = _master_out->input()->ports().port(*t, @@ -2311,6 +2360,11 @@ Session::add_routes_inner (RouteList& new_routes, bool input_auto_connect, bool ChanCount existing_outputs; uint32_t order = next_control_id(); + if (_order_hint != 0) { + order = _order_hint; + _order_hint = 0; + } + count_existing_track_channels (existing_inputs, existing_outputs); { @@ -2372,15 +2426,13 @@ Session::add_routes_inner (RouteList& new_routes, bool input_auto_connect, bool ID in most situations. */ - if (!r->has_order_key (EditorSort)) { + if (!r->has_order_key ()) { if (r->is_auditioner()) { /* use an arbitrarily high value */ - r->set_order_key (EditorSort, UINT_MAX); - r->set_order_key (MixerSort, UINT_MAX); + r->set_order_key (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); + r->set_order_key (order); order++; } } @@ -3258,12 +3310,16 @@ Session::source_by_id (const PBD::ID& id) return source; } -boost::shared_ptr -Session::source_by_path_and_channel (const string& path, uint16_t chn) +boost::shared_ptr +Session::audio_source_by_path_and_channel (const string& path, uint16_t chn) const { + /* Restricted to audio files because only audio sources have channel + as a property. + */ + Glib::Threads::Mutex::Lock lm (source_lock); - for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) { + for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) { boost::shared_ptr afs = boost::dynamic_pointer_cast(i->second); @@ -3271,7 +3327,31 @@ Session::source_by_path_and_channel (const string& path, uint16_t chn) return afs; } } - return boost::shared_ptr(); + + return boost::shared_ptr(); +} + +boost::shared_ptr +Session::midi_source_by_path (const std::string& path) const +{ + /* Restricted to MIDI files because audio sources require a channel + for unique identification, in addition to a path. + */ + + Glib::Threads::Mutex::Lock lm (source_lock); + + for (SourceMap::const_iterator s = sources.begin(); s != sources.end(); ++s) { + boost::shared_ptr ms + = boost::dynamic_pointer_cast(s->second); + boost::shared_ptr fs + = boost::dynamic_pointer_cast(s->second); + + if (ms && fs && fs->path() == path) { + return ms; + } + } + + return boost::shared_ptr(); } uint32_t @@ -3292,111 +3372,6 @@ Session::count_sources_by_origin (const string& path) return cnt; } - -string -Session::change_source_path_by_name (string path, string oldname, string newname, bool destructive) -{ - string look_for; - string old_basename = PBD::basename_nosuffix (oldname); - string new_legalized = legalize_for_path (newname); - - /* note: we know (or assume) the old path is already valid */ - - if (destructive) { - - /* destructive file sources have a name of the form: - - /path/to/Tnnnn-NAME(%[LR])?.wav - - the task here is to replace NAME with the new name. - */ - - string dir; - string prefix; - string::size_type dash; - - dir = Glib::path_get_dirname (path); - path = Glib::path_get_basename (path); - - /* '-' is not a legal character for the NAME part of the path */ - - if ((dash = path.find_last_of ('-')) == string::npos) { - return ""; - } - - prefix = path.substr (0, dash); - - path += prefix; - path += '-'; - path += new_legalized; - path += native_header_format_extension (config.get_native_file_header_format(), DataType::AUDIO); - path = Glib::build_filename (dir, path); - - } else { - - /* non-destructive file sources have a name of the form: - - /path/to/NAME-nnnnn(%[LR])?.ext - - the task here is to replace NAME with the new name. - */ - - string dir; - string suffix; - string::size_type dash; - string::size_type postfix; - - dir = Glib::path_get_dirname (path); - path = Glib::path_get_basename (path); - - /* '-' is not a legal character for the NAME part of the path */ - - if ((dash = path.find_last_of ('-')) == string::npos) { - return ""; - } - - suffix = path.substr (dash+1); - - // Suffix is now everything after the dash. Now we need to eliminate - // the nnnnn part, which is done by either finding a '%' or a '.' - - postfix = suffix.find_last_of ("%"); - if (postfix == string::npos) { - postfix = suffix.find_last_of ('.'); - } - - if (postfix != string::npos) { - suffix = suffix.substr (postfix); - } else { - error << "Logic error in Session::change_source_path_by_name(), please report" << endl; - return ""; - } - - const uint32_t limit = 10000; - char buf[PATH_MAX+1]; - - for (uint32_t cnt = 1; cnt <= limit; ++cnt) { - - snprintf (buf, sizeof(buf), "%s-%u%s", newname.c_str(), cnt, suffix.c_str()); - - if (!matching_unsuffixed_filename_exists_in (dir, buf)) { - path = Glib::build_filename (dir, buf); - break; - } - - path = ""; - } - - if (path.empty()) { - fatal << string_compose (_("FATAL ERROR! Could not find a suitable version of %1 for a rename"), - newname) << endl; - /*NOTREACHED*/ - } - } - - return path; -} - /** Return the full path (in some session directory) for a new within-session source. * \a name must be a session-unique name that does not contain slashes * (e.g. as returned by new_*_source_name) @@ -3500,6 +3475,22 @@ Session::new_audio_source_name (const string& base, uint32_t nchan, uint32_t cha existing++; break; } + + /* it is possible that we have the path already + * assigned to a source that has not yet been written + * (ie. the write source for a diskstream). we have to + * check this in order to make sure that our candidate + * path isn't used again, because that can lead to + * two Sources point to the same file with different + * notions of their removability. + */ + + string possible_path = Glib::build_filename (spath, buf); + + if (audio_source_by_path_and_channel (possible_path, chan)) { + existing++; + break; + } } if (existing == 0) { @@ -3529,19 +3520,21 @@ Session::create_audio_source_for_session (size_t n_chans, string const & n, uint SourceFactory::createWritable (DataType::AUDIO, *this, path, destructive, frame_rate())); } -/** Return a unique name based on \a base for a new internal MIDI source */ +/** Return a unique name based on \a owner_name for a new internal MIDI source */ string -Session::new_midi_source_name (const string& base) +Session::new_midi_source_name (const string& owner_name) { uint32_t cnt; char buf[PATH_MAX+1]; const uint32_t limit = 10000; string legalized; + string possible_name; buf[0] = '\0'; - legalized = legalize_for_path (base); + legalized = legalize_for_path (owner_name); // Find a "version" of the file name that doesn't exist in any of the possible directories. + for (cnt = 1; cnt <= limit; ++cnt) { vector::iterator i; @@ -3550,12 +3543,17 @@ Session::new_midi_source_name (const string& base) for (i = session_dirs.begin(); i != session_dirs.end(); ++i) { SessionDirectory sdir((*i).path); + + snprintf (buf, sizeof(buf), "%s-%u.mid", legalized.c_str(), cnt); + possible_name = buf; - std::string p = Glib::build_filename (sdir.midi_path(), legalized); - - snprintf (buf, sizeof(buf), "%s-%u.mid", p.c_str(), cnt); + std::string possible_path = Glib::build_filename (sdir.midi_path(), possible_name); + + if (Glib::file_test (possible_path, Glib::FILE_TEST_EXISTS)) { + existing++; + } - if (Glib::file_test (buf, Glib::FILE_TEST_EXISTS)) { + if (midi_source_by_path (possible_path)) { existing++; } } @@ -3567,37 +3565,64 @@ Session::new_midi_source_name (const string& base) if (cnt > limit) { error << string_compose( _("There are already %1 recordings for %2, which I consider too many."), - limit, base) << endmsg; + limit, owner_name) << endmsg; destroy (); throw failed_constructor(); } } - return Glib::path_get_basename(buf); + return possible_name; } /** Create a new within-session MIDI source */ boost::shared_ptr -Session::create_midi_source_for_session (Track* track, string const & n) +Session::create_midi_source_for_session (string const & basic_name) { - /* try to use the existing write source for the track, to keep numbering sane - */ + std::string name; - if (track) { - /*MidiTrack* mt = dynamic_cast (track); - assert (mt); - */ + if (name.empty()) { + name = new_midi_source_name (basic_name); + } - list > l = track->steal_write_sources (); + const string path = new_source_path_from_name (DataType::MIDI, name); - if (!l.empty()) { - assert (boost::dynamic_pointer_cast (l.front())); - return boost::dynamic_pointer_cast (l.front()); - } + return boost::dynamic_pointer_cast ( + SourceFactory::createWritable ( + DataType::MIDI, *this, path, false, frame_rate())); +} + +/** Create a new within-session MIDI source */ +boost::shared_ptr +Session::create_midi_source_by_stealing_name (boost::shared_ptr track) +{ + /* the caller passes in the track the source will be used in, + so that we can keep the numbering sane. + + Rationale: a track with the name "Foo" that has had N + captures carried out so far will ALREADY have a write source + named "Foo-N+1.mid" waiting to be used for the next capture. + + If we call new_midi_source_name() we will get "Foo-N+2". But + there is no region corresponding to "Foo-N+1", so when + "Foo-N+2" appears in the track, the gap presents the user + with odd behaviour - why did it skip past Foo-N+1? + + We could explain this to the user in some odd way, but + instead we rename "Foo-N+1.mid" as "Foo-N+2.mid", and then + use "Foo-N+1" here. + + If that attempted rename fails, we get "Foo-N+2.mid" anyway. + */ + + boost::shared_ptr mt = boost::dynamic_pointer_cast (track); + assert (mt); + std::string name = track->steal_write_source_name (); + + if (name.empty()) { + return boost::shared_ptr(); } - const string name = new_midi_source_name (n); const string path = new_source_path_from_name (DataType::MIDI, name); return boost::dynamic_pointer_cast ( @@ -3691,7 +3716,7 @@ Session::RoutePublicOrderSorter::operator() (boost::shared_ptr a, boost:: if (b->is_monitor()) { return false; } - return a->order_key (MixerSort) < b->order_key (MixerSort); + return a->order_key () < b->order_key (); } bool @@ -3858,7 +3883,7 @@ Session::update_locations_after_tempo_map_change (Locations::LocationList& loc) void Session::ensure_buffers (ChanCount howmany) { - BufferManager::ensure_buffers (howmany); + BufferManager::ensure_buffers (howmany, bounce_processing() ? bounce_chunk_size : 0); } void @@ -4099,7 +4124,7 @@ Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end, bool /*overwrite*/, vector >& srcs, InterThreadInfo& itt, boost::shared_ptr endpoint, bool include_endpoint, - bool for_export) + bool for_export, bool for_freeze) { boost::shared_ptr result; boost::shared_ptr playlist; @@ -4110,6 +4135,7 @@ Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end, framepos_t position; framecnt_t this_chunk; framepos_t to_do; + framepos_t latency_skip; BufferSet buffers; SessionDirectory sdir(get_best_session_directory_for_new_source ()); const string sound_dir = sdir.sound_path(); @@ -4124,12 +4150,28 @@ Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end, return result; } - const framecnt_t chunk_size = (256 * 1024)/4; + diskstream_channels = track.bounce_get_output_streams (diskstream_channels, endpoint, + include_endpoint, for_export, for_freeze); + + if (diskstream_channels.n_audio() < 1) { + error << _("Cannot write a range with no audio.") << endmsg; + return result; + } // block all process callback handling block_processing (); + { + // synchronize with AudioEngine::process_callback() + // make sure processing is not currently running + // and processing_blocked() is honored before + // acquiring thread buffers + Glib::Threads::Mutex::Lock lm (_engine.process_lock()); + } + + _bounce_processing_active = true; + /* call tree *MUST* hold route_lock */ if ((playlist = track.playlist()) == 0) { @@ -4171,13 +4213,17 @@ Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end, */ need_block_size_reset = true; - track.set_block_size (chunk_size); + track.set_block_size (bounce_chunk_size); + _engine.main_thread()->get_buffers (); position = start; to_do = len; + latency_skip = track.bounce_get_latency (endpoint, include_endpoint, for_export, for_freeze); /* create a set of reasonably-sized buffers */ - buffers.ensure_buffers (DataType::AUDIO, max_proc.n_audio(), chunk_size); + for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) { + buffers.ensure_buffers(*t, max_proc.get(*t), bounce_chunk_size); + } buffers.set_count (max_proc); for (vector >::iterator src = srcs.begin(); src != srcs.end(); ++src) { @@ -4188,28 +4234,56 @@ Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end, while (to_do && !itt.cancel) { - this_chunk = min (to_do, chunk_size); + this_chunk = min (to_do, bounce_chunk_size); - if (track.export_stuff (buffers, start, this_chunk, endpoint, include_endpoint, for_export)) { + if (track.export_stuff (buffers, start, this_chunk, endpoint, include_endpoint, for_export, for_freeze)) { goto out; } + start += this_chunk; + to_do -= this_chunk; + itt.progress = (float) (1.0 - ((double) to_do / len)); + + if (latency_skip >= bounce_chunk_size) { + latency_skip -= bounce_chunk_size; + continue; + } + + const framecnt_t current_chunk = this_chunk - latency_skip; + uint32_t n = 0; for (vector >::iterator src=srcs.begin(); src != srcs.end(); ++src, ++n) { boost::shared_ptr afs = boost::dynamic_pointer_cast(*src); if (afs) { - if (afs->write (buffers.get_audio(n).data(), this_chunk) != this_chunk) { + if (afs->write (buffers.get_audio(n).data(latency_skip), current_chunk) != current_chunk) { goto out; } } } + latency_skip = 0; + } - start += this_chunk; - to_do -= this_chunk; + /* post-roll, pick up delayed processor output */ + latency_skip = track.bounce_get_latency (endpoint, include_endpoint, for_export, for_freeze); - itt.progress = (float) (1.0 - ((double) to_do / len)); + while (latency_skip && !itt.cancel) { + this_chunk = min (latency_skip, bounce_chunk_size); + latency_skip -= this_chunk; + + buffers.silence (this_chunk, 0); + track.bounce_process (buffers, start, this_chunk, endpoint, include_endpoint, for_export, for_freeze); + + uint32_t n = 0; + for (vector >::iterator src=srcs.begin(); src != srcs.end(); ++src, ++n) { + boost::shared_ptr afs = boost::dynamic_pointer_cast(*src); + if (afs) { + if (afs->write (buffers.get_audio(n).data(), this_chunk) != this_chunk) { + goto out; + } + } + } } if (!itt.cancel) { @@ -4261,8 +4335,10 @@ Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end, } } + _bounce_processing_active = false; if (need_block_size_reset) { + _engine.main_thread()->drop_buffers (); track.set_block_size (get_block_size()); } @@ -4553,18 +4629,18 @@ Session::end_time_changed (framepos_t old) } } -string +std::vector Session::source_search_path (DataType type) const { - vector s; + Searchpath sp; if (session_dirs.size() == 1) { switch (type) { case DataType::AUDIO: - s.push_back (_session_dir->sound_path()); + sp.push_back (_session_dir->sound_path()); break; case DataType::MIDI: - s.push_back (_session_dir->midi_path()); + sp.push_back (_session_dir->midi_path()); break; } } else { @@ -4572,10 +4648,10 @@ Session::source_search_path (DataType type) const SessionDirectory sdir (i->path); switch (type) { case DataType::AUDIO: - s.push_back (sdir.sound_path()); + sp.push_back (sdir.sound_path()); break; case DataType::MIDI: - s.push_back (sdir.midi_path()); + sp.push_back (sdir.midi_path()); break; } } @@ -4584,49 +4660,30 @@ Session::source_search_path (DataType type) const 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)) { - if (find (s.begin(), s.end(), sound_path_2X) == s.end()) { - s.push_back (sound_path_2X); + if (find (sp.begin(), sp.end(), sound_path_2X) == sp.end()) { + sp.push_back (sound_path_2X); } } } - /* now check the explicit (possibly user-specified) search path - */ - - vector dirs; + // now check the explicit (possibly user-specified) search path switch (type) { case DataType::AUDIO: - split (config.get_audio_search_path (), dirs, ':'); + sp += Searchpath(config.get_audio_search_path ()); break; case DataType::MIDI: - split (config.get_midi_search_path (), dirs, ':'); + sp += Searchpath(config.get_midi_search_path ()); break; } - for (vector::iterator i = dirs.begin(); i != dirs.end(); ++i) { - if (find (s.begin(), s.end(), *i) == s.end()) { - s.push_back (*i); - } - } - - string search_path; - - for (vector::iterator si = s.begin(); si != s.end(); ++si) { - if (!search_path.empty()) { - search_path += ':'; - } - search_path += *si; - } - - return search_path; + return sp; } void Session::ensure_search_path_includes (const string& path, DataType type) { - string search_path; - vector dirs; + Searchpath sp; if (path == ".") { return; @@ -4634,16 +4691,14 @@ Session::ensure_search_path_includes (const string& path, DataType type) switch (type) { case DataType::AUDIO: - search_path = config.get_audio_search_path (); + sp += Searchpath(config.get_audio_search_path ()); break; case DataType::MIDI: - search_path = config.get_midi_search_path (); + sp += Searchpath (config.get_midi_search_path ()); break; } - split (search_path, dirs, ':'); - - for (vector::iterator i = dirs.begin(); i != dirs.end(); ++i) { + for (vector::iterator i = sp.begin(); i != sp.end(); ++i) { /* No need to add this new directory if it has the same inode as an existing one; checking inode rather than name prevents duplicated directories when we are using symlinks. @@ -4655,18 +4710,14 @@ Session::ensure_search_path_includes (const string& path, DataType type) } } - if (!search_path.empty()) { - search_path += ':'; - } - - search_path += path; + sp += path; switch (type) { case DataType::AUDIO: - config.set_audio_search_path (search_path); + config.set_audio_search_path (sp.to_string()); break; case DataType::MIDI: - config.set_midi_search_path (search_path); + config.set_midi_search_path (sp.to_string()); break; } } @@ -4928,8 +4979,7 @@ Session::notify_remote_id_change () } switch (Config->get_remote_model()) { - case MixerSort: - case EditorSort: + case MixerOrdered: Route::RemoteControlIDChange (); /* EMIT SIGNAL */ break; default: @@ -4938,7 +4988,7 @@ Session::notify_remote_id_change () } void -Session::sync_order_keys (RouteSortOrderKey sort_key_changed) +Session::sync_order_keys () { if (deletion_in_progress()) { return; @@ -4950,9 +5000,9 @@ Session::sync_order_keys (RouteSortOrderKey sort_key_changed) 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))); + DEBUG_TRACE (DEBUG::OrderKeys, "Sync Order Keys.\n"); - Route::SyncOrderKeys (sort_key_changed); /* EMIT SIGNAL */ + Route::SyncOrderKeys (); /* EMIT SIGNAL */ DEBUG_TRACE (DEBUG::OrderKeys, "\tsync done\n"); }