summaryrefslogtreecommitdiff
path: root/libs/ardour/session.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libs/ardour/session.cc')
-rw-r--r--libs/ardour/session.cc222
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");