Fix restoration of connections to control surface ports.
[ardour2.git] / libs / ardour / session_state.cc
blob00523ad933b75df743858dbdb7856345fce0d6e4
1 /*
2 Copyright (C) 1999-2002 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #ifdef WAF_BUILD
22 #include "libardour-config.h"
23 #endif
25 #include <stdint.h>
27 #include <algorithm>
28 #include <fstream>
29 #include <string>
30 #include <cerrno>
33 #include <cstdio> /* snprintf(3) ... grrr */
34 #include <cmath>
35 #include <unistd.h>
36 #include <sys/stat.h>
37 #include <climits>
38 #include <fcntl.h>
39 #include <poll.h>
40 #include <signal.h>
41 #include <sys/mman.h>
42 #include <sys/time.h>
44 #ifdef HAVE_SYS_VFS_H
45 #include <sys/vfs.h>
46 #else
47 #include <sys/param.h>
48 #include <sys/mount.h>
49 #endif
51 #include <glibmm.h>
52 #include <glibmm/thread.h>
54 #include "midi++/mmc.h"
55 #include "midi++/port.h"
56 #include "midi++/manager.h"
58 #include "pbd/boost_debug.h"
59 #include "pbd/basename.h"
60 #include "pbd/controllable_descriptor.h"
61 #include "pbd/enumwriter.h"
62 #include "pbd/error.h"
63 #include "pbd/pathscanner.h"
64 #include "pbd/pthread_utils.h"
65 #include "pbd/search_path.h"
66 #include "pbd/stacktrace.h"
67 #include "pbd/convert.h"
68 #include "pbd/clear_dir.h"
70 #include "ardour/amp.h"
71 #include "ardour/audio_diskstream.h"
72 #include "ardour/audio_track.h"
73 #include "ardour/audioengine.h"
74 #include "ardour/audiofilesource.h"
75 #include "ardour/audioplaylist.h"
76 #include "ardour/audioregion.h"
77 #include "ardour/auditioner.h"
78 #include "ardour/automation_control.h"
79 #include "ardour/buffer.h"
80 #include "ardour/butler.h"
81 #include "ardour/configuration.h"
82 #include "ardour/control_protocol_manager.h"
83 #include "ardour/crossfade.h"
84 #include "ardour/cycle_timer.h"
85 #include "ardour/directory_names.h"
86 #include "ardour/filename_extensions.h"
87 #include "ardour/io_processor.h"
88 #include "ardour/location.h"
89 #include "ardour/midi_diskstream.h"
90 #include "ardour/midi_patch_manager.h"
91 #include "ardour/midi_playlist.h"
92 #include "ardour/midi_region.h"
93 #include "ardour/midi_source.h"
94 #include "ardour/midi_track.h"
95 #include "ardour/named_selection.h"
96 #include "ardour/pannable.h"
97 #include "ardour/processor.h"
98 #include "ardour/port.h"
99 #include "ardour/proxy_controllable.h"
100 #include "ardour/region_factory.h"
101 #include "ardour/route_group.h"
102 #include "ardour/send.h"
103 #include "ardour/session.h"
104 #include "ardour/session_directory.h"
105 #include "ardour/session_metadata.h"
106 #include "ardour/session_state_utils.h"
107 #include "ardour/session_playlists.h"
108 #include "ardour/session_utils.h"
109 #include "ardour/silentfilesource.h"
110 #include "ardour/slave.h"
111 #include "ardour/smf_source.h"
112 #include "ardour/sndfile_helpers.h"
113 #include "ardour/sndfilesource.h"
114 #include "ardour/source_factory.h"
115 #include "ardour/template_utils.h"
116 #include "ardour/tempo.h"
117 #include "ardour/ticker.h"
118 #include "ardour/user_bundle.h"
119 #include "ardour/utils.h"
120 #include "ardour/utils.h"
121 #include "ardour/version.h"
122 #include "ardour/playlist_factory.h"
124 #include "control_protocol/control_protocol.h"
126 #include "i18n.h"
127 #include <locale.h>
129 using namespace std;
130 using namespace ARDOUR;
131 using namespace PBD;
134 void
135 Session::first_stage_init (string fullpath, string snapshot_name)
137 if (fullpath.length() == 0) {
138 destroy ();
139 throw failed_constructor();
142 char buf[PATH_MAX+1];
143 if (!realpath (fullpath.c_str(), buf) && (errno != ENOENT)) {
144 error << string_compose(_("Could not use path %1 (%s)"), buf, strerror(errno)) << endmsg;
145 destroy ();
146 throw failed_constructor();
149 _path = string(buf);
151 if (_path[_path.length()-1] != G_DIR_SEPARATOR) {
152 _path += G_DIR_SEPARATOR;
155 /* these two are just provisional settings. set_state()
156 will likely override them.
159 _name = _current_snapshot_name = snapshot_name;
161 set_history_depth (Config->get_history_depth());
163 _current_frame_rate = _engine.frame_rate ();
164 _nominal_frame_rate = _current_frame_rate;
165 _base_frame_rate = _current_frame_rate;
167 _tempo_map = new TempoMap (_current_frame_rate);
168 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
171 _non_soloed_outs_muted = false;
172 _listen_cnt = 0;
173 _solo_isolated_cnt = 0;
174 g_atomic_int_set (&processing_prohibited, 0);
175 _transport_speed = 0;
176 _last_transport_speed = 0;
177 _target_transport_speed = 0;
178 auto_play_legal = false;
179 transport_sub_state = 0;
180 _transport_frame = 0;
181 _requested_return_frame = -1;
182 _session_range_location = 0;
183 g_atomic_int_set (&_record_status, Disabled);
184 loop_changing = false;
185 play_loop = false;
186 have_looped = false;
187 _last_roll_location = 0;
188 _last_roll_or_reversal_location = 0;
189 _last_record_location = 0;
190 pending_locate_frame = 0;
191 pending_locate_roll = false;
192 pending_locate_flush = false;
193 state_was_pending = false;
194 set_next_event ();
195 outbound_mtc_timecode_frame = 0;
196 next_quarter_frame_to_send = -1;
197 current_block_size = 0;
198 solo_update_disabled = false;
199 _have_captured = false;
200 _worst_output_latency = 0;
201 _worst_input_latency = 0;
202 _worst_track_latency = 0;
203 _state_of_the_state = StateOfTheState(CannotSave|InitialConnecting|Loading);
204 _was_seamless = Config->get_seamless_loop ();
205 _slave = 0;
206 _send_qf_mtc = false;
207 _pframes_since_last_mtc = 0;
208 g_atomic_int_set (&_playback_load, 100);
209 g_atomic_int_set (&_capture_load, 100);
210 _play_range = false;
211 _exporting = false;
212 pending_abort = false;
213 destructive_index = 0;
214 first_file_data_format_reset = true;
215 first_file_header_format_reset = true;
216 post_export_sync = false;
217 midi_control_ui = 0;
218 _step_editors = 0;
219 no_questions_about_missing_files = false;
220 _speakers.reset (new Speakers);
222 AudioDiskstream::allocate_working_buffers();
224 /* default short fade = 15ms */
226 Crossfade::set_short_xfade_length ((framecnt_t) floor (config.get_short_xfade_seconds() * frame_rate()));
227 SndFileSource::setup_standard_crossfades (*this, frame_rate());
229 last_mmc_step.tv_sec = 0;
230 last_mmc_step.tv_usec = 0;
231 step_speed = 0.0;
233 /* click sounds are unset by default, which causes us to internal
234 waveforms for clicks.
237 click_length = 0;
238 click_emphasis_length = 0;
239 _clicking = false;
241 process_function = &Session::process_with_events;
243 if (config.get_use_video_sync()) {
244 waiting_for_sync_offset = true;
245 } else {
246 waiting_for_sync_offset = false;
249 last_timecode_when = 0;
250 last_timecode_valid = false;
252 sync_time_vars ();
254 last_rr_session_dir = session_dirs.begin();
255 refresh_disk_space ();
257 /* default: assume simple stereo speaker configuration */
259 _speakers->setup_default_speakers (2);
261 /* slave stuff */
263 average_slave_delta = 1800; // !!! why 1800 ????
264 have_first_delta_accumulator = false;
265 delta_accumulator_cnt = 0;
266 _slave_state = Stopped;
268 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
269 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
270 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
271 add_controllable (_solo_cut_control);
273 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
275 /* These are all static "per-class" signals */
277 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
278 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
279 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
280 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
281 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
283 /* stop IO objects from doing stuff until we're ready for them */
285 Delivery::disable_panners ();
286 IO::disable_connecting ();
290 Session::second_stage_init ()
292 AudioFileSource::set_peak_dir (_session_dir->peak_path().to_string());
294 if (!_is_new) {
295 if (load_state (_current_snapshot_name)) {
296 return -1;
300 if (_butler->start_thread()) {
301 return -1;
304 if (start_midi_thread ()) {
305 return -1;
308 setup_midi_machine_control ();
310 // set_state() will call setup_raid_path(), but if it's a new session we need
311 // to call setup_raid_path() here.
313 if (state_tree) {
314 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
315 return -1;
317 } else {
318 setup_raid_path(_path);
321 /* we can't save till after ::when_engine_running() is called,
322 because otherwise we save state with no connections made.
323 therefore, we reset _state_of_the_state because ::set_state()
324 will have cleared it.
326 we also have to include Loading so that any events that get
327 generated between here and the end of ::when_engine_running()
328 will be processed directly rather than queued.
331 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave|Loading);
333 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
334 _locations->added.connect_same_thread (*this, boost::bind (&Session::locations_added, this, _1));
335 setup_click_sounds (0);
336 setup_midi_control ();
338 /* Pay attention ... */
340 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
341 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
343 try {
344 when_engine_running ();
347 /* handle this one in a different way than all others, so that its clear what happened */
349 catch (AudioEngine::PortRegistrationFailure& err) {
350 error << err.what() << endmsg;
351 return -1;
354 catch (...) {
355 return -1;
358 BootMessage (_("Reset Remote Controls"));
360 send_full_time_code (0);
361 _engine.transport_locate (0);
363 MIDI::Manager::instance()->mmc()->send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
364 MIDI::Manager::instance()->mmc()->send (MIDI::MachineControlCommand (Timecode::Time ()));
366 MidiClockTicker::instance().set_session (this);
367 MIDI::Name::MidiPatchManager::instance().set_session (this);
369 /* initial program change will be delivered later; see ::config_changed() */
371 _state_of_the_state = Clean;
373 Port::set_connecting_blocked (false);
375 DirtyChanged (); /* EMIT SIGNAL */
377 if (state_was_pending) {
378 save_state (_current_snapshot_name);
379 remove_pending_capture_state ();
380 state_was_pending = false;
383 BootMessage (_("Session loading complete"));
385 return 0;
388 string
389 Session::raid_path () const
391 SearchPath raid_search_path;
393 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
394 raid_search_path += sys::path((*i).path);
397 return raid_search_path.to_string ();
400 void
401 Session::setup_raid_path (string path)
403 if (path.empty()) {
404 return;
407 space_and_path sp;
408 string fspath;
410 session_dirs.clear ();
412 SearchPath search_path(path);
413 SearchPath sound_search_path;
414 SearchPath midi_search_path;
416 for (SearchPath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
417 sp.path = (*i).to_string ();
418 sp.blocks = 0; // not needed
419 session_dirs.push_back (sp);
421 SessionDirectory sdir(sp.path);
423 sound_search_path += sdir.sound_path ();
424 midi_search_path += sdir.midi_path ();
427 // reset the round-robin soundfile path thingie
428 last_rr_session_dir = session_dirs.begin();
431 bool
432 Session::path_is_within_session (const std::string& path)
434 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
435 if (path.find ((*i).path) == 0) {
436 return true;
439 return false;
443 Session::ensure_subdirs ()
445 string dir;
447 dir = session_directory().peak_path().to_string();
449 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
450 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
451 return -1;
454 dir = session_directory().sound_path().to_string();
456 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
457 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
458 return -1;
461 dir = session_directory().midi_path().to_string();
463 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
464 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
465 return -1;
468 dir = session_directory().dead_path().to_string();
470 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
471 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
472 return -1;
475 dir = session_directory().export_path().to_string();
477 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
478 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
479 return -1;
482 dir = analysis_dir ();
484 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
485 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
486 return -1;
489 dir = plugins_dir ();
491 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
492 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
493 return -1;
496 return 0;
499 /** Caller must not hold process lock */
501 Session::create (const string& mix_template, BusProfile* bus_profile)
503 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
504 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
505 return -1;
508 if (ensure_subdirs ()) {
509 return -1;
512 _writable = exists_and_writable (sys::path (_path));
514 if (!mix_template.empty()) {
515 std::string in_path = mix_template;
517 ifstream in(in_path.c_str());
519 if (in) {
520 string out_path = _path;
521 out_path += _name;
522 out_path += statefile_suffix;
524 ofstream out(out_path.c_str());
526 if (out) {
527 out << in.rdbuf();
528 _is_new = false;
529 return 0;
531 } else {
532 error << string_compose (_("Could not open %1 for writing mix template"), out_path)
533 << endmsg;
534 return -1;
537 } else {
538 error << string_compose (_("Could not open mix template %1 for reading"), in_path)
539 << endmsg;
540 return -1;
545 /* Instantiate metadata */
547 _metadata = new SessionMetadata ();
549 /* set initial start + end point */
551 _state_of_the_state = Clean;
553 /* set up Master Out and Control Out if necessary */
555 if (bus_profile) {
557 RouteList rl;
558 int control_id = 1;
559 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
561 if (bus_profile->master_out_channels) {
562 boost::shared_ptr<Route> r (new Route (*this, _("master"), Route::MasterOut, DataType::AUDIO));
563 if (r->init ()) {
564 return -1;
566 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
567 boost_debug_shared_ptr_mark_interesting (rt.get(), "Route");
568 #endif
570 Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
571 r->input()->ensure_io (count, false, this);
572 r->output()->ensure_io (count, false, this);
574 r->set_remote_control_id (control_id++);
576 rl.push_back (r);
578 if (Config->get_use_monitor_bus()) {
579 boost::shared_ptr<Route> r (new Route (*this, _("monitor"), Route::MonitorOut, DataType::AUDIO));
580 if (r->init ()) {
581 return -1;
583 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
584 boost_debug_shared_ptr_mark_interesting (rt, "Route");
585 #endif
587 Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
588 r->input()->ensure_io (count, false, this);
589 r->output()->ensure_io (count, false, this);
591 r->set_remote_control_id (control_id);
593 rl.push_back (r);
596 } else {
597 /* prohibit auto-connect to master, because there isn't one */
598 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
601 if (!rl.empty()) {
602 add_routes (rl, false, false);
605 /* this allows the user to override settings with an environment variable.
608 if (no_auto_connect()) {
609 bus_profile->input_ac = AutoConnectOption (0);
610 bus_profile->output_ac = AutoConnectOption (0);
613 Config->set_input_auto_connect (bus_profile->input_ac);
614 Config->set_output_auto_connect (bus_profile->output_ac);
617 save_state ("");
619 return 0;
622 void
623 Session::maybe_write_autosave()
625 if (dirty() && record_status() != Recording) {
626 save_state("", true);
630 void
631 Session::remove_pending_capture_state ()
633 sys::path pending_state_file_path(_session_dir->root_path());
635 pending_state_file_path /= legalize_for_path (_current_snapshot_name) + pending_suffix;
639 sys::remove (pending_state_file_path);
641 catch(sys::filesystem_error& ex)
643 error << string_compose(_("Could remove pending capture state at path \"%1\" (%2)"),
644 pending_state_file_path.to_string(), ex.what()) << endmsg;
648 /** Rename a state file.
649 * @param snapshot_name Snapshot name.
651 void
652 Session::rename_state (string old_name, string new_name)
654 if (old_name == _current_snapshot_name || old_name == _name) {
655 /* refuse to rename the current snapshot or the "main" one */
656 return;
659 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
660 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
662 const sys::path old_xml_path = _session_dir->root_path() / old_xml_filename;
663 const sys::path new_xml_path = _session_dir->root_path() / new_xml_filename;
667 sys::rename (old_xml_path, new_xml_path);
669 catch (const sys::filesystem_error& err)
671 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
672 old_name, new_name, err.what()) << endmsg;
676 /** Remove a state file.
677 * @param snapshot_name Snapshot name.
679 void
680 Session::remove_state (string snapshot_name)
682 if (snapshot_name == _current_snapshot_name || snapshot_name == _name) {
683 // refuse to remove the current snapshot or the "main" one
684 return;
687 sys::path xml_path(_session_dir->root_path());
689 xml_path /= legalize_for_path (snapshot_name) + statefile_suffix;
691 if (!create_backup_file (xml_path)) {
692 // don't remove it if a backup can't be made
693 // create_backup_file will log the error.
694 return;
697 // and delete it
698 sys::remove (xml_path);
701 #ifdef HAVE_JACK_SESSION
702 void
703 Session::jack_session_event (jack_session_event_t * event)
705 char timebuf[128];
706 time_t n;
707 struct tm local_time;
709 time (&n);
710 localtime_r (&n, &local_time);
711 strftime (timebuf, sizeof(timebuf), "JS_%FT%T", &local_time);
713 if (event->type == JackSessionSaveTemplate)
715 if (save_template( timebuf )) {
716 event->flags = JackSessionSaveError;
717 } else {
718 string cmd ("ardour3 -P -U ");
719 cmd += event->client_uuid;
720 cmd += " -T ";
721 cmd += timebuf;
723 event->command_line = strdup (cmd.c_str());
726 else
728 if (save_state (timebuf)) {
729 event->flags = JackSessionSaveError;
730 } else {
731 sys::path xml_path (_session_dir->root_path());
732 xml_path /= legalize_for_path (timebuf) + statefile_suffix;
734 string cmd ("ardour3 -P -U ");
735 cmd += event->client_uuid;
736 cmd += " \"";
737 cmd += xml_path.to_string();
738 cmd += '\"';
740 event->command_line = strdup (cmd.c_str());
744 jack_session_reply (_engine.jack(), event);
746 if (event->type == JackSessionSaveAndQuit) {
747 Quit (); /* EMIT SIGNAL */
750 jack_session_event_free( event );
752 #endif
754 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
756 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot)
758 XMLTree tree;
759 sys::path xml_path(_session_dir->root_path());
761 if (!_writable || (_state_of_the_state & CannotSave)) {
762 return 1;
765 if (!_engine.connected ()) {
766 error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"),
767 PROGRAM_NAME)
768 << endmsg;
769 return 1;
772 /* tell sources we're saving first, in case they write out to a new file
773 * which should be saved with the state rather than the old one */
774 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
775 i->second->session_saved();
778 tree.set_root (&get_state());
780 if (snapshot_name.empty()) {
781 snapshot_name = _current_snapshot_name;
782 } else if (switch_to_snapshot) {
783 _current_snapshot_name = snapshot_name;
786 if (!pending) {
788 /* proper save: use statefile_suffix (.ardour in English) */
790 xml_path /= legalize_for_path (snapshot_name) + statefile_suffix;
792 /* make a backup copy of the old file */
794 if (sys::exists(xml_path) && !create_backup_file (xml_path)) {
795 // create_backup_file will log the error
796 return -1;
799 } else {
801 /* pending save: use pending_suffix (.pending in English) */
802 xml_path /= legalize_for_path (snapshot_name) + pending_suffix;
805 sys::path tmp_path(_session_dir->root_path());
807 tmp_path /= legalize_for_path (snapshot_name) + temp_suffix;
809 // cerr << "actually writing state to " << xml_path.to_string() << endl;
811 if (!tree.write (tmp_path.to_string())) {
812 error << string_compose (_("state could not be saved to %1"), tmp_path.to_string()) << endmsg;
813 sys::remove (tmp_path);
814 return -1;
816 } else {
818 if (rename (tmp_path.to_string().c_str(), xml_path.to_string().c_str()) != 0) {
819 error << string_compose (_("could not rename temporary session file %1 to %2"),
820 tmp_path.to_string(), xml_path.to_string()) << endmsg;
821 sys::remove (tmp_path);
822 return -1;
826 if (!pending) {
828 save_history (snapshot_name);
830 bool was_dirty = dirty();
832 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
834 if (was_dirty) {
835 DirtyChanged (); /* EMIT SIGNAL */
838 StateSaved (snapshot_name); /* EMIT SIGNAL */
841 return 0;
845 Session::restore_state (string snapshot_name)
847 if (load_state (snapshot_name) == 0) {
848 set_state (*state_tree->root(), Stateful::loading_state_version);
851 return 0;
855 Session::load_state (string snapshot_name)
857 delete state_tree;
858 state_tree = 0;
860 state_was_pending = false;
862 /* check for leftover pending state from a crashed capture attempt */
864 sys::path xmlpath(_session_dir->root_path());
865 xmlpath /= legalize_for_path (snapshot_name) + pending_suffix;
867 if (sys::exists (xmlpath)) {
869 /* there is pending state from a crashed capture attempt */
871 boost::optional<int> r = AskAboutPendingState();
872 if (r.get_value_or (1)) {
873 state_was_pending = true;
877 if (!state_was_pending) {
878 xmlpath = _session_dir->root_path();
879 xmlpath /= snapshot_name;
882 if (!sys::exists (xmlpath)) {
883 xmlpath = _session_dir->root_path();
884 xmlpath /= legalize_for_path (snapshot_name) + statefile_suffix;
885 if (!sys::exists (xmlpath)) {
886 error << string_compose(_("%1: session state information file \"%2\" doesn't exist!"), _name, xmlpath.to_string()) << endmsg;
887 return 1;
891 state_tree = new XMLTree;
893 set_dirty();
895 _writable = exists_and_writable (xmlpath);
897 if (!state_tree->read (xmlpath.to_string())) {
898 error << string_compose(_("Could not understand ardour file %1"), xmlpath.to_string()) << endmsg;
899 delete state_tree;
900 state_tree = 0;
901 return -1;
904 XMLNode& root (*state_tree->root());
906 if (root.name() != X_("Session")) {
907 error << string_compose (_("Session file %1 is not a session"), xmlpath.to_string()) << endmsg;
908 delete state_tree;
909 state_tree = 0;
910 return -1;
913 const XMLProperty* prop;
915 if ((prop = root.property ("version")) == 0) {
916 /* no version implies very old version of Ardour */
917 Stateful::loading_state_version = 1000;
918 } else {
919 int major;
920 int minor;
921 int micro;
923 sscanf (prop->value().c_str(), "%d.%d.%d", &major, &minor, &micro);
924 Stateful::loading_state_version = (major * 1000) + minor;
927 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION) {
929 sys::path backup_path(_session_dir->root_path());
931 backup_path /= legalize_for_path (snapshot_name) + "-1" + statefile_suffix;
933 // only create a backup once
934 if (sys::exists (backup_path)) {
935 return 0;
938 info << string_compose (_("Copying old session file %1 to %2\nUse %2 with %3 versions before 2.0 from now on"),
939 xmlpath.to_string(), backup_path.to_string(), PROGRAM_NAME)
940 << endmsg;
944 sys::copy_file (xmlpath, backup_path);
946 catch(sys::filesystem_error& ex)
948 error << string_compose (_("Unable to make backup of state file %1 (%2)"),
949 xmlpath.to_string(), ex.what())
950 << endmsg;
951 return -1;
955 return 0;
959 Session::load_options (const XMLNode& node)
961 LocaleGuard lg (X_("POSIX"));
962 config.set_variables (node);
963 return 0;
966 XMLNode&
967 Session::get_state()
969 return state(true);
972 XMLNode&
973 Session::get_template()
975 /* if we don't disable rec-enable, diskstreams
976 will believe they need to store their capture
977 sources in their state node.
980 disable_record (false);
982 return state(false);
985 XMLNode&
986 Session::state(bool full_state)
988 XMLNode* node = new XMLNode("Session");
989 XMLNode* child;
991 // store libardour version, just in case
992 char buf[16];
993 snprintf(buf, sizeof(buf), "%d.%d.%d", libardour3_major_version, libardour3_minor_version, libardour3_micro_version);
994 node->add_property("version", string(buf));
996 /* store configuration settings */
998 if (full_state) {
1000 node->add_property ("name", _name);
1001 snprintf (buf, sizeof (buf), "%" PRId64, _nominal_frame_rate);
1002 node->add_property ("sample-rate", buf);
1004 if (session_dirs.size() > 1) {
1006 string p;
1008 vector<space_and_path>::iterator i = session_dirs.begin();
1009 vector<space_and_path>::iterator next;
1011 ++i; /* skip the first one */
1012 next = i;
1013 ++next;
1015 while (i != session_dirs.end()) {
1017 p += (*i).path;
1019 if (next != session_dirs.end()) {
1020 p += ':';
1021 } else {
1022 break;
1025 ++next;
1026 ++i;
1029 child = node->add_child ("Path");
1030 child->add_content (p);
1034 /* save the ID counter */
1036 snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter());
1037 node->add_property ("id-counter", buf);
1039 /* save the event ID counter */
1041 snprintf (buf, sizeof (buf), "%d", Evoral::event_id_counter());
1042 node->add_property ("event-counter", buf);
1044 /* various options */
1046 node->add_child_nocopy (config.get_variables ());
1048 node->add_child_nocopy (_metadata->get_state());
1050 child = node->add_child ("Sources");
1052 if (full_state) {
1053 Glib::Mutex::Lock sl (source_lock);
1055 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1057 /* Don't save information about non-destructive file sources that are empty
1058 and unused by any regions.
1061 boost::shared_ptr<FileSource> fs;
1062 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
1063 if (!fs->destructive()) {
1064 if (fs->empty() && !fs->used()) {
1065 continue;
1070 child->add_child_nocopy (siter->second->get_state());
1074 child = node->add_child ("Regions");
1076 if (full_state) {
1077 Glib::Mutex::Lock rl (region_lock);
1078 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1079 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1080 boost::shared_ptr<Region> r = i->second;
1081 /* only store regions not attached to playlists */
1082 if (r->playlist() == 0) {
1083 child->add_child_nocopy (r->state ());
1088 if (full_state) {
1089 node->add_child_nocopy (_locations->get_state());
1090 } else {
1091 // for a template, just create a new Locations, populate it
1092 // with the default start and end, and get the state for that.
1093 Locations loc (*this);
1094 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange);
1095 range->set (max_framepos, 0);
1096 loc.add (range);
1097 node->add_child_nocopy (loc.get_state());
1100 child = node->add_child ("Bundles");
1102 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1103 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1104 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1105 if (b) {
1106 child->add_child_nocopy (b->get_state());
1111 child = node->add_child ("Routes");
1113 boost::shared_ptr<RouteList> r = routes.reader ();
1115 RoutePublicOrderSorter cmp;
1116 RouteList public_order (*r);
1117 public_order.sort (cmp);
1119 /* the sort should have put control outs first */
1121 if (_monitor_out) {
1122 assert (_monitor_out == public_order.front());
1125 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1126 if (!(*i)->is_hidden()) {
1127 if (full_state) {
1128 child->add_child_nocopy ((*i)->get_state());
1129 } else {
1130 child->add_child_nocopy ((*i)->get_template());
1136 playlists->add_state (node, full_state);
1138 child = node->add_child ("RouteGroups");
1139 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1140 child->add_child_nocopy ((*i)->get_state());
1143 if (_click_io) {
1144 child = node->add_child ("Click");
1145 child->add_child_nocopy (_click_io->state (full_state));
1148 if (full_state) {
1149 child = node->add_child ("NamedSelections");
1150 for (NamedSelectionList::iterator i = named_selections.begin(); i != named_selections.end(); ++i) {
1151 if (full_state) {
1152 child->add_child_nocopy ((*i)->get_state());
1157 node->add_child_nocopy (_speakers->get_state());
1158 node->add_child_nocopy (_tempo_map->get_state());
1159 node->add_child_nocopy (get_control_protocol_state());
1161 if (_extra_xml) {
1162 node->add_child_copy (*_extra_xml);
1165 return *node;
1168 XMLNode&
1169 Session::get_control_protocol_state ()
1171 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1172 return cpm.get_state();
1176 Session::set_state (const XMLNode& node, int version)
1178 XMLNodeList nlist;
1179 XMLNode* child;
1180 const XMLProperty* prop;
1181 int ret = -1;
1183 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1185 if (node.name() != X_("Session")) {
1186 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1187 return -1;
1190 if ((prop = node.property ("version")) != 0) {
1191 version = atoi (prop->value ()) * 1000;
1194 if ((prop = node.property ("name")) != 0) {
1195 _name = prop->value ();
1198 if ((prop = node.property (X_("sample-rate"))) != 0) {
1200 _nominal_frame_rate = atoi (prop->value());
1202 if (_nominal_frame_rate != _current_frame_rate) {
1203 boost::optional<int> r = AskAboutSampleRateMismatch (_nominal_frame_rate, _current_frame_rate);
1204 if (r.get_value_or (0)) {
1205 return -1;
1210 setup_raid_path(_session_dir->root_path().to_string());
1212 if ((prop = node.property (X_("id-counter"))) != 0) {
1213 uint64_t x;
1214 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1215 ID::init_counter (x);
1216 } else {
1217 /* old sessions used a timebased counter, so fake
1218 the startup ID counter based on a standard
1219 timestamp.
1221 time_t now;
1222 time (&now);
1223 ID::init_counter (now);
1226 if ((prop = node.property (X_("event-counter"))) != 0) {
1227 Evoral::init_event_id_counter (atoi (prop->value()));
1230 IO::disable_connecting ();
1232 if ((child = find_named_node (node, "Extra")) != 0) {
1233 _extra_xml = new XMLNode (*child);
1236 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1237 load_options (*child);
1238 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1239 load_options (*child);
1240 } else {
1241 error << _("Session: XML state has no options section") << endmsg;
1244 if (version >= 3000) {
1245 if ((child = find_named_node (node, "Metadata")) == 0) {
1246 warning << _("Session: XML state has no metadata section") << endmsg;
1247 } else if (_metadata->set_state (*child, version)) {
1248 goto out;
1252 if ((child = find_named_node (node, "Locations")) == 0) {
1253 error << _("Session: XML state has no locations section") << endmsg;
1254 goto out;
1255 } else if (_locations->set_state (*child, version)) {
1256 goto out;
1259 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1260 _speakers->set_state (*child, version);
1263 Location* location;
1265 if ((location = _locations->auto_loop_location()) != 0) {
1266 set_auto_loop_location (location);
1269 if ((location = _locations->auto_punch_location()) != 0) {
1270 set_auto_punch_location (location);
1273 if ((location = _locations->session_range_location()) != 0) {
1274 delete _session_range_location;
1275 _session_range_location = location;
1278 if (_session_range_location) {
1279 AudioFileSource::set_header_position_offset (_session_range_location->start());
1282 if ((child = find_named_node (node, "Sources")) == 0) {
1283 error << _("Session: XML state has no sources section") << endmsg;
1284 goto out;
1285 } else if (load_sources (*child)) {
1286 goto out;
1289 if ((child = find_named_node (node, "TempoMap")) == 0) {
1290 error << _("Session: XML state has no Tempo Map section") << endmsg;
1291 goto out;
1292 } else if (_tempo_map->set_state (*child, version)) {
1293 goto out;
1296 if ((child = find_named_node (node, "Regions")) == 0) {
1297 error << _("Session: XML state has no Regions section") << endmsg;
1298 goto out;
1299 } else if (load_regions (*child)) {
1300 goto out;
1303 if ((child = find_named_node (node, "Playlists")) == 0) {
1304 error << _("Session: XML state has no playlists section") << endmsg;
1305 goto out;
1306 } else if (playlists->load (*this, *child)) {
1307 goto out;
1310 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1311 // this is OK
1312 } else if (playlists->load_unused (*this, *child)) {
1313 goto out;
1316 if ((child = find_named_node (node, "NamedSelections")) != 0) {
1317 if (load_named_selections (*child)) {
1318 goto out;
1322 if (version >= 3000) {
1323 if ((child = find_named_node (node, "Bundles")) == 0) {
1324 warning << _("Session: XML state has no bundles section") << endmsg;
1325 //goto out;
1326 } else {
1327 /* We can't load Bundles yet as they need to be able
1328 to convert from port names to Port objects, which can't happen until
1329 later */
1330 _bundle_xml_node = new XMLNode (*child);
1334 if (version < 3000) {
1335 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1336 error << _("Session: XML state has no diskstreams section") << endmsg;
1337 goto out;
1338 } else if (load_diskstreams_2X (*child, version)) {
1339 goto out;
1343 if ((child = find_named_node (node, "Routes")) == 0) {
1344 error << _("Session: XML state has no routes section") << endmsg;
1345 goto out;
1346 } else if (load_routes (*child, version)) {
1347 goto out;
1350 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1351 _diskstreams_2X.clear ();
1353 if (version >= 3000) {
1355 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1356 error << _("Session: XML state has no route groups section") << endmsg;
1357 goto out;
1358 } else if (load_route_groups (*child, version)) {
1359 goto out;
1362 } else if (version < 3000) {
1364 if ((child = find_named_node (node, "EditGroups")) == 0) {
1365 error << _("Session: XML state has no edit groups section") << endmsg;
1366 goto out;
1367 } else if (load_route_groups (*child, version)) {
1368 goto out;
1371 if ((child = find_named_node (node, "MixGroups")) == 0) {
1372 error << _("Session: XML state has no mix groups section") << endmsg;
1373 goto out;
1374 } else if (load_route_groups (*child, version)) {
1375 goto out;
1379 if ((child = find_named_node (node, "Click")) == 0) {
1380 warning << _("Session: XML state has no click section") << endmsg;
1381 } else if (_click_io) {
1382 _click_io->set_state (*child, version);
1385 if ((child = find_named_node (node, "ControlProtocols")) != 0) {
1386 ControlProtocolManager::instance().set_protocol_states (*child);
1389 /* here beginneth the second phase ... */
1391 StateReady (); /* EMIT SIGNAL */
1393 return 0;
1395 out:
1396 return ret;
1400 Session::load_routes (const XMLNode& node, int version)
1402 XMLNodeList nlist;
1403 XMLNodeConstIterator niter;
1404 RouteList new_routes;
1406 nlist = node.children();
1408 set_dirty();
1410 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1412 boost::shared_ptr<Route> route;
1413 if (version < 3000) {
1414 route = XMLRouteFactory_2X (**niter, version);
1415 } else {
1416 route = XMLRouteFactory (**niter, version);
1419 if (route == 0) {
1420 error << _("Session: cannot create Route from XML description.") << endmsg;
1421 return -1;
1424 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1426 new_routes.push_back (route);
1429 add_routes (new_routes, false, false);
1431 return 0;
1434 boost::shared_ptr<Route>
1435 Session::XMLRouteFactory (const XMLNode& node, int version)
1437 boost::shared_ptr<Route> ret;
1439 if (node.name() != "Route") {
1440 return ret;
1443 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1445 DataType type = DataType::AUDIO;
1446 const XMLProperty* prop = node.property("default-type");
1448 if (prop) {
1449 type = DataType (prop->value());
1452 assert (type != DataType::NIL);
1454 if (ds_child) {
1456 boost::shared_ptr<Track> track;
1458 if (type == DataType::AUDIO) {
1459 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1460 } else {
1461 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1464 if (track->init()) {
1465 return ret;
1468 if (track->set_state (node, version)) {
1469 return ret;
1472 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1473 boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1474 #endif
1475 ret = track;
1477 } else {
1478 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML")));
1480 if (r->init () == 0 && r->set_state (node, version) == 0) {
1481 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1482 boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1483 #endif
1484 ret = r;
1488 return ret;
1491 boost::shared_ptr<Route>
1492 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1494 boost::shared_ptr<Route> ret;
1496 if (node.name() != "Route") {
1497 return ret;
1500 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1501 if (!ds_prop) {
1502 ds_prop = node.property (X_("diskstream"));
1505 DataType type = DataType::AUDIO;
1506 const XMLProperty* prop = node.property("default-type");
1508 if (prop) {
1509 type = DataType (prop->value());
1512 assert (type != DataType::NIL);
1514 if (ds_prop) {
1516 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1517 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1518 ++i;
1521 if (i == _diskstreams_2X.end()) {
1522 error << _("Could not find diskstream for route") << endmsg;
1523 return boost::shared_ptr<Route> ();
1526 boost::shared_ptr<Track> track;
1528 if (type == DataType::AUDIO) {
1529 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1530 } else {
1531 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1534 if (track->init()) {
1535 return ret;
1538 if (track->set_state (node, version)) {
1539 return ret;
1542 track->set_diskstream (*i);
1544 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1545 boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1546 #endif
1547 ret = track;
1549 } else {
1550 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML")));
1552 if (r->init () == 0 && r->set_state (node, version) == 0) {
1553 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1554 boost_debug_shared_ptr_mark_interesting (rt, "Route");
1555 #endif
1556 ret = r;
1560 return ret;
1564 Session::load_regions (const XMLNode& node)
1566 XMLNodeList nlist;
1567 XMLNodeConstIterator niter;
1568 boost::shared_ptr<Region> region;
1570 nlist = node.children();
1572 set_dirty();
1574 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1575 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1576 error << _("Session: cannot create Region from XML description.");
1577 const XMLProperty *name = (**niter).property("name");
1579 if (name) {
1580 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1583 error << endmsg;
1587 return 0;
1590 boost::shared_ptr<Region>
1591 Session::XMLRegionFactory (const XMLNode& node, bool full)
1593 const XMLProperty* type = node.property("type");
1595 try {
1597 if (!type || type->value() == "audio") {
1598 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1599 } else if (type->value() == "midi") {
1600 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1603 } catch (failed_constructor& err) {
1604 return boost::shared_ptr<Region> ();
1607 return boost::shared_ptr<Region> ();
1610 boost::shared_ptr<AudioRegion>
1611 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1613 const XMLProperty* prop;
1614 boost::shared_ptr<Source> source;
1615 boost::shared_ptr<AudioSource> as;
1616 SourceList sources;
1617 SourceList master_sources;
1618 uint32_t nchans = 1;
1619 char buf[128];
1621 if (node.name() != X_("Region")) {
1622 return boost::shared_ptr<AudioRegion>();
1625 if ((prop = node.property (X_("channels"))) != 0) {
1626 nchans = atoi (prop->value().c_str());
1629 if ((prop = node.property ("name")) == 0) {
1630 cerr << "no name for this region\n";
1631 abort ();
1634 if ((prop = node.property (X_("source-0"))) == 0) {
1635 if ((prop = node.property ("source")) == 0) {
1636 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1637 return boost::shared_ptr<AudioRegion>();
1641 PBD::ID s_id (prop->value());
1643 if ((source = source_by_id (s_id)) == 0) {
1644 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1645 return boost::shared_ptr<AudioRegion>();
1648 as = boost::dynamic_pointer_cast<AudioSource>(source);
1649 if (!as) {
1650 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1651 return boost::shared_ptr<AudioRegion>();
1654 sources.push_back (as);
1656 /* pickup other channels */
1658 for (uint32_t n=1; n < nchans; ++n) {
1659 snprintf (buf, sizeof(buf), X_("source-%d"), n);
1660 if ((prop = node.property (buf)) != 0) {
1662 PBD::ID id2 (prop->value());
1664 if ((source = source_by_id (id2)) == 0) {
1665 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1666 return boost::shared_ptr<AudioRegion>();
1669 as = boost::dynamic_pointer_cast<AudioSource>(source);
1670 if (!as) {
1671 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1672 return boost::shared_ptr<AudioRegion>();
1674 sources.push_back (as);
1678 for (uint32_t n = 0; n < nchans; ++n) {
1679 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
1680 if ((prop = node.property (buf)) != 0) {
1682 PBD::ID id2 (prop->value());
1684 if ((source = source_by_id (id2)) == 0) {
1685 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1686 return boost::shared_ptr<AudioRegion>();
1689 as = boost::dynamic_pointer_cast<AudioSource>(source);
1690 if (!as) {
1691 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1692 return boost::shared_ptr<AudioRegion>();
1694 master_sources.push_back (as);
1698 try {
1699 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
1701 /* a final detail: this is the one and only place that we know how long missing files are */
1703 if (region->whole_file()) {
1704 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1705 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1706 if (sfp) {
1707 sfp->set_length (region->length());
1712 if (!master_sources.empty()) {
1713 if (master_sources.size() != nchans) {
1714 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
1715 } else {
1716 region->set_master_sources (master_sources);
1720 return region;
1724 catch (failed_constructor& err) {
1725 return boost::shared_ptr<AudioRegion>();
1729 boost::shared_ptr<MidiRegion>
1730 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
1732 const XMLProperty* prop;
1733 boost::shared_ptr<Source> source;
1734 boost::shared_ptr<MidiSource> ms;
1735 SourceList sources;
1737 if (node.name() != X_("Region")) {
1738 return boost::shared_ptr<MidiRegion>();
1741 if ((prop = node.property ("name")) == 0) {
1742 cerr << "no name for this region\n";
1743 abort ();
1746 if ((prop = node.property (X_("source-0"))) == 0) {
1747 if ((prop = node.property ("source")) == 0) {
1748 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
1749 return boost::shared_ptr<MidiRegion>();
1753 PBD::ID s_id (prop->value());
1755 if ((source = source_by_id (s_id)) == 0) {
1756 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
1757 return boost::shared_ptr<MidiRegion>();
1760 ms = boost::dynamic_pointer_cast<MidiSource>(source);
1761 if (!ms) {
1762 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
1763 return boost::shared_ptr<MidiRegion>();
1766 sources.push_back (ms);
1768 try {
1769 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
1770 /* a final detail: this is the one and only place that we know how long missing files are */
1772 if (region->whole_file()) {
1773 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1774 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1775 if (sfp) {
1776 sfp->set_length (region->length());
1781 return region;
1784 catch (failed_constructor& err) {
1785 return boost::shared_ptr<MidiRegion>();
1789 XMLNode&
1790 Session::get_sources_as_xml ()
1793 XMLNode* node = new XMLNode (X_("Sources"));
1794 Glib::Mutex::Lock lm (source_lock);
1796 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
1797 node->add_child_nocopy (i->second->get_state());
1800 return *node;
1803 string
1804 Session::path_from_region_name (DataType type, string name, string identifier)
1806 char buf[PATH_MAX+1];
1807 uint32_t n;
1808 SessionDirectory sdir(get_best_session_directory_for_new_source());
1809 sys::path source_dir = ((type == DataType::AUDIO)
1810 ? sdir.sound_path() : sdir.midi_path());
1812 string ext = native_header_format_extension (config.get_native_file_header_format(), type);
1814 for (n = 0; n < 999999; ++n) {
1815 if (identifier.length()) {
1816 snprintf (buf, sizeof(buf), "%s%s%" PRIu32 "%s", name.c_str(),
1817 identifier.c_str(), n, ext.c_str());
1818 } else {
1819 snprintf (buf, sizeof(buf), "%s-%" PRIu32 "%s", name.c_str(),
1820 n, ext.c_str());
1823 sys::path source_path = source_dir / buf;
1825 if (!sys::exists (source_path)) {
1826 return source_path.to_string();
1830 error << string_compose (_("cannot create new file from region name \"%1\" with ident = \"%2\": too many existing files with similar names"),
1831 name, identifier)
1832 << endmsg;
1834 return "";
1839 Session::load_sources (const XMLNode& node)
1841 XMLNodeList nlist;
1842 XMLNodeConstIterator niter;
1843 boost::shared_ptr<Source> source;
1845 nlist = node.children();
1847 set_dirty();
1849 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1850 retry:
1851 try {
1852 if ((source = XMLSourceFactory (**niter)) == 0) {
1853 error << _("Session: cannot create Source from XML description.") << endmsg;
1856 } catch (MissingSource& err) {
1858 int user_choice;
1860 if (!no_questions_about_missing_files) {
1861 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
1862 } else {
1863 user_choice = -2;
1866 switch (user_choice) {
1867 case 0:
1868 /* user added a new search location, so try again */
1869 goto retry;
1872 case 1:
1873 /* user asked to quit the entire session load
1875 return -1;
1877 case 2:
1878 no_questions_about_missing_files = true;
1879 goto retry;
1881 case 3:
1882 no_questions_about_missing_files = true;
1883 /* fallthru */
1885 case -1:
1886 default:
1887 warning << _("A sound file is missing. It will be replaced by silence.") << endmsg;
1888 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
1889 break;
1894 return 0;
1897 boost::shared_ptr<Source>
1898 Session::XMLSourceFactory (const XMLNode& node)
1900 if (node.name() != "Source") {
1901 return boost::shared_ptr<Source>();
1904 try {
1905 /* note: do peak building in another thread when loading session state */
1906 return SourceFactory::create (*this, node, true);
1909 catch (failed_constructor& err) {
1910 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the progammers."), PROGRAM_NAME) << endmsg;
1911 return boost::shared_ptr<Source>();
1916 Session::save_template (string template_name)
1918 XMLTree tree;
1920 if (_state_of_the_state & CannotSave) {
1921 return -1;
1924 sys::path user_template_dir(user_template_directory());
1928 sys::create_directories (user_template_dir);
1930 catch(sys::filesystem_error& ex)
1932 error << string_compose(_("Could not create mix templates directory \"%1\" (%2)"),
1933 user_template_dir.to_string(), ex.what()) << endmsg;
1934 return -1;
1937 tree.set_root (&get_template());
1939 sys::path template_file_path(user_template_dir);
1940 template_file_path /= template_name + template_suffix;
1942 if (sys::exists (template_file_path))
1944 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
1945 template_file_path.to_string()) << endmsg;
1946 return -1;
1949 if (!tree.write (template_file_path.to_string())) {
1950 error << _("template not saved") << endmsg;
1951 return -1;
1954 return 0;
1958 Session::rename_template (string old_name, string new_name)
1960 sys::path old_path (user_template_directory());
1961 old_path /= old_name + template_suffix;
1963 sys::path new_path(user_template_directory());
1964 new_path /= new_name + template_suffix;
1966 if (sys::exists (new_path)) {
1967 warning << string_compose(_("Template \"%1\" already exists - template not renamed"),
1968 new_path.to_string()) << endmsg;
1969 return -1;
1972 try {
1973 sys::rename (old_path, new_path);
1974 return 0;
1975 } catch (...) {
1976 return -1;
1981 Session::delete_template (string name)
1983 sys::path path = user_template_directory();
1984 path /= name + template_suffix;
1986 try {
1987 sys::remove (path);
1988 return 0;
1989 } catch (...) {
1990 return -1;
1994 void
1995 Session::refresh_disk_space ()
1997 #if HAVE_SYS_VFS_H
1998 struct statfs statfsbuf;
1999 vector<space_and_path>::iterator i;
2000 Glib::Mutex::Lock lm (space_lock);
2001 double scale;
2003 /* get freespace on every FS that is part of the session path */
2005 _total_free_4k_blocks = 0;
2007 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2008 statfs ((*i).path.c_str(), &statfsbuf);
2010 scale = statfsbuf.f_bsize/4096.0;
2012 (*i).blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2013 _total_free_4k_blocks += (*i).blocks;
2015 #endif
2018 string
2019 Session::get_best_session_directory_for_new_source ()
2021 vector<space_and_path>::iterator i;
2022 string result = _session_dir->root_path().to_string();
2024 /* handle common case without system calls */
2026 if (session_dirs.size() == 1) {
2027 return result;
2030 /* OK, here's the algorithm we're following here:
2032 We want to select which directory to use for
2033 the next file source to be created. Ideally,
2034 we'd like to use a round-robin process so as to
2035 get maximum performance benefits from splitting
2036 the files across multiple disks.
2038 However, in situations without much diskspace, an
2039 RR approach may end up filling up a filesystem
2040 with new files while others still have space.
2041 Its therefore important to pay some attention to
2042 the freespace in the filesystem holding each
2043 directory as well. However, if we did that by
2044 itself, we'd keep creating new files in the file
2045 system with the most space until it was as full
2046 as all others, thus negating any performance
2047 benefits of this RAID-1 like approach.
2049 So, we use a user-configurable space threshold. If
2050 there are at least 2 filesystems with more than this
2051 much space available, we use RR selection between them.
2052 If not, then we pick the filesystem with the most space.
2054 This gets a good balance between the two
2055 approaches.
2058 refresh_disk_space ();
2060 int free_enough = 0;
2062 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2063 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2064 free_enough++;
2068 if (free_enough >= 2) {
2069 /* use RR selection process, ensuring that the one
2070 picked works OK.
2073 i = last_rr_session_dir;
2075 do {
2076 if (++i == session_dirs.end()) {
2077 i = session_dirs.begin();
2080 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2081 if (create_session_directory ((*i).path)) {
2082 result = (*i).path;
2083 last_rr_session_dir = i;
2084 return result;
2088 } while (i != last_rr_session_dir);
2090 } else {
2092 /* pick FS with the most freespace (and that
2093 seems to actually work ...)
2096 vector<space_and_path> sorted;
2097 space_and_path_ascending_cmp cmp;
2099 sorted = session_dirs;
2100 sort (sorted.begin(), sorted.end(), cmp);
2102 for (i = sorted.begin(); i != sorted.end(); ++i) {
2103 if (create_session_directory ((*i).path)) {
2104 result = (*i).path;
2105 last_rr_session_dir = i;
2106 return result;
2111 return result;
2115 Session::load_named_selections (const XMLNode& node)
2117 XMLNodeList nlist;
2118 XMLNodeConstIterator niter;
2119 NamedSelection *ns;
2121 nlist = node.children();
2123 set_dirty();
2125 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2127 if ((ns = XMLNamedSelectionFactory (**niter)) == 0) {
2128 error << _("Session: cannot create Named Selection from XML description.") << endmsg;
2132 return 0;
2135 NamedSelection *
2136 Session::XMLNamedSelectionFactory (const XMLNode& node)
2138 try {
2139 return new NamedSelection (*this, node);
2142 catch (failed_constructor& err) {
2143 return 0;
2147 string
2148 Session::automation_dir () const
2150 return Glib::build_filename (_path, "automation");
2153 string
2154 Session::analysis_dir () const
2156 return Glib::build_filename (_path, "analysis");
2159 string
2160 Session::plugins_dir () const
2162 return Glib::build_filename (_path, "plugins");
2166 Session::load_bundles (XMLNode const & node)
2168 XMLNodeList nlist = node.children();
2169 XMLNodeConstIterator niter;
2171 set_dirty();
2173 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2174 if ((*niter)->name() == "InputBundle") {
2175 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2176 } else if ((*niter)->name() == "OutputBundle") {
2177 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2178 } else {
2179 error << string_compose(_("Unknown node \"%1\" found in Bundles list from state file"), (*niter)->name()) << endmsg;
2180 return -1;
2184 return 0;
2188 Session::load_route_groups (const XMLNode& node, int version)
2190 XMLNodeList nlist = node.children();
2191 XMLNodeConstIterator niter;
2193 set_dirty ();
2195 if (version >= 3000) {
2197 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2198 if ((*niter)->name() == "RouteGroup") {
2199 RouteGroup* rg = new RouteGroup (*this, "");
2200 add_route_group (rg);
2201 rg->set_state (**niter, version);
2205 } else if (version < 3000) {
2207 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2208 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2209 RouteGroup* rg = new RouteGroup (*this, "");
2210 add_route_group (rg);
2211 rg->set_state (**niter, version);
2216 return 0;
2219 void
2220 Session::auto_save()
2222 save_state (_current_snapshot_name);
2225 static bool
2226 state_file_filter (const string &str, void */*arg*/)
2228 return (str.length() > strlen(statefile_suffix) &&
2229 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2232 struct string_cmp {
2233 bool operator()(const string* a, const string* b) {
2234 return *a < *b;
2238 static string*
2239 remove_end(string* state)
2241 string statename(*state);
2243 string::size_type start,end;
2244 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2245 statename = statename.substr (start+1);
2248 if ((end = statename.rfind(".ardour")) == string::npos) {
2249 end = statename.length();
2252 return new string(statename.substr (0, end));
2255 vector<string *> *
2256 Session::possible_states (string path)
2258 PathScanner scanner;
2259 vector<string*>* states = scanner (path, state_file_filter, 0, false, false);
2261 transform(states->begin(), states->end(), states->begin(), remove_end);
2263 string_cmp cmp;
2264 sort (states->begin(), states->end(), cmp);
2266 return states;
2269 vector<string *> *
2270 Session::possible_states () const
2272 return possible_states(_path);
2275 void
2276 Session::add_route_group (RouteGroup* g)
2278 _route_groups.push_back (g);
2279 route_group_added (g); /* EMIT SIGNAL */
2281 g->MembershipChanged.connect_same_thread (*this, boost::bind (&Session::route_group_changed, this));
2282 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_changed, this));
2284 set_dirty ();
2287 void
2288 Session::remove_route_group (RouteGroup& rg)
2290 list<RouteGroup*>::iterator i;
2292 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2293 _route_groups.erase (i);
2294 delete &rg;
2296 route_group_removed (); /* EMIT SIGNAL */
2300 /** Set a new order for our route groups, without adding or removing any.
2301 * @param groups Route group list in the new order.
2303 void
2304 Session::reorder_route_groups (list<RouteGroup*> groups)
2306 _route_groups = groups;
2308 route_groups_reordered (); /* EMIT SIGNAL */
2309 set_dirty ();
2313 RouteGroup *
2314 Session::route_group_by_name (string name)
2316 list<RouteGroup *>::iterator i;
2318 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2319 if ((*i)->name() == name) {
2320 return* i;
2323 return 0;
2326 RouteGroup&
2327 Session::all_route_group() const
2329 return *_all_route_group;
2332 void
2333 Session::add_commands (vector<Command*> const & cmds)
2335 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2336 add_command (*i);
2340 void
2341 Session::begin_reversible_command (const string& name)
2343 begin_reversible_command (g_quark_from_string (name.c_str ()));
2346 /** Begin a reversible command using a GQuark to identify it.
2347 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2348 * but there must be as many begin...()s as there are commit...()s.
2350 void
2351 Session::begin_reversible_command (GQuark q)
2353 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2354 to hold all the commands that are committed. This keeps the order of
2355 commands correct in the history.
2358 if (_current_trans == 0) {
2359 /* start a new transaction */
2360 assert (_current_trans_quarks.empty ());
2361 _current_trans = new UndoTransaction();
2362 _current_trans->set_name (g_quark_to_string (q));
2365 _current_trans_quarks.push_front (q);
2368 void
2369 Session::commit_reversible_command (Command *cmd)
2371 assert (_current_trans);
2372 assert (!_current_trans_quarks.empty ());
2374 struct timeval now;
2376 if (cmd) {
2377 _current_trans->add_command (cmd);
2380 _current_trans_quarks.pop_front ();
2382 if (!_current_trans_quarks.empty ()) {
2383 /* the transaction we're committing is not the top-level one */
2384 return;
2387 if (_current_trans->empty()) {
2388 /* no commands were added to the transaction, so just get rid of it */
2389 delete _current_trans;
2390 _current_trans = 0;
2391 return;
2394 gettimeofday (&now, 0);
2395 _current_trans->set_timestamp (now);
2397 _history.add (_current_trans);
2398 _current_trans = 0;
2401 static bool
2402 accept_all_audio_files (const string& path, void */*arg*/)
2404 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2405 return false;
2408 if (!AudioFileSource::safe_audio_file_extension (path)) {
2409 return false;
2412 return true;
2415 static bool
2416 accept_all_midi_files (const string& path, void */*arg*/)
2418 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2419 return false;
2422 return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
2423 (path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
2424 (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2427 static bool
2428 accept_all_state_files (const string& path, void */*arg*/)
2430 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2431 return false;
2434 return (path.length() > 7 && path.find (".ardour") == (path.length() - 7));
2438 Session::find_all_sources (string path, set<string>& result)
2440 XMLTree tree;
2441 XMLNode* node;
2443 if (!tree.read (path)) {
2444 return -1;
2447 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2448 return -2;
2451 XMLNodeList nlist;
2452 XMLNodeConstIterator niter;
2454 nlist = node->children();
2456 set_dirty();
2458 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2460 XMLProperty* prop;
2462 if ((prop = (*niter)->property (X_("type"))) == 0) {
2463 continue;
2466 DataType type (prop->value());
2468 if ((prop = (*niter)->property (X_("name"))) == 0) {
2469 continue;
2472 if (Glib::path_is_absolute (prop->value())) {
2473 /* external file, ignore */
2474 continue;
2477 string found_path;
2478 bool is_new;
2479 uint16_t chan;
2481 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
2482 result.insert (found_path);
2486 return 0;
2490 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
2492 PathScanner scanner;
2493 vector<string*>* state_files;
2494 string ripped;
2495 string this_snapshot_path;
2497 result.clear ();
2499 ripped = _path;
2501 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
2502 ripped = ripped.substr (0, ripped.length() - 1);
2505 state_files = scanner (ripped, accept_all_state_files, (void *) 0, false, true);
2507 if (state_files == 0) {
2508 /* impossible! */
2509 return 0;
2512 this_snapshot_path = _path;
2513 this_snapshot_path += legalize_for_path (_current_snapshot_name);
2514 this_snapshot_path += statefile_suffix;
2516 for (vector<string*>::iterator i = state_files->begin(); i != state_files->end(); ++i) {
2518 if (exclude_this_snapshot && **i == this_snapshot_path) {
2519 continue;
2522 if (find_all_sources (**i, result) < 0) {
2523 return -1;
2527 return 0;
2530 struct RegionCounter {
2531 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
2532 AudioSourceList::iterator iter;
2533 boost::shared_ptr<Region> region;
2534 uint32_t count;
2536 RegionCounter() : count (0) {}
2540 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
2542 boost::optional<int> r = AskAboutPlaylistDeletion (p);
2543 return r.get_value_or (1);
2546 void
2547 Session::cleanup_regions ()
2549 const RegionFactory::RegionMap& regions (RegionFactory::regions());
2551 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2553 boost::shared_ptr<AudioRegion> audio_region = boost::dynamic_pointer_cast<AudioRegion>( i->second);
2555 if (!audio_region) {
2556 continue;
2559 uint32_t used = playlists->region_use_count (audio_region);
2561 if (used == 0 && !audio_region->automatic()) {
2562 RegionFactory::map_remove(i->second);
2566 /* dump the history list */
2567 _history.clear ();
2569 save_state ("");
2573 Session::cleanup_sources (CleanupReport& rep)
2575 // FIXME: needs adaptation to midi
2577 vector<boost::shared_ptr<Source> > dead_sources;
2578 PathScanner scanner;
2579 string audio_path;
2580 string midi_path;
2581 vector<space_and_path>::iterator i;
2582 vector<space_and_path>::iterator nexti;
2583 vector<string*>* candidates;
2584 vector<string*>* candidates2;
2585 vector<string> unused;
2586 set<string> all_sources;
2587 bool used;
2588 string spath;
2589 int ret = -1;
2591 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
2593 /* consider deleting all unused playlists */
2595 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
2596 ret = 0;
2597 goto out;
2600 /* sync the "all regions" property of each playlist with its current state
2603 playlists->sync_all_regions_with_regions ();
2605 /* find all un-used sources */
2607 rep.paths.clear ();
2608 rep.space = 0;
2610 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
2612 SourceMap::iterator tmp;
2614 tmp = i;
2615 ++tmp;
2617 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
2618 capture files.
2621 if (!i->second->used() && (i->second->length(i->second->timeline_position() > 0))) {
2622 dead_sources.push_back (i->second);
2623 i->second->drop_references ();
2626 i = tmp;
2629 /* build a list of all the possible audio directories for the session */
2631 for (i = session_dirs.begin(); i != session_dirs.end(); ) {
2633 nexti = i;
2634 ++nexti;
2636 SessionDirectory sdir ((*i).path);
2637 audio_path += sdir.sound_path().to_string();
2639 if (nexti != session_dirs.end()) {
2640 audio_path += ':';
2643 i = nexti;
2647 /* build a list of all the possible midi directories for the session */
2649 for (i = session_dirs.begin(); i != session_dirs.end(); ) {
2651 nexti = i;
2652 ++nexti;
2654 SessionDirectory sdir ((*i).path);
2655 midi_path += sdir.midi_path().to_string();
2657 if (nexti != session_dirs.end()) {
2658 midi_path += ':';
2661 i = nexti;
2664 candidates = scanner (audio_path, accept_all_audio_files, (void *) 0, true, true);
2665 candidates2 = scanner (midi_path, accept_all_midi_files, (void *) 0, true, true);
2667 /* merge them */
2669 if (candidates) {
2670 if (candidates2) {
2671 for (vector<string*>::iterator i = candidates2->begin(); i != candidates2->end(); ++i) {
2672 candidates->push_back (*i);
2674 delete candidates2;
2676 } else {
2677 candidates = candidates2; // might still be null
2680 /* find all sources, but don't use this snapshot because the
2681 state file on disk still references sources we may have already
2682 dropped.
2685 find_all_sources_across_snapshots (all_sources, true);
2687 /* add our current source list
2690 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
2691 boost::shared_ptr<FileSource> fs;
2692 SourceMap::iterator tmp = i;
2693 ++tmp;
2695 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) != 0) {
2696 if (playlists->source_use_count (fs) != 0) {
2697 all_sources.insert (fs->path());
2698 } else {
2700 /* we might not remove this source from disk, because it may be used
2701 by other snapshots, but its not being used in this version
2702 so lets get rid of it now, along with any representative regions
2703 in the region list.
2706 RegionFactory::remove_regions_using_source (i->second);
2707 sources.erase (i);
2711 i = tmp;
2714 char tmppath1[PATH_MAX+1];
2715 char tmppath2[PATH_MAX+1];
2717 if (candidates) {
2718 for (vector<string*>::iterator x = candidates->begin(); x != candidates->end(); ++x) {
2720 used = false;
2721 spath = **x;
2723 for (set<string>::iterator i = all_sources.begin(); i != all_sources.end(); ++i) {
2725 if (realpath(spath.c_str(), tmppath1) == 0) {
2726 error << string_compose (_("Cannot expand path %1 (%2)"),
2727 spath, strerror (errno)) << endmsg;
2728 continue;
2731 if (realpath((*i).c_str(), tmppath2) == 0) {
2732 error << string_compose (_("Cannot expand path %1 (%2)"),
2733 (*i), strerror (errno)) << endmsg;
2734 continue;
2737 if (strcmp(tmppath1, tmppath2) == 0) {
2738 used = true;
2739 break;
2743 if (!used) {
2744 unused.push_back (spath);
2747 delete *x;
2750 delete candidates;
2753 /* now try to move all unused files into the "dead" directory(ies) */
2755 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
2756 struct stat statbuf;
2758 string newpath;
2760 /* don't move the file across filesystems, just
2761 stick it in the `dead_dir_name' directory
2762 on whichever filesystem it was already on.
2765 if ((*x).find ("/sounds/") != string::npos) {
2767 /* old school, go up 1 level */
2769 newpath = Glib::path_get_dirname (*x); // "sounds"
2770 newpath = Glib::path_get_dirname (newpath); // "session-name"
2772 } else {
2774 /* new school, go up 4 levels */
2776 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
2777 newpath = Glib::path_get_dirname (newpath); // "session-name"
2778 newpath = Glib::path_get_dirname (newpath); // "interchange"
2779 newpath = Glib::path_get_dirname (newpath); // "session-dir"
2782 newpath = Glib::build_filename (newpath, dead_dir_name);
2784 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
2785 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
2786 return -1;
2789 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
2791 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2793 /* the new path already exists, try versioning */
2795 char buf[PATH_MAX+1];
2796 int version = 1;
2797 string newpath_v;
2799 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
2800 newpath_v = buf;
2802 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
2803 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
2804 newpath_v = buf;
2807 if (version == 999) {
2808 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
2809 newpath)
2810 << endmsg;
2811 } else {
2812 newpath = newpath_v;
2815 } else {
2817 /* it doesn't exist, or we can't read it or something */
2821 stat ((*x).c_str(), &statbuf);
2823 if (::rename ((*x).c_str(), newpath.c_str()) != 0) {
2824 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"),
2825 (*x), newpath, strerror (errno))
2826 << endmsg;
2827 goto out;
2830 /* see if there an easy to find peakfile for this file, and remove it.
2833 string base = basename_nosuffix (*x);
2834 base += "%A"; /* this is what we add for the channel suffix of all native files,
2835 or for the first channel of embedded files. it will miss
2836 some peakfiles for other channels
2838 string peakpath = peak_path (base);
2840 if (Glib::file_test (peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
2841 if (::unlink (peakpath.c_str()) != 0) {
2842 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"),
2843 peakpath, _path, strerror (errno))
2844 << endmsg;
2845 /* try to back out */
2846 rename (newpath.c_str(), _path.c_str());
2847 goto out;
2851 rep.paths.push_back (*x);
2852 rep.space += statbuf.st_size;
2855 /* dump the history list */
2857 _history.clear ();
2859 /* save state so we don't end up a session file
2860 referring to non-existent sources.
2863 save_state ("");
2864 ret = 0;
2866 out:
2867 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
2869 return ret;
2873 Session::cleanup_trash_sources (CleanupReport& rep)
2875 // FIXME: needs adaptation for MIDI
2877 vector<space_and_path>::iterator i;
2878 string dead_dir;
2880 rep.paths.clear ();
2881 rep.space = 0;
2883 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2885 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
2887 clear_directory (dead_dir, &rep.space, &rep.paths);
2890 return 0;
2893 void
2894 Session::set_dirty ()
2896 bool was_dirty = dirty();
2898 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
2901 if (!was_dirty) {
2902 DirtyChanged(); /* EMIT SIGNAL */
2907 void
2908 Session::set_clean ()
2910 bool was_dirty = dirty();
2912 _state_of_the_state = Clean;
2915 if (was_dirty) {
2916 DirtyChanged(); /* EMIT SIGNAL */
2920 void
2921 Session::set_deletion_in_progress ()
2923 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
2926 void
2927 Session::clear_deletion_in_progress ()
2929 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
2932 void
2933 Session::add_controllable (boost::shared_ptr<Controllable> c)
2935 /* this adds a controllable to the list managed by the Session.
2936 this is a subset of those managed by the Controllable class
2937 itself, and represents the only ones whose state will be saved
2938 as part of the session.
2941 Glib::Mutex::Lock lm (controllables_lock);
2942 controllables.insert (c);
2945 struct null_deleter { void operator()(void const *) const {} };
2947 void
2948 Session::remove_controllable (Controllable* c)
2950 if (_state_of_the_state | Deletion) {
2951 return;
2954 Glib::Mutex::Lock lm (controllables_lock);
2956 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
2958 if (x != controllables.end()) {
2959 controllables.erase (x);
2963 boost::shared_ptr<Controllable>
2964 Session::controllable_by_id (const PBD::ID& id)
2966 Glib::Mutex::Lock lm (controllables_lock);
2968 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
2969 if ((*i)->id() == id) {
2970 return *i;
2974 return boost::shared_ptr<Controllable>();
2977 boost::shared_ptr<Controllable>
2978 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
2980 boost::shared_ptr<Controllable> c;
2981 boost::shared_ptr<Route> r;
2983 switch (desc.top_level_type()) {
2984 case ControllableDescriptor::NamedRoute:
2986 std::string str = desc.top_level_name();
2987 if (str == "master") {
2988 r = _master_out;
2989 } else if (str == "control" || str == "listen") {
2990 r = _monitor_out;
2991 } else {
2992 r = route_by_name (desc.top_level_name());
2994 break;
2997 case ControllableDescriptor::RemoteControlID:
2998 r = route_by_remote_id (desc.rid());
2999 break;
3002 if (!r) {
3003 return c;
3006 switch (desc.subtype()) {
3007 case ControllableDescriptor::Gain:
3008 c = r->gain_control ();
3009 break;
3011 case ControllableDescriptor::Solo:
3012 c = r->solo_control();
3013 break;
3015 case ControllableDescriptor::Mute:
3016 c = r->mute_control();
3017 break;
3019 case ControllableDescriptor::Recenable:
3021 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(r);
3023 if (t) {
3024 c = t->rec_enable_control ();
3026 break;
3029 case ControllableDescriptor::PanDirection:
3031 c = r->pannable()->pan_azimuth_control;
3032 break;
3035 case ControllableDescriptor::PanWidth:
3037 c = r->pannable()->pan_width_control;
3038 break;
3041 case ControllableDescriptor::PanElevation:
3043 c = r->pannable()->pan_elevation_control;
3044 break;
3047 case ControllableDescriptor::Balance:
3048 /* XXX simple pan control */
3049 break;
3051 case ControllableDescriptor::PluginParameter:
3053 uint32_t plugin = desc.target (0);
3054 uint32_t parameter_index = desc.target (1);
3056 /* revert to zero based counting */
3058 if (plugin > 0) {
3059 --plugin;
3062 if (parameter_index > 0) {
3063 --parameter_index;
3066 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3068 if (p) {
3069 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3070 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3072 break;
3075 case ControllableDescriptor::SendGain:
3077 uint32_t send = desc.target (0);
3079 /* revert to zero-based counting */
3081 if (send > 0) {
3082 --send;
3085 boost::shared_ptr<Processor> p = r->nth_send (send);
3087 if (p) {
3088 boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
3089 boost::shared_ptr<Amp> a = s->amp();
3091 if (a) {
3092 c = s->amp()->gain_control();
3095 break;
3098 default:
3099 /* relax and return a null pointer */
3100 break;
3103 return c;
3106 void
3107 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3109 if (_writable) {
3110 Stateful::add_instant_xml (node, _path);
3113 if (write_to_config) {
3114 Config->add_instant_xml (node);
3118 XMLNode*
3119 Session::instant_xml (const string& node_name)
3121 return Stateful::instant_xml (node_name, _path);
3125 Session::save_history (string snapshot_name)
3127 XMLTree tree;
3129 if (!_writable) {
3130 return 0;
3133 if (snapshot_name.empty()) {
3134 snapshot_name = _current_snapshot_name;
3137 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3138 const string backup_filename = history_filename + backup_suffix;
3139 const sys::path xml_path = _session_dir->root_path() / history_filename;
3140 const sys::path backup_path = _session_dir->root_path() / backup_filename;
3142 if (sys::exists (xml_path)) {
3145 sys::rename (xml_path, backup_path);
3147 catch (const sys::filesystem_error& err)
3149 error << _("could not backup old history file, current history not saved") << endmsg;
3150 return -1;
3154 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0) {
3155 return 0;
3158 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3160 if (!tree.write (xml_path.to_string()))
3162 error << string_compose (_("history could not be saved to %1"), xml_path.to_string()) << endmsg;
3166 sys::remove (xml_path);
3167 sys::rename (backup_path, xml_path);
3169 catch (const sys::filesystem_error& err)
3171 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3172 backup_path.to_string(), err.what()) << endmsg;
3175 return -1;
3178 return 0;
3182 Session::restore_history (string snapshot_name)
3184 XMLTree tree;
3186 if (snapshot_name.empty()) {
3187 snapshot_name = _current_snapshot_name;
3190 const string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3191 const sys::path xml_path = _session_dir->root_path() / xml_filename;
3193 info << "Loading history from " << xml_path.to_string() << endmsg;
3195 if (!sys::exists (xml_path)) {
3196 info << string_compose (_("%1: no history file \"%2\" for this session."),
3197 _name, xml_path.to_string()) << endmsg;
3198 return 1;
3201 if (!tree.read (xml_path.to_string())) {
3202 error << string_compose (_("Could not understand session history file \"%1\""),
3203 xml_path.to_string()) << endmsg;
3204 return -1;
3207 // replace history
3208 _history.clear();
3210 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); it++) {
3212 XMLNode *t = *it;
3213 UndoTransaction* ut = new UndoTransaction ();
3214 struct timeval tv;
3216 ut->set_name(t->property("name")->value());
3217 stringstream ss(t->property("tv-sec")->value());
3218 ss >> tv.tv_sec;
3219 ss.str(t->property("tv-usec")->value());
3220 ss >> tv.tv_usec;
3221 ut->set_timestamp(tv);
3223 for (XMLNodeConstIterator child_it = t->children().begin();
3224 child_it != t->children().end(); child_it++)
3226 XMLNode *n = *child_it;
3227 Command *c;
3229 if (n->name() == "MementoCommand" ||
3230 n->name() == "MementoUndoCommand" ||
3231 n->name() == "MementoRedoCommand") {
3233 if ((c = memento_command_factory(n))) {
3234 ut->add_command(c);
3237 } else if (n->name() == "NoteDiffCommand") {
3238 PBD::ID id (n->property("midi-source")->value());
3239 boost::shared_ptr<MidiSource> midi_source =
3240 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3241 if (midi_source) {
3242 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3243 } else {
3244 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3247 } else if (n->name() == "SysExDiffCommand") {
3249 PBD::ID id (n->property("midi-source")->value());
3250 boost::shared_ptr<MidiSource> midi_source =
3251 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3252 if (midi_source) {
3253 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3254 } else {
3255 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3258 } else if (n->name() == "PatchChangeDiffCommand") {
3260 PBD::ID id (n->property("midi-source")->value());
3261 boost::shared_ptr<MidiSource> midi_source =
3262 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3263 if (midi_source) {
3264 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3265 } else {
3266 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3269 } else if (n->name() == "StatefulDiffCommand") {
3270 if ((c = stateful_diff_command_factory (n))) {
3271 ut->add_command (c);
3273 } else {
3274 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3278 _history.add (ut);
3281 return 0;
3284 void
3285 Session::config_changed (std::string p, bool ours)
3287 if (ours) {
3288 set_dirty ();
3291 if (p == "seamless-loop") {
3293 } else if (p == "rf-speed") {
3295 } else if (p == "auto-loop") {
3297 } else if (p == "auto-input") {
3299 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3300 /* auto-input only makes a difference if we're rolling */
3301 set_track_monitor_input_status (!config.get_auto_input());
3304 } else if (p == "punch-in") {
3306 Location* location;
3308 if ((location = _locations->auto_punch_location()) != 0) {
3310 if (config.get_punch_in ()) {
3311 replace_event (SessionEvent::PunchIn, location->start());
3312 } else {
3313 remove_event (location->start(), SessionEvent::PunchIn);
3317 } else if (p == "punch-out") {
3319 Location* location;
3321 if ((location = _locations->auto_punch_location()) != 0) {
3323 if (config.get_punch_out()) {
3324 replace_event (SessionEvent::PunchOut, location->end());
3325 } else {
3326 clear_events (SessionEvent::PunchOut);
3330 } else if (p == "edit-mode") {
3332 Glib::Mutex::Lock lm (playlists->lock);
3334 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3335 (*i)->set_edit_mode (Config->get_edit_mode ());
3338 } else if (p == "use-video-sync") {
3340 waiting_for_sync_offset = config.get_use_video_sync();
3342 } else if (p == "mmc-control") {
3344 //poke_midi_thread ();
3346 } else if (p == "mmc-device-id" || p == "mmc-receive-id") {
3348 MIDI::Manager::instance()->mmc()->set_receive_device_id (Config->get_mmc_receive_device_id());
3350 } else if (p == "mmc-send-id") {
3352 MIDI::Manager::instance()->mmc()->set_send_device_id (Config->get_mmc_send_device_id());
3354 } else if (p == "midi-control") {
3356 //poke_midi_thread ();
3358 } else if (p == "raid-path") {
3360 setup_raid_path (config.get_raid_path());
3362 } else if (p == "timecode-format") {
3364 sync_time_vars ();
3366 } else if (p == "video-pullup") {
3368 sync_time_vars ();
3370 } else if (p == "seamless-loop") {
3372 if (play_loop && transport_rolling()) {
3373 // to reset diskstreams etc
3374 request_play_loop (true);
3377 } else if (p == "rf-speed") {
3379 cumulative_rf_motion = 0;
3380 reset_rf_scale (0);
3382 } else if (p == "click-sound") {
3384 setup_click_sounds (1);
3386 } else if (p == "click-emphasis-sound") {
3388 setup_click_sounds (-1);
3390 } else if (p == "clicking") {
3392 if (Config->get_clicking()) {
3393 if (_click_io && click_data) { // don't require emphasis data
3394 _clicking = true;
3396 } else {
3397 _clicking = false;
3400 } else if (p == "send-mtc") {
3402 if (Config->get_send_mtc ()) {
3403 /* mark us ready to send */
3404 next_quarter_frame_to_send = 0;
3407 } else if (p == "send-mmc") {
3409 MIDI::Manager::instance()->mmc()->enable_send (Config->get_send_mmc ());
3411 } else if (p == "midi-feedback") {
3413 session_midi_feedback = Config->get_midi_feedback();
3415 } else if (p == "jack-time-master") {
3417 engine().reset_timebase ();
3419 } else if (p == "native-file-header-format") {
3421 if (!first_file_header_format_reset) {
3422 reset_native_file_format ();
3425 first_file_header_format_reset = false;
3427 } else if (p == "native-file-data-format") {
3429 if (!first_file_data_format_reset) {
3430 reset_native_file_format ();
3433 first_file_data_format_reset = false;
3435 } else if (p == "external-sync") {
3436 if (!config.get_external_sync()) {
3437 drop_sync_source ();
3438 } else {
3439 switch_to_sync_source (config.get_sync_source());
3441 } else if (p == "remote-model") {
3442 set_remote_control_ids ();
3443 } else if (p == "denormal-model") {
3444 setup_fpu ();
3445 } else if (p == "history-depth") {
3446 set_history_depth (Config->get_history_depth());
3447 } else if (p == "sync-all-route-ordering") {
3448 sync_order_keys ("session");
3449 } else if (p == "initial-program-change") {
3451 if (MIDI::Manager::instance()->mmc()->output_port() && Config->get_initial_program_change() >= 0) {
3452 MIDI::byte buf[2];
3454 buf[0] = MIDI::program; // channel zero by default
3455 buf[1] = (Config->get_initial_program_change() & 0x7f);
3457 MIDI::Manager::instance()->mmc()->output_port()->midimsg (buf, sizeof (buf), 0);
3459 } else if (p == "solo-mute-override") {
3460 // catch_up_on_solo_mute_override ();
3461 } else if (p == "listen-position" || p == "pfl-position") {
3462 listen_position_changed ();
3463 } else if (p == "solo-control-is-listen-control") {
3464 solo_control_mode_changed ();
3465 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
3466 last_timecode_valid = false;
3469 set_dirty ();
3472 void
3473 Session::set_history_depth (uint32_t d)
3475 _history.set_depth (d);
3479 Session::load_diskstreams_2X (XMLNode const & node, int)
3481 XMLNodeList clist;
3482 XMLNodeConstIterator citer;
3484 clist = node.children();
3486 for (citer = clist.begin(); citer != clist.end(); ++citer) {
3488 try {
3489 /* diskstreams added automatically by DiskstreamCreated handler */
3490 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
3491 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
3492 _diskstreams_2X.push_back (dsp);
3493 } else {
3494 error << _("Session: unknown diskstream type in XML") << endmsg;
3498 catch (failed_constructor& err) {
3499 error << _("Session: could not load diskstream via XML state") << endmsg;
3500 return -1;
3504 return 0;
3507 /** Connect things to the MMC object */
3508 void
3509 Session::setup_midi_machine_control ()
3511 MIDI::MachineControl* mmc = MIDI::Manager::instance()->mmc ();
3513 mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3514 mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3515 mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
3516 mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
3517 mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
3518 mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
3519 mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
3520 mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
3521 mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
3522 mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
3523 mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
3524 mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
3525 mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
3527 /* also handle MIDI SPP because its so common */
3529 mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this, _1, _2));
3530 mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this, _1, _2));
3531 mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this, _1, _2));
3534 boost::shared_ptr<Controllable>
3535 Session::solo_cut_control() const
3537 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
3538 controls in Ardour that currently get presented to the user in the GUI that require
3539 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
3541 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
3542 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
3543 parameter.
3546 return _solo_cut_control;