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.
22 #include "libardour-config.h"
33 #include <cstdio> /* snprintf(3) ... grrr */
47 #include <sys/param.h>
48 #include <sys/mount.h>
54 #include <glibmm/thread.h>
56 #include "midi++/mmc.h"
57 #include "midi++/port.h"
58 #include "midi++/manager.h"
60 #include "pbd/boost_debug.h"
61 #include "pbd/basename.h"
62 #include "pbd/controllable_descriptor.h"
63 #include "pbd/enumwriter.h"
64 #include "pbd/error.h"
65 #include "pbd/pathscanner.h"
66 #include "pbd/pthread_utils.h"
67 #include "pbd/search_path.h"
68 #include "pbd/stacktrace.h"
69 #include "pbd/convert.h"
70 #include "pbd/clear_dir.h"
72 #include "ardour/amp.h"
73 #include "ardour/audio_diskstream.h"
74 #include "ardour/audio_playlist_source.h"
75 #include "ardour/audio_track.h"
76 #include "ardour/audioengine.h"
77 #include "ardour/audiofilesource.h"
78 #include "ardour/audioplaylist.h"
79 #include "ardour/audioregion.h"
80 #include "ardour/auditioner.h"
81 #include "ardour/automation_control.h"
82 #include "ardour/buffer.h"
83 #include "ardour/butler.h"
84 #include "ardour/configuration.h"
85 #include "ardour/control_protocol_manager.h"
86 #include "ardour/crossfade.h"
87 #include "ardour/cycle_timer.h"
88 #include "ardour/directory_names.h"
89 #include "ardour/filename_extensions.h"
90 #include "ardour/io_processor.h"
91 #include "ardour/location.h"
92 #include "ardour/midi_diskstream.h"
93 #include "ardour/midi_patch_manager.h"
94 #include "ardour/midi_playlist.h"
95 #include "ardour/midi_region.h"
96 #include "ardour/midi_source.h"
97 #include "ardour/midi_track.h"
98 #include "ardour/named_selection.h"
99 #include "ardour/pannable.h"
100 #include "ardour/processor.h"
101 #include "ardour/port.h"
102 #include "ardour/proxy_controllable.h"
103 #include "ardour/recent_sessions.h"
104 #include "ardour/region_factory.h"
105 #include "ardour/route_group.h"
106 #include "ardour/send.h"
107 #include "ardour/session.h"
108 #include "ardour/session_directory.h"
109 #include "ardour/session_metadata.h"
110 #include "ardour/session_state_utils.h"
111 #include "ardour/session_playlists.h"
112 #include "ardour/session_utils.h"
113 #include "ardour/silentfilesource.h"
114 #include "ardour/slave.h"
115 #include "ardour/smf_source.h"
116 #include "ardour/sndfile_helpers.h"
117 #include "ardour/sndfilesource.h"
118 #include "ardour/source_factory.h"
119 #include "ardour/template_utils.h"
120 #include "ardour/tempo.h"
121 #include "ardour/ticker.h"
122 #include "ardour/user_bundle.h"
123 #include "ardour/utils.h"
124 #include "ardour/utils.h"
125 #include "ardour/version.h"
126 #include "ardour/playlist_factory.h"
128 #include "control_protocol/control_protocol.h"
134 using namespace ARDOUR
;
139 Session::first_stage_init (string fullpath
, string snapshot_name
)
141 if (fullpath
.length() == 0) {
143 throw failed_constructor();
146 char buf
[PATH_MAX
+1];
147 if (!realpath (fullpath
.c_str(), buf
) && (errno
!= ENOENT
)) {
148 error
<< string_compose(_("Could not use path %1 (%s)"), buf
, strerror(errno
)) << endmsg
;
150 throw failed_constructor();
155 if (_path
[_path
.length()-1] != G_DIR_SEPARATOR
) {
156 _path
+= G_DIR_SEPARATOR
;
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;
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;
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;
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 ();
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);
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;
223 no_questions_about_missing_files
= false;
224 _speakers
.reset (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;
237 /* click sounds are unset by default, which causes us to internal
238 waveforms for clicks.
242 click_emphasis_length
= 0;
245 process_function
= &Session::process_with_events
;
247 if (config
.get_use_video_sync()) {
248 waiting_for_sync_offset
= true;
250 waiting_for_sync_offset
= false;
253 last_timecode_when
= 0;
254 last_timecode_valid
= false;
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);
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());
299 if (load_state (_current_snapshot_name
)) {
304 if (_butler
->start_thread()) {
308 if (start_midi_thread ()) {
312 setup_midi_machine_control ();
314 // set_state() will call setup_raid_path(), but if it's a new session we need
315 // to call setup_raid_path() here.
318 if (set_state (*state_tree
->root(), Stateful::loading_state_version
)) {
322 setup_raid_path(_path
);
325 /* we can't save till after ::when_engine_running() is called,
326 because otherwise we save state with no connections made.
327 therefore, we reset _state_of_the_state because ::set_state()
328 will have cleared it.
330 we also have to include Loading so that any events that get
331 generated between here and the end of ::when_engine_running()
332 will be processed directly rather than queued.
335 _state_of_the_state
= StateOfTheState (_state_of_the_state
|CannotSave
|Loading
);
337 _locations
->changed
.connect_same_thread (*this, boost::bind (&Session::locations_changed
, this));
338 _locations
->added
.connect_same_thread (*this, boost::bind (&Session::locations_added
, this, _1
));
339 setup_click_sounds (0);
340 setup_midi_control ();
342 /* Pay attention ... */
344 _engine
.Halted
.connect_same_thread (*this, boost::bind (&Session::engine_halted
, this));
345 _engine
.Xrun
.connect_same_thread (*this, boost::bind (&Session::xrun_recovery
, this));
348 when_engine_running ();
351 /* handle this one in a different way than all others, so that its clear what happened */
353 catch (AudioEngine::PortRegistrationFailure
& err
) {
354 error
<< err
.what() << endmsg
;
362 BootMessage (_("Reset Remote Controls"));
364 send_full_time_code (0);
365 _engine
.transport_locate (0);
367 MIDI::Manager::instance()->mmc()->send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset
));
368 MIDI::Manager::instance()->mmc()->send (MIDI::MachineControlCommand (Timecode::Time ()));
370 MidiClockTicker::instance().set_session (this);
371 MIDI::Name::MidiPatchManager::instance().set_session (this);
373 /* initial program change will be delivered later; see ::config_changed() */
375 _state_of_the_state
= Clean
;
377 Port::set_connecting_blocked (false);
379 DirtyChanged (); /* EMIT SIGNAL */
381 if (state_was_pending
) {
382 save_state (_current_snapshot_name
);
383 remove_pending_capture_state ();
384 state_was_pending
= false;
387 BootMessage (_("Session loading complete"));
393 Session::raid_path () const
395 SearchPath raid_search_path
;
397 for (vector
<space_and_path
>::const_iterator i
= session_dirs
.begin(); i
!= session_dirs
.end(); ++i
) {
398 raid_search_path
+= sys::path((*i
).path
);
401 return raid_search_path
.to_string ();
405 Session::setup_raid_path (string path
)
414 session_dirs
.clear ();
416 SearchPath
search_path(path
);
417 SearchPath sound_search_path
;
418 SearchPath midi_search_path
;
420 for (SearchPath::const_iterator i
= search_path
.begin(); i
!= search_path
.end(); ++i
) {
421 sp
.path
= (*i
).to_string ();
422 sp
.blocks
= 0; // not needed
423 session_dirs
.push_back (sp
);
425 SessionDirectory
sdir(sp
.path
);
427 sound_search_path
+= sdir
.sound_path ();
428 midi_search_path
+= sdir
.midi_path ();
431 // reset the round-robin soundfile path thingie
432 last_rr_session_dir
= session_dirs
.begin();
436 Session::path_is_within_session (const std::string
& path
)
438 for (vector
<space_and_path
>::const_iterator i
= session_dirs
.begin(); i
!= session_dirs
.end(); ++i
) {
439 if (path
.find ((*i
).path
) == 0) {
447 Session::ensure_subdirs ()
451 dir
= session_directory().peak_path().to_string();
453 if (g_mkdir_with_parents (dir
.c_str(), 0755) < 0) {
454 error
<< string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir
, strerror (errno
)) << endmsg
;
458 dir
= session_directory().sound_path().to_string();
460 if (g_mkdir_with_parents (dir
.c_str(), 0755) < 0) {
461 error
<< string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir
, strerror (errno
)) << endmsg
;
465 dir
= session_directory().midi_path().to_string();
467 if (g_mkdir_with_parents (dir
.c_str(), 0755) < 0) {
468 error
<< string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir
, strerror (errno
)) << endmsg
;
472 dir
= session_directory().dead_path().to_string();
474 if (g_mkdir_with_parents (dir
.c_str(), 0755) < 0) {
475 error
<< string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir
, strerror (errno
)) << endmsg
;
479 dir
= session_directory().export_path().to_string();
481 if (g_mkdir_with_parents (dir
.c_str(), 0755) < 0) {
482 error
<< string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir
, strerror (errno
)) << endmsg
;
486 dir
= analysis_dir ();
488 if (g_mkdir_with_parents (dir
.c_str(), 0755) < 0) {
489 error
<< string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir
, strerror (errno
)) << endmsg
;
493 dir
= plugins_dir ();
495 if (g_mkdir_with_parents (dir
.c_str(), 0755) < 0) {
496 error
<< string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir
, strerror (errno
)) << endmsg
;
503 /** Caller must not hold process lock */
505 Session::create (const string
& mix_template
, BusProfile
* bus_profile
)
507 if (g_mkdir_with_parents (_path
.c_str(), 0755) < 0) {
508 error
<< string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path
, strerror (errno
)) << endmsg
;
512 if (ensure_subdirs ()) {
516 _writable
= exists_and_writable (sys::path (_path
));
518 if (!mix_template
.empty()) {
519 std::string in_path
= mix_template
;
521 ifstream
in(in_path
.c_str());
524 string out_path
= _path
;
526 out_path
+= statefile_suffix
;
528 ofstream
out(out_path
.c_str());
536 error
<< string_compose (_("Could not open %1 for writing mix template"), out_path
)
542 error
<< string_compose (_("Could not open mix template %1 for reading"), in_path
)
549 /* Instantiate metadata */
551 _metadata
= new SessionMetadata ();
553 /* set initial start + end point */
555 _state_of_the_state
= Clean
;
557 /* set up Master Out and Control Out if necessary */
563 ChanCount
count(DataType::AUDIO
, bus_profile
->master_out_channels
);
565 if (bus_profile
->master_out_channels
) {
566 boost::shared_ptr
<Route
> r (new Route (*this, _("master"), Route::MasterOut
, DataType::AUDIO
));
570 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
571 boost_debug_shared_ptr_mark_interesting (r
.get(), "Route");
574 Glib::Mutex::Lock
lm (AudioEngine::instance()->process_lock ());
575 r
->input()->ensure_io (count
, false, this);
576 r
->output()->ensure_io (count
, false, this);
578 r
->set_remote_control_id (control_id
++);
582 if (Config
->get_use_monitor_bus()) {
583 boost::shared_ptr
<Route
> r (new Route (*this, _("monitor"), Route::MonitorOut
, DataType::AUDIO
));
587 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
588 boost_debug_shared_ptr_mark_interesting (r
.get(), "Route");
591 Glib::Mutex::Lock
lm (AudioEngine::instance()->process_lock ());
592 r
->input()->ensure_io (count
, false, this);
593 r
->output()->ensure_io (count
, false, this);
595 r
->set_remote_control_id (control_id
);
601 /* prohibit auto-connect to master, because there isn't one */
602 bus_profile
->output_ac
= AutoConnectOption (bus_profile
->output_ac
& ~AutoConnectMaster
);
606 add_routes (rl
, false, false);
609 /* this allows the user to override settings with an environment variable.
612 if (no_auto_connect()) {
613 bus_profile
->input_ac
= AutoConnectOption (0);
614 bus_profile
->output_ac
= AutoConnectOption (0);
617 Config
->set_input_auto_connect (bus_profile
->input_ac
);
618 Config
->set_output_auto_connect (bus_profile
->output_ac
);
627 Session::maybe_write_autosave()
629 if (dirty() && record_status() != Recording
) {
630 save_state("", true);
635 Session::remove_pending_capture_state ()
637 sys::path
pending_state_file_path(_session_dir
->root_path());
639 pending_state_file_path
/= legalize_for_path (_current_snapshot_name
) + pending_suffix
;
643 sys::remove (pending_state_file_path
);
645 catch(sys::filesystem_error
& ex
)
647 error
<< string_compose(_("Could remove pending capture state at path \"%1\" (%2)"),
648 pending_state_file_path
.to_string(), ex
.what()) << endmsg
;
652 /** Rename a state file.
653 * @param old_name Old snapshot name.
654 * @param new_name New snapshot name.
657 Session::rename_state (string old_name
, string new_name
)
659 if (old_name
== _current_snapshot_name
|| old_name
== _name
) {
660 /* refuse to rename the current snapshot or the "main" one */
664 const string old_xml_filename
= legalize_for_path (old_name
) + statefile_suffix
;
665 const string new_xml_filename
= legalize_for_path (new_name
) + statefile_suffix
;
667 const sys::path old_xml_path
= _session_dir
->root_path() / old_xml_filename
;
668 const sys::path new_xml_path
= _session_dir
->root_path() / new_xml_filename
;
672 sys::rename (old_xml_path
, new_xml_path
);
674 catch (const sys::filesystem_error
& err
)
676 error
<< string_compose(_("could not rename snapshot %1 to %2 (%3)"),
677 old_name
, new_name
, err
.what()) << endmsg
;
681 /** Remove a state file.
682 * @param snapshot_name Snapshot name.
685 Session::remove_state (string snapshot_name
)
687 if (snapshot_name
== _current_snapshot_name
|| snapshot_name
== _name
) {
688 // refuse to remove the current snapshot or the "main" one
692 sys::path
xml_path(_session_dir
->root_path());
694 xml_path
/= legalize_for_path (snapshot_name
) + statefile_suffix
;
696 if (!create_backup_file (xml_path
)) {
697 // don't remove it if a backup can't be made
698 // create_backup_file will log the error.
703 sys::remove (xml_path
);
706 #ifdef HAVE_JACK_SESSION
708 Session::jack_session_event (jack_session_event_t
* event
)
712 struct tm local_time
;
715 localtime_r (&n
, &local_time
);
716 strftime (timebuf
, sizeof(timebuf
), "JS_%FT%T", &local_time
);
718 if (event
->type
== JackSessionSaveTemplate
)
720 if (save_template( timebuf
)) {
721 event
->flags
= JackSessionSaveError
;
723 string
cmd ("ardour3 -P -U ");
724 cmd
+= event
->client_uuid
;
728 event
->command_line
= strdup (cmd
.c_str());
733 if (save_state (timebuf
)) {
734 event
->flags
= JackSessionSaveError
;
736 sys::path
xml_path (_session_dir
->root_path());
737 xml_path
/= legalize_for_path (timebuf
) + statefile_suffix
;
739 string
cmd ("ardour3 -P -U ");
740 cmd
+= event
->client_uuid
;
742 cmd
+= xml_path
.to_string();
745 event
->command_line
= strdup (cmd
.c_str());
749 jack_session_reply (_engine
.jack(), event
);
751 if (event
->type
== JackSessionSaveAndQuit
) {
752 Quit (); /* EMIT SIGNAL */
755 jack_session_event_free( event
);
759 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
761 Session::save_state (string snapshot_name
, bool pending
, bool switch_to_snapshot
)
764 sys::path
xml_path(_session_dir
->root_path());
766 if (!_writable
|| (_state_of_the_state
& CannotSave
)) {
770 if (!_engine
.connected ()) {
771 error
<< string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"),
777 /* tell sources we're saving first, in case they write out to a new file
778 * which should be saved with the state rather than the old one */
779 for (SourceMap::const_iterator i
= sources
.begin(); i
!= sources
.end(); ++i
) {
780 i
->second
->session_saved();
783 tree
.set_root (&get_state());
785 if (snapshot_name
.empty()) {
786 snapshot_name
= _current_snapshot_name
;
787 } else if (switch_to_snapshot
) {
788 _current_snapshot_name
= snapshot_name
;
793 /* proper save: use statefile_suffix (.ardour in English) */
795 xml_path
/= legalize_for_path (snapshot_name
) + statefile_suffix
;
797 /* make a backup copy of the old file */
799 if (sys::exists(xml_path
) && !create_backup_file (xml_path
)) {
800 // create_backup_file will log the error
806 /* pending save: use pending_suffix (.pending in English) */
807 xml_path
/= legalize_for_path (snapshot_name
) + pending_suffix
;
810 sys::path
tmp_path(_session_dir
->root_path());
812 tmp_path
/= legalize_for_path (snapshot_name
) + temp_suffix
;
814 // cerr << "actually writing state to " << xml_path.to_string() << endl;
816 if (!tree
.write (tmp_path
.to_string())) {
817 error
<< string_compose (_("state could not be saved to %1"), tmp_path
.to_string()) << endmsg
;
818 sys::remove (tmp_path
);
823 if (::rename (tmp_path
.to_string().c_str(), xml_path
.to_string().c_str()) != 0) {
824 error
<< string_compose (_("could not rename temporary session file %1 to %2"),
825 tmp_path
.to_string(), xml_path
.to_string()) << endmsg
;
826 sys::remove (tmp_path
);
833 save_history (snapshot_name
);
835 bool was_dirty
= dirty();
837 _state_of_the_state
= StateOfTheState (_state_of_the_state
& ~Dirty
);
840 DirtyChanged (); /* EMIT SIGNAL */
843 StateSaved (snapshot_name
); /* EMIT SIGNAL */
850 Session::restore_state (string snapshot_name
)
852 if (load_state (snapshot_name
) == 0) {
853 set_state (*state_tree
->root(), Stateful::loading_state_version
);
860 Session::load_state (string snapshot_name
)
865 state_was_pending
= false;
867 /* check for leftover pending state from a crashed capture attempt */
869 sys::path
xmlpath(_session_dir
->root_path());
870 xmlpath
/= legalize_for_path (snapshot_name
) + pending_suffix
;
872 if (sys::exists (xmlpath
)) {
874 /* there is pending state from a crashed capture attempt */
876 boost::optional
<int> r
= AskAboutPendingState();
877 if (r
.get_value_or (1)) {
878 state_was_pending
= true;
882 if (!state_was_pending
) {
883 xmlpath
= _session_dir
->root_path();
884 xmlpath
/= snapshot_name
;
887 if (!sys::exists (xmlpath
)) {
888 xmlpath
= _session_dir
->root_path();
889 xmlpath
/= legalize_for_path (snapshot_name
) + statefile_suffix
;
890 if (!sys::exists (xmlpath
)) {
891 error
<< string_compose(_("%1: session state information file \"%2\" doesn't exist!"), _name
, xmlpath
.to_string()) << endmsg
;
896 state_tree
= new XMLTree
;
900 _writable
= exists_and_writable (xmlpath
);
902 if (!state_tree
->read (xmlpath
.to_string())) {
903 error
<< string_compose(_("Could not understand ardour file %1"), xmlpath
.to_string()) << endmsg
;
909 XMLNode
& root (*state_tree
->root());
911 if (root
.name() != X_("Session")) {
912 error
<< string_compose (_("Session file %1 is not a session"), xmlpath
.to_string()) << endmsg
;
918 const XMLProperty
* prop
;
920 if ((prop
= root
.property ("version")) == 0) {
921 /* no version implies very old version of Ardour */
922 Stateful::loading_state_version
= 1000;
928 sscanf (prop
->value().c_str(), "%d.%d.%d", &major
, &minor
, µ
);
929 Stateful::loading_state_version
= (major
* 1000) + minor
;
932 if (Stateful::loading_state_version
< CURRENT_SESSION_FILE_VERSION
) {
934 sys::path
backup_path(_session_dir
->root_path());
936 backup_path
/= legalize_for_path (snapshot_name
) + "-1" + statefile_suffix
;
938 // only create a backup once
939 if (sys::exists (backup_path
)) {
943 info
<< string_compose (_("Copying old session file %1 to %2\nUse %2 with %3 versions before 2.0 from now on"),
944 xmlpath
.to_string(), backup_path
.to_string(), PROGRAM_NAME
)
949 sys::copy_file (xmlpath
, backup_path
);
951 catch(sys::filesystem_error
& ex
)
953 error
<< string_compose (_("Unable to make backup of state file %1 (%2)"),
954 xmlpath
.to_string(), ex
.what())
964 Session::load_options (const XMLNode
& node
)
966 LocaleGuard
lg (X_("POSIX"));
967 config
.set_variables (node
);
978 Session::get_template()
980 /* if we don't disable rec-enable, diskstreams
981 will believe they need to store their capture
982 sources in their state node.
985 disable_record (false);
991 Session::state(bool full_state
)
993 XMLNode
* node
= new XMLNode("Session");
996 // store libardour version, just in case
998 snprintf(buf
, sizeof(buf
), "%d.%d.%d", libardour3_major_version
, libardour3_minor_version
, libardour3_micro_version
);
999 node
->add_property("version", string(buf
));
1001 /* store configuration settings */
1005 node
->add_property ("name", _name
);
1006 snprintf (buf
, sizeof (buf
), "%" PRId64
, _nominal_frame_rate
);
1007 node
->add_property ("sample-rate", buf
);
1009 if (session_dirs
.size() > 1) {
1013 vector
<space_and_path
>::iterator i
= session_dirs
.begin();
1014 vector
<space_and_path
>::iterator next
;
1016 ++i
; /* skip the first one */
1020 while (i
!= session_dirs
.end()) {
1024 if (next
!= session_dirs
.end()) {
1034 child
= node
->add_child ("Path");
1035 child
->add_content (p
);
1039 /* save the ID counter */
1041 snprintf (buf
, sizeof (buf
), "%" PRIu64
, ID::counter());
1042 node
->add_property ("id-counter", buf
);
1044 /* save the event ID counter */
1046 snprintf (buf
, sizeof (buf
), "%d", Evoral::event_id_counter());
1047 node
->add_property ("event-counter", buf
);
1049 /* various options */
1051 node
->add_child_nocopy (config
.get_variables ());
1053 node
->add_child_nocopy (_metadata
->get_state());
1055 child
= node
->add_child ("Sources");
1058 Glib::Mutex::Lock
sl (source_lock
);
1060 for (SourceMap::iterator siter
= sources
.begin(); siter
!= sources
.end(); ++siter
) {
1062 /* Don't save information about non-file Sources, or
1063 * about non-destructive file sources that are empty
1064 * and unused by any regions.
1067 boost::shared_ptr
<FileSource
> fs
;
1069 if ((fs
= boost::dynamic_pointer_cast
<FileSource
> (siter
->second
)) != 0) {
1071 if (!fs
->destructive()) {
1072 if (fs
->empty() && !fs
->used()) {
1077 child
->add_child_nocopy (siter
->second
->get_state());
1082 child
= node
->add_child ("Regions");
1085 Glib::Mutex::Lock
rl (region_lock
);
1086 const RegionFactory::RegionMap
& region_map (RegionFactory::all_regions());
1087 for (RegionFactory::RegionMap::const_iterator i
= region_map
.begin(); i
!= region_map
.end(); ++i
) {
1088 boost::shared_ptr
<Region
> r
= i
->second
;
1089 /* only store regions not attached to playlists */
1090 if (r
->playlist() == 0) {
1091 child
->add_child_nocopy (r
->state ());
1095 RegionFactory::CompoundAssociations
& cassocs (RegionFactory::compound_associations());
1097 if (!cassocs
.empty()) {
1098 XMLNode
* ca
= node
->add_child (X_("CompoundAssociations"));
1100 for (RegionFactory::CompoundAssociations::iterator i
= cassocs
.begin(); i
!= cassocs
.end(); ++i
) {
1102 XMLNode
* can
= new XMLNode (X_("CompoundAssociation"));
1103 i
->first
->id().print (buf
, sizeof (buf
));
1104 can
->add_property (X_("copy"), buf
);
1105 i
->second
->id().print (buf
, sizeof (buf
));
1106 can
->add_property (X_("original"), buf
);
1107 ca
->add_child_nocopy (*can
);
1113 node
->add_child_nocopy (_locations
->get_state());
1115 // for a template, just create a new Locations, populate it
1116 // with the default start and end, and get the state for that.
1117 Locations
loc (*this);
1118 Location
* range
= new Location (*this, 0, 0, _("session"), Location::IsSessionRange
);
1119 range
->set (max_framepos
, 0);
1121 node
->add_child_nocopy (loc
.get_state());
1124 child
= node
->add_child ("Bundles");
1126 boost::shared_ptr
<BundleList
> bundles
= _bundles
.reader ();
1127 for (BundleList::iterator i
= bundles
->begin(); i
!= bundles
->end(); ++i
) {
1128 boost::shared_ptr
<UserBundle
> b
= boost::dynamic_pointer_cast
<UserBundle
> (*i
);
1130 child
->add_child_nocopy (b
->get_state());
1135 child
= node
->add_child ("Routes");
1137 boost::shared_ptr
<RouteList
> r
= routes
.reader ();
1139 RoutePublicOrderSorter cmp
;
1140 RouteList
public_order (*r
);
1141 public_order
.sort (cmp
);
1143 /* the sort should have put control outs first */
1146 assert (_monitor_out
== public_order
.front());
1149 for (RouteList::iterator i
= public_order
.begin(); i
!= public_order
.end(); ++i
) {
1150 if (!(*i
)->is_hidden()) {
1152 child
->add_child_nocopy ((*i
)->get_state());
1154 child
->add_child_nocopy ((*i
)->get_template());
1160 playlists
->add_state (node
, full_state
);
1162 child
= node
->add_child ("RouteGroups");
1163 for (list
<RouteGroup
*>::iterator i
= _route_groups
.begin(); i
!= _route_groups
.end(); ++i
) {
1164 child
->add_child_nocopy ((*i
)->get_state());
1168 child
= node
->add_child ("Click");
1169 child
->add_child_nocopy (_click_io
->state (full_state
));
1173 child
= node
->add_child ("NamedSelections");
1174 for (NamedSelectionList::iterator i
= named_selections
.begin(); i
!= named_selections
.end(); ++i
) {
1176 child
->add_child_nocopy ((*i
)->get_state());
1181 node
->add_child_nocopy (_speakers
->get_state());
1182 node
->add_child_nocopy (_tempo_map
->get_state());
1183 node
->add_child_nocopy (get_control_protocol_state());
1186 node
->add_child_copy (*_extra_xml
);
1193 Session::get_control_protocol_state ()
1195 ControlProtocolManager
& cpm (ControlProtocolManager::instance());
1196 return cpm
.get_state();
1200 Session::set_state (const XMLNode
& node
, int version
)
1204 const XMLProperty
* prop
;
1207 _state_of_the_state
= StateOfTheState (_state_of_the_state
|CannotSave
);
1209 if (node
.name() != X_("Session")) {
1210 fatal
<< _("programming error: Session: incorrect XML node sent to set_state()") << endmsg
;
1214 if ((prop
= node
.property ("version")) != 0) {
1215 version
= atoi (prop
->value ()) * 1000;
1218 if ((prop
= node
.property ("name")) != 0) {
1219 _name
= prop
->value ();
1222 if ((prop
= node
.property (X_("sample-rate"))) != 0) {
1224 _nominal_frame_rate
= atoi (prop
->value());
1226 if (_nominal_frame_rate
!= _current_frame_rate
) {
1227 boost::optional
<int> r
= AskAboutSampleRateMismatch (_nominal_frame_rate
, _current_frame_rate
);
1228 if (r
.get_value_or (0)) {
1234 setup_raid_path(_session_dir
->root_path().to_string());
1236 if ((prop
= node
.property (X_("id-counter"))) != 0) {
1238 sscanf (prop
->value().c_str(), "%" PRIu64
, &x
);
1239 ID::init_counter (x
);
1241 /* old sessions used a timebased counter, so fake
1242 the startup ID counter based on a standard
1247 ID::init_counter (now
);
1250 if ((prop
= node
.property (X_("event-counter"))) != 0) {
1251 Evoral::init_event_id_counter (atoi (prop
->value()));
1254 IO::disable_connecting ();
1256 Stateful::save_extra_xml (node
);
1258 if (((child
= find_named_node (node
, "Options")) != 0)) { /* old style */
1259 load_options (*child
);
1260 } else if ((child
= find_named_node (node
, "Config")) != 0) { /* new style */
1261 load_options (*child
);
1263 error
<< _("Session: XML state has no options section") << endmsg
;
1266 if (version
>= 3000) {
1267 if ((child
= find_named_node (node
, "Metadata")) == 0) {
1268 warning
<< _("Session: XML state has no metadata section") << endmsg
;
1269 } else if (_metadata
->set_state (*child
, version
)) {
1274 if ((child
= find_named_node (node
, "Locations")) == 0) {
1275 error
<< _("Session: XML state has no locations section") << endmsg
;
1277 } else if (_locations
->set_state (*child
, version
)) {
1281 if ((child
= find_named_node (node
, X_("Speakers"))) != 0) {
1282 _speakers
->set_state (*child
, version
);
1287 if ((location
= _locations
->auto_loop_location()) != 0) {
1288 set_auto_loop_location (location
);
1291 if ((location
= _locations
->auto_punch_location()) != 0) {
1292 set_auto_punch_location (location
);
1295 if ((location
= _locations
->session_range_location()) != 0) {
1296 delete _session_range_location
;
1297 _session_range_location
= location
;
1300 if (_session_range_location
) {
1301 AudioFileSource::set_header_position_offset (_session_range_location
->start());
1304 if ((child
= find_named_node (node
, "Sources")) == 0) {
1305 error
<< _("Session: XML state has no sources section") << endmsg
;
1307 } else if (load_sources (*child
)) {
1311 if ((child
= find_named_node (node
, "TempoMap")) == 0) {
1312 error
<< _("Session: XML state has no Tempo Map section") << endmsg
;
1314 } else if (_tempo_map
->set_state (*child
, version
)) {
1318 if ((child
= find_named_node (node
, "Regions")) == 0) {
1319 error
<< _("Session: XML state has no Regions section") << endmsg
;
1321 } else if (load_regions (*child
)) {
1325 if ((child
= find_named_node (node
, "Playlists")) == 0) {
1326 error
<< _("Session: XML state has no playlists section") << endmsg
;
1328 } else if (playlists
->load (*this, *child
)) {
1332 if ((child
= find_named_node (node
, "UnusedPlaylists")) == 0) {
1334 } else if (playlists
->load_unused (*this, *child
)) {
1338 if ((child
= find_named_node (node
, "CompoundAssociations")) != 0) {
1339 if (load_compounds (*child
)) {
1344 if ((child
= find_named_node (node
, "NamedSelections")) != 0) {
1345 if (load_named_selections (*child
)) {
1350 if (version
>= 3000) {
1351 if ((child
= find_named_node (node
, "Bundles")) == 0) {
1352 warning
<< _("Session: XML state has no bundles section") << endmsg
;
1355 /* We can't load Bundles yet as they need to be able
1356 to convert from port names to Port objects, which can't happen until
1358 _bundle_xml_node
= new XMLNode (*child
);
1362 if (version
< 3000) {
1363 if ((child
= find_named_node (node
, X_("DiskStreams"))) == 0) {
1364 error
<< _("Session: XML state has no diskstreams section") << endmsg
;
1366 } else if (load_diskstreams_2X (*child
, version
)) {
1371 if ((child
= find_named_node (node
, "Routes")) == 0) {
1372 error
<< _("Session: XML state has no routes section") << endmsg
;
1374 } else if (load_routes (*child
, version
)) {
1378 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1379 _diskstreams_2X
.clear ();
1381 if (version
>= 3000) {
1383 if ((child
= find_named_node (node
, "RouteGroups")) == 0) {
1384 error
<< _("Session: XML state has no route groups section") << endmsg
;
1386 } else if (load_route_groups (*child
, version
)) {
1390 } else if (version
< 3000) {
1392 if ((child
= find_named_node (node
, "EditGroups")) == 0) {
1393 error
<< _("Session: XML state has no edit groups section") << endmsg
;
1395 } else if (load_route_groups (*child
, version
)) {
1399 if ((child
= find_named_node (node
, "MixGroups")) == 0) {
1400 error
<< _("Session: XML state has no mix groups section") << endmsg
;
1402 } else if (load_route_groups (*child
, version
)) {
1407 if ((child
= find_named_node (node
, "Click")) == 0) {
1408 warning
<< _("Session: XML state has no click section") << endmsg
;
1409 } else if (_click_io
) {
1410 _click_io
->set_state (*child
, version
);
1413 if ((child
= find_named_node (node
, "ControlProtocols")) != 0) {
1414 ControlProtocolManager::instance().set_protocol_states (*child
);
1417 /* here beginneth the second phase ... */
1419 StateReady (); /* EMIT SIGNAL */
1428 Session::load_routes (const XMLNode
& node
, int version
)
1431 XMLNodeConstIterator niter
;
1432 RouteList new_routes
;
1434 nlist
= node
.children();
1438 for (niter
= nlist
.begin(); niter
!= nlist
.end(); ++niter
) {
1440 boost::shared_ptr
<Route
> route
;
1441 if (version
< 3000) {
1442 route
= XMLRouteFactory_2X (**niter
, version
);
1444 route
= XMLRouteFactory (**niter
, version
);
1448 error
<< _("Session: cannot create Route from XML description.") << endmsg
;
1452 BootMessage (string_compose (_("Loaded track/bus %1"), route
->name()));
1454 new_routes
.push_back (route
);
1457 add_routes (new_routes
, false, false);
1462 boost::shared_ptr
<Route
>
1463 Session::XMLRouteFactory (const XMLNode
& node
, int version
)
1465 boost::shared_ptr
<Route
> ret
;
1467 if (node
.name() != "Route") {
1471 XMLNode
* ds_child
= find_named_node (node
, X_("Diskstream"));
1473 DataType type
= DataType::AUDIO
;
1474 const XMLProperty
* prop
= node
.property("default-type");
1477 type
= DataType (prop
->value());
1480 assert (type
!= DataType::NIL
);
1484 boost::shared_ptr
<Track
> track
;
1486 if (type
== DataType::AUDIO
) {
1487 track
.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1489 track
.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1492 if (track
->init()) {
1496 if (track
->set_state (node
, version
)) {
1500 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1501 boost_debug_shared_ptr_mark_interesting (track
.get(), "Track");
1506 boost::shared_ptr
<Route
> r (new Route (*this, X_("toBeResetFroXML")));
1508 if (r
->init () == 0 && r
->set_state (node
, version
) == 0) {
1509 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1510 boost_debug_shared_ptr_mark_interesting (r
.get(), "Route");
1519 boost::shared_ptr
<Route
>
1520 Session::XMLRouteFactory_2X (const XMLNode
& node
, int version
)
1522 boost::shared_ptr
<Route
> ret
;
1524 if (node
.name() != "Route") {
1528 XMLProperty
const * ds_prop
= node
.property (X_("diskstream-id"));
1530 ds_prop
= node
.property (X_("diskstream"));
1533 DataType type
= DataType::AUDIO
;
1534 const XMLProperty
* prop
= node
.property("default-type");
1537 type
= DataType (prop
->value());
1540 assert (type
!= DataType::NIL
);
1544 list
<boost::shared_ptr
<Diskstream
> >::iterator i
= _diskstreams_2X
.begin ();
1545 while (i
!= _diskstreams_2X
.end() && (*i
)->id() != ds_prop
->value()) {
1549 if (i
== _diskstreams_2X
.end()) {
1550 error
<< _("Could not find diskstream for route") << endmsg
;
1551 return boost::shared_ptr
<Route
> ();
1554 boost::shared_ptr
<Track
> track
;
1556 if (type
== DataType::AUDIO
) {
1557 track
.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1559 track
.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1562 if (track
->init()) {
1566 if (track
->set_state (node
, version
)) {
1570 track
->set_diskstream (*i
);
1572 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1573 boost_debug_shared_ptr_mark_interesting (track
.get(), "Track");
1578 boost::shared_ptr
<Route
> r (new Route (*this, X_("toBeResetFroXML")));
1580 if (r
->init () == 0 && r
->set_state (node
, version
) == 0) {
1581 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1582 boost_debug_shared_ptr_mark_interesting (r
.get(), "Route");
1592 Session::load_regions (const XMLNode
& node
)
1595 XMLNodeConstIterator niter
;
1596 boost::shared_ptr
<Region
> region
;
1598 nlist
= node
.children();
1602 for (niter
= nlist
.begin(); niter
!= nlist
.end(); ++niter
) {
1603 if ((region
= XMLRegionFactory (**niter
, false)) == 0) {
1604 error
<< _("Session: cannot create Region from XML description.");
1605 const XMLProperty
*name
= (**niter
).property("name");
1608 error
<< " " << string_compose (_("Can not load state for region '%1'"), name
->value());
1619 Session::load_compounds (const XMLNode
& node
)
1621 XMLNodeList calist
= node
.children();
1622 XMLNodeConstIterator caiter
;
1623 XMLProperty
*caprop
;
1625 for (caiter
= calist
.begin(); caiter
!= calist
.end(); ++caiter
) {
1626 XMLNode
* ca
= *caiter
;
1630 if ((caprop
= ca
->property (X_("original"))) == 0) {
1633 orig_id
= caprop
->value();
1635 if ((caprop
= ca
->property (X_("copy"))) == 0) {
1638 copy_id
= caprop
->value();
1640 boost::shared_ptr
<Region
> orig
= RegionFactory::region_by_id (orig_id
);
1641 boost::shared_ptr
<Region
> copy
= RegionFactory::region_by_id (copy_id
);
1643 if (!orig
|| !copy
) {
1644 warning
<< string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1650 RegionFactory::add_compound_association (orig
, copy
);
1657 Session::load_nested_sources (const XMLNode
& node
)
1660 XMLNodeConstIterator niter
;
1662 nlist
= node
.children();
1664 for (niter
= nlist
.begin(); niter
!= nlist
.end(); ++niter
) {
1665 if ((*niter
)->name() == "Source") {
1667 /* it may already exist, so don't recreate it unnecessarily
1670 XMLProperty
* prop
= (*niter
)->property (X_("id"));
1672 error
<< _("Nested source has no ID info in session state file! (ignored)") << endmsg
;
1676 ID
source_id (prop
->value());
1678 if (!source_by_id (source_id
)) {
1681 SourceFactory::create (*this, **niter
, true);
1683 catch (failed_constructor
& err
) {
1684 error
<< string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg
;
1691 boost::shared_ptr
<Region
>
1692 Session::XMLRegionFactory (const XMLNode
& node
, bool full
)
1694 const XMLProperty
* type
= node
.property("type");
1698 const XMLNodeList
& nlist
= node
.children();
1700 for (XMLNodeConstIterator niter
= nlist
.begin(); niter
!= nlist
.end(); ++niter
) {
1701 XMLNode
*child
= (*niter
);
1702 if (child
->name() == "NestedSource") {
1703 load_nested_sources (*child
);
1707 if (!type
|| type
->value() == "audio") {
1708 return boost::shared_ptr
<Region
>(XMLAudioRegionFactory (node
, full
));
1709 } else if (type
->value() == "midi") {
1710 return boost::shared_ptr
<Region
>(XMLMidiRegionFactory (node
, full
));
1713 } catch (failed_constructor
& err
) {
1714 return boost::shared_ptr
<Region
> ();
1717 return boost::shared_ptr
<Region
> ();
1720 boost::shared_ptr
<AudioRegion
>
1721 Session::XMLAudioRegionFactory (const XMLNode
& node
, bool /*full*/)
1723 const XMLProperty
* prop
;
1724 boost::shared_ptr
<Source
> source
;
1725 boost::shared_ptr
<AudioSource
> as
;
1727 SourceList master_sources
;
1728 uint32_t nchans
= 1;
1731 if (node
.name() != X_("Region")) {
1732 return boost::shared_ptr
<AudioRegion
>();
1735 if ((prop
= node
.property (X_("channels"))) != 0) {
1736 nchans
= atoi (prop
->value().c_str());
1739 if ((prop
= node
.property ("name")) == 0) {
1740 cerr
<< "no name for this region\n";
1744 if ((prop
= node
.property (X_("source-0"))) == 0) {
1745 if ((prop
= node
.property ("source")) == 0) {
1746 error
<< _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg
;
1747 return boost::shared_ptr
<AudioRegion
>();
1751 PBD::ID
s_id (prop
->value());
1753 if ((source
= source_by_id (s_id
)) == 0) {
1754 error
<< string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id
) << endmsg
;
1755 return boost::shared_ptr
<AudioRegion
>();
1758 as
= boost::dynamic_pointer_cast
<AudioSource
>(source
);
1760 error
<< string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id
) << endmsg
;
1761 return boost::shared_ptr
<AudioRegion
>();
1764 sources
.push_back (as
);
1766 /* pickup other channels */
1768 for (uint32_t n
=1; n
< nchans
; ++n
) {
1769 snprintf (buf
, sizeof(buf
), X_("source-%d"), n
);
1770 if ((prop
= node
.property (buf
)) != 0) {
1772 PBD::ID
id2 (prop
->value());
1774 if ((source
= source_by_id (id2
)) == 0) {
1775 error
<< string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2
) << endmsg
;
1776 return boost::shared_ptr
<AudioRegion
>();
1779 as
= boost::dynamic_pointer_cast
<AudioSource
>(source
);
1781 error
<< string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2
) << endmsg
;
1782 return boost::shared_ptr
<AudioRegion
>();
1784 sources
.push_back (as
);
1788 for (uint32_t n
= 0; n
< nchans
; ++n
) {
1789 snprintf (buf
, sizeof(buf
), X_("master-source-%d"), n
);
1790 if ((prop
= node
.property (buf
)) != 0) {
1792 PBD::ID
id2 (prop
->value());
1794 if ((source
= source_by_id (id2
)) == 0) {
1795 error
<< string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2
) << endmsg
;
1796 return boost::shared_ptr
<AudioRegion
>();
1799 as
= boost::dynamic_pointer_cast
<AudioSource
>(source
);
1801 error
<< string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2
) << endmsg
;
1802 return boost::shared_ptr
<AudioRegion
>();
1804 master_sources
.push_back (as
);
1809 boost::shared_ptr
<AudioRegion
> region (boost::dynamic_pointer_cast
<AudioRegion
> (RegionFactory::create (sources
, node
)));
1811 /* a final detail: this is the one and only place that we know how long missing files are */
1813 if (region
->whole_file()) {
1814 for (SourceList::iterator sx
= sources
.begin(); sx
!= sources
.end(); ++sx
) {
1815 boost::shared_ptr
<SilentFileSource
> sfp
= boost::dynamic_pointer_cast
<SilentFileSource
> (*sx
);
1817 sfp
->set_length (region
->length());
1822 if (!master_sources
.empty()) {
1823 if (master_sources
.size() != nchans
) {
1824 error
<< _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg
;
1826 region
->set_master_sources (master_sources
);
1834 catch (failed_constructor
& err
) {
1835 return boost::shared_ptr
<AudioRegion
>();
1839 boost::shared_ptr
<MidiRegion
>
1840 Session::XMLMidiRegionFactory (const XMLNode
& node
, bool /*full*/)
1842 const XMLProperty
* prop
;
1843 boost::shared_ptr
<Source
> source
;
1844 boost::shared_ptr
<MidiSource
> ms
;
1847 if (node
.name() != X_("Region")) {
1848 return boost::shared_ptr
<MidiRegion
>();
1851 if ((prop
= node
.property ("name")) == 0) {
1852 cerr
<< "no name for this region\n";
1856 if ((prop
= node
.property (X_("source-0"))) == 0) {
1857 if ((prop
= node
.property ("source")) == 0) {
1858 error
<< _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg
;
1859 return boost::shared_ptr
<MidiRegion
>();
1863 PBD::ID
s_id (prop
->value());
1865 if ((source
= source_by_id (s_id
)) == 0) {
1866 error
<< string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id
) << endmsg
;
1867 return boost::shared_ptr
<MidiRegion
>();
1870 ms
= boost::dynamic_pointer_cast
<MidiSource
>(source
);
1872 error
<< string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id
) << endmsg
;
1873 return boost::shared_ptr
<MidiRegion
>();
1876 sources
.push_back (ms
);
1879 boost::shared_ptr
<MidiRegion
> region (boost::dynamic_pointer_cast
<MidiRegion
> (RegionFactory::create (sources
, node
)));
1880 /* a final detail: this is the one and only place that we know how long missing files are */
1882 if (region
->whole_file()) {
1883 for (SourceList::iterator sx
= sources
.begin(); sx
!= sources
.end(); ++sx
) {
1884 boost::shared_ptr
<SilentFileSource
> sfp
= boost::dynamic_pointer_cast
<SilentFileSource
> (*sx
);
1886 sfp
->set_length (region
->length());
1894 catch (failed_constructor
& err
) {
1895 return boost::shared_ptr
<MidiRegion
>();
1900 Session::get_sources_as_xml ()
1903 XMLNode
* node
= new XMLNode (X_("Sources"));
1904 Glib::Mutex::Lock
lm (source_lock
);
1906 for (SourceMap::iterator i
= sources
.begin(); i
!= sources
.end(); ++i
) {
1907 node
->add_child_nocopy (i
->second
->get_state());
1914 Session::path_from_region_name (DataType type
, string name
, string identifier
)
1916 char buf
[PATH_MAX
+1];
1918 SessionDirectory
sdir(get_best_session_directory_for_new_source());
1919 sys::path source_dir
= ((type
== DataType::AUDIO
)
1920 ? sdir
.sound_path() : sdir
.midi_path());
1922 string ext
= native_header_format_extension (config
.get_native_file_header_format(), type
);
1924 for (n
= 0; n
< 999999; ++n
) {
1925 if (identifier
.length()) {
1926 snprintf (buf
, sizeof(buf
), "%s%s%" PRIu32
"%s", name
.c_str(),
1927 identifier
.c_str(), n
, ext
.c_str());
1929 snprintf (buf
, sizeof(buf
), "%s-%" PRIu32
"%s", name
.c_str(),
1933 sys::path source_path
= source_dir
/ buf
;
1935 if (!sys::exists (source_path
)) {
1936 return source_path
.to_string();
1940 error
<< string_compose (_("cannot create new file from region name \"%1\" with ident = \"%2\": too many existing files with similar names"),
1949 Session::load_sources (const XMLNode
& node
)
1952 XMLNodeConstIterator niter
;
1953 boost::shared_ptr
<Source
> source
;
1955 nlist
= node
.children();
1959 for (niter
= nlist
.begin(); niter
!= nlist
.end(); ++niter
) {
1962 if ((source
= XMLSourceFactory (**niter
)) == 0) {
1963 error
<< _("Session: cannot create Source from XML description.") << endmsg
;
1966 } catch (MissingSource
& err
) {
1970 if (!no_questions_about_missing_files
) {
1971 user_choice
= MissingFile (this, err
.path
, err
.type
).get_value_or (-1);
1976 switch (user_choice
) {
1978 /* user added a new search location, so try again */
1983 /* user asked to quit the entire session load
1988 no_questions_about_missing_files
= true;
1992 no_questions_about_missing_files
= true;
1997 warning
<< _("A sound file is missing. It will be replaced by silence.") << endmsg
;
1998 source
= SourceFactory::createSilent (*this, **niter
, max_framecnt
, _current_frame_rate
);
2007 boost::shared_ptr
<Source
>
2008 Session::XMLSourceFactory (const XMLNode
& node
)
2010 if (node
.name() != "Source") {
2011 return boost::shared_ptr
<Source
>();
2015 /* note: do peak building in another thread when loading session state */
2016 return SourceFactory::create (*this, node
, true);
2019 catch (failed_constructor
& err
) {
2020 error
<< string_compose (_("Found a sound file that cannot be used by %1. Talk to the progammers."), PROGRAM_NAME
) << endmsg
;
2021 return boost::shared_ptr
<Source
>();
2026 Session::save_template (string template_name
)
2030 if (_state_of_the_state
& CannotSave
) {
2034 sys::path
user_template_dir(user_template_directory());
2038 sys::create_directories (user_template_dir
);
2040 catch(sys::filesystem_error
& ex
)
2042 error
<< string_compose(_("Could not create mix templates directory \"%1\" (%2)"),
2043 user_template_dir
.to_string(), ex
.what()) << endmsg
;
2047 tree
.set_root (&get_template());
2049 sys::path
template_file_path(user_template_dir
);
2050 template_file_path
/= template_name
+ template_suffix
;
2052 if (sys::exists (template_file_path
))
2054 warning
<< string_compose(_("Template \"%1\" already exists - new version not created"),
2055 template_file_path
.to_string()) << endmsg
;
2059 if (!tree
.write (template_file_path
.to_string())) {
2060 error
<< _("template not saved") << endmsg
;
2068 Session::rename_template (string old_name
, string new_name
)
2070 sys::path
old_path (user_template_directory());
2071 old_path
/= old_name
+ template_suffix
;
2073 sys::path
new_path(user_template_directory());
2074 new_path
/= new_name
+ template_suffix
;
2076 if (sys::exists (new_path
)) {
2077 warning
<< string_compose(_("Template \"%1\" already exists - template not renamed"),
2078 new_path
.to_string()) << endmsg
;
2083 sys::rename (old_path
, new_path
);
2091 Session::delete_template (string name
)
2093 sys::path path
= user_template_directory();
2094 path
/= name
+ template_suffix
;
2105 Session::refresh_disk_space ()
2108 struct statfs statfsbuf
;
2109 vector
<space_and_path
>::iterator i
;
2110 Glib::Mutex::Lock
lm (space_lock
);
2113 /* get freespace on every FS that is part of the session path */
2115 _total_free_4k_blocks
= 0;
2117 for (i
= session_dirs
.begin(); i
!= session_dirs
.end(); ++i
) {
2118 statfs ((*i
).path
.c_str(), &statfsbuf
);
2120 scale
= statfsbuf
.f_bsize
/4096.0;
2122 (*i
).blocks
= (uint32_t) floor (statfsbuf
.f_bavail
* scale
);
2123 _total_free_4k_blocks
+= (*i
).blocks
;
2129 Session::get_best_session_directory_for_new_source ()
2131 vector
<space_and_path
>::iterator i
;
2132 string result
= _session_dir
->root_path().to_string();
2134 /* handle common case without system calls */
2136 if (session_dirs
.size() == 1) {
2140 /* OK, here's the algorithm we're following here:
2142 We want to select which directory to use for
2143 the next file source to be created. Ideally,
2144 we'd like to use a round-robin process so as to
2145 get maximum performance benefits from splitting
2146 the files across multiple disks.
2148 However, in situations without much diskspace, an
2149 RR approach may end up filling up a filesystem
2150 with new files while others still have space.
2151 Its therefore important to pay some attention to
2152 the freespace in the filesystem holding each
2153 directory as well. However, if we did that by
2154 itself, we'd keep creating new files in the file
2155 system with the most space until it was as full
2156 as all others, thus negating any performance
2157 benefits of this RAID-1 like approach.
2159 So, we use a user-configurable space threshold. If
2160 there are at least 2 filesystems with more than this
2161 much space available, we use RR selection between them.
2162 If not, then we pick the filesystem with the most space.
2164 This gets a good balance between the two
2168 refresh_disk_space ();
2170 int free_enough
= 0;
2172 for (i
= session_dirs
.begin(); i
!= session_dirs
.end(); ++i
) {
2173 if ((*i
).blocks
* 4096 >= Config
->get_disk_choice_space_threshold()) {
2178 if (free_enough
>= 2) {
2179 /* use RR selection process, ensuring that the one
2183 i
= last_rr_session_dir
;
2186 if (++i
== session_dirs
.end()) {
2187 i
= session_dirs
.begin();
2190 if ((*i
).blocks
* 4096 >= Config
->get_disk_choice_space_threshold()) {
2191 if (create_session_directory ((*i
).path
)) {
2193 last_rr_session_dir
= i
;
2198 } while (i
!= last_rr_session_dir
);
2202 /* pick FS with the most freespace (and that
2203 seems to actually work ...)
2206 vector
<space_and_path
> sorted
;
2207 space_and_path_ascending_cmp cmp
;
2209 sorted
= session_dirs
;
2210 sort (sorted
.begin(), sorted
.end(), cmp
);
2212 for (i
= sorted
.begin(); i
!= sorted
.end(); ++i
) {
2213 if (create_session_directory ((*i
).path
)) {
2215 last_rr_session_dir
= i
;
2225 Session::load_named_selections (const XMLNode
& node
)
2228 XMLNodeConstIterator niter
;
2231 nlist
= node
.children();
2235 for (niter
= nlist
.begin(); niter
!= nlist
.end(); ++niter
) {
2237 if ((ns
= XMLNamedSelectionFactory (**niter
)) == 0) {
2238 error
<< _("Session: cannot create Named Selection from XML description.") << endmsg
;
2246 Session::XMLNamedSelectionFactory (const XMLNode
& node
)
2249 return new NamedSelection (*this, node
);
2252 catch (failed_constructor
& err
) {
2258 Session::automation_dir () const
2260 return Glib::build_filename (_path
, "automation");
2264 Session::analysis_dir () const
2266 return Glib::build_filename (_path
, "analysis");
2270 Session::plugins_dir () const
2272 return Glib::build_filename (_path
, "plugins");
2276 Session::load_bundles (XMLNode
const & node
)
2278 XMLNodeList nlist
= node
.children();
2279 XMLNodeConstIterator niter
;
2283 for (niter
= nlist
.begin(); niter
!= nlist
.end(); ++niter
) {
2284 if ((*niter
)->name() == "InputBundle") {
2285 add_bundle (boost::shared_ptr
<UserBundle
> (new UserBundle (**niter
, true)));
2286 } else if ((*niter
)->name() == "OutputBundle") {
2287 add_bundle (boost::shared_ptr
<UserBundle
> (new UserBundle (**niter
, false)));
2289 error
<< string_compose(_("Unknown node \"%1\" found in Bundles list from state file"), (*niter
)->name()) << endmsg
;
2298 Session::load_route_groups (const XMLNode
& node
, int version
)
2300 XMLNodeList nlist
= node
.children();
2301 XMLNodeConstIterator niter
;
2305 if (version
>= 3000) {
2307 for (niter
= nlist
.begin(); niter
!= nlist
.end(); ++niter
) {
2308 if ((*niter
)->name() == "RouteGroup") {
2309 RouteGroup
* rg
= new RouteGroup (*this, "");
2310 add_route_group (rg
);
2311 rg
->set_state (**niter
, version
);
2315 } else if (version
< 3000) {
2317 for (niter
= nlist
.begin(); niter
!= nlist
.end(); ++niter
) {
2318 if ((*niter
)->name() == "EditGroup" || (*niter
)->name() == "MixGroup") {
2319 RouteGroup
* rg
= new RouteGroup (*this, "");
2320 add_route_group (rg
);
2321 rg
->set_state (**niter
, version
);
2330 Session::auto_save()
2332 save_state (_current_snapshot_name
);
2336 state_file_filter (const string
&str
, void */
*arg*/
)
2338 return (str
.length() > strlen(statefile_suffix
) &&
2339 str
.find (statefile_suffix
) == (str
.length() - strlen (statefile_suffix
)));
2343 bool operator()(const string
* a
, const string
* b
) {
2349 remove_end(string
* state
)
2351 string
statename(*state
);
2353 string::size_type start
,end
;
2354 if ((start
= statename
.find_last_of (G_DIR_SEPARATOR
)) != string::npos
) {
2355 statename
= statename
.substr (start
+1);
2358 if ((end
= statename
.rfind(".ardour")) == string::npos
) {
2359 end
= statename
.length();
2362 return new string(statename
.substr (0, end
));
2366 Session::possible_states (string path
)
2368 PathScanner scanner
;
2369 vector
<string
*>* states
= scanner (path
, state_file_filter
, 0, false, false);
2371 transform(states
->begin(), states
->end(), states
->begin(), remove_end
);
2374 sort (states
->begin(), states
->end(), cmp
);
2380 Session::possible_states () const
2382 return possible_states(_path
);
2386 Session::add_route_group (RouteGroup
* g
)
2388 _route_groups
.push_back (g
);
2389 route_group_added (g
); /* EMIT SIGNAL */
2391 g
->MembershipChanged
.connect_same_thread (*this, boost::bind (&Session::route_group_changed
, this));
2392 g
->PropertyChanged
.connect_same_thread (*this, boost::bind (&Session::route_group_changed
, this));
2398 Session::remove_route_group (RouteGroup
& rg
)
2400 list
<RouteGroup
*>::iterator i
;
2402 if ((i
= find (_route_groups
.begin(), _route_groups
.end(), &rg
)) != _route_groups
.end()) {
2403 _route_groups
.erase (i
);
2406 route_group_removed (); /* EMIT SIGNAL */
2410 /** Set a new order for our route groups, without adding or removing any.
2411 * @param groups Route group list in the new order.
2414 Session::reorder_route_groups (list
<RouteGroup
*> groups
)
2416 _route_groups
= groups
;
2418 route_groups_reordered (); /* EMIT SIGNAL */
2424 Session::route_group_by_name (string name
)
2426 list
<RouteGroup
*>::iterator i
;
2428 for (i
= _route_groups
.begin(); i
!= _route_groups
.end(); ++i
) {
2429 if ((*i
)->name() == name
) {
2437 Session::all_route_group() const
2439 return *_all_route_group
;
2443 Session::add_commands (vector
<Command
*> const & cmds
)
2445 for (vector
<Command
*>::const_iterator i
= cmds
.begin(); i
!= cmds
.end(); ++i
) {
2451 Session::begin_reversible_command (const string
& name
)
2453 begin_reversible_command (g_quark_from_string (name
.c_str ()));
2456 /** Begin a reversible command using a GQuark to identify it.
2457 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2458 * but there must be as many begin...()s as there are commit...()s.
2461 Session::begin_reversible_command (GQuark q
)
2463 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2464 to hold all the commands that are committed. This keeps the order of
2465 commands correct in the history.
2468 if (_current_trans
== 0) {
2469 /* start a new transaction */
2470 assert (_current_trans_quarks
.empty ());
2471 _current_trans
= new UndoTransaction();
2472 _current_trans
->set_name (g_quark_to_string (q
));
2475 _current_trans_quarks
.push_front (q
);
2479 Session::commit_reversible_command (Command
*cmd
)
2481 assert (_current_trans
);
2482 assert (!_current_trans_quarks
.empty ());
2487 _current_trans
->add_command (cmd
);
2490 _current_trans_quarks
.pop_front ();
2492 if (!_current_trans_quarks
.empty ()) {
2493 /* the transaction we're committing is not the top-level one */
2497 if (_current_trans
->empty()) {
2498 /* no commands were added to the transaction, so just get rid of it */
2499 delete _current_trans
;
2504 gettimeofday (&now
, 0);
2505 _current_trans
->set_timestamp (now
);
2507 _history
.add (_current_trans
);
2512 accept_all_audio_files (const string
& path
, void */
*arg*/
)
2514 if (!Glib::file_test (path
, Glib::FILE_TEST_IS_REGULAR
)) {
2518 if (!AudioFileSource::safe_audio_file_extension (path
)) {
2526 accept_all_midi_files (const string
& path
, void */
*arg*/
)
2528 if (!Glib::file_test (path
, Glib::FILE_TEST_IS_REGULAR
)) {
2532 return ((path
.length() > 4 && path
.find (".mid") != (path
.length() - 4)) ||
2533 (path
.length() > 4 && path
.find (".smf") != (path
.length() - 4)) ||
2534 (path
.length() > 5 && path
.find (".midi") != (path
.length() - 5)));
2538 accept_all_state_files (const string
& path
, void */
*arg*/
)
2540 if (!Glib::file_test (path
, Glib::FILE_TEST_IS_REGULAR
)) {
2544 return (path
.length() > 7 && path
.find (".ardour") == (path
.length() - 7));
2548 Session::find_all_sources (string path
, set
<string
>& result
)
2553 if (!tree
.read (path
)) {
2557 if ((node
= find_named_node (*tree
.root(), "Sources")) == 0) {
2562 XMLNodeConstIterator niter
;
2564 nlist
= node
->children();
2568 for (niter
= nlist
.begin(); niter
!= nlist
.end(); ++niter
) {
2572 if ((prop
= (*niter
)->property (X_("type"))) == 0) {
2576 DataType
type (prop
->value());
2578 if ((prop
= (*niter
)->property (X_("name"))) == 0) {
2582 if (Glib::path_is_absolute (prop
->value())) {
2583 /* external file, ignore */
2591 if (FileSource::find (*this, type
, prop
->value(), true, is_new
, chan
, found_path
)) {
2592 result
.insert (found_path
);
2600 Session::find_all_sources_across_snapshots (set
<string
>& result
, bool exclude_this_snapshot
)
2602 PathScanner scanner
;
2603 vector
<string
*>* state_files
;
2605 string this_snapshot_path
;
2611 if (ripped
[ripped
.length()-1] == G_DIR_SEPARATOR
) {
2612 ripped
= ripped
.substr (0, ripped
.length() - 1);
2615 state_files
= scanner (ripped
, accept_all_state_files
, (void *) 0, false, true);
2617 if (state_files
== 0) {
2622 this_snapshot_path
= _path
;
2623 this_snapshot_path
+= legalize_for_path (_current_snapshot_name
);
2624 this_snapshot_path
+= statefile_suffix
;
2626 for (vector
<string
*>::iterator i
= state_files
->begin(); i
!= state_files
->end(); ++i
) {
2628 if (exclude_this_snapshot
&& **i
== this_snapshot_path
) {
2632 if (find_all_sources (**i
, result
) < 0) {
2640 struct RegionCounter
{
2641 typedef std::map
<PBD::ID
,boost::shared_ptr
<AudioSource
> > AudioSourceList
;
2642 AudioSourceList::iterator iter
;
2643 boost::shared_ptr
<Region
> region
;
2646 RegionCounter() : count (0) {}
2650 Session::ask_about_playlist_deletion (boost::shared_ptr
<Playlist
> p
)
2652 boost::optional
<int> r
= AskAboutPlaylistDeletion (p
);
2653 return r
.get_value_or (1);
2657 Session::cleanup_regions ()
2659 const RegionFactory::RegionMap
& regions (RegionFactory::regions());
2661 for (RegionFactory::RegionMap::const_iterator i
= regions
.begin(); i
!= regions
.end(); ++i
) {
2663 boost::shared_ptr
<AudioRegion
> audio_region
= boost::dynamic_pointer_cast
<AudioRegion
>( i
->second
);
2665 if (!audio_region
) {
2669 uint32_t used
= playlists
->region_use_count (audio_region
);
2671 if (used
== 0 && !audio_region
->automatic()) {
2672 RegionFactory::map_remove(i
->second
);
2676 /* dump the history list */
2683 Session::cleanup_sources (CleanupReport
& rep
)
2685 // FIXME: needs adaptation to midi
2687 vector
<boost::shared_ptr
<Source
> > dead_sources
;
2688 PathScanner scanner
;
2691 vector
<space_and_path
>::iterator i
;
2692 vector
<space_and_path
>::iterator nexti
;
2693 vector
<string
*>* candidates
;
2694 vector
<string
*>* candidates2
;
2695 vector
<string
> unused
;
2696 set
<string
> all_sources
;
2701 _state_of_the_state
= (StateOfTheState
) (_state_of_the_state
| InCleanup
);
2703 /* consider deleting all unused playlists */
2705 if (playlists
->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion
, _1
))) {
2710 /* sync the "all regions" property of each playlist with its current state
2713 playlists
->sync_all_regions_with_regions ();
2715 /* find all un-used sources */
2720 for (SourceMap::iterator i
= sources
.begin(); i
!= sources
.end(); ) {
2722 SourceMap::iterator tmp
;
2727 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
2731 if (!i
->second
->used() && (i
->second
->length(i
->second
->timeline_position() > 0))) {
2732 dead_sources
.push_back (i
->second
);
2733 i
->second
->drop_references ();
2739 /* build a list of all the possible audio directories for the session */
2741 for (i
= session_dirs
.begin(); i
!= session_dirs
.end(); ) {
2746 SessionDirectory
sdir ((*i
).path
);
2747 audio_path
+= sdir
.sound_path().to_string();
2749 if (nexti
!= session_dirs
.end()) {
2757 /* build a list of all the possible midi directories for the session */
2759 for (i
= session_dirs
.begin(); i
!= session_dirs
.end(); ) {
2764 SessionDirectory
sdir ((*i
).path
);
2765 midi_path
+= sdir
.midi_path().to_string();
2767 if (nexti
!= session_dirs
.end()) {
2774 candidates
= scanner (audio_path
, accept_all_audio_files
, (void *) 0, true, true);
2775 candidates2
= scanner (midi_path
, accept_all_midi_files
, (void *) 0, true, true);
2781 for (vector
<string
*>::iterator i
= candidates2
->begin(); i
!= candidates2
->end(); ++i
) {
2782 candidates
->push_back (*i
);
2787 candidates
= candidates2
; // might still be null
2790 /* find all sources, but don't use this snapshot because the
2791 state file on disk still references sources we may have already
2795 find_all_sources_across_snapshots (all_sources
, true);
2797 /* add our current source list
2800 for (SourceMap::iterator i
= sources
.begin(); i
!= sources
.end(); ) {
2801 boost::shared_ptr
<FileSource
> fs
;
2802 SourceMap::iterator tmp
= i
;
2805 if ((fs
= boost::dynamic_pointer_cast
<FileSource
> (i
->second
)) != 0) {
2806 if (playlists
->source_use_count (fs
) != 0) {
2807 all_sources
.insert (fs
->path());
2810 /* we might not remove this source from disk, because it may be used
2811 by other snapshots, but its not being used in this version
2812 so lets get rid of it now, along with any representative regions
2816 RegionFactory::remove_regions_using_source (i
->second
);
2824 char tmppath1
[PATH_MAX
+1];
2825 char tmppath2
[PATH_MAX
+1];
2828 for (vector
<string
*>::iterator x
= candidates
->begin(); x
!= candidates
->end(); ++x
) {
2833 for (set
<string
>::iterator i
= all_sources
.begin(); i
!= all_sources
.end(); ++i
) {
2835 if (realpath(spath
.c_str(), tmppath1
) == 0) {
2836 error
<< string_compose (_("Cannot expand path %1 (%2)"),
2837 spath
, strerror (errno
)) << endmsg
;
2841 if (realpath((*i
).c_str(), tmppath2
) == 0) {
2842 error
<< string_compose (_("Cannot expand path %1 (%2)"),
2843 (*i
), strerror (errno
)) << endmsg
;
2847 if (strcmp(tmppath1
, tmppath2
) == 0) {
2854 unused
.push_back (spath
);
2863 /* now try to move all unused files into the "dead" directory(ies) */
2865 for (vector
<string
>::iterator x
= unused
.begin(); x
!= unused
.end(); ++x
) {
2866 struct stat statbuf
;
2870 /* don't move the file across filesystems, just
2871 stick it in the `dead_dir_name' directory
2872 on whichever filesystem it was already on.
2875 if ((*x
).find ("/sounds/") != string::npos
) {
2877 /* old school, go up 1 level */
2879 newpath
= Glib::path_get_dirname (*x
); // "sounds"
2880 newpath
= Glib::path_get_dirname (newpath
); // "session-name"
2884 /* new school, go up 4 levels */
2886 newpath
= Glib::path_get_dirname (*x
); // "audiofiles" or "midifiles"
2887 newpath
= Glib::path_get_dirname (newpath
); // "session-name"
2888 newpath
= Glib::path_get_dirname (newpath
); // "interchange"
2889 newpath
= Glib::path_get_dirname (newpath
); // "session-dir"
2892 newpath
= Glib::build_filename (newpath
, dead_dir_name
);
2894 if (g_mkdir_with_parents (newpath
.c_str(), 0755) < 0) {
2895 error
<< string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath
, strerror (errno
)) << endmsg
;
2899 newpath
= Glib::build_filename (newpath
, Glib::path_get_basename ((*x
)));
2901 if (Glib::file_test (newpath
, Glib::FILE_TEST_EXISTS
)) {
2903 /* the new path already exists, try versioning */
2905 char buf
[PATH_MAX
+1];
2909 snprintf (buf
, sizeof (buf
), "%s.%d", newpath
.c_str(), version
);
2912 while (Glib::file_test (newpath_v
.c_str(), Glib::FILE_TEST_EXISTS
) && version
< 999) {
2913 snprintf (buf
, sizeof (buf
), "%s.%d", newpath
.c_str(), ++version
);
2917 if (version
== 999) {
2918 error
<< string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
2922 newpath
= newpath_v
;
2927 /* it doesn't exist, or we can't read it or something */
2931 stat ((*x
).c_str(), &statbuf
);
2933 if (::rename ((*x
).c_str(), newpath
.c_str()) != 0) {
2934 error
<< string_compose (_("cannot rename unused file source from %1 to %2 (%3)"),
2935 (*x
), newpath
, strerror (errno
))
2940 /* see if there an easy to find peakfile for this file, and remove it.
2943 string base
= basename_nosuffix (*x
);
2944 base
+= "%A"; /* this is what we add for the channel suffix of all native files,
2945 or for the first channel of embedded files. it will miss
2946 some peakfiles for other channels
2948 string peakpath
= peak_path (base
);
2950 if (Glib::file_test (peakpath
.c_str(), Glib::FILE_TEST_EXISTS
)) {
2951 if (::unlink (peakpath
.c_str()) != 0) {
2952 error
<< string_compose (_("cannot remove peakfile %1 for %2 (%3)"),
2953 peakpath
, _path
, strerror (errno
))
2955 /* try to back out */
2956 ::rename (newpath
.c_str(), _path
.c_str());
2961 rep
.paths
.push_back (*x
);
2962 rep
.space
+= statbuf
.st_size
;
2965 /* dump the history list */
2969 /* save state so we don't end up a session file
2970 referring to non-existent sources.
2977 _state_of_the_state
= (StateOfTheState
) (_state_of_the_state
& ~InCleanup
);
2983 Session::cleanup_trash_sources (CleanupReport
& rep
)
2985 // FIXME: needs adaptation for MIDI
2987 vector
<space_and_path
>::iterator i
;
2993 for (i
= session_dirs
.begin(); i
!= session_dirs
.end(); ++i
) {
2995 dead_dir
= Glib::build_filename ((*i
).path
, dead_dir_name
);
2997 clear_directory (dead_dir
, &rep
.space
, &rep
.paths
);
3004 Session::set_dirty ()
3006 bool was_dirty
= dirty();
3008 _state_of_the_state
= StateOfTheState (_state_of_the_state
| Dirty
);
3012 DirtyChanged(); /* EMIT SIGNAL */
3018 Session::set_clean ()
3020 bool was_dirty
= dirty();
3022 _state_of_the_state
= Clean
;
3026 DirtyChanged(); /* EMIT SIGNAL */
3031 Session::set_deletion_in_progress ()
3033 _state_of_the_state
= StateOfTheState (_state_of_the_state
| Deletion
);
3037 Session::clear_deletion_in_progress ()
3039 _state_of_the_state
= StateOfTheState (_state_of_the_state
& (~Deletion
));
3043 Session::add_controllable (boost::shared_ptr
<Controllable
> c
)
3045 /* this adds a controllable to the list managed by the Session.
3046 this is a subset of those managed by the Controllable class
3047 itself, and represents the only ones whose state will be saved
3048 as part of the session.
3051 Glib::Mutex::Lock
lm (controllables_lock
);
3052 controllables
.insert (c
);
3055 struct null_deleter
{ void operator()(void const *) const {} };
3058 Session::remove_controllable (Controllable
* c
)
3060 if (_state_of_the_state
| Deletion
) {
3064 Glib::Mutex::Lock
lm (controllables_lock
);
3066 Controllables::iterator x
= controllables
.find (boost::shared_ptr
<Controllable
>(c
, null_deleter()));
3068 if (x
!= controllables
.end()) {
3069 controllables
.erase (x
);
3073 boost::shared_ptr
<Controllable
>
3074 Session::controllable_by_id (const PBD::ID
& id
)
3076 Glib::Mutex::Lock
lm (controllables_lock
);
3078 for (Controllables::iterator i
= controllables
.begin(); i
!= controllables
.end(); ++i
) {
3079 if ((*i
)->id() == id
) {
3084 return boost::shared_ptr
<Controllable
>();
3087 boost::shared_ptr
<Controllable
>
3088 Session::controllable_by_descriptor (const ControllableDescriptor
& desc
)
3090 boost::shared_ptr
<Controllable
> c
;
3091 boost::shared_ptr
<Route
> r
;
3093 switch (desc
.top_level_type()) {
3094 case ControllableDescriptor::NamedRoute
:
3096 std::string str
= desc
.top_level_name();
3097 if (str
== "master") {
3099 } else if (str
== "control" || str
== "listen") {
3102 r
= route_by_name (desc
.top_level_name());
3107 case ControllableDescriptor::RemoteControlID
:
3108 r
= route_by_remote_id (desc
.rid());
3116 switch (desc
.subtype()) {
3117 case ControllableDescriptor::Gain
:
3118 c
= r
->gain_control ();
3121 case ControllableDescriptor::Solo
:
3122 c
= r
->solo_control();
3125 case ControllableDescriptor::Mute
:
3126 c
= r
->mute_control();
3129 case ControllableDescriptor::Recenable
:
3131 boost::shared_ptr
<Track
> t
= boost::dynamic_pointer_cast
<Track
>(r
);
3134 c
= t
->rec_enable_control ();
3139 case ControllableDescriptor::PanDirection
:
3141 c
= r
->pannable()->pan_azimuth_control
;
3145 case ControllableDescriptor::PanWidth
:
3147 c
= r
->pannable()->pan_width_control
;
3151 case ControllableDescriptor::PanElevation
:
3153 c
= r
->pannable()->pan_elevation_control
;
3157 case ControllableDescriptor::Balance
:
3158 /* XXX simple pan control */
3161 case ControllableDescriptor::PluginParameter
:
3163 uint32_t plugin
= desc
.target (0);
3164 uint32_t parameter_index
= desc
.target (1);
3166 /* revert to zero based counting */
3172 if (parameter_index
> 0) {
3176 boost::shared_ptr
<Processor
> p
= r
->nth_plugin (plugin
);
3179 c
= boost::dynamic_pointer_cast
<ARDOUR::AutomationControl
>(
3180 p
->control(Evoral::Parameter(PluginAutomation
, 0, parameter_index
)));
3185 case ControllableDescriptor::SendGain
:
3187 uint32_t send
= desc
.target (0);
3189 /* revert to zero-based counting */
3195 boost::shared_ptr
<Processor
> p
= r
->nth_send (send
);
3198 boost::shared_ptr
<Send
> s
= boost::dynamic_pointer_cast
<Send
>(p
);
3199 boost::shared_ptr
<Amp
> a
= s
->amp();
3202 c
= s
->amp()->gain_control();
3209 /* relax and return a null pointer */
3217 Session::add_instant_xml (XMLNode
& node
, bool write_to_config
)
3220 Stateful::add_instant_xml (node
, _path
);
3223 if (write_to_config
) {
3224 Config
->add_instant_xml (node
);
3229 Session::instant_xml (const string
& node_name
)
3231 return Stateful::instant_xml (node_name
, _path
);
3235 Session::save_history (string snapshot_name
)
3243 if (snapshot_name
.empty()) {
3244 snapshot_name
= _current_snapshot_name
;
3247 const string history_filename
= legalize_for_path (snapshot_name
) + history_suffix
;
3248 const string backup_filename
= history_filename
+ backup_suffix
;
3249 const sys::path xml_path
= _session_dir
->root_path() / history_filename
;
3250 const sys::path backup_path
= _session_dir
->root_path() / backup_filename
;
3252 if (sys::exists (xml_path
)) {
3255 sys::rename (xml_path
, backup_path
);
3257 catch (const sys::filesystem_error
& err
)
3259 error
<< _("could not backup old history file, current history not saved") << endmsg
;
3264 if (!Config
->get_save_history() || Config
->get_saved_history_depth() < 0) {
3268 tree
.set_root (&_history
.get_state (Config
->get_saved_history_depth()));
3270 if (!tree
.write (xml_path
.to_string()))
3272 error
<< string_compose (_("history could not be saved to %1"), xml_path
.to_string()) << endmsg
;
3276 sys::remove (xml_path
);
3277 sys::rename (backup_path
, xml_path
);
3279 catch (const sys::filesystem_error
& err
)
3281 error
<< string_compose (_("could not restore history file from backup %1 (%2)"),
3282 backup_path
.to_string(), err
.what()) << endmsg
;
3292 Session::restore_history (string snapshot_name
)
3296 if (snapshot_name
.empty()) {
3297 snapshot_name
= _current_snapshot_name
;
3300 const string xml_filename
= legalize_for_path (snapshot_name
) + history_suffix
;
3301 const sys::path xml_path
= _session_dir
->root_path() / xml_filename
;
3303 info
<< "Loading history from " << xml_path
.to_string() << endmsg
;
3305 if (!sys::exists (xml_path
)) {
3306 info
<< string_compose (_("%1: no history file \"%2\" for this session."),
3307 _name
, xml_path
.to_string()) << endmsg
;
3311 if (!tree
.read (xml_path
.to_string())) {
3312 error
<< string_compose (_("Could not understand session history file \"%1\""),
3313 xml_path
.to_string()) << endmsg
;
3320 for (XMLNodeConstIterator it
= tree
.root()->children().begin(); it
!= tree
.root()->children().end(); it
++) {
3323 UndoTransaction
* ut
= new UndoTransaction ();
3326 ut
->set_name(t
->property("name")->value());
3327 stringstream
ss(t
->property("tv-sec")->value());
3329 ss
.str(t
->property("tv-usec")->value());
3331 ut
->set_timestamp(tv
);
3333 for (XMLNodeConstIterator child_it
= t
->children().begin();
3334 child_it
!= t
->children().end(); child_it
++)
3336 XMLNode
*n
= *child_it
;
3339 if (n
->name() == "MementoCommand" ||
3340 n
->name() == "MementoUndoCommand" ||
3341 n
->name() == "MementoRedoCommand") {
3343 if ((c
= memento_command_factory(n
))) {
3347 } else if (n
->name() == "NoteDiffCommand") {
3348 PBD::ID
id (n
->property("midi-source")->value());
3349 boost::shared_ptr
<MidiSource
> midi_source
=
3350 boost::dynamic_pointer_cast
<MidiSource
, Source
>(source_by_id(id
));
3352 ut
->add_command (new MidiModel::NoteDiffCommand(midi_source
->model(), *n
));
3354 error
<< _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg
;
3357 } else if (n
->name() == "SysExDiffCommand") {
3359 PBD::ID
id (n
->property("midi-source")->value());
3360 boost::shared_ptr
<MidiSource
> midi_source
=
3361 boost::dynamic_pointer_cast
<MidiSource
, Source
>(source_by_id(id
));
3363 ut
->add_command (new MidiModel::SysExDiffCommand (midi_source
->model(), *n
));
3365 error
<< _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg
;
3368 } else if (n
->name() == "PatchChangeDiffCommand") {
3370 PBD::ID
id (n
->property("midi-source")->value());
3371 boost::shared_ptr
<MidiSource
> midi_source
=
3372 boost::dynamic_pointer_cast
<MidiSource
, Source
>(source_by_id(id
));
3374 ut
->add_command (new MidiModel::PatchChangeDiffCommand (midi_source
->model(), *n
));
3376 error
<< _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg
;
3379 } else if (n
->name() == "StatefulDiffCommand") {
3380 if ((c
= stateful_diff_command_factory (n
))) {
3381 ut
->add_command (c
);
3384 error
<< string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n
->name()) << endmsg
;
3395 Session::config_changed (std::string p
, bool ours
)
3401 if (p
== "seamless-loop") {
3403 } else if (p
== "rf-speed") {
3405 } else if (p
== "auto-loop") {
3407 } else if (p
== "auto-input") {
3409 if (Config
->get_monitoring_model() == HardwareMonitoring
&& transport_rolling()) {
3410 /* auto-input only makes a difference if we're rolling */
3411 set_track_monitor_input_status (!config
.get_auto_input());
3414 } else if (p
== "punch-in") {
3418 if ((location
= _locations
->auto_punch_location()) != 0) {
3420 if (config
.get_punch_in ()) {
3421 replace_event (SessionEvent::PunchIn
, location
->start());
3423 remove_event (location
->start(), SessionEvent::PunchIn
);
3427 } else if (p
== "punch-out") {
3431 if ((location
= _locations
->auto_punch_location()) != 0) {
3433 if (config
.get_punch_out()) {
3434 replace_event (SessionEvent::PunchOut
, location
->end());
3436 clear_events (SessionEvent::PunchOut
);
3440 } else if (p
== "edit-mode") {
3442 Glib::Mutex::Lock
lm (playlists
->lock
);
3444 for (SessionPlaylists::List::iterator i
= playlists
->playlists
.begin(); i
!= playlists
->playlists
.end(); ++i
) {
3445 (*i
)->set_edit_mode (Config
->get_edit_mode ());
3448 } else if (p
== "use-video-sync") {
3450 waiting_for_sync_offset
= config
.get_use_video_sync();
3452 } else if (p
== "mmc-control") {
3454 //poke_midi_thread ();
3456 } else if (p
== "mmc-device-id" || p
== "mmc-receive-id" || p
== "mmc-receive-device-id") {
3458 MIDI::Manager::instance()->mmc()->set_receive_device_id (Config
->get_mmc_receive_device_id());
3460 } else if (p
== "mmc-send-id" || p
== "mmc-send-device-id") {
3462 MIDI::Manager::instance()->mmc()->set_send_device_id (Config
->get_mmc_send_device_id());
3464 } else if (p
== "midi-control") {
3466 //poke_midi_thread ();
3468 } else if (p
== "raid-path") {
3470 setup_raid_path (config
.get_raid_path());
3472 } else if (p
== "timecode-format") {
3476 } else if (p
== "video-pullup") {
3480 } else if (p
== "seamless-loop") {
3482 if (play_loop
&& transport_rolling()) {
3483 // to reset diskstreams etc
3484 request_play_loop (true);
3487 } else if (p
== "rf-speed") {
3489 cumulative_rf_motion
= 0;
3492 } else if (p
== "click-sound") {
3494 setup_click_sounds (1);
3496 } else if (p
== "click-emphasis-sound") {
3498 setup_click_sounds (-1);
3500 } else if (p
== "clicking") {
3502 if (Config
->get_clicking()) {
3503 if (_click_io
&& click_data
) { // don't require emphasis data
3510 } else if (p
== "send-mtc") {
3512 if (Config
->get_send_mtc ()) {
3513 /* mark us ready to send */
3514 next_quarter_frame_to_send
= 0;
3517 } else if (p
== "send-mmc") {
3519 MIDI::Manager::instance()->mmc()->enable_send (Config
->get_send_mmc ());
3521 } else if (p
== "midi-feedback") {
3523 session_midi_feedback
= Config
->get_midi_feedback();
3525 } else if (p
== "jack-time-master") {
3527 engine().reset_timebase ();
3529 } else if (p
== "native-file-header-format") {
3531 if (!first_file_header_format_reset
) {
3532 reset_native_file_format ();
3535 first_file_header_format_reset
= false;
3537 } else if (p
== "native-file-data-format") {
3539 if (!first_file_data_format_reset
) {
3540 reset_native_file_format ();
3543 first_file_data_format_reset
= false;
3545 } else if (p
== "external-sync") {
3546 if (!config
.get_external_sync()) {
3547 drop_sync_source ();
3549 switch_to_sync_source (config
.get_sync_source());
3551 } else if (p
== "remote-model") {
3552 set_remote_control_ids ();
3553 } else if (p
== "denormal-model") {
3555 } else if (p
== "history-depth") {
3556 set_history_depth (Config
->get_history_depth());
3557 } else if (p
== "sync-all-route-ordering") {
3558 sync_order_keys ("session");
3559 } else if (p
== "initial-program-change") {
3561 if (MIDI::Manager::instance()->mmc()->output_port() && Config
->get_initial_program_change() >= 0) {
3564 buf
[0] = MIDI::program
; // channel zero by default
3565 buf
[1] = (Config
->get_initial_program_change() & 0x7f);
3567 MIDI::Manager::instance()->mmc()->output_port()->midimsg (buf
, sizeof (buf
), 0);
3569 } else if (p
== "solo-mute-override") {
3570 // catch_up_on_solo_mute_override ();
3571 } else if (p
== "listen-position" || p
== "pfl-position") {
3572 listen_position_changed ();
3573 } else if (p
== "solo-control-is-listen-control") {
3574 solo_control_mode_changed ();
3575 } else if (p
== "timecode-offset" || p
== "timecode-offset-negative") {
3576 last_timecode_valid
= false;
3577 } else if (p
== "playback-buffer-seconds") {
3578 AudioSource::allocate_working_buffers (frame_rate());
3585 Session::set_history_depth (uint32_t d
)
3587 _history
.set_depth (d
);
3591 Session::load_diskstreams_2X (XMLNode
const & node
, int)
3594 XMLNodeConstIterator citer
;
3596 clist
= node
.children();
3598 for (citer
= clist
.begin(); citer
!= clist
.end(); ++citer
) {
3601 /* diskstreams added automatically by DiskstreamCreated handler */
3602 if ((*citer
)->name() == "AudioDiskstream" || (*citer
)->name() == "DiskStream") {
3603 boost::shared_ptr
<AudioDiskstream
> dsp (new AudioDiskstream (*this, **citer
));
3604 _diskstreams_2X
.push_back (dsp
);
3606 error
<< _("Session: unknown diskstream type in XML") << endmsg
;
3610 catch (failed_constructor
& err
) {
3611 error
<< _("Session: could not load diskstream via XML state") << endmsg
;
3619 /** Connect things to the MMC object */
3621 Session::setup_midi_machine_control ()
3623 MIDI::MachineControl
* mmc
= MIDI::Manager::instance()->mmc ();
3625 mmc
->Play
.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play
, this, _1
));
3626 mmc
->DeferredPlay
.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play
, this, _1
));
3627 mmc
->Stop
.connect_same_thread (*this, boost::bind (&Session::mmc_stop
, this, _1
));
3628 mmc
->FastForward
.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward
, this, _1
));
3629 mmc
->Rewind
.connect_same_thread (*this, boost::bind (&Session::mmc_rewind
, this, _1
));
3630 mmc
->Pause
.connect_same_thread (*this, boost::bind (&Session::mmc_pause
, this, _1
));
3631 mmc
->RecordPause
.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause
, this, _1
));
3632 mmc
->RecordStrobe
.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe
, this, _1
));
3633 mmc
->RecordExit
.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit
, this, _1
));
3634 mmc
->Locate
.connect_same_thread (*this, boost::bind (&Session::mmc_locate
, this, _1
, _2
));
3635 mmc
->Step
.connect_same_thread (*this, boost::bind (&Session::mmc_step
, this, _1
, _2
));
3636 mmc
->Shuttle
.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle
, this, _1
, _2
, _3
));
3637 mmc
->TrackRecordStatusChange
.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable
, this, _1
, _2
, _3
));
3639 /* also handle MIDI SPP because its so common */
3641 mmc
->SPPStart
.connect_same_thread (*this, boost::bind (&Session::spp_start
, this, _1
, _2
));
3642 mmc
->SPPContinue
.connect_same_thread (*this, boost::bind (&Session::spp_continue
, this, _1
, _2
));
3643 mmc
->SPPStop
.connect_same_thread (*this, boost::bind (&Session::spp_stop
, this, _1
, _2
));
3646 boost::shared_ptr
<Controllable
>
3647 Session::solo_cut_control() const
3649 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
3650 controls in Ardour that currently get presented to the user in the GUI that require
3651 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
3653 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
3654 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
3658 return _solo_cut_control
;
3662 Session::rename (const std::string
& new_name
)
3664 string legal_name
= legalize_for_path (new_name
);
3670 #define RENAME ::rename
3675 * interchange subdirectory
3679 * Backup files are left unchanged and not renamed.
3682 /* pass one: not 100% safe check that the new directory names don't
3686 for (vector
<space_and_path
>::const_iterator i
= session_dirs
.begin(); i
!= session_dirs
.end(); ++i
) {
3691 /* this is a stupid hack because Glib::path_get_dirname() is
3692 * lexical-only, and so passing it /a/b/c/ gives a different
3693 * result than passing it /a/b/c ...
3696 if (oldstr
[oldstr
.length()-1] == G_DIR_SEPARATOR
) {
3697 oldstr
= oldstr
.substr (0, oldstr
.length() - 1);
3700 string base
= Glib::path_get_dirname (oldstr
);
3701 string p
= Glib::path_get_basename (oldstr
);
3703 newstr
= Glib::build_filename (base
, legal_name
);
3705 if (Glib::file_test (newstr
, Glib::FILE_TEST_EXISTS
)) {
3712 for (vector
<space_and_path
>::const_iterator i
= session_dirs
.begin(); i
!= session_dirs
.end(); ++i
) {
3717 /* this is a stupid hack because Glib::path_get_dirname() is
3718 * lexical-only, and so passing it /a/b/c/ gives a different
3719 * result than passing it /a/b/c ...
3722 if (oldstr
[oldstr
.length()-1] == G_DIR_SEPARATOR
) {
3723 oldstr
= oldstr
.substr (0, oldstr
.length() - 1);
3726 string base
= Glib::path_get_dirname (oldstr
);
3727 string p
= Glib::path_get_basename (oldstr
);
3729 newstr
= Glib::build_filename (base
, legal_name
);
3731 cerr
<< "Rename " << oldstr
<< " => " << newstr
<< endl
;
3733 if (RENAME (oldstr
.c_str(), newstr
.c_str()) != 0) {
3738 (*_session_dir
) = newstr
;
3743 /* directory below interchange */
3745 v
.push_back (newstr
);
3746 v
.push_back (interchange_dir_name
);
3749 oldstr
= Glib::build_filename (v
);
3752 v
.push_back (newstr
);
3753 v
.push_back (interchange_dir_name
);
3754 v
.push_back (legal_name
);
3756 newstr
= Glib::build_filename (v
);
3758 cerr
<< "Rename " << oldstr
<< " => " << newstr
<< endl
;
3760 if (RENAME (oldstr
.c_str(), newstr
.c_str()) != 0) {
3767 oldstr
= Glib::build_filename (newpath
, _current_snapshot_name
) + statefile_suffix
;
3768 newstr
= Glib::build_filename (newpath
, legal_name
) + statefile_suffix
;
3770 cerr
<< "Rename " << oldstr
<< " => " << newstr
<< endl
;
3772 if (RENAME (oldstr
.c_str(), newstr
.c_str()) != 0) {
3779 oldstr
= Glib::build_filename (newpath
, _current_snapshot_name
) + history_suffix
;
3781 if (Glib::file_test (oldstr
, Glib::FILE_TEST_EXISTS
)) {
3782 newstr
= Glib::build_filename (newpath
, legal_name
) + history_suffix
;
3784 cerr
<< "Rename " << oldstr
<< " => " << newstr
<< endl
;
3786 if (RENAME (oldstr
.c_str(), newstr
.c_str()) != 0) {
3791 /* remove old name from recent sessions */
3793 remove_recent_sessions (_path
);
3796 _current_snapshot_name
= new_name
;
3801 /* save state again to get everything just right */
3803 save_state (_current_snapshot_name
);
3806 /* add to recent sessions */
3808 store_recent_sessions (new_name
, _path
);