Minor cleanups.
[ardour2.git] / libs / ardour / session_state.cc
blob9a359e1b05aae04be1b97bd14bd4844c71218b4a
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/controllable_descriptor.h"
60 #include "pbd/enumwriter.h"
61 #include "pbd/error.h"
62 #include "pbd/pathscanner.h"
63 #include "pbd/pthread_utils.h"
64 #include "pbd/search_path.h"
65 #include "pbd/stacktrace.h"
66 #include "pbd/convert.h"
67 #include "pbd/clear_dir.h"
69 #include "ardour/amp.h"
70 #include "ardour/audio_diskstream.h"
71 #include "ardour/audio_track.h"
72 #include "ardour/audioengine.h"
73 #include "ardour/audiofilesource.h"
74 #include "ardour/audioplaylist.h"
75 #include "ardour/audioregion.h"
76 #include "ardour/auditioner.h"
77 #include "ardour/automation_control.h"
78 #include "ardour/buffer.h"
79 #include "ardour/butler.h"
80 #include "ardour/configuration.h"
81 #include "ardour/control_protocol_manager.h"
82 #include "ardour/crossfade.h"
83 #include "ardour/cycle_timer.h"
84 #include "ardour/directory_names.h"
85 #include "ardour/filename_extensions.h"
86 #include "ardour/io_processor.h"
87 #include "ardour/location.h"
88 #include "ardour/midi_diskstream.h"
89 #include "ardour/midi_patch_manager.h"
90 #include "ardour/midi_playlist.h"
91 #include "ardour/midi_region.h"
92 #include "ardour/midi_source.h"
93 #include "ardour/midi_track.h"
94 #include "ardour/named_selection.h"
95 #include "ardour/pannable.h"
96 #include "ardour/processor.h"
97 #include "ardour/port.h"
98 #include "ardour/proxy_controllable.h"
99 #include "ardour/region_factory.h"
100 #include "ardour/route_group.h"
101 #include "ardour/send.h"
102 #include "ardour/session.h"
103 #include "ardour/session_directory.h"
104 #include "ardour/session_metadata.h"
105 #include "ardour/session_state_utils.h"
106 #include "ardour/session_playlists.h"
107 #include "ardour/session_utils.h"
108 #include "ardour/silentfilesource.h"
109 #include "ardour/slave.h"
110 #include "ardour/smf_source.h"
111 #include "ardour/sndfile_helpers.h"
112 #include "ardour/sndfilesource.h"
113 #include "ardour/source_factory.h"
114 #include "ardour/template_utils.h"
115 #include "ardour/tempo.h"
116 #include "ardour/ticker.h"
117 #include "ardour/user_bundle.h"
118 #include "ardour/utils.h"
119 #include "ardour/utils.h"
120 #include "ardour/version.h"
121 #include "ardour/playlist_factory.h"
123 #include "control_protocol/control_protocol.h"
125 #include "i18n.h"
126 #include <locale.h>
128 using namespace std;
129 using namespace ARDOUR;
130 using namespace PBD;
132 void
133 Session::first_stage_init (string fullpath, string snapshot_name)
135 if (fullpath.length() == 0) {
136 destroy ();
137 throw failed_constructor();
140 char buf[PATH_MAX+1];
141 if (!realpath (fullpath.c_str(), buf) && (errno != ENOENT)) {
142 error << string_compose(_("Could not use path %1 (%s)"), buf, strerror(errno)) << endmsg;
143 destroy ();
144 throw failed_constructor();
147 _path = string(buf);
149 if (_path[_path.length()-1] != '/') {
150 _path += G_DIR_SEPARATOR;
153 if (Glib::file_test (_path, Glib::FILE_TEST_EXISTS) && ::access (_path.c_str(), W_OK)) {
154 _writable = false;
155 } else {
156 _writable = true;
159 /* these two are just provisional settings. set_state()
160 will likely override them.
163 _name = _current_snapshot_name = snapshot_name;
165 set_history_depth (Config->get_history_depth());
167 _current_frame_rate = _engine.frame_rate ();
168 _nominal_frame_rate = _current_frame_rate;
169 _base_frame_rate = _current_frame_rate;
171 _tempo_map = new TempoMap (_current_frame_rate);
172 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
175 _non_soloed_outs_muted = false;
176 _listen_cnt = 0;
177 _solo_isolated_cnt = 0;
178 g_atomic_int_set (&processing_prohibited, 0);
179 _transport_speed = 0;
180 _last_transport_speed = 0;
181 _target_transport_speed = 0;
182 auto_play_legal = false;
183 transport_sub_state = 0;
184 _transport_frame = 0;
185 _requested_return_frame = -1;
186 _session_range_location = 0;
187 g_atomic_int_set (&_record_status, Disabled);
188 loop_changing = false;
189 play_loop = false;
190 have_looped = false;
191 _last_roll_location = 0;
192 _last_roll_or_reversal_location = 0;
193 _last_record_location = 0;
194 pending_locate_frame = 0;
195 pending_locate_roll = false;
196 pending_locate_flush = false;
197 state_was_pending = false;
198 set_next_event ();
199 outbound_mtc_timecode_frame = 0;
200 next_quarter_frame_to_send = -1;
201 current_block_size = 0;
202 solo_update_disabled = false;
203 _have_captured = false;
204 _worst_output_latency = 0;
205 _worst_input_latency = 0;
206 _worst_track_latency = 0;
207 _state_of_the_state = StateOfTheState(CannotSave|InitialConnecting|Loading);
208 _was_seamless = Config->get_seamless_loop ();
209 _slave = 0;
210 _send_qf_mtc = false;
211 _pframes_since_last_mtc = 0;
212 g_atomic_int_set (&_playback_load, 100);
213 g_atomic_int_set (&_capture_load, 100);
214 _play_range = false;
215 _exporting = false;
216 pending_abort = false;
217 destructive_index = 0;
218 first_file_data_format_reset = true;
219 first_file_header_format_reset = true;
220 post_export_sync = false;
221 midi_control_ui = 0;
222 _step_editors = 0;
223 no_questions_about_missing_files = false;
224 _speakers = new Speakers;
226 AudioDiskstream::allocate_working_buffers();
228 /* default short fade = 15ms */
230 Crossfade::set_short_xfade_length ((framecnt_t) floor (config.get_short_xfade_seconds() * frame_rate()));
231 SndFileSource::setup_standard_crossfades (*this, frame_rate());
233 last_mmc_step.tv_sec = 0;
234 last_mmc_step.tv_usec = 0;
235 step_speed = 0.0;
237 /* click sounds are unset by default, which causes us to internal
238 waveforms for clicks.
241 click_length = 0;
242 click_emphasis_length = 0;
243 _clicking = false;
245 process_function = &Session::process_with_events;
247 if (config.get_use_video_sync()) {
248 waiting_for_sync_offset = true;
249 } else {
250 waiting_for_sync_offset = false;
253 last_timecode_when = 0;
254 last_timecode_valid = false;
256 sync_time_vars ();
258 last_rr_session_dir = session_dirs.begin();
259 refresh_disk_space ();
261 /* default: assume simple stereo speaker configuration */
263 _speakers->setup_default_speakers (2);
265 /* slave stuff */
267 average_slave_delta = 1800; // !!! why 1800 ????
268 have_first_delta_accumulator = false;
269 delta_accumulator_cnt = 0;
270 _slave_state = Stopped;
272 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
273 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
274 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
275 add_controllable (_solo_cut_control);
277 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
279 /* These are all static "per-class" signals */
281 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
282 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
283 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
284 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
285 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
287 /* stop IO objects from doing stuff until we're ready for them */
289 Delivery::disable_panners ();
290 IO::disable_connecting ();
294 Session::second_stage_init ()
296 AudioFileSource::set_peak_dir (_session_dir->peak_path().to_string());
298 if (!_is_new) {
299 if (load_state (_current_snapshot_name)) {
300 return -1;
302 cleanup_stubfiles ();
305 if (_butler->start_thread()) {
306 return -1;
309 if (start_midi_thread ()) {
310 return -1;
313 setup_midi_machine_control ();
315 // set_state() will call setup_raid_path(), but if it's a new session we need
316 // to call setup_raid_path() here.
318 if (state_tree) {
319 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
320 return -1;
322 } else {
323 setup_raid_path(_path);
326 /* we can't save till after ::when_engine_running() is called,
327 because otherwise we save state with no connections made.
328 therefore, we reset _state_of_the_state because ::set_state()
329 will have cleared it.
331 we also have to include Loading so that any events that get
332 generated between here and the end of ::when_engine_running()
333 will be processed directly rather than queued.
336 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave|Loading);
338 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
339 _locations->added.connect_same_thread (*this, boost::bind (&Session::locations_added, this, _1));
340 setup_click_sounds (0);
341 setup_midi_control ();
343 /* Pay attention ... */
345 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
346 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
348 try {
349 when_engine_running ();
352 /* handle this one in a different way than all others, so that its clear what happened */
354 catch (AudioEngine::PortRegistrationFailure& err) {
355 error << err.what() << endmsg;
356 return -1;
359 catch (...) {
360 return -1;
363 BootMessage (_("Reset Remote Controls"));
365 send_full_time_code (0);
366 _engine.transport_locate (0);
368 MIDI::Manager::instance()->mmc()->send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
369 MIDI::Manager::instance()->mmc()->send (MIDI::MachineControlCommand (Timecode::Time ()));
371 MidiClockTicker::instance().set_session (this);
372 MIDI::Name::MidiPatchManager::instance().set_session (this);
374 /* initial program change will be delivered later; see ::config_changed() */
376 BootMessage (_("Reset Control Protocols"));
378 ControlProtocolManager::instance().set_session (this);
380 _state_of_the_state = Clean;
382 Port::set_connecting_blocked (false);
384 DirtyChanged (); /* EMIT SIGNAL */
386 if (state_was_pending) {
387 save_state (_current_snapshot_name);
388 remove_pending_capture_state ();
389 state_was_pending = false;
392 BootMessage (_("Session loading complete"));
394 return 0;
397 string
398 Session::raid_path () const
400 SearchPath raid_search_path;
402 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
403 raid_search_path += sys::path((*i).path);
406 return raid_search_path.to_string ();
409 void
410 Session::setup_raid_path (string path)
412 if (path.empty()) {
413 return;
416 space_and_path sp;
417 string fspath;
419 session_dirs.clear ();
421 SearchPath search_path(path);
422 SearchPath sound_search_path;
423 SearchPath midi_search_path;
425 for (SearchPath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
426 sp.path = (*i).to_string ();
427 sp.blocks = 0; // not needed
428 session_dirs.push_back (sp);
430 SessionDirectory sdir(sp.path);
432 sound_search_path += sdir.sound_path ();
433 midi_search_path += sdir.midi_path ();
436 // reset the round-robin soundfile path thingie
437 last_rr_session_dir = session_dirs.begin();
440 bool
441 Session::path_is_within_session (const std::string& path)
443 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
444 if (path.find ((*i).path) == 0) {
445 return true;
448 return false;
452 Session::ensure_subdirs ()
454 string dir;
456 dir = session_directory().peak_path().to_string();
458 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
459 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
460 return -1;
463 dir = session_directory().sound_path().to_string();
465 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
466 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
467 return -1;
470 dir = session_directory().sound_stub_path().to_string();
472 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
473 error << string_compose(_("Session: cannot create session stub sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
474 return -1;
477 dir = session_directory().midi_path().to_string();
479 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
480 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
481 return -1;
484 dir = session_directory().midi_stub_path().to_string();
486 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
487 error << string_compose(_("Session: cannot create session stub midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
488 return -1;
491 dir = session_directory().dead_sound_path().to_string();
493 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
494 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
495 return -1;
498 dir = session_directory().export_path().to_string();
500 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
501 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
502 return -1;
505 dir = analysis_dir ();
507 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
508 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
509 return -1;
512 dir = plugins_dir ();
514 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
515 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
516 return -1;
519 return 0;
522 /** Caller must not hold process lock */
524 Session::create (const string& mix_template, BusProfile* bus_profile)
526 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
527 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
528 return -1;
531 if (ensure_subdirs ()) {
532 return -1;
535 if (!mix_template.empty()) {
536 std::string in_path = mix_template;
538 ifstream in(in_path.c_str());
540 if (in) {
541 string out_path = _path;
542 out_path += _name;
543 out_path += statefile_suffix;
545 ofstream out(out_path.c_str());
547 if (out) {
548 out << in.rdbuf();
549 _is_new = false;
550 return 0;
552 } else {
553 error << string_compose (_("Could not open %1 for writing mix template"), out_path)
554 << endmsg;
555 return -1;
558 } else {
559 error << string_compose (_("Could not open mix template %1 for reading"), in_path)
560 << endmsg;
561 return -1;
566 /* Instantiate metadata */
568 _metadata = new SessionMetadata ();
570 /* set initial start + end point */
572 _state_of_the_state = Clean;
574 /* set up Master Out and Control Out if necessary */
576 if (bus_profile) {
578 RouteList rl;
579 int control_id = 1;
580 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
582 if (bus_profile->master_out_channels) {
583 Route* rt = new Route (*this, _("master"), Route::MasterOut, DataType::AUDIO);
584 if (rt->init ()) {
585 delete rt;
586 return -1;
588 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
589 boost_debug_shared_ptr_mark_interesting (rt, "Route");
590 #endif
591 boost::shared_ptr<Route> r (rt);
593 Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
594 r->input()->ensure_io (count, false, this);
595 r->output()->ensure_io (count, false, this);
597 r->set_remote_control_id (control_id++);
599 rl.push_back (r);
601 if (Config->get_use_monitor_bus()) {
602 Route* rt = new Route (*this, _("monitor"), Route::MonitorOut, DataType::AUDIO);
603 if (rt->init ()) {
604 delete rt;
605 return -1;
607 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
608 boost_debug_shared_ptr_mark_interesting (rt, "Route");
609 #endif
610 boost::shared_ptr<Route> r (rt);
612 Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
613 r->input()->ensure_io (count, false, this);
614 r->output()->ensure_io (count, false, this);
616 r->set_remote_control_id (control_id);
618 rl.push_back (r);
621 } else {
622 /* prohibit auto-connect to master, because there isn't one */
623 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
626 if (!rl.empty()) {
627 add_routes (rl, false);
630 /* this allows the user to override settings with an environment variable.
633 if (no_auto_connect()) {
634 bus_profile->input_ac = AutoConnectOption (0);
635 bus_profile->output_ac = AutoConnectOption (0);
638 Config->set_input_auto_connect (bus_profile->input_ac);
639 Config->set_output_auto_connect (bus_profile->output_ac);
642 save_state ("");
644 return 0;
647 void
648 Session::maybe_write_autosave()
650 if (dirty() && record_status() != Recording) {
651 save_state("", true);
655 void
656 Session::remove_pending_capture_state ()
658 sys::path pending_state_file_path(_session_dir->root_path());
660 pending_state_file_path /= legalize_for_path (_current_snapshot_name) + pending_suffix;
664 sys::remove (pending_state_file_path);
666 catch(sys::filesystem_error& ex)
668 error << string_compose(_("Could remove pending capture state at path \"%1\" (%2)"),
669 pending_state_file_path.to_string(), ex.what()) << endmsg;
673 /** Rename a state file.
674 * @param snapshot_name Snapshot name.
676 void
677 Session::rename_state (string old_name, string new_name)
679 if (old_name == _current_snapshot_name || old_name == _name) {
680 /* refuse to rename the current snapshot or the "main" one */
681 return;
684 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
685 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
687 const sys::path old_xml_path = _session_dir->root_path() / old_xml_filename;
688 const sys::path new_xml_path = _session_dir->root_path() / new_xml_filename;
692 sys::rename (old_xml_path, new_xml_path);
694 catch (const sys::filesystem_error& err)
696 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
697 old_name, new_name, err.what()) << endmsg;
701 /** Remove a state file.
702 * @param snapshot_name Snapshot name.
704 void
705 Session::remove_state (string snapshot_name)
707 if (snapshot_name == _current_snapshot_name || snapshot_name == _name) {
708 // refuse to remove the current snapshot or the "main" one
709 return;
712 sys::path xml_path(_session_dir->root_path());
714 xml_path /= legalize_for_path (snapshot_name) + statefile_suffix;
716 if (!create_backup_file (xml_path)) {
717 // don't remove it if a backup can't be made
718 // create_backup_file will log the error.
719 return;
722 // and delete it
723 sys::remove (xml_path);
726 #ifdef HAVE_JACK_SESSION
727 void
728 Session::jack_session_event (jack_session_event_t * event)
730 char timebuf[128];
731 time_t n;
732 struct tm local_time;
734 time (&n);
735 localtime_r (&n, &local_time);
736 strftime (timebuf, sizeof(timebuf), "JS_%FT%T", &local_time);
738 if (event->type == JackSessionSaveTemplate)
740 if (save_template( timebuf )) {
741 event->flags = JackSessionSaveError;
742 } else {
743 string cmd ("ardour3 -P -U ");
744 cmd += event->client_uuid;
745 cmd += " -T ";
746 cmd += timebuf;
748 event->command_line = strdup (cmd.c_str());
751 else
753 if (save_state (timebuf)) {
754 event->flags = JackSessionSaveError;
755 } else {
756 sys::path xml_path (_session_dir->root_path());
757 xml_path /= legalize_for_path (timebuf) + statefile_suffix;
759 string cmd ("ardour3 -P -U ");
760 cmd += event->client_uuid;
761 cmd += " \"";
762 cmd += xml_path.to_string();
763 cmd += '\"';
765 event->command_line = strdup (cmd.c_str());
769 jack_session_reply (_engine.jack(), event);
771 if (event->type == JackSessionSaveAndQuit) {
772 Quit (); /* EMIT SIGNAL */
775 jack_session_event_free( event );
777 #endif
780 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot)
782 XMLTree tree;
783 sys::path xml_path(_session_dir->root_path());
785 if (!_writable || (_state_of_the_state & CannotSave)) {
786 return 1;
789 if (!_engine.connected ()) {
790 error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"),
791 PROGRAM_NAME)
792 << endmsg;
793 return 1;
796 /* tell sources we're saving first, in case they write out to a new file
797 * which should be saved with the state rather than the old one */
798 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
799 i->second->session_saved();
802 tree.set_root (&get_state());
804 if (snapshot_name.empty()) {
805 snapshot_name = _current_snapshot_name;
806 } else if (switch_to_snapshot) {
807 _current_snapshot_name = snapshot_name;
810 if (!pending) {
812 /* proper save: use statefile_suffix (.ardour in English) */
814 xml_path /= legalize_for_path (snapshot_name) + statefile_suffix;
816 /* make a backup copy of the old file */
818 if (sys::exists(xml_path) && !create_backup_file (xml_path)) {
819 // create_backup_file will log the error
820 return -1;
823 } else {
825 /* pending save: use pending_suffix (.pending in English) */
826 xml_path /= legalize_for_path (snapshot_name) + pending_suffix;
829 sys::path tmp_path(_session_dir->root_path());
831 tmp_path /= legalize_for_path (snapshot_name) + temp_suffix;
833 // cerr << "actually writing state to " << xml_path.to_string() << endl;
835 if (!tree.write (tmp_path.to_string())) {
836 error << string_compose (_("state could not be saved to %1"), tmp_path.to_string()) << endmsg;
837 sys::remove (tmp_path);
838 return -1;
840 } else {
842 if (rename (tmp_path.to_string().c_str(), xml_path.to_string().c_str()) != 0) {
843 error << string_compose (_("could not rename temporary session file %1 to %2"),
844 tmp_path.to_string(), xml_path.to_string()) << endmsg;
845 sys::remove (tmp_path);
846 return -1;
850 if (!pending) {
852 save_history (snapshot_name);
854 bool was_dirty = dirty();
856 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
858 if (was_dirty) {
859 DirtyChanged (); /* EMIT SIGNAL */
862 StateSaved (snapshot_name); /* EMIT SIGNAL */
865 return 0;
869 Session::restore_state (string snapshot_name)
871 if (load_state (snapshot_name) == 0) {
872 set_state (*state_tree->root(), Stateful::loading_state_version);
875 return 0;
879 Session::load_state (string snapshot_name)
881 delete state_tree;
882 state_tree = 0;
884 state_was_pending = false;
886 /* check for leftover pending state from a crashed capture attempt */
888 sys::path xmlpath(_session_dir->root_path());
889 xmlpath /= legalize_for_path (snapshot_name) + pending_suffix;
891 if (sys::exists (xmlpath)) {
893 /* there is pending state from a crashed capture attempt */
895 boost::optional<int> r = AskAboutPendingState();
896 if (r.get_value_or (1)) {
897 state_was_pending = true;
901 if (!state_was_pending) {
902 xmlpath = _session_dir->root_path();
903 xmlpath /= snapshot_name;
906 if (!sys::exists (xmlpath)) {
907 xmlpath = _session_dir->root_path();
908 xmlpath /= legalize_for_path (snapshot_name) + statefile_suffix;
909 if (!sys::exists (xmlpath)) {
910 error << string_compose(_("%1: session state information file \"%2\" doesn't exist!"), _name, xmlpath.to_string()) << endmsg;
911 return 1;
915 state_tree = new XMLTree;
917 set_dirty();
919 /* writable() really reflects the whole folder, but if for any
920 reason the session state file can't be written to, still
921 make us unwritable.
924 if (::access (xmlpath.to_string().c_str(), W_OK) != 0) {
925 _writable = false;
928 if (!state_tree->read (xmlpath.to_string())) {
929 error << string_compose(_("Could not understand ardour file %1"), xmlpath.to_string()) << endmsg;
930 delete state_tree;
931 state_tree = 0;
932 return -1;
935 XMLNode& root (*state_tree->root());
937 if (root.name() != X_("Session")) {
938 error << string_compose (_("Session file %1 is not a session"), xmlpath.to_string()) << endmsg;
939 delete state_tree;
940 state_tree = 0;
941 return -1;
944 const XMLProperty* prop;
946 if ((prop = root.property ("version")) == 0) {
947 /* no version implies very old version of Ardour */
948 Stateful::loading_state_version = 1000;
949 } else {
950 int major;
951 int minor;
952 int micro;
954 sscanf (prop->value().c_str(), "%d.%d.%d", &major, &minor, &micro);
955 Stateful::loading_state_version = (major * 1000) + minor;
958 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION) {
960 sys::path backup_path(_session_dir->root_path());
962 backup_path /= legalize_for_path (snapshot_name) + "-1" + statefile_suffix;
964 // only create a backup once
965 if (sys::exists (backup_path)) {
966 return 0;
969 info << string_compose (_("Copying old session file %1 to %2\nUse %2 with %3 versions before 2.0 from now on"),
970 xmlpath.to_string(), backup_path.to_string(), PROGRAM_NAME)
971 << endmsg;
975 sys::copy_file (xmlpath, backup_path);
977 catch(sys::filesystem_error& ex)
979 error << string_compose (_("Unable to make backup of state file %1 (%2)"),
980 xmlpath.to_string(), ex.what())
981 << endmsg;
982 return -1;
986 return 0;
990 Session::load_options (const XMLNode& node)
992 LocaleGuard lg (X_("POSIX"));
993 config.set_variables (node);
994 return 0;
997 XMLNode&
998 Session::get_state()
1000 return state(true);
1003 XMLNode&
1004 Session::get_template()
1006 /* if we don't disable rec-enable, diskstreams
1007 will believe they need to store their capture
1008 sources in their state node.
1011 disable_record (false);
1013 return state(false);
1016 XMLNode&
1017 Session::state(bool full_state)
1019 XMLNode* node = new XMLNode("Session");
1020 XMLNode* child;
1022 // store libardour version, just in case
1023 char buf[16];
1024 snprintf(buf, sizeof(buf), "%d.%d.%d", libardour3_major_version, libardour3_minor_version, libardour3_micro_version);
1025 node->add_property("version", string(buf));
1027 /* store configuration settings */
1029 if (full_state) {
1031 node->add_property ("name", _name);
1032 snprintf (buf, sizeof (buf), "%" PRId64, _nominal_frame_rate);
1033 node->add_property ("sample-rate", buf);
1035 if (session_dirs.size() > 1) {
1037 string p;
1039 vector<space_and_path>::iterator i = session_dirs.begin();
1040 vector<space_and_path>::iterator next;
1042 ++i; /* skip the first one */
1043 next = i;
1044 ++next;
1046 while (i != session_dirs.end()) {
1048 p += (*i).path;
1050 if (next != session_dirs.end()) {
1051 p += ':';
1052 } else {
1053 break;
1056 ++next;
1057 ++i;
1060 child = node->add_child ("Path");
1061 child->add_content (p);
1065 /* save the ID counter */
1067 snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter());
1068 node->add_property ("id-counter", buf);
1070 /* save the event ID counter */
1072 snprintf (buf, sizeof (buf), "%d", Evoral::event_id_counter());
1073 node->add_property ("event-counter", buf);
1075 /* various options */
1077 node->add_child_nocopy (config.get_variables ());
1079 node->add_child_nocopy (_metadata->get_state());
1081 child = node->add_child ("Sources");
1083 if (full_state) {
1084 Glib::Mutex::Lock sl (source_lock);
1086 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1088 /* Don't save information about non-destructive file sources that are empty
1089 and unused by any regions.
1092 boost::shared_ptr<FileSource> fs;
1093 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
1094 if (!fs->destructive()) {
1095 if (fs->empty() && !fs->used()) {
1096 continue;
1101 child->add_child_nocopy (siter->second->get_state());
1105 child = node->add_child ("Regions");
1107 if (full_state) {
1108 Glib::Mutex::Lock rl (region_lock);
1109 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1110 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1111 boost::shared_ptr<Region> r = i->second;
1112 /* only store regions not attached to playlists */
1113 if (r->playlist() == 0) {
1114 child->add_child_nocopy (r->state ());
1119 if (full_state) {
1120 node->add_child_nocopy (_locations->get_state());
1121 } else {
1122 // for a template, just create a new Locations, populate it
1123 // with the default start and end, and get the state for that.
1124 Locations loc (*this);
1125 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange);
1126 range->set (max_framepos, 0);
1127 loc.add (range);
1128 node->add_child_nocopy (loc.get_state());
1131 child = node->add_child ("Bundles");
1133 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1134 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1135 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1136 if (b) {
1137 child->add_child_nocopy (b->get_state());
1142 child = node->add_child ("Routes");
1144 boost::shared_ptr<RouteList> r = routes.reader ();
1146 RoutePublicOrderSorter cmp;
1147 RouteList public_order (*r);
1148 public_order.sort (cmp);
1150 /* the sort should have put control outs first */
1152 if (_monitor_out) {
1153 assert (_monitor_out == public_order.front());
1156 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1157 if (!(*i)->is_hidden()) {
1158 if (full_state) {
1159 child->add_child_nocopy ((*i)->get_state());
1160 } else {
1161 child->add_child_nocopy ((*i)->get_template());
1167 playlists->add_state (node, full_state);
1169 child = node->add_child ("RouteGroups");
1170 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1171 child->add_child_nocopy ((*i)->get_state());
1174 if (_click_io) {
1175 child = node->add_child ("Click");
1176 child->add_child_nocopy (_click_io->state (full_state));
1179 if (full_state) {
1180 child = node->add_child ("NamedSelections");
1181 for (NamedSelectionList::iterator i = named_selections.begin(); i != named_selections.end(); ++i) {
1182 if (full_state) {
1183 child->add_child_nocopy ((*i)->get_state());
1188 node->add_child_nocopy (_speakers->get_state());
1190 node->add_child_nocopy (_tempo_map->get_state());
1192 node->add_child_nocopy (get_control_protocol_state());
1194 if (_extra_xml) {
1195 node->add_child_copy (*_extra_xml);
1198 return *node;
1201 XMLNode&
1202 Session::get_control_protocol_state ()
1204 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1205 return cpm.get_state();
1209 Session::set_state (const XMLNode& node, int version)
1211 XMLNodeList nlist;
1212 XMLNode* child;
1213 const XMLProperty* prop;
1214 int ret = -1;
1216 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1218 if (node.name() != X_("Session")) {
1219 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1220 return -1;
1223 if ((prop = node.property ("version")) != 0) {
1224 version = atoi (prop->value ()) * 1000;
1227 if ((prop = node.property ("name")) != 0) {
1228 _name = prop->value ();
1231 if ((prop = node.property (X_("sample-rate"))) != 0) {
1233 _nominal_frame_rate = atoi (prop->value());
1235 if (_nominal_frame_rate != _current_frame_rate) {
1236 boost::optional<int> r = AskAboutSampleRateMismatch (_nominal_frame_rate, _current_frame_rate);
1237 if (r.get_value_or (0)) {
1238 return -1;
1243 setup_raid_path(_session_dir->root_path().to_string());
1245 if ((prop = node.property (X_("id-counter"))) != 0) {
1246 uint64_t x;
1247 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1248 ID::init_counter (x);
1249 } else {
1250 /* old sessions used a timebased counter, so fake
1251 the startup ID counter based on a standard
1252 timestamp.
1254 time_t now;
1255 time (&now);
1256 ID::init_counter (now);
1259 if ((prop = node.property (X_("event-counter"))) != 0) {
1260 Evoral::init_event_id_counter (atoi (prop->value()));
1263 IO::disable_connecting ();
1265 /* Object loading order:
1267 Path
1268 Extra
1269 Options/Config
1270 MIDI Control // relies on data from Options/Config
1271 Metadata
1272 Locations
1273 Sources
1274 AudioRegions
1275 Connections
1276 Routes
1277 RouteGroups
1278 MixGroups
1279 Click
1280 ControlProtocols
1283 if ((child = find_named_node (node, "Extra")) != 0) {
1284 _extra_xml = new XMLNode (*child);
1287 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1288 load_options (*child);
1289 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1290 load_options (*child);
1291 } else {
1292 error << _("Session: XML state has no options section") << endmsg;
1295 if (version >= 3000) {
1296 if ((child = find_named_node (node, "Metadata")) == 0) {
1297 warning << _("Session: XML state has no metadata section") << endmsg;
1298 } else if (_metadata->set_state (*child, version)) {
1299 goto out;
1303 if ((child = find_named_node (node, "Locations")) == 0) {
1304 error << _("Session: XML state has no locations section") << endmsg;
1305 goto out;
1306 } else if (_locations->set_state (*child, version)) {
1307 goto out;
1310 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1311 _speakers->set_state (*child, version);
1314 Location* location;
1316 if ((location = _locations->auto_loop_location()) != 0) {
1317 set_auto_loop_location (location);
1320 if ((location = _locations->auto_punch_location()) != 0) {
1321 set_auto_punch_location (location);
1324 if ((location = _locations->session_range_location()) != 0) {
1325 delete _session_range_location;
1326 _session_range_location = location;
1329 if (_session_range_location) {
1330 AudioFileSource::set_header_position_offset (_session_range_location->start());
1333 if ((child = find_named_node (node, "Sources")) == 0) {
1334 error << _("Session: XML state has no sources section") << endmsg;
1335 goto out;
1336 } else if (load_sources (*child)) {
1337 goto out;
1340 if ((child = find_named_node (node, "Regions")) == 0) {
1341 error << _("Session: XML state has no Regions section") << endmsg;
1342 goto out;
1343 } else if (load_regions (*child)) {
1344 goto out;
1347 if ((child = find_named_node (node, "Playlists")) == 0) {
1348 error << _("Session: XML state has no playlists section") << endmsg;
1349 goto out;
1350 } else if (playlists->load (*this, *child)) {
1351 goto out;
1354 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1355 // this is OK
1356 } else if (playlists->load_unused (*this, *child)) {
1357 goto out;
1360 if ((child = find_named_node (node, "NamedSelections")) != 0) {
1361 if (load_named_selections (*child)) {
1362 goto out;
1366 if (version >= 3000) {
1367 if ((child = find_named_node (node, "Bundles")) == 0) {
1368 warning << _("Session: XML state has no bundles section") << endmsg;
1369 //goto out;
1370 } else {
1371 /* We can't load Bundles yet as they need to be able
1372 to convert from port names to Port objects, which can't happen until
1373 later */
1374 _bundle_xml_node = new XMLNode (*child);
1378 if ((child = find_named_node (node, "TempoMap")) == 0) {
1379 error << _("Session: XML state has no Tempo Map section") << endmsg;
1380 goto out;
1381 } else if (_tempo_map->set_state (*child, version)) {
1382 goto out;
1385 if (version < 3000) {
1386 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1387 error << _("Session: XML state has no diskstreams section") << endmsg;
1388 goto out;
1389 } else if (load_diskstreams_2X (*child, version)) {
1390 goto out;
1394 if ((child = find_named_node (node, "Routes")) == 0) {
1395 error << _("Session: XML state has no routes section") << endmsg;
1396 goto out;
1397 } else if (load_routes (*child, version)) {
1398 goto out;
1401 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1402 _diskstreams_2X.clear ();
1404 if (version >= 3000) {
1406 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1407 error << _("Session: XML state has no route groups section") << endmsg;
1408 goto out;
1409 } else if (load_route_groups (*child, version)) {
1410 goto out;
1413 } else if (version < 3000) {
1415 if ((child = find_named_node (node, "EditGroups")) == 0) {
1416 error << _("Session: XML state has no edit groups section") << endmsg;
1417 goto out;
1418 } else if (load_route_groups (*child, version)) {
1419 goto out;
1422 if ((child = find_named_node (node, "MixGroups")) == 0) {
1423 error << _("Session: XML state has no mix groups section") << endmsg;
1424 goto out;
1425 } else if (load_route_groups (*child, version)) {
1426 goto out;
1430 if ((child = find_named_node (node, "Click")) == 0) {
1431 warning << _("Session: XML state has no click section") << endmsg;
1432 } else if (_click_io) {
1433 _click_io->set_state (*child, version);
1436 if ((child = find_named_node (node, "ControlProtocols")) != 0) {
1437 ControlProtocolManager::instance().set_protocol_states (*child);
1440 /* here beginneth the second phase ... */
1442 StateReady (); /* EMIT SIGNAL */
1444 return 0;
1446 out:
1447 return ret;
1451 Session::load_routes (const XMLNode& node, int version)
1453 XMLNodeList nlist;
1454 XMLNodeConstIterator niter;
1455 RouteList new_routes;
1457 nlist = node.children();
1459 set_dirty();
1461 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1463 boost::shared_ptr<Route> route;
1464 if (version < 3000) {
1465 route = XMLRouteFactory_2X (**niter, version);
1466 } else {
1467 route = XMLRouteFactory (**niter, version);
1470 if (route == 0) {
1471 error << _("Session: cannot create Route from XML description.") << endmsg;
1472 return -1;
1475 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1477 new_routes.push_back (route);
1480 add_routes (new_routes, false);
1482 return 0;
1485 boost::shared_ptr<Route>
1486 Session::XMLRouteFactory (const XMLNode& node, int version)
1488 boost::shared_ptr<Route> ret;
1490 if (node.name() != "Route") {
1491 return ret;
1494 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1496 DataType type = DataType::AUDIO;
1497 const XMLProperty* prop = node.property("default-type");
1499 if (prop) {
1500 type = DataType (prop->value());
1503 assert (type != DataType::NIL);
1505 if (ds_child) {
1507 Track* track;
1509 if (type == DataType::AUDIO) {
1510 track = new AudioTrack (*this, X_("toBeResetFroXML"));
1512 } else {
1513 track = new MidiTrack (*this, X_("toBeResetFroXML"));
1516 if (track->init()) {
1517 delete track;
1518 return ret;
1521 if (track->set_state (node, version)) {
1522 delete track;
1523 return ret;
1526 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1527 boost_debug_shared_ptr_mark_interesting (track, "Track");
1528 #endif
1529 ret.reset (track);
1531 } else {
1532 Route* rt = new Route (*this, X_("toBeResetFroXML"));
1534 if (rt->init () == 0 && rt->set_state (node, version) == 0) {
1535 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1536 boost_debug_shared_ptr_mark_interesting (rt, "Route");
1537 #endif
1538 ret.reset (rt);
1539 } else {
1540 delete rt;
1544 return ret;
1547 boost::shared_ptr<Route>
1548 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1550 boost::shared_ptr<Route> ret;
1552 if (node.name() != "Route") {
1553 return ret;
1556 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1557 if (!ds_prop) {
1558 ds_prop = node.property (X_("diskstream"));
1561 DataType type = DataType::AUDIO;
1562 const XMLProperty* prop = node.property("default-type");
1564 if (prop) {
1565 type = DataType (prop->value());
1568 assert (type != DataType::NIL);
1570 if (ds_prop) {
1572 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1573 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1574 ++i;
1577 if (i == _diskstreams_2X.end()) {
1578 error << _("Could not find diskstream for route") << endmsg;
1579 return boost::shared_ptr<Route> ();
1582 Track* track;
1584 if (type == DataType::AUDIO) {
1585 track = new AudioTrack (*this, X_("toBeResetFroXML"));
1587 } else {
1588 track = new MidiTrack (*this, X_("toBeResetFroXML"));
1591 if (track->init()) {
1592 delete track;
1593 return ret;
1596 if (track->set_state (node, version)) {
1597 delete track;
1598 return ret;
1601 track->set_diskstream (*i);
1603 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1604 boost_debug_shared_ptr_mark_interesting (track, "Track");
1605 #endif
1606 ret.reset (track);
1608 } else {
1609 Route* rt = new Route (*this, X_("toBeResetFroXML"));
1611 if (rt->init () == 0 && rt->set_state (node, version) == 0) {
1612 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1613 boost_debug_shared_ptr_mark_interesting (rt, "Route");
1614 #endif
1615 ret.reset (rt);
1616 } else {
1617 delete rt;
1621 return ret;
1625 Session::load_regions (const XMLNode& node)
1627 XMLNodeList nlist;
1628 XMLNodeConstIterator niter;
1629 boost::shared_ptr<Region> region;
1631 nlist = node.children();
1633 set_dirty();
1635 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1636 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1637 error << _("Session: cannot create Region from XML description.");
1638 const XMLProperty *name = (**niter).property("name");
1640 if (name) {
1641 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1644 error << endmsg;
1648 return 0;
1651 boost::shared_ptr<Region>
1652 Session::XMLRegionFactory (const XMLNode& node, bool full)
1654 const XMLProperty* type = node.property("type");
1656 try {
1658 if (!type || type->value() == "audio") {
1659 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1660 } else if (type->value() == "midi") {
1661 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1664 } catch (failed_constructor& err) {
1665 return boost::shared_ptr<Region> ();
1668 return boost::shared_ptr<Region> ();
1671 boost::shared_ptr<AudioRegion>
1672 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1674 const XMLProperty* prop;
1675 boost::shared_ptr<Source> source;
1676 boost::shared_ptr<AudioSource> as;
1677 SourceList sources;
1678 SourceList master_sources;
1679 uint32_t nchans = 1;
1680 char buf[128];
1682 if (node.name() != X_("Region")) {
1683 return boost::shared_ptr<AudioRegion>();
1686 if ((prop = node.property (X_("channels"))) != 0) {
1687 nchans = atoi (prop->value().c_str());
1690 if ((prop = node.property ("name")) == 0) {
1691 cerr << "no name for this region\n";
1692 abort ();
1695 if ((prop = node.property (X_("source-0"))) == 0) {
1696 if ((prop = node.property ("source")) == 0) {
1697 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1698 return boost::shared_ptr<AudioRegion>();
1702 PBD::ID s_id (prop->value());
1704 if ((source = source_by_id (s_id)) == 0) {
1705 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1706 return boost::shared_ptr<AudioRegion>();
1709 as = boost::dynamic_pointer_cast<AudioSource>(source);
1710 if (!as) {
1711 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1712 return boost::shared_ptr<AudioRegion>();
1715 sources.push_back (as);
1717 /* pickup other channels */
1719 for (uint32_t n=1; n < nchans; ++n) {
1720 snprintf (buf, sizeof(buf), X_("source-%d"), n);
1721 if ((prop = node.property (buf)) != 0) {
1723 PBD::ID id2 (prop->value());
1725 if ((source = source_by_id (id2)) == 0) {
1726 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1727 return boost::shared_ptr<AudioRegion>();
1730 as = boost::dynamic_pointer_cast<AudioSource>(source);
1731 if (!as) {
1732 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1733 return boost::shared_ptr<AudioRegion>();
1735 sources.push_back (as);
1739 for (uint32_t n = 0; n < nchans; ++n) {
1740 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
1741 if ((prop = node.property (buf)) != 0) {
1743 PBD::ID id2 (prop->value());
1745 if ((source = source_by_id (id2)) == 0) {
1746 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1747 return boost::shared_ptr<AudioRegion>();
1750 as = boost::dynamic_pointer_cast<AudioSource>(source);
1751 if (!as) {
1752 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1753 return boost::shared_ptr<AudioRegion>();
1755 master_sources.push_back (as);
1759 try {
1760 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
1762 /* a final detail: this is the one and only place that we know how long missing files are */
1764 if (region->whole_file()) {
1765 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1766 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1767 if (sfp) {
1768 sfp->set_length (region->length());
1773 if (!master_sources.empty()) {
1774 if (master_sources.size() != nchans) {
1775 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
1776 } else {
1777 region->set_master_sources (master_sources);
1781 return region;
1785 catch (failed_constructor& err) {
1786 return boost::shared_ptr<AudioRegion>();
1790 boost::shared_ptr<MidiRegion>
1791 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
1793 const XMLProperty* prop;
1794 boost::shared_ptr<Source> source;
1795 boost::shared_ptr<MidiSource> ms;
1796 SourceList sources;
1798 if (node.name() != X_("Region")) {
1799 return boost::shared_ptr<MidiRegion>();
1802 if ((prop = node.property ("name")) == 0) {
1803 cerr << "no name for this region\n";
1804 abort ();
1807 if ((prop = node.property (X_("source-0"))) == 0) {
1808 if ((prop = node.property ("source")) == 0) {
1809 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
1810 return boost::shared_ptr<MidiRegion>();
1814 PBD::ID s_id (prop->value());
1816 if ((source = source_by_id (s_id)) == 0) {
1817 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
1818 return boost::shared_ptr<MidiRegion>();
1821 ms = boost::dynamic_pointer_cast<MidiSource>(source);
1822 if (!ms) {
1823 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
1824 return boost::shared_ptr<MidiRegion>();
1827 sources.push_back (ms);
1829 try {
1830 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
1831 /* a final detail: this is the one and only place that we know how long missing files are */
1833 if (region->whole_file()) {
1834 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1835 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1836 if (sfp) {
1837 sfp->set_length (region->length());
1842 return region;
1845 catch (failed_constructor& err) {
1846 return boost::shared_ptr<MidiRegion>();
1850 XMLNode&
1851 Session::get_sources_as_xml ()
1854 XMLNode* node = new XMLNode (X_("Sources"));
1855 Glib::Mutex::Lock lm (source_lock);
1857 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
1858 node->add_child_nocopy (i->second->get_state());
1861 return *node;
1864 string
1865 Session::path_from_region_name (DataType type, string name, string identifier)
1867 char buf[PATH_MAX+1];
1868 uint32_t n;
1869 SessionDirectory sdir(get_best_session_directory_for_new_source());
1870 sys::path source_dir = ((type == DataType::AUDIO)
1871 ? sdir.sound_path() : sdir.midi_path());
1873 string ext = native_header_format_extension (config.get_native_file_header_format(), type);
1875 for (n = 0; n < 999999; ++n) {
1876 if (identifier.length()) {
1877 snprintf (buf, sizeof(buf), "%s%s%" PRIu32 "%s", name.c_str(),
1878 identifier.c_str(), n, ext.c_str());
1879 } else {
1880 snprintf (buf, sizeof(buf), "%s-%" PRIu32 "%s", name.c_str(),
1881 n, ext.c_str());
1884 sys::path source_path = source_dir / buf;
1886 if (!sys::exists (source_path)) {
1887 return source_path.to_string();
1891 error << string_compose (_("cannot create new file from region name \"%1\" with ident = \"%2\": too many existing files with similar names"),
1892 name, identifier)
1893 << endmsg;
1895 return "";
1900 Session::load_sources (const XMLNode& node)
1902 XMLNodeList nlist;
1903 XMLNodeConstIterator niter;
1904 boost::shared_ptr<Source> source;
1906 nlist = node.children();
1908 set_dirty();
1910 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1911 retry:
1912 try {
1913 if ((source = XMLSourceFactory (**niter)) == 0) {
1914 error << _("Session: cannot create Source from XML description.") << endmsg;
1917 } catch (MissingSource& err) {
1919 int user_choice;
1921 if (!no_questions_about_missing_files) {
1922 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
1923 } else {
1924 user_choice = -2;
1927 switch (user_choice) {
1928 case 0:
1929 /* user added a new search location, so try again */
1930 goto retry;
1933 case 1:
1934 /* user asked to quit the entire session load
1936 return -1;
1938 case 2:
1939 no_questions_about_missing_files = true;
1940 goto retry;
1942 case 3:
1943 no_questions_about_missing_files = true;
1944 /* fallthru */
1946 case -1:
1947 default:
1948 warning << _("A sound file is missing. It will be replaced by silence.") << endmsg;
1949 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
1950 break;
1955 return 0;
1958 boost::shared_ptr<Source>
1959 Session::XMLSourceFactory (const XMLNode& node)
1961 if (node.name() != "Source") {
1962 return boost::shared_ptr<Source>();
1965 try {
1966 /* note: do peak building in another thread when loading session state */
1967 return SourceFactory::create (*this, node, true);
1970 catch (failed_constructor& err) {
1971 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the progammers."), PROGRAM_NAME) << endmsg;
1972 return boost::shared_ptr<Source>();
1977 Session::save_template (string template_name)
1979 XMLTree tree;
1981 if (_state_of_the_state & CannotSave) {
1982 return -1;
1985 sys::path user_template_dir(user_template_directory());
1989 sys::create_directories (user_template_dir);
1991 catch(sys::filesystem_error& ex)
1993 error << string_compose(_("Could not create mix templates directory \"%1\" (%2)"),
1994 user_template_dir.to_string(), ex.what()) << endmsg;
1995 return -1;
1998 tree.set_root (&get_template());
2000 sys::path template_file_path(user_template_dir);
2001 template_file_path /= template_name + template_suffix;
2003 if (sys::exists (template_file_path))
2005 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2006 template_file_path.to_string()) << endmsg;
2007 return -1;
2010 if (!tree.write (template_file_path.to_string())) {
2011 error << _("template not saved") << endmsg;
2012 return -1;
2015 return 0;
2019 Session::rename_template (string old_name, string new_name)
2021 sys::path old_path (user_template_directory());
2022 old_path /= old_name + template_suffix;
2024 sys::path new_path(user_template_directory());
2025 new_path /= new_name + template_suffix;
2027 if (sys::exists (new_path)) {
2028 warning << string_compose(_("Template \"%1\" already exists - template not renamed"),
2029 new_path.to_string()) << endmsg;
2030 return -1;
2033 try {
2034 sys::rename (old_path, new_path);
2035 return 0;
2036 } catch (...) {
2037 return -1;
2042 Session::delete_template (string name)
2044 sys::path path = user_template_directory();
2045 path /= name + template_suffix;
2047 try {
2048 sys::remove (path);
2049 return 0;
2050 } catch (...) {
2051 return -1;
2055 void
2056 Session::refresh_disk_space ()
2058 #if HAVE_SYS_VFS_H
2059 struct statfs statfsbuf;
2060 vector<space_and_path>::iterator i;
2061 Glib::Mutex::Lock lm (space_lock);
2062 double scale;
2064 /* get freespace on every FS that is part of the session path */
2066 _total_free_4k_blocks = 0;
2068 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2069 statfs ((*i).path.c_str(), &statfsbuf);
2071 scale = statfsbuf.f_bsize/4096.0;
2073 (*i).blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2074 _total_free_4k_blocks += (*i).blocks;
2076 #endif
2079 string
2080 Session::get_best_session_directory_for_new_source ()
2082 vector<space_and_path>::iterator i;
2083 string result = _session_dir->root_path().to_string();
2085 /* handle common case without system calls */
2087 if (session_dirs.size() == 1) {
2088 return result;
2091 /* OK, here's the algorithm we're following here:
2093 We want to select which directory to use for
2094 the next file source to be created. Ideally,
2095 we'd like to use a round-robin process so as to
2096 get maximum performance benefits from splitting
2097 the files across multiple disks.
2099 However, in situations without much diskspace, an
2100 RR approach may end up filling up a filesystem
2101 with new files while others still have space.
2102 Its therefore important to pay some attention to
2103 the freespace in the filesystem holding each
2104 directory as well. However, if we did that by
2105 itself, we'd keep creating new files in the file
2106 system with the most space until it was as full
2107 as all others, thus negating any performance
2108 benefits of this RAID-1 like approach.
2110 So, we use a user-configurable space threshold. If
2111 there are at least 2 filesystems with more than this
2112 much space available, we use RR selection between them.
2113 If not, then we pick the filesystem with the most space.
2115 This gets a good balance between the two
2116 approaches.
2119 refresh_disk_space ();
2121 int free_enough = 0;
2123 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2124 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2125 free_enough++;
2129 if (free_enough >= 2) {
2130 /* use RR selection process, ensuring that the one
2131 picked works OK.
2134 i = last_rr_session_dir;
2136 do {
2137 if (++i == session_dirs.end()) {
2138 i = session_dirs.begin();
2141 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2142 if (create_session_directory ((*i).path)) {
2143 result = (*i).path;
2144 last_rr_session_dir = i;
2145 return result;
2149 } while (i != last_rr_session_dir);
2151 } else {
2153 /* pick FS with the most freespace (and that
2154 seems to actually work ...)
2157 vector<space_and_path> sorted;
2158 space_and_path_ascending_cmp cmp;
2160 sorted = session_dirs;
2161 sort (sorted.begin(), sorted.end(), cmp);
2163 for (i = sorted.begin(); i != sorted.end(); ++i) {
2164 if (create_session_directory ((*i).path)) {
2165 result = (*i).path;
2166 last_rr_session_dir = i;
2167 return result;
2172 return result;
2176 Session::load_named_selections (const XMLNode& node)
2178 XMLNodeList nlist;
2179 XMLNodeConstIterator niter;
2180 NamedSelection *ns;
2182 nlist = node.children();
2184 set_dirty();
2186 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2188 if ((ns = XMLNamedSelectionFactory (**niter)) == 0) {
2189 error << _("Session: cannot create Named Selection from XML description.") << endmsg;
2193 return 0;
2196 NamedSelection *
2197 Session::XMLNamedSelectionFactory (const XMLNode& node)
2199 try {
2200 return new NamedSelection (*this, node);
2203 catch (failed_constructor& err) {
2204 return 0;
2208 string
2209 Session::automation_dir () const
2211 return Glib::build_filename (_path, "automation");
2214 string
2215 Session::analysis_dir () const
2217 return Glib::build_filename (_path, "analysis");
2220 string
2221 Session::plugins_dir () const
2223 return Glib::build_filename (_path, "plugins");
2227 Session::load_bundles (XMLNode const & node)
2229 XMLNodeList nlist = node.children();
2230 XMLNodeConstIterator niter;
2232 set_dirty();
2234 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2235 if ((*niter)->name() == "InputBundle") {
2236 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2237 } else if ((*niter)->name() == "OutputBundle") {
2238 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2239 } else {
2240 error << string_compose(_("Unknown node \"%1\" found in Bundles list from state file"), (*niter)->name()) << endmsg;
2241 return -1;
2245 return 0;
2249 Session::load_route_groups (const XMLNode& node, int version)
2251 XMLNodeList nlist = node.children();
2252 XMLNodeConstIterator niter;
2254 set_dirty ();
2256 if (version >= 3000) {
2258 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2259 if ((*niter)->name() == "RouteGroup") {
2260 RouteGroup* rg = new RouteGroup (*this, "");
2261 add_route_group (rg);
2262 rg->set_state (**niter, version);
2266 } else if (version < 3000) {
2268 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2269 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2270 RouteGroup* rg = new RouteGroup (*this, "");
2271 add_route_group (rg);
2272 rg->set_state (**niter, version);
2277 return 0;
2280 void
2281 Session::auto_save()
2283 save_state (_current_snapshot_name);
2286 static bool
2287 state_file_filter (const string &str, void */*arg*/)
2289 return (str.length() > strlen(statefile_suffix) &&
2290 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2293 struct string_cmp {
2294 bool operator()(const string* a, const string* b) {
2295 return *a < *b;
2299 static string*
2300 remove_end(string* state)
2302 string statename(*state);
2304 string::size_type start,end;
2305 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2306 statename = statename.substr (start+1);
2309 if ((end = statename.rfind(".ardour")) == string::npos) {
2310 end = statename.length();
2313 return new string(statename.substr (0, end));
2316 vector<string *> *
2317 Session::possible_states (string path)
2319 PathScanner scanner;
2320 vector<string*>* states = scanner (path, state_file_filter, 0, false, false);
2322 transform(states->begin(), states->end(), states->begin(), remove_end);
2324 string_cmp cmp;
2325 sort (states->begin(), states->end(), cmp);
2327 return states;
2330 vector<string *> *
2331 Session::possible_states () const
2333 return possible_states(_path);
2336 void
2337 Session::add_route_group (RouteGroup* g)
2339 _route_groups.push_back (g);
2340 route_group_added (g); /* EMIT SIGNAL */
2342 g->MembershipChanged.connect_same_thread (*this, boost::bind (&Session::route_group_changed, this));
2343 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_changed, this));
2345 set_dirty ();
2348 void
2349 Session::remove_route_group (RouteGroup& rg)
2351 list<RouteGroup*>::iterator i;
2353 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2354 _route_groups.erase (i);
2355 delete &rg;
2357 route_group_removed (); /* EMIT SIGNAL */
2362 RouteGroup *
2363 Session::route_group_by_name (string name)
2365 list<RouteGroup *>::iterator i;
2367 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2368 if ((*i)->name() == name) {
2369 return* i;
2372 return 0;
2375 RouteGroup&
2376 Session::all_route_group() const
2378 return *_all_route_group;
2381 void
2382 Session::add_commands (vector<Command*> const & cmds)
2384 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2385 add_command (*i);
2389 void
2390 Session::begin_reversible_command (const string& name)
2392 begin_reversible_command (g_quark_from_string (name.c_str ()));
2395 /** Begin a reversible command using a GQuark to identify it.
2396 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2397 * but there must be as many begin...()s as there are commit...()s.
2399 void
2400 Session::begin_reversible_command (GQuark q)
2402 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2403 to hold all the commands that are committed. This keeps the order of
2404 commands correct in the history.
2407 if (_current_trans == 0) {
2408 /* start a new transaction */
2409 assert (_current_trans_quarks.empty ());
2410 _current_trans = new UndoTransaction();
2411 _current_trans->set_name (g_quark_to_string (q));
2414 _current_trans_quarks.push_front (q);
2417 void
2418 Session::commit_reversible_command (Command *cmd)
2420 assert (_current_trans);
2421 assert (!_current_trans_quarks.empty ());
2423 struct timeval now;
2425 if (cmd) {
2426 _current_trans->add_command (cmd);
2429 _current_trans_quarks.pop_front ();
2431 if (!_current_trans_quarks.empty ()) {
2432 /* the transaction we're committing is not the top-level one */
2433 return;
2436 if (_current_trans->empty()) {
2437 /* no commands were added to the transaction, so just get rid of it */
2438 delete _current_trans;
2439 _current_trans = 0;
2440 return;
2443 gettimeofday (&now, 0);
2444 _current_trans->set_timestamp (now);
2446 _history.add (_current_trans);
2447 _current_trans = 0;
2450 static bool
2451 accept_all_non_peak_files (const string& path, void */*arg*/)
2453 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2454 return false;
2457 return (path.length() > 5 && path.find (peakfile_suffix) != (path.length() - 5));
2460 static bool
2461 accept_all_state_files (const string& path, void */*arg*/)
2463 return (path.length() > 7 && path.find (".ardour") == (path.length() - 7));
2467 Session::find_all_sources (string path, set<string>& result)
2469 XMLTree tree;
2470 XMLNode* node;
2472 if (!tree.read (path)) {
2473 return -1;
2476 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2477 return -2;
2480 XMLNodeList nlist;
2481 XMLNodeConstIterator niter;
2483 nlist = node->children();
2485 set_dirty();
2487 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2489 XMLProperty* prop;
2491 if ((prop = (*niter)->property (X_("type"))) == 0) {
2492 continue;
2495 DataType type (prop->value());
2497 if ((prop = (*niter)->property (X_("name"))) == 0) {
2498 continue;
2501 if (Glib::path_is_absolute (prop->value())) {
2502 /* external file, ignore */
2503 continue;
2506 string found_path;
2507 bool is_new;
2508 uint16_t chan;
2510 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
2511 result.insert (found_path);
2515 return 0;
2519 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
2521 PathScanner scanner;
2522 vector<string*>* state_files;
2523 string ripped;
2524 string this_snapshot_path;
2526 result.clear ();
2528 ripped = _path;
2530 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
2531 ripped = ripped.substr (0, ripped.length() - 1);
2534 state_files = scanner (ripped, accept_all_state_files, (void *) 0, false, true);
2536 if (state_files == 0) {
2537 /* impossible! */
2538 return 0;
2541 this_snapshot_path = _path;
2542 this_snapshot_path += legalize_for_path (_current_snapshot_name);
2543 this_snapshot_path += statefile_suffix;
2545 for (vector<string*>::iterator i = state_files->begin(); i != state_files->end(); ++i) {
2547 if (exclude_this_snapshot && **i == this_snapshot_path) {
2548 continue;
2551 if (find_all_sources (**i, result) < 0) {
2552 return -1;
2556 return 0;
2559 struct RegionCounter {
2560 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
2561 AudioSourceList::iterator iter;
2562 boost::shared_ptr<Region> region;
2563 uint32_t count;
2565 RegionCounter() : count (0) {}
2569 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
2571 boost::optional<int> r = AskAboutPlaylistDeletion (p);
2572 return r.get_value_or (1);
2575 void
2576 Session::cleanup_regions ()
2578 const RegionFactory::RegionMap& regions (RegionFactory::regions());
2580 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2582 boost::shared_ptr<AudioRegion> audio_region = boost::dynamic_pointer_cast<AudioRegion>( i->second);
2584 if (!audio_region) {
2585 continue;
2588 uint32_t used = playlists->region_use_count (audio_region);
2590 if (used == 0 && !audio_region->automatic()) {
2591 RegionFactory::map_remove(i->second);
2595 /* dump the history list */
2596 _history.clear ();
2598 save_state ("");
2602 Session::cleanup_sources (CleanupReport& rep)
2604 // FIXME: needs adaptation to midi
2606 vector<boost::shared_ptr<Source> > dead_sources;
2607 PathScanner scanner;
2608 string sound_path;
2609 vector<space_and_path>::iterator i;
2610 vector<space_and_path>::iterator nexti;
2611 vector<string*>* soundfiles;
2612 vector<string> unused;
2613 set<string> all_sources;
2614 bool used;
2615 string spath;
2616 int ret = -1;
2618 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
2620 /* step 1: consider deleting all unused playlists */
2622 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
2623 ret = 0;
2624 goto out;
2627 /* step 2: find all un-used sources */
2629 rep.paths.clear ();
2630 rep.space = 0;
2632 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
2634 SourceMap::iterator tmp;
2636 tmp = i;
2637 ++tmp;
2639 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
2640 capture files.
2643 if (!i->second->used() && (i->second->length(i->second->timeline_position() > 0))) {
2644 dead_sources.push_back (i->second);
2645 i->second->drop_references ();
2648 i = tmp;
2651 /* build a list of all the possible sound directories for the session */
2653 for (i = session_dirs.begin(); i != session_dirs.end(); ) {
2655 nexti = i;
2656 ++nexti;
2658 SessionDirectory sdir ((*i).path);
2659 sound_path += sdir.sound_path().to_string();
2661 if (nexti != session_dirs.end()) {
2662 sound_path += ':';
2665 i = nexti;
2668 /* now do the same thing for the files that ended up in the sounds dir(s)
2669 but are not referenced as sources in any snapshot.
2672 soundfiles = scanner (sound_path, accept_all_non_peak_files, (void *) 0, false, true);
2674 if (soundfiles == 0) {
2675 return 0;
2678 /* find all sources, but don't use this snapshot because the
2679 state file on disk still references sources we may have already
2680 dropped.
2683 find_all_sources_across_snapshots (all_sources, true);
2685 /* add our current source list
2688 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2689 boost::shared_ptr<FileSource> fs;
2691 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) != 0) {
2692 all_sources.insert (fs->path());
2696 char tmppath1[PATH_MAX+1];
2697 char tmppath2[PATH_MAX+1];
2699 for (vector<string*>::iterator x = soundfiles->begin(); x != soundfiles->end(); ++x) {
2701 used = false;
2702 spath = **x;
2704 for (set<string>::iterator i = all_sources.begin(); i != all_sources.end(); ++i) {
2706 if (realpath(spath.c_str(), tmppath1) == 0) {
2707 error << string_compose (_("Cannot expand path %1 (%2)"),
2708 spath, strerror (errno)) << endmsg;
2709 continue;
2712 if (realpath((*i).c_str(), tmppath2) == 0) {
2713 error << string_compose (_("Cannot expand path %1 (%2)"),
2714 (*i), strerror (errno)) << endmsg;
2715 continue;
2718 if (strcmp(tmppath1, tmppath2) == 0) {
2719 used = true;
2720 break;
2724 if (!used) {
2725 unused.push_back (spath);
2729 /* now try to move all unused files into the "dead_sounds" directory(ies) */
2731 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
2732 struct stat statbuf;
2734 rep.paths.push_back (*x);
2735 if (stat ((*x).c_str(), &statbuf) == 0) {
2736 rep.space += statbuf.st_size;
2739 string newpath;
2741 /* don't move the file across filesystems, just
2742 stick it in the `dead_sound_dir_name' directory
2743 on whichever filesystem it was already on.
2746 if ((*x).find ("/sounds/") != string::npos) {
2748 /* old school, go up 1 level */
2750 newpath = Glib::path_get_dirname (*x); // "sounds"
2751 newpath = Glib::path_get_dirname (newpath); // "session-name"
2753 } else {
2755 /* new school, go up 4 levels */
2757 newpath = Glib::path_get_dirname (*x); // "audiofiles"
2758 newpath = Glib::path_get_dirname (newpath); // "session-name"
2759 newpath = Glib::path_get_dirname (newpath); // "interchange"
2760 newpath = Glib::path_get_dirname (newpath); // "session-dir"
2763 newpath = Glib::build_filename (newpath, dead_sound_dir_name);
2765 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
2766 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
2767 return -1;
2770 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
2772 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2774 /* the new path already exists, try versioning */
2776 char buf[PATH_MAX+1];
2777 int version = 1;
2778 string newpath_v;
2780 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
2781 newpath_v = buf;
2783 while (access (newpath_v.c_str(), F_OK) == 0 && version < 999) {
2784 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
2785 newpath_v = buf;
2788 if (version == 999) {
2789 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
2790 newpath)
2791 << endmsg;
2792 } else {
2793 newpath = newpath_v;
2796 } else {
2798 /* it doesn't exist, or we can't read it or something */
2802 if (::rename ((*x).c_str(), newpath.c_str()) != 0) {
2803 error << string_compose (_("cannot rename audio file source from %1 to %2 (%3)"),
2804 (*x), newpath, strerror (errno))
2805 << endmsg;
2806 goto out;
2809 /* see if there an easy to find peakfile for this file, and remove it.
2812 string peakpath = (*x).substr (0, (*x).find_last_of ('.'));
2813 peakpath += peakfile_suffix;
2815 if (access (peakpath.c_str(), W_OK) == 0) {
2816 if (::unlink (peakpath.c_str()) != 0) {
2817 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"),
2818 peakpath, _path, strerror (errno))
2819 << endmsg;
2820 /* try to back out */
2821 rename (newpath.c_str(), _path.c_str());
2822 goto out;
2827 ret = 0;
2829 /* dump the history list */
2831 _history.clear ();
2833 /* save state so we don't end up a session file
2834 referring to non-existent sources.
2837 save_state ("");
2839 out:
2840 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
2842 return ret;
2846 Session::cleanup_trash_sources (CleanupReport& rep)
2848 // FIXME: needs adaptation for MIDI
2850 vector<space_and_path>::iterator i;
2851 string dead_sound_dir;
2853 rep.paths.clear ();
2854 rep.space = 0;
2856 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2858 dead_sound_dir = (*i).path;
2859 dead_sound_dir += dead_sound_dir_name;
2861 clear_directory (dead_sound_dir, &rep.space, &rep.paths);
2864 return 0;
2867 void
2868 Session::cleanup_stubfiles ()
2870 vector<space_and_path>::iterator i;
2872 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2874 string dir;
2875 string lname = legalize_for_path (_name);
2877 vector<string> v;
2879 /* XXX this is a hack caused by semantic conflicts
2880 between space_and_path and the SessionDirectory concept.
2883 v.push_back ((*i).path);
2884 v.push_back ("interchange");
2885 v.push_back (lname);
2886 v.push_back ("audiofiles");
2887 v.push_back (stub_dir_name);
2889 dir = Glib::build_filename (v);
2891 clear_directory (dir);
2893 v.clear ();
2894 v.push_back ((*i).path);
2895 v.push_back ("interchange");
2896 v.push_back (lname);
2897 v.push_back ("midifiles");
2898 v.push_back (stub_dir_name);
2900 dir = Glib::build_filename (v);
2902 clear_directory (dir);
2906 void
2907 Session::set_dirty ()
2909 bool was_dirty = dirty();
2911 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
2914 if (!was_dirty) {
2915 DirtyChanged(); /* EMIT SIGNAL */
2920 void
2921 Session::set_clean ()
2923 bool was_dirty = dirty();
2925 _state_of_the_state = Clean;
2928 if (was_dirty) {
2929 DirtyChanged(); /* EMIT SIGNAL */
2933 void
2934 Session::set_deletion_in_progress ()
2936 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
2939 void
2940 Session::clear_deletion_in_progress ()
2942 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
2945 void
2946 Session::add_controllable (boost::shared_ptr<Controllable> c)
2948 /* this adds a controllable to the list managed by the Session.
2949 this is a subset of those managed by the Controllable class
2950 itself, and represents the only ones whose state will be saved
2951 as part of the session.
2954 Glib::Mutex::Lock lm (controllables_lock);
2955 controllables.insert (c);
2958 struct null_deleter { void operator()(void const *) const {} };
2960 void
2961 Session::remove_controllable (Controllable* c)
2963 if (_state_of_the_state | Deletion) {
2964 return;
2967 Glib::Mutex::Lock lm (controllables_lock);
2969 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
2971 if (x != controllables.end()) {
2972 controllables.erase (x);
2976 boost::shared_ptr<Controllable>
2977 Session::controllable_by_id (const PBD::ID& id)
2979 Glib::Mutex::Lock lm (controllables_lock);
2981 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
2982 if ((*i)->id() == id) {
2983 return *i;
2987 return boost::shared_ptr<Controllable>();
2990 boost::shared_ptr<Controllable>
2991 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
2993 boost::shared_ptr<Controllable> c;
2994 boost::shared_ptr<Route> r;
2996 switch (desc.top_level_type()) {
2997 case ControllableDescriptor::NamedRoute:
2999 std::string str = desc.top_level_name();
3000 if (str == "master") {
3001 r = _master_out;
3002 } else if (str == "control" || str == "listen") {
3003 r = _monitor_out;
3004 } else {
3005 r = route_by_name (desc.top_level_name());
3007 break;
3010 case ControllableDescriptor::RemoteControlID:
3011 r = route_by_remote_id (desc.rid());
3012 break;
3015 if (!r) {
3016 return c;
3019 switch (desc.subtype()) {
3020 case ControllableDescriptor::Gain:
3021 c = r->gain_control ();
3022 break;
3024 case ControllableDescriptor::Solo:
3025 c = r->solo_control();
3026 break;
3028 case ControllableDescriptor::Mute:
3029 c = r->mute_control();
3030 break;
3032 case ControllableDescriptor::Recenable:
3034 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(r);
3036 if (t) {
3037 c = t->rec_enable_control ();
3039 break;
3042 case ControllableDescriptor::PanDirection:
3044 c = r->pannable()->pan_azimuth_control;
3045 break;
3048 case ControllableDescriptor::PanWidth:
3050 c = r->pannable()->pan_width_control;
3051 break;
3054 case ControllableDescriptor::PanElevation:
3056 c = r->pannable()->pan_elevation_control;
3057 break;
3060 case ControllableDescriptor::Balance:
3061 /* XXX simple pan control */
3062 break;
3064 case ControllableDescriptor::PluginParameter:
3066 uint32_t plugin = desc.target (0);
3067 uint32_t parameter_index = desc.target (1);
3069 /* revert to zero based counting */
3071 if (plugin > 0) {
3072 --plugin;
3075 if (parameter_index > 0) {
3076 --parameter_index;
3079 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3081 if (p) {
3082 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3083 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3085 break;
3088 case ControllableDescriptor::SendGain:
3090 uint32_t send = desc.target (0);
3092 /* revert to zero-based counting */
3094 if (send > 0) {
3095 --send;
3098 boost::shared_ptr<Processor> p = r->nth_send (send);
3100 if (p) {
3101 boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
3102 boost::shared_ptr<Amp> a = s->amp();
3104 if (a) {
3105 c = s->amp()->gain_control();
3108 break;
3111 default:
3112 /* relax and return a null pointer */
3113 break;
3116 return c;
3119 void
3120 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3122 if (_writable) {
3123 Stateful::add_instant_xml (node, _path);
3126 if (write_to_config) {
3127 Config->add_instant_xml (node);
3131 XMLNode*
3132 Session::instant_xml (const string& node_name)
3134 return Stateful::instant_xml (node_name, _path);
3138 Session::save_history (string snapshot_name)
3140 XMLTree tree;
3142 if (!_writable) {
3143 return 0;
3146 if (snapshot_name.empty()) {
3147 snapshot_name = _current_snapshot_name;
3150 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3151 const string backup_filename = history_filename + backup_suffix;
3152 const sys::path xml_path = _session_dir->root_path() / history_filename;
3153 const sys::path backup_path = _session_dir->root_path() / backup_filename;
3155 if (sys::exists (xml_path)) {
3158 sys::rename (xml_path, backup_path);
3160 catch (const sys::filesystem_error& err)
3162 error << _("could not backup old history file, current history not saved") << endmsg;
3163 return -1;
3167 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0) {
3168 return 0;
3171 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3173 if (!tree.write (xml_path.to_string()))
3175 error << string_compose (_("history could not be saved to %1"), xml_path.to_string()) << endmsg;
3179 sys::remove (xml_path);
3180 sys::rename (backup_path, xml_path);
3182 catch (const sys::filesystem_error& err)
3184 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3185 backup_path.to_string(), err.what()) << endmsg;
3188 return -1;
3191 return 0;
3195 Session::restore_history (string snapshot_name)
3197 XMLTree tree;
3199 if (snapshot_name.empty()) {
3200 snapshot_name = _current_snapshot_name;
3203 const string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3204 const sys::path xml_path = _session_dir->root_path() / xml_filename;
3206 info << "Loading history from " << xml_path.to_string() << endmsg;
3208 if (!sys::exists (xml_path)) {
3209 info << string_compose (_("%1: no history file \"%2\" for this session."),
3210 _name, xml_path.to_string()) << endmsg;
3211 return 1;
3214 if (!tree.read (xml_path.to_string())) {
3215 error << string_compose (_("Could not understand session history file \"%1\""),
3216 xml_path.to_string()) << endmsg;
3217 return -1;
3220 // replace history
3221 _history.clear();
3223 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); it++) {
3225 XMLNode *t = *it;
3226 UndoTransaction* ut = new UndoTransaction ();
3227 struct timeval tv;
3229 ut->set_name(t->property("name")->value());
3230 stringstream ss(t->property("tv-sec")->value());
3231 ss >> tv.tv_sec;
3232 ss.str(t->property("tv-usec")->value());
3233 ss >> tv.tv_usec;
3234 ut->set_timestamp(tv);
3236 for (XMLNodeConstIterator child_it = t->children().begin();
3237 child_it != t->children().end(); child_it++)
3239 XMLNode *n = *child_it;
3240 Command *c;
3242 if (n->name() == "MementoCommand" ||
3243 n->name() == "MementoUndoCommand" ||
3244 n->name() == "MementoRedoCommand") {
3246 if ((c = memento_command_factory(n))) {
3247 ut->add_command(c);
3250 } else if (n->name() == "NoteDiffCommand") {
3251 PBD::ID id (n->property("midi-source")->value());
3252 boost::shared_ptr<MidiSource> midi_source =
3253 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3254 if (midi_source) {
3255 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3256 } else {
3257 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3260 } else if (n->name() == "SysExDiffCommand") {
3262 PBD::ID id (n->property("midi-source")->value());
3263 boost::shared_ptr<MidiSource> midi_source =
3264 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3265 if (midi_source) {
3266 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3267 } else {
3268 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3271 } else if (n->name() == "PatchChangeDiffCommand") {
3273 PBD::ID id (n->property("midi-source")->value());
3274 boost::shared_ptr<MidiSource> midi_source =
3275 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3276 if (midi_source) {
3277 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3278 } else {
3279 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3282 } else if (n->name() == "StatefulDiffCommand") {
3283 if ((c = stateful_diff_command_factory (n))) {
3284 ut->add_command (c);
3286 } else {
3287 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3291 _history.add (ut);
3294 return 0;
3297 void
3298 Session::config_changed (std::string p, bool ours)
3300 if (ours) {
3301 set_dirty ();
3304 if (p == "seamless-loop") {
3306 } else if (p == "rf-speed") {
3308 } else if (p == "auto-loop") {
3310 } else if (p == "auto-input") {
3312 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3313 /* auto-input only makes a difference if we're rolling */
3315 boost::shared_ptr<RouteList> rl = routes.reader ();
3316 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
3317 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
3318 if (tr && tr->record_enabled ()) {
3319 tr->monitor_input (!config.get_auto_input());
3324 } else if (p == "punch-in") {
3326 Location* location;
3328 if ((location = _locations->auto_punch_location()) != 0) {
3330 if (config.get_punch_in ()) {
3331 replace_event (SessionEvent::PunchIn, location->start());
3332 } else {
3333 remove_event (location->start(), SessionEvent::PunchIn);
3337 } else if (p == "punch-out") {
3339 Location* location;
3341 if ((location = _locations->auto_punch_location()) != 0) {
3343 if (config.get_punch_out()) {
3344 replace_event (SessionEvent::PunchOut, location->end());
3345 } else {
3346 clear_events (SessionEvent::PunchOut);
3350 } else if (p == "edit-mode") {
3352 Glib::Mutex::Lock lm (playlists->lock);
3354 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3355 (*i)->set_edit_mode (Config->get_edit_mode ());
3358 } else if (p == "use-video-sync") {
3360 waiting_for_sync_offset = config.get_use_video_sync();
3362 } else if (p == "mmc-control") {
3364 //poke_midi_thread ();
3366 } else if (p == "mmc-device-id" || p == "mmc-receive-id") {
3368 MIDI::Manager::instance()->mmc()->set_receive_device_id (Config->get_mmc_receive_device_id());
3370 } else if (p == "mmc-send-id") {
3372 MIDI::Manager::instance()->mmc()->set_send_device_id (Config->get_mmc_send_device_id());
3374 } else if (p == "midi-control") {
3376 //poke_midi_thread ();
3378 } else if (p == "raid-path") {
3380 setup_raid_path (config.get_raid_path());
3382 } else if (p == "timecode-format") {
3384 sync_time_vars ();
3386 } else if (p == "video-pullup") {
3388 sync_time_vars ();
3390 } else if (p == "seamless-loop") {
3392 if (play_loop && transport_rolling()) {
3393 // to reset diskstreams etc
3394 request_play_loop (true);
3397 } else if (p == "rf-speed") {
3399 cumulative_rf_motion = 0;
3400 reset_rf_scale (0);
3402 } else if (p == "click-sound") {
3404 setup_click_sounds (1);
3406 } else if (p == "click-emphasis-sound") {
3408 setup_click_sounds (-1);
3410 } else if (p == "clicking") {
3412 if (Config->get_clicking()) {
3413 if (_click_io && click_data) { // don't require emphasis data
3414 _clicking = true;
3416 } else {
3417 _clicking = false;
3420 } else if (p == "send-mtc") {
3422 if (Config->get_send_mtc ()) {
3423 /* mark us ready to send */
3424 next_quarter_frame_to_send = 0;
3427 } else if (p == "send-mmc") {
3429 MIDI::Manager::instance()->mmc()->enable_send (Config->get_send_mmc ());
3431 } else if (p == "midi-feedback") {
3433 session_midi_feedback = Config->get_midi_feedback();
3435 } else if (p == "jack-time-master") {
3437 engine().reset_timebase ();
3439 } else if (p == "native-file-header-format") {
3441 if (!first_file_header_format_reset) {
3442 reset_native_file_format ();
3445 first_file_header_format_reset = false;
3447 } else if (p == "native-file-data-format") {
3449 if (!first_file_data_format_reset) {
3450 reset_native_file_format ();
3453 first_file_data_format_reset = false;
3455 } else if (p == "external-sync") {
3456 if (!config.get_external_sync()) {
3457 drop_sync_source ();
3458 } else {
3459 switch_to_sync_source (config.get_sync_source());
3461 } else if (p == "remote-model") {
3462 set_remote_control_ids ();
3463 } else if (p == "denormal-model") {
3464 setup_fpu ();
3465 } else if (p == "history-depth") {
3466 set_history_depth (Config->get_history_depth());
3467 } else if (p == "sync-all-route-ordering") {
3468 sync_order_keys ("session");
3469 } else if (p == "initial-program-change") {
3471 if (MIDI::Manager::instance()->mmc()->output_port() && Config->get_initial_program_change() >= 0) {
3472 MIDI::byte buf[2];
3474 buf[0] = MIDI::program; // channel zero by default
3475 buf[1] = (Config->get_initial_program_change() & 0x7f);
3477 MIDI::Manager::instance()->mmc()->output_port()->midimsg (buf, sizeof (buf), 0);
3479 } else if (p == "solo-mute-override") {
3480 // catch_up_on_solo_mute_override ();
3481 } else if (p == "listen-position") {
3482 listen_position_changed ();
3483 } else if (p == "solo-control-is-listen-control") {
3484 solo_control_mode_changed ();
3485 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
3486 last_timecode_valid = false;
3489 set_dirty ();
3492 void
3493 Session::set_history_depth (uint32_t d)
3495 _history.set_depth (d);
3499 Session::load_diskstreams_2X (XMLNode const & node, int)
3501 XMLNodeList clist;
3502 XMLNodeConstIterator citer;
3504 clist = node.children();
3506 for (citer = clist.begin(); citer != clist.end(); ++citer) {
3508 try {
3509 /* diskstreams added automatically by DiskstreamCreated handler */
3510 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
3511 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
3512 _diskstreams_2X.push_back (dsp);
3513 } else {
3514 error << _("Session: unknown diskstream type in XML") << endmsg;
3518 catch (failed_constructor& err) {
3519 error << _("Session: could not load diskstream via XML state") << endmsg;
3520 return -1;
3524 return 0;
3527 /** Connect things to the MMC object */
3528 void
3529 Session::setup_midi_machine_control ()
3531 MIDI::MachineControl* mmc = MIDI::Manager::instance()->mmc ();
3533 mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3534 mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3535 mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
3536 mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
3537 mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
3538 mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
3539 mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
3540 mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
3541 mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
3542 mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
3543 mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
3544 mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
3545 mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
3547 /* also handle MIDI SPP because its so common */
3549 mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this, _1, _2));
3550 mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this, _1, _2));
3551 mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this, _1, _2));
3554 boost::shared_ptr<Controllable>
3555 Session::solo_cut_control() const
3557 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
3558 controls in Ardour that currently get presented to the user in the GUI that require
3559 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
3561 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
3562 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
3563 parameter.
3566 return _solo_cut_control;