diff options
Diffstat (limited to 'libs/ardour/session.cc')
-rw-r--r-- | libs/ardour/session.cc | 222 |
1 files changed, 163 insertions, 59 deletions
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 0e4a10f76b..ae39d7c468 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -39,14 +39,13 @@ #include "pbd/convert.h" #include "pbd/error.h" #include "pbd/boost_debug.h" -#include "pbd/pathscanner.h" #include "pbd/stl_delete.h" #include "pbd/basename.h" #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" @@ -69,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" @@ -82,6 +82,7 @@ #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" @@ -125,6 +126,7 @@ PBD::Signal0<void> Session::FeedbackDetected; PBD::Signal0<void> Session::SuccessfulGraphSort; PBD::Signal2<void,std::string,std::string> 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); @@ -137,6 +139,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) @@ -192,6 +195,8 @@ Session::Session (AudioEngine &eng, , state_tree (0) , state_was_pending (false) , _state_of_the_state (StateOfTheState(CannotSave|InitialConnecting|Loading)) + , _suspend_save (0) + , _save_queued (false) , _last_roll_location (0) , _last_roll_or_reversal_location (0) , _last_record_location (0) @@ -233,6 +238,7 @@ Session::Session (AudioEngine &eng, , routes (new RouteList) , _adding_routes_in_progress (false) , destructive_index (0) + , _track_number_decimals(1) , solo_update_disabled (false) , default_fade_steepness (0) , default_fade_msecs (0) @@ -261,6 +267,7 @@ Session::Session (AudioEngine &eng, , _speakers (new Speakers) , _order_hint (0) , ignore_route_processor_changes (false) + , _scene_changer (0) , _midi_ports (0) , _mmc (0) { @@ -294,6 +301,9 @@ Session::Session (AudioEngine &eng, throw failed_constructor (); } + /* load default session properties - if any */ + config.load_state(); + } else { if (load_state (_current_snapshot_name)) { @@ -491,6 +501,14 @@ Session::destroy () clear_clicks (); + /* need to remove auditioner before monitoring section + * otherwise it is re-connected */ + auditioner.reset (); + + /* drop references to routes held by the monitoring section + * specifically _monitor_out aux/listen references */ + remove_monitor_section(); + /* clear out any pending dead wood from RCU managed objects */ routes.flush (); @@ -510,7 +528,6 @@ Session::destroy () /* reset these three references to special routes before we do the usual route delete thing */ - auditioner.reset (); _master_out.reset (); _monitor_out.reset (); @@ -548,6 +565,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; @@ -1874,6 +1893,7 @@ Session::new_midi_track (const ChanCount& input, const ChanCount& output, boost: failed: if (!new_routes.empty()) { + StateProtector sp (this); add_routes (new_routes, true, true, true); if (instrument) { @@ -2115,6 +2135,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod failed: if (!new_routes.empty()) { + StateProtector sp (this); add_routes (new_routes, true, true, true); } @@ -2200,6 +2221,7 @@ Session::new_audio_route (int input_channels, int output_channels, RouteGroup* r failure: if (!ret.empty()) { + StateProtector sp (this); add_routes (ret, false, true, true); // autoconnect outputs only } @@ -2316,6 +2338,7 @@ Session::new_route_from_template (uint32_t how_many, const std::string& template out: if (!ret.empty()) { + StateProtector sp (this); add_routes (ret, true, true, true); IO::enable_connecting (); } @@ -2345,6 +2368,8 @@ Session::add_routes (RouteList& new_routes, bool input_auto_connect, bool output save_state (_current_snapshot_name); } + reassign_track_numbers(); + RouteAdded (new_routes); /* EMIT SIGNAL */ } @@ -2586,6 +2611,13 @@ Session::remove_route (boost::shared_ptr<Route> route) } } + /* 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); + } + boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (route); if (mt && mt->step_editing()) { if (_step_editors > 0) { @@ -2622,6 +2654,7 @@ Session::remove_route (boost::shared_ptr<Route> route) if (save_state (_current_snapshot_name)) { save_history (_current_snapshot_name); } + reassign_track_numbers(); } void @@ -3038,6 +3071,42 @@ Session::route_by_remote_id (uint32_t id) return boost::shared_ptr<Route> ((Route*) 0); } + +void +Session::reassign_track_numbers () +{ + int64_t tn = 0; + int64_t bn = 0; + RouteList r (*(routes.reader ())); + SignalOrderRouteSorter sorter; + r.sort (sorter); + + StateProtector sp (this); + + for (RouteList::iterator i = r.begin(); i != r.end(); ++i) { + if (boost::dynamic_pointer_cast<Track> (*i)) { + (*i)->set_track_number(++tn); + } + else if (!(*i)->is_master() && !(*i)->is_monitor() && !(*i)->is_auditioner()) { + (*i)->set_track_number(--bn); + } + } + const uint32_t decimals = ceilf (log10f (tn + 1)); + const bool decimals_changed = _track_number_decimals != decimals; + _track_number_decimals = decimals; + + if (decimals_changed && config.get_track_name_number ()) { + for (RouteList::iterator i = r.begin(); i != r.end(); ++i) { + boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*i); + if (t) { + t->resync_track_name(); + } + } + // trigger GUI re-layout + config.ParameterChanged("track-name-number"); + } +} + void Session::playlist_region_added (boost::weak_ptr<Region> w) { @@ -3681,6 +3750,9 @@ Session::audition_region (boost::shared_ptr<Region> r) void Session::cancel_audition () { + if (!auditioner) { + return; + } if (auditioner->auditioning()) { auditioner->cancel_audition (); AuditionActive (false); /* EMIT SIGNAL */ @@ -3863,7 +3935,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 @@ -4104,7 +4176,7 @@ Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end, bool /*overwrite*/, vector<boost::shared_ptr<Source> >& srcs, InterThreadInfo& itt, boost::shared_ptr<Processor> endpoint, bool include_endpoint, - bool for_export) + bool for_export, bool for_freeze) { boost::shared_ptr<Region> result; boost::shared_ptr<Playlist> playlist; @@ -4113,10 +4185,13 @@ 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; framepos_t len = end - start; bool need_block_size_reset = false; ChanCount const max_proc = track.max_processor_streams (); + string legal_playlist_name; + string possible_path; if (end <= start) { error << string_compose (_("Cannot write a range where end <= start (e.g. %1 <= %2)"), @@ -4124,22 +4199,40 @@ 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) { goto out; } + legal_playlist_name = legalize_for_path (playlist->name()); + for (uint32_t chan_n = 0; chan_n < diskstream_channels.n_audio(); ++chan_n) { string base_name = string_compose ("%1-%2-bounce", playlist->name(), chan_n); - string path = new_audio_source_path (base_name, diskstream_channels.n_audio(), chan_n, false, true); + string path = new_audio_source_path (legal_playlist_name, diskstream_channels.n_audio(), chan_n, false, true); if (path.empty()) { goto out; @@ -4164,13 +4257,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<boost::shared_ptr<Source> >::iterator src = srcs.begin(); src != srcs.end(); ++src) { @@ -4181,28 +4278,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<boost::shared_ptr<Source> >::iterator src=srcs.begin(); src != srcs.end(); ++src, ++n) { boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*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<boost::shared_ptr<Source> >::iterator src=srcs.begin(); src != srcs.end(); ++src, ++n) { + boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*src); + + if (afs) { + if (afs->write (buffers.get_audio(n).data(), this_chunk) != this_chunk) { + goto out; + } + } + } } if (!itt.cancel) { @@ -4254,8 +4379,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()); } @@ -4546,18 +4673,18 @@ Session::end_time_changed (framepos_t old) } } -string +std::vector<std::string> Session::source_search_path (DataType type) const { - vector<string> 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 { @@ -4565,10 +4692,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; } } @@ -4577,49 +4704,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<string> 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<string>::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<string>::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<string> dirs; + Searchpath sp; if (path == ".") { return; @@ -4627,16 +4735,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<string>::iterator i = dirs.begin(); i != dirs.end(); ++i) { + for (vector<std::string>::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. @@ -4648,18 +4754,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; } } @@ -4944,6 +5046,8 @@ Session::sync_order_keys () DEBUG_TRACE (DEBUG::OrderKeys, "Sync Order Keys.\n"); + reassign_track_numbers(); + Route::SyncOrderKeys (); /* EMIT SIGNAL */ DEBUG_TRACE (DEBUG::OrderKeys, "\tsync done\n"); |